Numerous Pulsating Martians

    coffee
    TypeScript icon, indicating that this package has built-in type declarations

    5.4.0 • Public • Published

    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.

    Install

    npm i coffee

    DownloadsWeekly Downloads

    35,003

    Version

    5.4.0

    License

    MIT

    Unpacked Size

    30.5 kB

    Total Files

    9

    Last publish

    Collaborators

    • atian25
    • dead_horse
    • fengmk2
    • popomore