# Coffee
|
|
Test command line on Node.js.
|
|
---
|
|
[](https://npmjs.org/package/coffee)
|
[](https://travis-ci.org/node-modules/coffee)
|
[](http://codecov.io/github/node-modules/coffee?branch=master)
|
[](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.
|
|
### Spwan
|
|
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.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:
|
|
```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.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: disable
|
|
Alternative 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.
|
|
## LISENCE
|
|
Copyright (c) 2017 node-modules. Licensed under the MIT license.
|
|
[nyc]: https://github.com/istanbuljs/nyc
|