# coffee

> Test command line on Node.js.

Latest version **5.5.1** (published 2023-09-19) · MIT license · 0 weekly downloads

## Install

```sh
npm install coffee
pnpm add coffee
yarn add coffee
bun add coffee
```

## Health

**Score 25/100 (F)** — status: abandoned.

Positive: has types; no vulnerabilities; high quality score.

Warnings: low downloads; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 5.5.1 |
| Published | 2023-09-19 |
| First published | 2015-01-13 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | CommonJS |
| Node | >= 6.0.0 |
| Dependencies | 3 |
| Unpacked size | 27 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 99 |
| Author | popomore |
| Maintainers | atian25, dead_horse, popomore, fengmk2 |
| Keywords | cli, test, shell, spawn, fork, child_process, exec |

## Links

- npm: https://www.npmjs.com/package/coffee
- Repository: https://github.com/node-modules/coffee
- Issues: https://github.com/node-modules/coffee/issues
- npm.io page: https://npm.io/package/coffee

## Dependencies (3)

- [debug](https://npm.io/package/debug.md) ^4.1.0
- [is-type-of](https://npm.io/package/is-type-of.md) ^1.2.1
- [cross-spawn](https://npm.io/package/cross-spawn.md) ^6.0.5

## Alternatives

- [duck](https://npm.io/package/duck.md) — 4.2M weekly downloads
- [ava](https://npm.io/package/ava.md) — 560.2K weekly downloads
- [storybook-addon-module-mock](https://npm.io/package/storybook-addon-module-mock.md) — 71.7K weekly downloads
- [vest](https://npm.io/package/vest.md) — 50.1K weekly downloads
- [@ethereum-waffle/mock-contract](https://npm.io/package/@ethereum-waffle/mock-contract.md) — 40.0K weekly downloads

## Recent versions

- 5.5.1 (latest) — 2023-09-19
- 4.2.1 (latest-4) — 2018-09-28
- 3.3.3 (latest-3) — 2018-09-28
- 5.5.0 — 2022-11-22
- 5.4.0 — 2020-04-28
- 5.3.0 — 2020-04-22
- 5.2.2 — 2019-07-30
- 5.2.1 — 2018-12-27
- 5.2.0 — 2018-12-21
- 5.1.1 — 2018-12-17
- 5.1.0 — 2018-08-08
- 5.0.1 — 2018-08-07
- 4.2.0 — 2018-08-01
- 4.1.0 — 2017-06-29
- 4.0.1 — 2017-06-18
- … 25 more at https://npm.io/package/coffee/versions

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

[nyc]: https://github.com/istanbuljs/nyc

---
_Source: https://npm.io/package/coffee · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
