{"id":10638,"library":"cli-testlab","title":"CLI Testlab - Test Framework for Node.js CLIs","description":"cli-testlab is a specialized test framework designed for Node.js command-line interface (CLI) applications. Currently at stable version 6.0.1, it provides a streamlined API for executing shell commands, capturing their standard output and error streams, and asserting on their content. Key features include the `execCommand` function, which integrates robust assertion capabilities for positive, negative, and error-based output checks, supporting both string and array inputs for comprehensive validation. It also facilitates the management of environment variables per command execution and offers a `FileTestHelper` class for automatic cleanup of test-generated files. This library differentiates itself by focusing specifically on the unique challenges of CLI testing, offering built-in utilities that abstract away common complexities like child process management and output parsing, making it simpler to write reliable and maintainable tests for CLI tools without relying on heavy general-purpose test runners for these specific tasks.","status":"active","version":"6.0.1","language":"javascript","source_language":"en","source_url":"git://github.com/kibertoad/cli-testlab","tags":["javascript","cli","test","tests","testing","framework","commandline","terminal","typescript"],"install":[{"cmd":"npm install cli-testlab","lang":"bash","label":"npm"},{"cmd":"yarn add cli-testlab","lang":"bash","label":"yarn"},{"cmd":"pnpm add cli-testlab","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"cli-testlab v6+ is primarily designed for ESM usage. Direct CJS require() of named exports will likely fail unless using an interoperability layer or explicit import assertions.","wrong":"const { execCommand } = require('cli-testlab')","symbol":"execCommand","correct":"import { execCommand } from 'cli-testlab'"},{"note":"Used for managing test files with automatic cleanup. Ensure proper instantiation and use in `beforeEach`/`afterEach` hooks for automated cleanup.","wrong":"const FileTestHelper = require('cli-testlab').FileTestHelper","symbol":"FileTestHelper","correct":"import { FileTestHelper } from 'cli-testlab'"},{"note":"While named imports are preferred, for full interoperability with some environments or tooling, accessing named exports from a default import might be an alternative.","symbol":"execCommand default","correct":"import cliTestlab from 'cli-testlab'; const { execCommand } = cliTestlab;"}],"quickstart":{"code":"import { execCommand, FileTestHelper } from 'cli-testlab';\nimport { promises as fs } from 'node:fs';\nimport { resolve } from 'node:path';\n\ndescribe('My CLI application', () => {\n  let fileHelper: FileTestHelper;\n\n  beforeEach(() => {\n    fileHelper = new FileTestHelper('temp-test-dir');\n  });\n\n  afterEach(async () => {\n    await fileHelper.cleanup();\n  });\n\n  it('should report version correctly', async () => {\n    // Assuming 'my-cli.js' is in the same directory as the test file for simplicity\n    // In a real project, you might use 'path.resolve' to locate it.\n    await execCommand('node my-cli.js --version', {\n      expectedOutput: '1.0.0',\n      baseDir: process.cwd() // Or the directory where my-cli.js resides\n    });\n  });\n\n  it('should show an error for unknown commands', async () => {\n    await execCommand('node my-cli.js unknown-command', {\n      expectedErrorMessage: 'Unknown command',\n      baseDir: process.cwd()\n    });\n  });\n\n  it('should create a file and clean it up', async () => {\n    const testFilePath = fileHelper.createFile('test.txt', 'hello world');\n    // Assume your CLI has a command like 'my-cli.js process-file test.txt'\n    await execCommand(`node my-cli.js process-file ${testFilePath}`, {\n      expectedOutput: 'File processed'\n    });\n    // Verify the file exists before cleanup\n    await expect(fs.access(resolve(fileHelper.tempDir, 'test.txt'))).resolves.toBeUndefined();\n  });\n});","lang":"typescript","description":"This quickstart demonstrates basic command execution, output assertions, error handling, and file management with automatic cleanup using `FileTestHelper` within a typical test suite."},"warnings":[{"fix":"Consult the official cli-testlab v6 changelog on GitHub or npm for specific migration instructions and updated API signatures.","message":"Major version 6 likely introduced breaking changes. While specific changes aren't detailed in the provided README, users upgrading from v5 or earlier should review the official changelog for API shifts, particularly regarding import paths, options for `execCommand`, or assertion behavior.","severity":"breaking","affected_versions":">=6.0.0"},{"fix":"Always prepend `execCommand` calls with `await` within `async` test functions: `await execCommand(...)`.","message":"`execCommand` is an asynchronous function and must always be `await`ed. Forgetting `await` will result in tests passing prematurely or unexpected behavior, as assertions will not be evaluated.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure your testing environment uses Node.js v18 or newer. Update Node.js or configure your project's `engines` field in `package.json` to reflect this requirement.","message":"cli-testlab has a minimum Node.js version requirement of 18. Running tests with older Node.js versions will lead to errors, potentially including syntax errors for modern JavaScript features or module resolution failures.","severity":"gotcha","affected_versions":">=6.0.0"},{"fix":"Use `expectedOutput` or `notExpectedOutput` for commands expected to succeed (exit code 0). Use `expectedErrorMessage` for commands expected to fail (non-zero exit code).","message":"Assertions for successful commands (`expectedOutput`, `notExpectedOutput`) are checked against `stdout`, while `expectedErrorMessage` is checked against `stderr` specifically when a command exits with a non-zero code. Mixing these or using `expectedErrorMessage` for a successful command will not work as expected.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always instantiate `FileTestHelper` in a `beforeEach` hook and ensure `fileHelper.cleanup()` is called in an `afterEach` hook for reliable test isolation and resource management.","message":"Forgetting to use `FileTestHelper.cleanup()` or manually clean up test-generated files can lead to 'polluted' test environments, causing flaky tests or consuming excessive disk space. While `FileTestHelper` automates this, it still needs to be explicitly invoked.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure your project is configured for ESM, typically by setting `\"type\": \"module\"` in `package.json`, and use `import { execCommand } from 'cli-testlab'`. If using a bundler like Webpack or Rollup, ensure its configuration properly handles ESM modules.","cause":"Attempting to use CommonJS `require()` syntax or an outdated bundler configuration that struggles with ESM named exports, despite the package being ESM-first.","error":"TypeError: (0 , cli_testlab__WEBPACK_IMPORTED_MODULE_0__.execCommand) is not a function"},{"fix":"If the command is expected to fail, add `expectedErrorMessage: 'Partial or full error message'` to the `execCommand` options. If it's *not* expected to fail, investigate the CLI command and its environment (`baseDir`, `env`) to understand why it's returning a non-zero exit code.","cause":"The `execCommand` function throws an error if the executed command exits with a non-zero status code and no `expectedErrorMessage` is provided.","error":"Error: Command 'node my-cli.js unknown-command' failed with exit code 1 and output: '...' (stderr: '...')"},{"fix":"Verify the exact output of your CLI command (e.g., by running it manually or inspecting `result.stdout` in debug) and adjust the `expectedOutput` string to precisely match. Remember that assertions are case-sensitive and whitespace-sensitive.","cause":"The `expectedOutput` assertion failed because the specified text was not present in the command's standard output.","error":"AssertionError: Expected output 'Expected text' was not found in stdout."},{"fix":"Ensure the command string is correct and includes the necessary prefix (e.g., `node` for Node.js scripts). Check the `baseDir` option to confirm the working directory for the command execution is correct and the target script/executable exists at that relative path. If it's a globally installed binary, ensure your test runner environment has the correct PATH configured.","cause":"The shell could not find the specified command. This often happens if the command is not in the system's PATH, or the path to a Node.js script is incorrect.","error":"Error: spawn <command> ENOENT"}],"ecosystem":"npm"}