first-base
v1.6.0
Published
Integration testing for CLI applications
Downloads
24,024
Readme
first-base
Integration testing for CLI applications.
Usage Example
const { spawn } = require("first-base");
test("something", async () => {
const run = spawn("node", ["-i"]); // launch node REPL
await run.outputContains("> "); // wait until `> ` is logged
run.write("2 + 2\n"); // enter `2 + 2` and press enter
await run.outputContains("4"); // wait until `4` is logged
run.kill(); // Ctrl+C
await run.completion; // Wait until process exits
});API
spawn(command: string, args?: Array<string>, options?: Object) => RunContext
args and options are the same as child_process.spawn.
Returns a RunContext object; see below.
RunContext#result
An object with the following properties on it:
stdout(string): All the data the process has written to STDOUT so farstderr(string): All the data the process has written to STDERR so farcode(number | null): Exit status code, if the process has finishederror(boolean): If the process errored out, this istrue
This object gets updated over time as the process runs.
Usage
const run = spawn("ls", { cwd: __dirname });
console.log(run.result); // { stdout: '', stderr: '', code: null, error: false }
await run.completion;
console.log(run.result); // { stdout: 'README.md\npackage.json\nindex.js\n', stderr: '', code: 0, error: false }RunContext#completion
A Promise that gets resolved when the process completes. You can await it in your tests.
Usage
const run = spawn("ls", { cwd: __dirname });
await run.completion; // Waits until the `ls` process finishesRunContext#debug() => RunContext
Enables debug logging for the RunContext and returns it. Useful when your tests are failing and you want to understand what's going on.
Returns itself so you can add it to a variable declaration easily.
Usage
const run = spawn("ls", { cwd: __dirname }).debug();
// The following messages are logged to the console over time:
//
// STDOUT: README.md\npackage.json\nindex.js
// Process exited
// { stdout: 'README.md\npackage.json\nindex.js', stderr: '', code: 0, error: false }RunContext#outputContains(value: string | RegExp) => Promise<void>
Returns a Promise that will resolve once the process's output (combined STDOUT/STDERR) contains either the specified string or matches the specified RegExp. Ignores ANSI control characters.
Usage
const run = spawn("node", ["-i"]); // start Node.js REPL
await run.outputContains("> "); // Wait until prompt appearsRunContext#clearOutputContainsBuffer()
Clears the buffer of "seen" output as far as the outputContains method is concerned. Useful if the output already contains the specified value, and you want to wait until it appears a second time.
Usage
const run = spawn("node", ["-i"]); // start Node.js REPL
await run.outputContains("> "); // Wait until prompt appears
run.write("2 + 2\n"); // Write 2 + 2 then press enter
run.clearOutputContainsBuffer();
await run.outputContains("> "); // Wait until prompt appears a second time. If we hadn't cleared the buffer, this would resolve immediately.RunContext#write(data: string | Buffer)
Write some data into the process's STDIN stream.
Usage
const run = spawn("node", ["-i"]); // start Node.js REPL
await run.outputContains("> "); // Wait until prompt appears
run.write("2 + 2\n"); // Write 2 + 2 then press enter
await run.outputContains("4");RunContext#close(stream: 'stdin' | 'stdout' | 'stderr')
Close one of the processes's associated stdio streams.
Usage
const run = spawn("node", ["-i"]); // start Node.js REPL
await run.outputContains("> "); // Wait until prompt appears
run.close("stdin"); // Like pressing Ctrl+D; sends EOF
await run.completion;RunContext#kill(signal?: string)
Kills the process. If no signal is specified, it defaults to "SIGINT".
Usage
const run = spawn("node", ["-i"]);
run.kill(); // Kill with SIGINT
// OR:
run.kill("SIGKILL"); // Kill with SIGKILLRunContext#cleanResult()
A function which returns a new object with the same shape as RunContext#result but with its stdout/stderr passed through the sanitizers Array (see below).
Unlike result, this object does NOT get updated over time as the process runs.
sanitizers: Array<(string) => string>
An array of functions that will be run on stdout/stderr when calling
RunContext#cleanResult().
By default, it contains 5 functions, which are run in order:
stripAnsi: Removes ANSI control charactersreplaceRootDir: Replaces eg/home/suchipi/Code/first-base/src/index.jswith<rootDir>/src/index.js- This function searches upwards for the root dir using a heuristic, and caches results in the {@link Map}
replaceRootDir.cache. - The heuristic is:
- Look upwards for a folder containing
.gitor.hg - if none is found, look upwards for a folder containing
package-lock.json,.gitignoreor.hgignore, - if none is found, look upwards for a folder containing
package.jsonorREADME.md - if none is found, consider the present working directory to be the root dir.
- Look upwards for a folder containing
- This function searches upwards for the root dir using a heuristic, and caches results in the {@link Map}
replaceCwd: Replaces the current working directory with<cwd>collapseStackTrace: For Node.JS-style stack traces, replaces the long chain of "at ..." lines with a single "at somewhere" lineomitThrowLineNumber: For Node.JS error source display, removes the line number
You can remove them or replace them or add to them by mutating the sanitizers Array.
allInflightRunContexts: Set<RunContext>
All runs that have been spawned which haven't reached completion (see RunContext#completion).
It may be beneficial to clean these up in a test timeout handler or etc.
License
MIT
