Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/node-modules/coffee
Test command line on Node.js
https://github.com/node-modules/coffee
cli command-line unittesting
Last synced: about 2 months ago
JSON representation
Test command line on Node.js
- Host: GitHub
- URL: https://github.com/node-modules/coffee
- Owner: node-modules
- Created: 2015-01-18T16:09:14.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2023-09-19T17:02:05.000Z (about 1 year ago)
- Last Synced: 2024-04-14T08:35:42.532Z (5 months ago)
- Topics: cli, command-line, unittesting
- Language: JavaScript
- Homepage:
- Size: 160 KB
- Stars: 99
- Watchers: 7
- Forks: 18
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
# Coffee
Test command line on Node.js.
---
[![NPM version](https://img.shields.io/npm/v/coffee.svg?style=flat)](https://npmjs.org/package/coffee)
[![Build Status](https://img.shields.io/travis/node-modules/coffee.svg?style=flat)](https://travis-ci.org/node-modules/coffee)
[![codecov.io](https://img.shields.io/codecov/c/github/node-modules/coffee.svg?style=flat)](http://codecov.io/github/node-modules/coffee?branch=master)
[![NPM downloads](http://img.shields.io/npm/dm/coffee.svg?style=flat)](https://npmjs.org/package/coffee)## Install
```bash
$ npm i coffee --save-dev
```## Usage
Coffee is useful for test command line in test frammework (like Mocha).
### Fork
You can use `fork` for spawning Node processes.
```js
const coffee = require('coffee');describe('cli', () => {
it('should fork node cli', () => {
return coffee.fork('/path/to/file.js')
.expect('stdout', '12\n')
.expect('stderr', /34/)
.expect('code', 0)
.end();
});
});
```In file.js
```js
console.log(12);
console.error(34);
```You can pass `args` and `opts` to [child_process fork](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options).
```js
coffee.fork('/path/to/file.js', [ 'args' ], { execArgv: [ '--inspect' ]})
.expect('stdout', '12\n')
.expect('stderr', '34\n')
.expect('code', 0)
.end();
```And more:
```js
coffee.fork('/path/to/file.js')
// print origin stdio
.debug()// inject a script
.beforeScript(mockScript)// interact with prompt
.waitForPrompt()
.write('tz\n')// string strict equals
.expect('stdout', 'abcdefg')
// regex
.expect('stdout', /^abc/)
// multiple
.expect('stdout', [ 'abcdefg', /abc/ ])
.expect('code', 0)
.end();
```see the API chapter below for more details.
### Spawn
You can also use `spawn` for spawning normal shell scripts.
```js
coffee.spawn('cat')
.write('1')
.write('2')
.expect('stdout', '12')
.expect('code', 0)
.end();
```## Rule
### code
Check the exit code.
```js
coffee.fork('/path/to/file.js', [ 'args' ])
.expect('code', 0)
// .expect('code', 1)
.end();
```### stdout / stderr
Check the stdout and stderr.
```js
coffee.fork('/path/to/file.js', [ 'args' ])
.expect('stdout', '12\n')
.expect('stderr', '34\n')
.expect('code', 0)
.end();
```### custom
Support custom rules, see `test/fixtures/extendable` for more details.
```js
const { Coffee, Rule } = require('coffee');class FileRule extends Rule {
constructor(opts) {
super(opts);
// `args` is which pass to `expect(type, ...args)`, `expected` is the first args.
const { args, expected } = opts;
}assert(actual, expected, message) {
// do sth
return super.assert(fs.existsSync(expected), true, `should exists file ${expected}`);
}
}class MyCoffee extends Coffee {
constructor(...args) {
super(...args);
this.setRule('file', FileRule);
}static fork(modulePath, args, opt) {
return new MyCoffee({
method: 'fork',
cmd: modulePath,
args,
opt,
});
}
}
```Usage:
```js
// test/custom.test.js
const coffee = require('MyCoffee');
coffee.fork('/path/to/file.js', [ 'args' ])
.expect('file', `${root}/README.md`);
.notExpect('file', `${root}/not-exist`);
```## Support multiple process coverage with nyc
Recommend to use [nyc] for coverage, you can use [any test frammework supported by nyc](https://istanbul.js.org/docs/tutorials/).
## API
### coffee.spawn
Run command using `child_process.spawn`, then return `Coffee` instance.
Arguments see [child_process.spawn](http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options)
### coffee.fork
Run command using `child_process.fork`, then return `Coffee` instance.
Arguments see [child_process.fork](http://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)
### coffee.Coffee
Assertion object
#### coffee.expect(type, ...args)
Assert type with expected value, expected value can be string, regular expression, and array.
```js
coffee.spawn('echo', [ 'abcdefg' ])
.expect('stdout', 'abcdefg')
.expect('stdout', /^abc/)
.expect('stdout', [ 'abcdefg', /abc/ ])
.end();
```Accept type: `stdout` / `stderr` / `code` / `error`, see built-in rules description above.
#### coffee.notExpect(type, ...args)
The opposite assertion of `expect`.
#### coffee.includes(type, ...args)
Assert type with expected string value, expected value should be string only.
```js
coffee.spawn('echo', [ 'abcdefg' ])
.includes('stdout', 'abc')
.expect('stdout', [ 'abc', 'efg' ])
.end();
```Accept type: `stdout` / `stderr`, see built-in rules description above.
#### coffee.notIncludes(type, ...args)
The opposite assertion of `includes`.
#### coffee.write(data)
Write data to stdin.
```js
coffee.fork(path.join(fixtures, 'stdin.js'))
.write('1\n')
.write('2')
.expect('stdout', '1\n2')
.end();
```#### coffee.writeKey(...args)
Write special key sequence to stdin, support `UP` / `DOWN` / `LEFT` / `RIGHT` / `ENTER` / `SPACE`.
All args will join as one key.
```js
coffee.fork(path.join(fixtures, 'stdin.js'))
.writeKey('1', 'ENTER', '2')
.expect('stdout', '1\n2')
.end();
```#### coffee.waitForPrompt(bool)
If you set false, coffee will write stdin immediately, otherwise will wait for `prompt` message.
```js
coffee.fork('/path/to/cli', [ 'abcdefg' ])
.waitForPrompt()
.write('tz\n')
// choose the second item
.writeKey('DOWN', 'DOWN', 'ENTER');
.end(done);
```**cli process should emit `prompt` message:**
> Or use `coffee.on('stdout', callback)` instead, see docs below.
```js
const readline = require('readline');const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});function ask(q, callback) {
process.send({ type: 'prompt' });
rl.question(q, callback);
}ask('What\'s your name? ', answer => {
console.log(`hi, ${answer}`);
ask('How many coffee do you want? ', answer => {
console.log(`here is your ${answer} coffee`);
rl.close();
});
});
```#### coffee.end([callback])
Callback will be called after completing the assertion, the first argument is Error if throw exception.
```js
coffee.fork('path/to/cli')
.expect('stdout', 'abcdefg')
.end(done);// recommended to left undefind and use promise style.
const { stdout, stderr, code } = await coffee.fork('path/to/cli').end();
assert(stdout.includes(abcdefg));
```#### coffee.on(event, callback)
Emit `stdout/stderr` event.
use for kill long-run process:
```js
coffee.fork('path/to/cli')
.on('stdout', (buf, { proc }) => {
if (buf.includes('egg-ready')) {
proc.exitCode = 0;
proc.kill();
}
})
.expect('stdout', 'egg-ready')
.end(done);
```use for prompt:
```js
// do not call `waitForPrompt` / `write` / `writeKey`
coffee.fork('path/to/cli')
.on('stdout', (buf, { proc }) => {
if (buf.includes('Your Name: ')) {
proc.stdin.write('TZ\n');
}
})
.expect('stdout', 'Your Name: TZ\n')
.end(done);
```#### coffee.debug(level)
Write data to process.stdout and process.stderr for debug
`level` can be
- 0 (default): pipe stdout + stderr
- 1: pipe stdout
- 2: pipe stderr
- false: disableAlternative you can use `COFFEE_DEBUG` env.
#### coffee.coverage()
If you set false, coffee will not generate coverage.json, default: true.
#### coffee.beforeScript(scriptFile)
Add a hook script before fork child process run.
### coffee.Rule
Assertion Rule base class.
## LICENSE
Copyright (c) 2017 - 2019 node-modules. Licensed under the MIT license.
[nyc]: https://github.com/istanbuljs/nyc