CLI Testing Library
CLI Testing Library provides a set of simple and complete utilities for testing command-line interface (CLI) applications, encouraging good testing practices by focusing on user interaction and observable output rather than internal implementation details. Inspired by the popular React Testing Library, it helps developers simulate user input and assert on console output (stdout, stderr). The library is currently at version 3.0.1, released in January 2025, and maintains an active development cadence with regular updates and major version bumps that introduce breaking changes and improvements. Its key differentiators include a focus on accessibility and user experience in tests, first-class TypeScript support, and integration with popular test runners like Jest and Vitest through dedicated extensions. It abstracts away the complexities of spawning and managing child processes, making CLI testing straightforward.
Common errors
-
TypeError: expect(...).toBeInTheConsole is not a function
cause The custom matchers for CLI Testing Library have not been correctly imported and extended into your test runner's `expect` object.fixFor Jest, add `import 'cli-testing-library/jest'` to your test setup file or at the top of relevant test files. For Vitest, use `import 'cli-testing-library/vitest'`. -
Error: Cannot find module 'cli-testing-library/extend-expect' from ...
cause You are attempting to import the `extend-expect` module using a deprecated path, which was removed in version 3.0.0.fixUpdate your import statement to use the new test runner-specific paths: `import 'cli-testing-library/jest'` for Jest, or `import 'cli-testing-library/vitest'` for Vitest. -
TypeError: Cannot read properties of undefined (reading 'contents')
cause Your code is attempting to access `item.contents` on the `stdout` or `stderr` array, but is running against a version of `cli-testing-library` older than v2.0.0, where `stdout`/`stderr` contained raw strings/buffers.fixEither upgrade `cli-testing-library` to v2.0.0 or newer to match the expected object shape, or adjust your code to access the raw string/buffer directly (e.g., `output.stdout[0]`) if remaining on an older version.
Warnings
- breaking The `extend-expect` import path for custom matchers has been split into test-runner specific paths. Directly importing `cli-testing-library/extend-expect` will fail.
- breaking The shape of `stderr` and `stdout` arrays returned by `render` changed from `Array<string | Buffer>` to `Array<{contents: string | Buffer, timestamp: number}>`.
- breaking The underlying `chalk` dependency has been replaced with `picocolors` for performance and bundle size. While typically an internal change, direct usage of `chalk` functionality exposed through `cli-testing-library` might be affected.
- gotcha CLI Testing Library may not function properly in Windows CI environments (e.g., GitHub Actions on Windows).
Install
-
npm install cli-testing-library -
yarn add cli-testing-library -
pnpm add cli-testing-library
Imports
- render
const { render } = require('cli-testing-library')import { render } from 'cli-testing-library' - userEvent
import userEvent from 'cli-testing-library/userEvent'
import { userEvent } from 'cli-testing-library' - Jest Matchers
import 'cli-testing-library/extend-expect'
import 'cli-testing-library/jest'
Quickstart
import { resolve } from 'path';
import { render } from 'cli-testing-library';
import 'cli-testing-library/jest'; // Extend Jest's expect with CLI matchers
describe('Interactive CLI Testing', () => {
test('Should be able to make terminal input and view in-progress stdout', async () => {
// Assuming a simple Node.js script that prompts for input
const scriptPath = resolve(__dirname, './fixtures/stdio-inquirer.js');
const { clear, findByText, queryByText, userEvent } = await render('node', [
scriptPath,
]);
// Wait for the first prompt to appear
const initialPrompt = await findByText('First option');
expect(initialPrompt).toBeInTheConsole();
// Verify current selection
expect(await findByText('❯ One')).toBeInTheConsole();
// Clear console output for better readability in tests
clear();
// Simulate arrow down key press to select 'Two'
userEvent('[ArrowDown]');
// Verify new selection
expect(await findByText('❯ Two')).toBeInTheConsole();
clear();
// Simulate Enter key press to confirm selection
userEvent.keyboard('[Enter]');
// Verify the final output after selection
expect(await findByText('First option: Two')).toBeInTheConsole();
expect(await queryByText('First option: Three')).not.toBeInTheConsole();
// Optional: Clean up after the test if the CLI process persists
// await cleanup();
}, 10000); // Increase timeout for interactive CLI tests
});