Skip to content
Branch: master
Go to file
Code

Latest commit

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
lib
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Coffee

Test command line on Node.js.


NPM version Build Status codecov.io NPM downloads

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.

Spwan

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.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.

You can’t perform that action at this time.