Skip to content

@cliffx/test

The test package provides utilities for integration testing your CLI commands.

Installation

bash
pnpm add -D @cliffx/test

createTestApp

Create a test-friendly CLI instance that captures all output.

ts
import { createTestApp } from '@cliffx/test';
import { defineCommand } from '@cliffx/core';

const app = createTestApp({
  commands: [
    defineCommand({
      name: 'greet',
      options: {
        name: { type: 'string', default: 'World' },
      },
      async run({ options, ui }) {
        ui.success(`Hello, ${options.name}!`);
      },
    }),
  ],
  cliOptions: {
    name: 'test-cli',
    version: '1.0.0',
  },
});

Parameters:

ts
interface TestAppOptions {
  commands?: CommandDef[];
  cliOptions?: Partial<CliOptions>;
}

Returns:

ts
{
  cli: Cli;
  run: (args: string[]) => Promise<RunResult>;
}

RunResult

ts
interface RunResult {
  stdout: string;
  stderr: string;
  exitCode: number;
}

Usage with Vitest

ts
import { describe, it, expect } from 'vitest';
import { createTestApp } from '@cliffx/test';
import { defineCommand } from '@cliffx/core';

describe('greet', () => {
  const app = createTestApp({
    commands: [
      defineCommand({
        name: 'greet',
        options: { name: { type: 'string', default: 'World' } },
        async run({ options, ui }) {
          ui.success(`Hello, ${options.name}!`);
        },
      }),
    ],
  });

  it('greets with default name', async () => {
    const { stderr, exitCode } = await app.run(['greet']);
    expect(stderr).toContain('Hello, World!');
    expect(exitCode).toBe(0);
  });

  it('greets with custom name', async () => {
    const { stderr } = await app.run(['greet', '--name', 'Alice']);
    expect(stderr).toContain('Hello, Alice!');
  });

  it('handles unknown commands', async () => {
    const { exitCode } = await app.run(['unknown']);
    expect(exitCode).toBe(1);
  });
});

How It Works

The test harness intercepts three Node.js globals:

InterceptedCaptured As
process.stdout.writeresult.stdout
process.stderr.writeresult.stderr
process.exitresult.exitCode

After run() completes, all globals are restored to their original values. The test harness is safe to use in parallel tests.

MIT Licensed