cli-testing-tool
Advanced tools
Comparing version 0.1.3 to 0.2.0
const AnsiTerminal = require('node-ansiterminal').AnsiTerminal; | ||
const AnsiParser = require('node-ansiparser'); | ||
// types | ||
/** | ||
* @typedef {({ | ||
* stringOutput: string, | ||
* tokenizedOutput: string, | ||
* rawOutput: string | ||
* })} ParsedOutput | ||
* | ||
* @typedef {({ | ||
* typeDelay: number, | ||
* logData: boolean, | ||
* cwd: string, | ||
* env: any | ||
* })} Options | ||
*/ | ||
// Big shoutout to https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 for super cool reference to all ansi codes | ||
@@ -21,0 +5,0 @@ const ESC = '(?:\\x1[bB])|(?:\\u001b)\\['; |
@@ -6,10 +6,36 @@ const { spawn } = require('child_process'); | ||
// types | ||
/** | ||
* @typedef {({ | ||
* stringOutput: string, | ||
* tokenizedOutput: string, | ||
* rawOutput: string | ||
* })} ParsedOutput | ||
* | ||
* @typedef {({ | ||
* typeDelay: number, | ||
* logData: boolean, | ||
* logError: boolean, | ||
* cwd: string, | ||
* env: any | ||
* })} Options | ||
*/ | ||
/** @type {Options} defaultOptions */ | ||
const defaultOptions = { | ||
typeDelay: 100, | ||
logData: false, | ||
logError: true, | ||
cwd: process.cwd(), | ||
env: undefined | ||
}; | ||
/** | ||
* | ||
* @param {string} commandString | ||
* @param {Options} options | ||
* @param {Options} userOptions | ||
*/ | ||
const createCommandInterface = (commandString, options) => { | ||
// /** @type {import('child_process').ChildProcessWithoutNullStreams} */ | ||
// let command; | ||
const createCommandInterface = (commandString, userOptions = {}) => { | ||
const options = { ...defaultOptions, ...userOptions }; | ||
const commandArgs = commandString.split(' '); | ||
@@ -19,4 +45,4 @@ const command = spawn(commandArgs[0], commandArgs.slice(1), { | ||
stdio: 'pipe', | ||
cwd: options.cwd || process.cwd(), | ||
env: options.env || undefined | ||
cwd: options.cwd, | ||
env: options.env | ||
}); | ||
@@ -53,3 +79,3 @@ | ||
await wait(options.typeDelay ? options.typeDelay : 100); | ||
await wait(options.typeDelay); | ||
@@ -70,3 +96,3 @@ return new Promise((resolve) => { | ||
/** | ||
* @returns {Promise<import('./cli-ansi-parser').ParsedOutput>} | ||
* @returns {Promise<ParsedOutput>} | ||
*/ | ||
@@ -73,0 +99,0 @@ const getOutput = () => { |
{ | ||
"name": "cli-testing-tool", | ||
"version": "0.1.3", | ||
"version": "0.2.0", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -1,6 +0,6 @@ | ||
# [WIP] CLI Testing Library | ||
# CLI Testing Tool | ||
A testing library that allows you to test input and outputs of your CLI command. | ||
*Note: This is a work in progress. The API is likely going to change.* | ||
*Note: This is a work in progress.* | ||
@@ -35,28 +35,49 @@ **Terminal Text Parsing Support Checklist** | ||
### Eg 1: Hello World Example | ||
### Testing Colored Terminal Text | ||
Check out [this example of StackBlitz](https://stackblitz.com/edit/node-kfod5b?file=examples%2Fgraphic-hello-world%2Fgraphic-hello-world.test.js) | ||
```js | ||
// hello-world.test.js | ||
// colored-greeting.test.js | ||
const { createCommandInterface } = require('cli-testing-tool'); | ||
test('should print greetings', async () => { | ||
const commandInterface = createCommandInterface('node ./hello-world.js', { | ||
cwd: __dirname, // Directory from where you want to run the command | ||
test('should print colored greetings', async () => { | ||
const commandInterface = createCommandInterface('node ./graphic-print.js', { | ||
cwd: __dirname, // considering, the test file is in the same directory as the cli file | ||
}); | ||
await commandInterface.type('Saurabh\n'); | ||
const terminal = await commandInterface.getOutput(); | ||
expect(terminal.stringOutput).toBe("What's your name?Hi, Saurabh!"); | ||
// ANSI Escape codes are tokenized into readable text token in tokenizedOutput | ||
// Helpful when libraries like inquirer or prompts add ansi-escape codes. | ||
expect(terminal.tokenizedOutput).toBe( | ||
"What's your name?Hi, [BOLD_START][RED_START]Saurabh[COLOR_END][BOLD_END]!" | ||
); | ||
// ANSI Escape codes are not tokenized. | ||
expect(terminal.rawOutput).toBe( | ||
`What's your name?Hi, \x1B[1m\x1B[31mSaurabh\x1B[39m\x1B[22m!` | ||
); | ||
// ANSI Escape codes are removed | ||
expect(terminal.stringOutput).toBe(`What's your name?Hi, Saurabh!`); | ||
}); | ||
``` | ||
The code that we're testing- | ||
<details> | ||
<summary>Code of the CLI that we're testing in above snippet</summary> | ||
```js | ||
// hello-world.js | ||
// colored-greeting.js | ||
const readline = require('readline').createInterface({ | ||
input: process.stdin, | ||
output: process.stdout, | ||
output: process.stdout | ||
}); | ||
const bold = (str) => `\x1b[1m${str}\x1b[22m`; | ||
const red = (str) => `\x1b[31m${str}\x1b[39m`; | ||
readline.question(`What's your name?`, (name) => { | ||
console.log(`Hi, ${name}!`); | ||
console.log(`Hi, ${bold(red('Saurabh'))}!`); | ||
readline.close(); | ||
@@ -67,28 +88,26 @@ }); | ||
### Eg 2: Tokenized Output | ||
</details> | ||
Check out [this example of StackBlitz](https://stackblitz.com/edit/node-kfod5b?file=examples%2Fcolored-output%2Fcolored-output.test.js) | ||
Sometimes you may want to test if the output has correct color and graphics. You can use the `.tokenizedOutput` method to get tokens in the output. | ||
Check out [list of tokens](https://github.com/saurabhdaware/cli-testing-tool/blob/18e1e12d86cec7b429f949cdd571b13b64fd4747/lib/cli-ansi-parser.js#L28) that library outputs. | ||
## Options | ||
You can pass options as 2nd param to `createCommandInterface`. | ||
The default options are: | ||
```js | ||
// colored-output.test.js | ||
const { createCommandInterface } = require('cli-testing-tool'); | ||
test('should have bold red text', async () => { | ||
const commandInterface = createCommandInterface('node ./colored-output.js', { | ||
cwd: __dirname, | ||
}); | ||
const terminal = await commandInterface.getOutput(); | ||
expect(terminal.tokenizedOutput).toBe("This has a [BOLD_START][RED_START]red and bold[COLOR_END][BOLD_END] text."); | ||
}); | ||
const defaultOptions = { | ||
typeDelay: 100, // number. delay between each `.type()` call | ||
logData: false, // boolean. if true, logs the command data on terminal | ||
logError: true, // boolean. if false, won't add command errors on terminal | ||
cwd: process.cwd(), // string. working directory from where your simulated command is executed | ||
env: undefined // object | undefined. environment variables object if there are any | ||
}; | ||
``` | ||
[More Examples on Stackblitz](https://stackblitz.com/edit/node-kfod5b?file=examples%2Fprompts%2Fprompts.test.js) | ||
---- | ||
Big Shoutout to | ||
- [@fnky](https://github.com/fnky) for the [list of all ansi escape codes](https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797). | ||
- [@netzkolchose](https://github.com/netzkolchose) for [node-ansiterminal](https://github.com/netzkolchose/node-ansiterminal) library. | ||
- [@netzkolchose](https://github.com/netzkolchose) for [node-ansiterminal](https://github.com/netzkolchose/node-ansiterminal) library. |
10572
226
111