mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-04-29 04:19:30 +00:00
test: add CLI version output, dispatch routing, and flag validation tests (#674)
Add 62 subprocess-based integration tests that exercise the actual index.ts entry point, catching issues that unit tests with mocked modules miss: - showVersion output format (version string, runtime, platform, arch) - Version/help flag aliases (--version, -v, -V, --help, -h) - Trailing help flags on subcommands (agents --help, matrix -h, etc.) - handleNoCommand error paths (--dry-run, --prompt without agent/cloud) - Unknown flag detection and error messaging - Flag value requirements (--prompt, -p, --prompt-file, -f) - --prompt and --prompt-file mutual exclusion - Verb alias routing (run, launch, start, deploy, exec) - Extra arguments warning - Prompt file error handling (nonexistent, directory) - Non-interactive terminal detection - Subcommand alias routing (m for matrix, ls/history for list) - List command -a/-c flag validation Agent: test-engineer Co-authored-by: A <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
cbffb856aa
commit
e103a6f2af
1 changed files with 523 additions and 0 deletions
523
cli/src/__tests__/cli-version-and-dispatch.test.ts
Normal file
523
cli/src/__tests__/cli-version-and-dispatch.test.ts
Normal file
|
|
@ -0,0 +1,523 @@
|
|||
import { describe, it, expect, beforeEach, afterEach, spyOn } from "bun:test";
|
||||
import { resolve } from "path";
|
||||
|
||||
/**
|
||||
* Tests for CLI version output and dispatch routing via subprocess execution.
|
||||
*
|
||||
* These tests exercise the ACTUAL index.ts entry point by running it as a
|
||||
* subprocess, verifying the real behavior users see when they run spawn commands.
|
||||
* This catches integration issues that unit tests with mocked modules miss:
|
||||
*
|
||||
* - showVersion: output format, runtime info (bun/node, platform, arch)
|
||||
* - Version flags: --version, -v, -V, and "version" subcommand
|
||||
* - Help flags: --help, -h, and "help" subcommand
|
||||
* - handleNoCommand: --dry-run and --prompt without agent/cloud
|
||||
* - Subcommand aliases: "m" for "matrix", "ls"/"history" for "list"
|
||||
* - Verb alias routing: "run", "launch", "start", "deploy", "exec"
|
||||
* - Unknown flag error messaging
|
||||
* - Extra args warning
|
||||
* - showInfoOrError: unknown command with fuzzy suggestions
|
||||
*
|
||||
* Agent: test-engineer
|
||||
*/
|
||||
|
||||
const CLI_PATH = resolve(import.meta.dir, "../../src/index.ts");
|
||||
const REPO_ROOT = resolve(import.meta.dir, "../../..");
|
||||
|
||||
/**
|
||||
* Run the CLI with given args as a subprocess.
|
||||
* Sets SPAWN_NO_UPDATE_CHECK to skip auto-update and BUN_ENV=test to skip
|
||||
* local manifest loading. Returns { stdout, stderr, exitCode }.
|
||||
*/
|
||||
function runCLI(
|
||||
args: string[],
|
||||
env?: Record<string, string>,
|
||||
): { stdout: string; stderr: string; exitCode: number } {
|
||||
const { spawnSync } = require("child_process");
|
||||
const result = spawnSync("bun", ["run", CLI_PATH, ...args], {
|
||||
cwd: REPO_ROOT,
|
||||
encoding: "utf-8",
|
||||
timeout: 15000,
|
||||
env: {
|
||||
...process.env,
|
||||
SPAWN_NO_UPDATE_CHECK: "1",
|
||||
BUN_ENV: "test",
|
||||
// Avoid terminal-dependent output
|
||||
TERM: "dumb",
|
||||
SPAWN_NO_UNICODE: "1",
|
||||
// Ensure no color codes in output for easier assertion
|
||||
NO_COLOR: "1",
|
||||
...env,
|
||||
},
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
return {
|
||||
stdout: (result.stdout || "").toString(),
|
||||
stderr: (result.stderr || "").toString(),
|
||||
exitCode: result.status ?? 1,
|
||||
};
|
||||
}
|
||||
|
||||
// ── showVersion output ──────────────────────────────────────────────────────
|
||||
|
||||
describe("showVersion via CLI subprocess", () => {
|
||||
it("should show version string with 'spawn v' prefix", () => {
|
||||
const { stdout, exitCode } = runCLI(["version"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toMatch(/spawn v\d+\.\d+\.\d+/);
|
||||
});
|
||||
|
||||
it("should show bun runtime info", () => {
|
||||
const { stdout, exitCode } = runCLI(["version"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("bun");
|
||||
});
|
||||
|
||||
it("should show platform info", () => {
|
||||
const { stdout, exitCode } = runCLI(["version"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain(process.platform);
|
||||
});
|
||||
|
||||
it("should show arch info", () => {
|
||||
const { stdout, exitCode } = runCLI(["version"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain(process.arch);
|
||||
});
|
||||
|
||||
it("should suggest 'spawn update' command", () => {
|
||||
const { stdout, exitCode } = runCLI(["version"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("spawn update");
|
||||
});
|
||||
|
||||
it("should show binary path", () => {
|
||||
const { stdout, exitCode } = runCLI(["version"]);
|
||||
expect(exitCode).toBe(0);
|
||||
// The binary path should contain the path to index.ts
|
||||
expect(stdout).toContain("index.ts");
|
||||
});
|
||||
});
|
||||
|
||||
// ── Version flag aliases ────────────────────────────────────────────────────
|
||||
|
||||
describe("version flag aliases", () => {
|
||||
it("--version should produce same version line as 'version'", () => {
|
||||
const versionResult = runCLI(["version"]);
|
||||
const flagResult = runCLI(["--version"]);
|
||||
expect(flagResult.exitCode).toBe(0);
|
||||
// Both should contain the version string
|
||||
const versionMatch = versionResult.stdout.match(/spawn v[\d.]+/);
|
||||
const flagMatch = flagResult.stdout.match(/spawn v[\d.]+/);
|
||||
expect(versionMatch).not.toBeNull();
|
||||
expect(flagMatch).not.toBeNull();
|
||||
expect(versionMatch![0]).toBe(flagMatch![0]);
|
||||
});
|
||||
|
||||
it("-v should produce same version line as 'version'", () => {
|
||||
const { stdout, exitCode } = runCLI(["-v"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toMatch(/spawn v\d+\.\d+\.\d+/);
|
||||
});
|
||||
|
||||
it("-V should produce same version line as 'version'", () => {
|
||||
const { stdout, exitCode } = runCLI(["-V"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toMatch(/spawn v\d+\.\d+\.\d+/);
|
||||
});
|
||||
});
|
||||
|
||||
// ── Help flags ──────────────────────────────────────────────────────────────
|
||||
|
||||
describe("help command and flags", () => {
|
||||
it("'help' should show USAGE section", () => {
|
||||
const { stdout, exitCode } = runCLI(["help"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("USAGE");
|
||||
});
|
||||
|
||||
it("--help should show USAGE section", () => {
|
||||
const { stdout, exitCode } = runCLI(["--help"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("USAGE");
|
||||
});
|
||||
|
||||
it("-h should show USAGE section", () => {
|
||||
const { stdout, exitCode } = runCLI(["-h"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("USAGE");
|
||||
});
|
||||
|
||||
it("help should include EXAMPLES section", () => {
|
||||
const { stdout } = runCLI(["help"]);
|
||||
expect(stdout).toContain("EXAMPLES");
|
||||
});
|
||||
|
||||
it("help should include AUTHENTICATION section", () => {
|
||||
const { stdout } = runCLI(["help"]);
|
||||
expect(stdout).toContain("AUTHENTICATION");
|
||||
});
|
||||
|
||||
it("help should include ENVIRONMENT VARIABLES section", () => {
|
||||
const { stdout } = runCLI(["help"]);
|
||||
expect(stdout).toContain("ENVIRONMENT VARIABLES");
|
||||
});
|
||||
|
||||
it("help should include TROUBLESHOOTING section", () => {
|
||||
const { stdout } = runCLI(["help"]);
|
||||
expect(stdout).toContain("TROUBLESHOOTING");
|
||||
});
|
||||
|
||||
it("help should mention --dry-run flag", () => {
|
||||
const { stdout } = runCLI(["help"]);
|
||||
expect(stdout).toContain("--dry-run");
|
||||
});
|
||||
|
||||
it("help should mention --prompt-file flag", () => {
|
||||
const { stdout } = runCLI(["help"]);
|
||||
expect(stdout).toContain("--prompt-file");
|
||||
});
|
||||
|
||||
it("help should mention list aliases (ls, history)", () => {
|
||||
const { stdout } = runCLI(["help"]);
|
||||
expect(stdout).toContain("ls");
|
||||
expect(stdout).toContain("history");
|
||||
});
|
||||
|
||||
it("help should mention matrix alias (m)", () => {
|
||||
const { stdout } = runCLI(["help"]);
|
||||
expect(stdout).toContain("matrix");
|
||||
});
|
||||
});
|
||||
|
||||
// ── Trailing help flag on subcommands ───────────────────────────────────────
|
||||
|
||||
describe("trailing help flag on subcommands", () => {
|
||||
it("'agents --help' should show help, not agents list", () => {
|
||||
const { stdout, exitCode } = runCLI(["agents", "--help"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("USAGE");
|
||||
});
|
||||
|
||||
it("'clouds -h' should show help", () => {
|
||||
const { stdout, exitCode } = runCLI(["clouds", "-h"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("USAGE");
|
||||
});
|
||||
|
||||
it("'matrix --help' should show help", () => {
|
||||
const { stdout, exitCode } = runCLI(["matrix", "--help"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("USAGE");
|
||||
});
|
||||
|
||||
it("'list --help' should show help", () => {
|
||||
const { stdout, exitCode } = runCLI(["list", "--help"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("USAGE");
|
||||
});
|
||||
|
||||
it("'update --help' should show help", () => {
|
||||
const { stdout, exitCode } = runCLI(["update", "--help"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("USAGE");
|
||||
});
|
||||
});
|
||||
|
||||
// ── handleNoCommand: --dry-run and --prompt without agent/cloud ─────────────
|
||||
|
||||
describe("handleNoCommand error paths", () => {
|
||||
it("--dry-run without agent/cloud should error", () => {
|
||||
const { stderr, exitCode } = runCLI(["--dry-run"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("--dry-run requires both");
|
||||
});
|
||||
|
||||
it("-n without agent/cloud should error", () => {
|
||||
const { stderr, exitCode } = runCLI(["-n"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("--dry-run requires both");
|
||||
});
|
||||
|
||||
it("--prompt without agent/cloud should error", () => {
|
||||
const { stderr, exitCode } = runCLI(["--prompt", "hello"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("--prompt requires both");
|
||||
});
|
||||
|
||||
it("--prompt-file with nonexistent file should error with file-not-found", () => {
|
||||
const { stderr, exitCode } = runCLI(["--prompt-file", "/tmp/nonexistent-spawn-test"]);
|
||||
expect(exitCode).toBe(1);
|
||||
// The file read error occurs before the no-agent/cloud check
|
||||
expect(stderr).toContain("not found");
|
||||
});
|
||||
});
|
||||
|
||||
// ── --dry-run with only agent (no cloud) ────────────────────────────────────
|
||||
|
||||
describe("--dry-run with only agent", () => {
|
||||
it("should error when --dry-run is used with agent only", () => {
|
||||
const { stderr, exitCode } = runCLI(["claude", "--dry-run"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("--dry-run requires both");
|
||||
});
|
||||
});
|
||||
|
||||
// ── --prompt with only agent (no cloud) ─────────────────────────────────────
|
||||
|
||||
describe("--prompt with only agent (no cloud)", () => {
|
||||
it("should error when --prompt is used with agent only", () => {
|
||||
const { stderr, exitCode } = runCLI(["claude", "--prompt", "hello"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("--prompt requires both");
|
||||
});
|
||||
|
||||
it("should suggest available clouds for the agent", () => {
|
||||
const { stderr, exitCode } = runCLI(["claude", "--prompt", "hello"]);
|
||||
expect(exitCode).toBe(1);
|
||||
// Should suggest cloud options
|
||||
expect(stderr).toContain("spawn claude");
|
||||
});
|
||||
});
|
||||
|
||||
// ── Unknown flag detection ──────────────────────────────────────────────────
|
||||
|
||||
describe("unknown flag detection", () => {
|
||||
it("should error on --unknown flag", () => {
|
||||
const { stderr, exitCode } = runCLI(["--unknown"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("Unknown flag");
|
||||
expect(stderr).toContain("--unknown");
|
||||
});
|
||||
|
||||
it("should show supported flags in error message", () => {
|
||||
const { stderr, exitCode } = runCLI(["--xyz"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("Supported flags");
|
||||
expect(stderr).toContain("--prompt");
|
||||
expect(stderr).toContain("--dry-run");
|
||||
expect(stderr).toContain("--help");
|
||||
expect(stderr).toContain("--version");
|
||||
});
|
||||
|
||||
it("should suggest 'spawn help' when unknown flag is used", () => {
|
||||
const { stderr, exitCode } = runCLI(["--foo"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("spawn help");
|
||||
});
|
||||
|
||||
it("should not treat -1 as a flag (numeric prefix)", () => {
|
||||
// -1 starts with - but matches /^-\d/, so it should not be caught as unknown flag
|
||||
// It will fail for other reasons (not a valid agent) but not as "unknown flag"
|
||||
const { stderr, exitCode } = runCLI(["-1"]);
|
||||
expect(stderr).not.toContain("Unknown flag");
|
||||
});
|
||||
|
||||
it("should treat --prompt-files (typo) as unknown flag", () => {
|
||||
const { stderr, exitCode } = runCLI(["--prompt-files", "test.txt"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("Unknown flag");
|
||||
expect(stderr).toContain("--prompt-files");
|
||||
});
|
||||
});
|
||||
|
||||
// ── Flag value requirements ─────────────────────────────────────────────────
|
||||
|
||||
describe("flag value requirements", () => {
|
||||
it("--prompt without value should error", () => {
|
||||
const { stderr, exitCode } = runCLI(["claude", "sprite", "--prompt"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("--prompt");
|
||||
expect(stderr).toContain("requires a value");
|
||||
});
|
||||
|
||||
it("-p without value should error", () => {
|
||||
const { stderr, exitCode } = runCLI(["claude", "sprite", "-p"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("-p");
|
||||
expect(stderr).toContain("requires a value");
|
||||
});
|
||||
|
||||
it("--prompt-file without value should error", () => {
|
||||
const { stderr, exitCode } = runCLI(["claude", "sprite", "--prompt-file"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("--prompt-file");
|
||||
expect(stderr).toContain("requires a value");
|
||||
});
|
||||
|
||||
it("-f without value should error", () => {
|
||||
const { stderr, exitCode } = runCLI(["claude", "sprite", "-f"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("-f");
|
||||
expect(stderr).toContain("requires a value");
|
||||
});
|
||||
|
||||
it("--prompt and --prompt-file together should error", () => {
|
||||
const { stderr, exitCode } = runCLI([
|
||||
"claude", "sprite",
|
||||
"--prompt", "hello",
|
||||
"--prompt-file", "/tmp/test.txt",
|
||||
]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("cannot be used together");
|
||||
});
|
||||
});
|
||||
|
||||
// ── Verb alias routing ──────────────────────────────────────────────────────
|
||||
|
||||
describe("verb alias routing", () => {
|
||||
it("'run' without args should error with usage hint", () => {
|
||||
const { stderr, exitCode } = runCLI(["run"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("requires an agent and cloud");
|
||||
});
|
||||
|
||||
it("'launch' without args should error with usage hint", () => {
|
||||
const { stderr, exitCode } = runCLI(["launch"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("requires an agent and cloud");
|
||||
});
|
||||
|
||||
it("'start' without args should error with usage hint", () => {
|
||||
const { stderr, exitCode } = runCLI(["start"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("requires an agent and cloud");
|
||||
});
|
||||
|
||||
it("'deploy' without args should error with usage hint", () => {
|
||||
const { stderr, exitCode } = runCLI(["deploy"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("requires an agent and cloud");
|
||||
});
|
||||
|
||||
it("'exec' without args should error with usage hint", () => {
|
||||
const { stderr, exitCode } = runCLI(["exec"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("requires an agent and cloud");
|
||||
});
|
||||
|
||||
it("verb alias error should mention it's optional", () => {
|
||||
const { stderr } = runCLI(["run"]);
|
||||
expect(stderr).toContain("optional");
|
||||
expect(stderr).toContain("spawn <agent> <cloud>");
|
||||
});
|
||||
});
|
||||
|
||||
// ── Extra args warning ──────────────────────────────────────────────────────
|
||||
|
||||
describe("extra arguments warning", () => {
|
||||
it("should warn about extra args after version command", () => {
|
||||
const { stderr, stdout, exitCode } = runCLI(["version", "extra"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stderr).toContain("extra argument");
|
||||
expect(stderr).toContain("ignored");
|
||||
// Should still show version
|
||||
expect(stdout).toMatch(/spawn v\d+\.\d+/);
|
||||
});
|
||||
|
||||
it("should warn about multiple extra args", () => {
|
||||
const { stderr, exitCode } = runCLI(["version", "a", "b", "c"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stderr).toContain("extra arguments");
|
||||
expect(stderr).toContain("ignored");
|
||||
});
|
||||
|
||||
it("should not warn when no extra args", () => {
|
||||
const { stderr } = runCLI(["version"]);
|
||||
expect(stderr).not.toContain("extra argument");
|
||||
});
|
||||
});
|
||||
|
||||
// ── Prompt file errors ──────────────────────────────────────────────────────
|
||||
|
||||
describe("prompt file error handling", () => {
|
||||
it("should show file-not-found error for nonexistent prompt file", () => {
|
||||
const { stderr, exitCode } = runCLI([
|
||||
"claude", "sprite",
|
||||
"--prompt-file", "/tmp/spawn-test-nonexistent-file-xyz123",
|
||||
]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("not found");
|
||||
});
|
||||
|
||||
it("should show directory error when prompt-file is a directory", () => {
|
||||
const { stderr, exitCode } = runCLI([
|
||||
"claude", "sprite",
|
||||
"--prompt-file", "/tmp",
|
||||
]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("directory");
|
||||
});
|
||||
});
|
||||
|
||||
// ── Non-interactive terminal without command ────────────────────────────────
|
||||
|
||||
describe("non-interactive terminal handling", () => {
|
||||
it("should show usage hint when no args and no TTY", () => {
|
||||
// Running as subprocess inherently lacks a TTY for stdin
|
||||
const { stderr, exitCode } = runCLI([]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("No interactive terminal");
|
||||
expect(stderr).toContain("spawn <agent> <cloud>");
|
||||
expect(stderr).toContain("spawn agents");
|
||||
expect(stderr).toContain("spawn clouds");
|
||||
expect(stderr).toContain("spawn help");
|
||||
});
|
||||
});
|
||||
|
||||
// ── Subcommand alias routing ────────────────────────────────────────────────
|
||||
|
||||
describe("subcommand alias routing", () => {
|
||||
it("'m' should work as alias for 'matrix'", () => {
|
||||
const { stdout, exitCode } = runCLI(["m"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("Availability Matrix");
|
||||
});
|
||||
|
||||
it("'agents' should list agents", () => {
|
||||
const { stdout, exitCode } = runCLI(["agents"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("Agents");
|
||||
});
|
||||
|
||||
it("'clouds' should list clouds", () => {
|
||||
const { stdout, exitCode } = runCLI(["clouds"]);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("Cloud Providers");
|
||||
});
|
||||
});
|
||||
|
||||
// ── List command aliases ────────────────────────────────────────────────────
|
||||
|
||||
describe("list command aliases", () => {
|
||||
it("'list' should not crash with empty history", () => {
|
||||
const { exitCode } = runCLI(["list"], { SPAWN_HOME: "/tmp/spawn-test-empty-home-" + Date.now() });
|
||||
// May exit 0 (shows "no spawns") or run interactive picker in non-TTY
|
||||
// The important thing is it doesn't crash
|
||||
expect(exitCode).toBeDefined();
|
||||
});
|
||||
|
||||
it("'ls' should work as alias for 'list'", () => {
|
||||
const { exitCode } = runCLI(["ls"], { SPAWN_HOME: "/tmp/spawn-test-empty-home-" + Date.now() });
|
||||
expect(exitCode).toBeDefined();
|
||||
});
|
||||
|
||||
it("'history' should work as alias for 'list'", () => {
|
||||
const { exitCode } = runCLI(["history"], { SPAWN_HOME: "/tmp/spawn-test-empty-home-" + Date.now() });
|
||||
expect(exitCode).toBeDefined();
|
||||
});
|
||||
|
||||
it("'list -a' without value should error", () => {
|
||||
const { stderr, exitCode } = runCLI(["list", "-a"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("-a");
|
||||
expect(stderr).toContain("requires");
|
||||
});
|
||||
|
||||
it("'list -c' without value should error", () => {
|
||||
const { stderr, exitCode } = runCLI(["list", "-c"]);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("-c");
|
||||
expect(stderr).toContain("requires");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue