coffee v5.5.1
Coffee
Test command line on Node.js.
Install
$ 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.
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
console.log(12);
console.error(34);
You can pass args
and opts
to child_process fork.
coffee.fork('/path/to/file.js', [ 'args' ], { execArgv: [ '--inspect' ]})
.expect('stdout', '12\n')
.expect('stderr', '34\n')
.expect('code', 0)
.end();
And more:
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.
coffee.spawn('cat')
.write('1')
.write('2')
.expect('stdout', '12')
.expect('code', 0)
.end();
Rule
code
Check the exit code.
coffee.fork('/path/to/file.js', [ 'args' ])
.expect('code', 0)
// .expect('code', 1)
.end();
stdout / stderr
Check the stdout and stderr.
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.
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:
// 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.
API
coffee.spawn
Run command using child_process.spawn
, then return Coffee
instance.
Arguments see child_process.spawn
coffee.fork
Run command using child_process.fork
, then return Coffee
instance.
Arguments see child_process.fork
coffee.Coffee
Assertion object
coffee.expect(type, ...args)
Assert type with expected value, expected value can be string, regular expression, and array.
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.
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.
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.
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.
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.
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.
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:
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:
// 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: 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.
LICENSE
Copyright (c) 2017 - 2019 node-modules. Licensed under the MIT license.
2 years ago
3 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
12 years ago