Testing
Test your CLI commands by capturing stdout/stderr, exit codes, and temporary environment variables.
npm install @seedcli/testingThe testing module provides utilities for testing CLI commands in isolation by capturing output, checking exit codes, setting temporary environment variables with env(), creating mock Seed contexts with mockSeed(), and using createInterceptor() directly when needed.
Creating a Test CLI
import { build } from '@seedcli/core'
import { createTestCli } from '@seedcli/testing'
import { describe, test, expect } from 'vitest'
// Build your runtime as usual
const runtime = build('my-cli')
.src('./src')
.create()
describe('greet command', () => {
test('greets the user', async () => {
const cli = createTestCli(runtime)
const result = await cli.run('greet Alice')
expect(result.stdout).toContain('Hello, Alice!')
expect(result.exitCode).toBe(0)
})
test('shows error for missing name', async () => {
const cli = createTestCli(runtime)
const result = await cli.run('greet')
expect(result.stderr).toContain('required')
expect(result.exitCode).toBe(1)
})
})Test Result
| Property | Type | Description |
|---|---|---|
stdout | string | Captured standard output |
stderr | string | Captured standard error |
exitCode | number | Process exit code |
Builder Methods
createTestCli(runtime) returns a chainable builder with mockPrompt(), mockConfig(), mockSystem(), env(), and run().
In the current implementation, only env() affects run(). The mockPrompt(), mockConfig(), and mockSystem() methods are exposed on the builder but are not applied during execution yet.
Mock Seed
Create a mock seed context for unit testing command handlers directly. All module methods are no-ops by default — override specific properties when you need custom behavior:
import { mockSeed } from '@seedcli/testing'
test('deploy handler', async () => {
const seed = mockSeed({
args: { environment: 'staging' },
flags: { force: true },
})
await deployCommand.run(seed)
})MockSeedOptions
| Option | Type | Description |
|---|---|---|
args | Record<string, unknown> | Mock argument values |
flags | Record<string, unknown> | Mock flag values |
commandName | string | Command name (default: 'test') |
brand | string | CLI brand (default: 'test-cli') |
version | string | Version string (default: '0.0.0') |
Output Interceptor
Capture console output and exit codes by intercepting console.log, console.error, and process.exitCode:
import { createInterceptor } from '@seedcli/testing'
test('output formatting', async () => {
const interceptor = createInterceptor()
interceptor.start()
console.log('Hello, world!')
console.error('Something went wrong')
interceptor.stop()
expect(interceptor.stdout).toContain('Hello, world!')
expect(interceptor.stderr).toContain('Something went wrong')
expect(interceptor.exitCode).toBe(0)
})Note: createTestCli uses an interceptor internally — you don't need to create one manually when using createTestCli.
Testing Patterns
Testing flag validation
test('rejects invalid port', async () => {
const result = await createTestCli(runtime).run('serve --port 99999')
expect(result.stderr).toContain('Port must be between')
expect(result.exitCode).toBe(1)
})