Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock test a Node.js CLI with Jest?

Tags:

node.js

jestjs

I'm stuck at the very beginning, simply requiring the CLI and capturing its output. I've tried two methods but both don't work.

This is my cli.js:

#!/usr/bin/env node

console.log('Testing...');
process.exit(0);

And this my cli.test.js:

test('Attempt 1', () => {
    let stdout = require("test-console").stdout;
    let output = stdout.inspectSync(function() {
        require('./cli.js');
    });
    expect(output).toBe('Testing...');
});

test('Attempt 2', () => {
    console.log = jest.fn();
    require('./cli.js');
    expect(console.log.calls).toBe(['Testing...']);
});

Doesn't really matter which test is actually being run, the output is always:

$ jest

 RUNS  bin/cli.test.js
Done in 3.10s.
like image 251
AndyO Avatar asked May 16 '18 21:05

AndyO


People also ask

Can you use Jest to test node?

Jest is a delightful JavaScript Testing Framework with a focus on simplicity. It works with projects using: Babel, TypeScript, Node, React, Angular, Vue and more!

How do I run a Jest test in node JS?

In order to run a specific test, you'll need to use the jest command. npm test will not work. To access jest directly on the command line, install it via npm i -g jest-cli or yarn global add jest-cli . Then simply run your specific test with jest bar.

Can you run Jest tests from the terminal?

You can run Jest directly from the CLI (if it's globally available in your PATH , e.g. by yarn global add jest or npm install jest --global ) with a variety of useful options.

How do you mock in node JS?

In Jest, Node. js modules are automatically mocked in your tests when you place the mock files in a __mocks__ folder that's next to the node_modules folder. For example, if you a file called __mock__/fs. js , then every time the fs module is called in your test, Jest will automatically use the mocks.


1 Answers

Node.js CLI applications are no different to other applications except their reliance on environment. They are expected to extensively use process members, e.g.:

  • process.stdin
  • process.stdout
  • process.argv
  • process.exit

If any of these things are used, they should be mocked and tested accordingly.

Since console.log is called directly for output, there's no problem to spy on it directly, although helper packages like test-console can be used too.

In this case process.exit(0) is called in imported file, so spec file early exits, and next Done output is from parent process. It should be stubbed. Throwing the error is necessary so that code execution is stopped - to mimic the normal behavior:

test('Attempt 2', () => {
    const spy = jest.spyOn(console, 'log');
    jest.spyOn(process, 'exit').mockImplementationOnce(() => {
      throw new Error('process.exit() was called.')
    });

    expect(() => {
      require('./cli.js');
    }).toThrow('process.exit() was called.');
    expect(spy.mock.calls).toEqual([['Testing...']]);
    expect(process.exit).toHaveBeenCalledWith(0);
});
like image 147
Estus Flask Avatar answered Sep 21 '22 15:09

Estus Flask