Skip to content

Testing examples using @kjanat/dreamcli/testkit.

Testing examples using @kjanat/dreamcli/testkit.

  • Source: examples/testing.ts

  • Demonstrates: runCommand(), prompt answers, env/config injection, output assertions, middleware context, and activity assertions.

Usage

bash
bun test examples/testing.ts

Source

ts
#!/usr/bin/env bun
/**
 * Testing examples using @kjanat/dreamcli/testkit.
 *
 * Demonstrates: `runCommand()`, prompt answers, env/config injection, output
 * assertions, middleware context, and activity assertions.
 *
 * This file is structured as a Vitest test suite — run with
 * `bun test examples/testing.ts`.
 *
 * Usage:
 *   bun test examples/testing.ts
 */

import { arg, command, flag, middleware } from '@kjanat/dreamcli';
import { createTestPrompter, PROMPT_CANCEL, runCommand } from '@kjanat/dreamcli/testkit';
import { describe, expect, it } from 'vitest';

// --- Command under test ---

const deploy = command('deploy')
	.description('Deploy to an environment')
	.arg('target', arg.string().describe('Deploy target'))
	.flag(
		'region',
		flag
			.enum(['us', 'eu', 'ap'])
			.env('DEPLOY_REGION')
			.config('deploy.region')
			.prompt({ kind: 'select', message: 'Which region?' })
			.describe('Target region'),
	)
	.flag('force', flag.boolean().alias('f'))
	.action(({ args, flags, out }) => {
		if (!flags.force) {
			out.warn('Use --force to skip confirmation');
		}
		out.log(`Deploying ${args.target} to ${flags.region}`);
	});

// --- Tests ---

describe('deploy command', () => {
	it('deploys with explicit flags', async () => {
		const result = await runCommand(deploy, ['production', '--region', 'eu', '--force']);

		expect(result.exitCode).toBe(0);
		expect(result.stdout).toEqual(['Deploying production to eu\n']);
		expect(result.stderr).toEqual([]);
	});

	it('resolves region from environment variable', async () => {
		const result = await runCommand(deploy, ['staging', '--force'], {
			env: { DEPLOY_REGION: 'ap' },
		});

		expect(result.exitCode).toBe(0);
		expect(result.stdout).toEqual(['Deploying staging to ap\n']);
	});

	it('resolves region from config file', async () => {
		const result = await runCommand(deploy, ['staging', '--force'], {
			config: { deploy: { region: 'eu' } },
		});

		expect(result.exitCode).toBe(0);
		expect(result.stdout).toEqual(['Deploying staging to eu\n']);
	});

	it('prompts for region when not provided', async () => {
		const result = await runCommand(deploy, ['staging', '--force'], {
			answers: ['us'],
		});

		expect(result.exitCode).toBe(0);
		expect(result.stdout).toEqual(['Deploying staging to us\n']);
	});

	it('handles prompt cancellation', async () => {
		const result = await runCommand(deploy, ['staging'], {
			prompter: createTestPrompter([PROMPT_CANCEL]),
		});

		expect(result.exitCode).not.toBe(0);
	});

	it('shows warning when --force is not set', async () => {
		const result = await runCommand(deploy, ['production', '--region', 'us']);

		expect(result.exitCode).toBe(0);
		expect(result.stderr).toEqual(['Use --force to skip confirmation\n']);
		expect(result.stdout).toEqual(['Deploying production to us\n']);
	});

	it('renders help text', async () => {
		const result = await runCommand(deploy, ['--help']);

		expect(result.exitCode).toBe(0);
		expect(result.stdout.join('')).toContain('Deploy to an environment');
		expect(result.stdout.join('')).toContain('--region');
	});
});

// --- Middleware testing ---

const auth = middleware<{ user: string }>(async ({ next }) => {
	return next({ user: 'alice' });
});

const guarded = command('secret')
	.description('Protected command')
	.middleware(auth)
	.action(({ ctx, out }) => {
		out.log(`Hello, ${ctx.user}`);
	});

describe('middleware context', () => {
	it('passes context from middleware to action', async () => {
		const result = await runCommand(guarded, []);

		expect(result.exitCode).toBe(0);
		expect(result.stdout).toEqual(['Hello, alice\n']);
	});
});

// --- Spinner/progress activity events ---

const build = command('build')
	.description('Build something')
	.action(({ out }) => {
		const spinner = out.spinner('Building...');
		spinner.succeed('Done');
	});

describe('activity events', () => {
	it('captures spinner lifecycle in activity array', async () => {
		const result = await runCommand(build, []);

		expect(result.exitCode).toBe(0);
		expect(result.activity).toContainEqual(
			expect.objectContaining({ type: 'spinner:start', text: 'Building...' }),
		);
		expect(result.activity).toContainEqual(
			expect.objectContaining({ type: 'spinner:succeed', text: 'Done' }),
		);
	});
});

Released under the MIT License.