40

Is there a way to use node-inspector to debug unit tests with Jest? It would be nice to step through sometimes to see why tests are failing

I have tried a few ways

node-debug jest --runInBand 

from the as well as starting up the inspector first eg

$ node-inspector
$ node --debug-brk .\node_modules\jest-cli --runInBand

and then navigate to http://127.0.0.1:8080/debug?port=5858

I have found that occasionally (1 in 10 or so times), the debugger opens the jest src files and its possible to debug them. Generally though, the scripts in the debugger only contain a 'no domain' folder and another irrelevant folder. Also the test scripts themselves are never loaded in the debugger.

Has anyone tried this before?

Ron
  • 1,875
  • 1
  • 18
  • 14

4 Answers4

16

Looks like the issue is that jest is using harmonize, which spawns a child process to ensure that the --harmony option is used.

harmonize/harmonize.js, lines 30-35

var node = child_process.spawn(process.argv[0], ['--harmony'].concat(process.argv.slice(1)), {});
node.stdout.pipe(process.stdout);
node.stderr.pipe(process.stderr);
node.on("close", function(code) {
    process.exit(code);
});

I was able to successfully debug jest tests (although tests that use JSX transforms are incredibly slow) by commenting out the code that jest is using to spawn the harmonized process.

node_modules/jest-cli/bin/jest.js, last lines of the file:

if (require.main === module) {
  //harmonize();                  <--- comment out
  _main(function (success) {
    process.exit(success ? 0 : 1);
  });
}

Then you can run:

$ node-debug --nodejs --harmony ./node_modules/jest-cli/bin/jest.js --runInBand

Jest relies on the --harmony flag being there, so that's why we need to add it back with --nodejs --harmony. We also add --runInBand so that the tests run in sequence, not in parallel.

This opens up the web debugger, and you can debug the tests, although it can be pretty slow to get to the test you want. Please comment if anyone knows a way to make this faster, and I'll update my answer.

You can add this to your package.json to make it easier to kick off:

...
    scripts: {
        "test": "jest",
        "test-debug": "node-debug --nodejs --harmony ./node_modules/jest-cli/bin/jest.js --runInBand"
    }
...

Of course, main concern with this solution is the editing of the jest source code. Will think about how to make a pull request to make this stick.

Created Github Issue Here: https://github.com/facebook/jest/issues/152

Sean Adkinson
  • 8,425
  • 3
  • 45
  • 64
  • Worked great for me! Didn't need the [monkeypatch](https://github.com/dcodeIO/node-harmonize/blob/master/harmonize.js#L25) and removing --runInBand seems to get you to the test a little faster. Thanks for the script tip. – Phil Toms Dec 07 '14 at 08:59
  • Yeah, my PR was declined bc of the line you just referenced where it checks for `Proxy`, but I didn't think it worked for me without the manual `--harmony` flag, but I haven't gotten around to trying again lately. If I can verify it works without the monkey patch, I'll update this answer. – Sean Adkinson Dec 08 '14 at 16:54
  • is there step by steps to get this working with webstorm debugger? – SuperUberDuper Jan 24 '16 at 03:20
14

This is now officially supported with Node >= 6.3.
Quoting Jest documentation:

Place a debugger; statement in any of your tests, and then, in your project's directory, run:

node --debug-brk --inspect ./node_modules/.bin/jest -i [any other arguments here]

This will output a link that you can open in Chrome. After opening that link, the Chrome Developer Tools will be displayed, and a breakpoint will be set at the first line of the Jest CLI script (this is done simply to give you time to open the developer tools and to prevent Jest from executing before you have time to do so). Click the button that looks like a "play" button in the upper right hand side of the screen to continue execution. When Jest executes the test that contains the debugger statement, execution will pause and you can examine the current scope and call stack.

Note: the -i cli option makes sure Jest runs test in the same process rather than spawning processes for individual tests. Normally Jest parallelizes test runs across processes but it is hard to debug many processes at the same time.

More information on the V8 inspector can be found here: https://nodejs.org/api/debugger.html#debugger_v8_inspector_integration_for_node_js

Community
  • 1
  • 1
Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
  • 3
    This looks promising, I tried it, but it never stops on the debugger statement. Any ideas? – hakunin Nov 01 '16 at 09:00
  • 1
    Same here. The script correctly start and i can open the browser window and click on the Play-like button... The debugger never gets hit though :| – Belgor Nov 21 '16 at 11:22
  • 1
    for me, the path of jest is different, so my command is `node --debug-brk --inspect ./node_modules/jest/bin/jest -i --env jest-environment-node-debug ` – Nitin Jadhav Mar 06 '17 at 05:20
  • I am also not seeing jest stop on the `debugger` statement in my spec using this approach. – dmarr Jul 19 '17 at 21:00
  • 1
    It works for me but `window` is not defined when running the tests – Tim Jul 26 '17 at 15:24
  • Use [Node.js V8 --inspector Manager NiM](https://chrome.google.com/webstore/detail/nodejs-v8-inspector-manag/gnhhdgbaldcilmgcpfddgdbkhjohddkj?hl=en) to connect automatically isntead of copying the url to the browser. Also you can type `debugger;` to setup a breakpoint in the code. I finally managed to inspect that my axios request is returning something. Now I have to check further... – Adrian Moisa Apr 22 '18 at 12:37
  • Nice! `node --inspect-brk --inspect ./node_modules/.bin/jest -i` works for me (node v14.15.5). Add a `debugger` statement in your test. Open a new tab in Chrome, right-click->inspect. Click the Node.js icon. Hit "play" icon – Stephen Kaiser May 13 '22 at 20:58
5

Using Node 7.4.0, Jest 18.x, and the jest-environment-node-debug package (from this comment), it's now possible to use the chrome devtools to debug Jest tests:

$ npm install -D jest-environment-node-debug
$ node --inspect-brk ./node_modules/.bin/jest -i --env jest-environment-node-debug
ptaylor
  • 171
  • 1
  • 7
4

Here's a Gruntfile.js config to automate @Sean's answer with Grunt.

grunt testd

OR

grunt testd --tests=MyTestName

OR

grunt testd --tests=MyTestName,AnotherTestName

Requires "node-inspector" (must be installed globally to get the node-debug bin in your path), "lodash", "jest-cli" and "grunt-shell" node modules.

var _ = require('lodash');

var commaSplitToRegex = function(input) {
  return _.map(input.split(','), function(part) {
    return '(' + part + ')';
  }).join('|');
};

var getTestRegex = function(tests) {
  if (tests) {
    return '.*' + commaSplitToRegex(tests) + '.*';
  }

  return '.*';
}

module.exports = function(grunt) {
  grunt.loadNpmTasks('grunt-shell');

  grunt.initConfig({
    shell: {
      jestd: {
        command: function() {
          var testsRegex = getTestRegex(grunt.option('tests'));
          var cmd = 'node-debug --nodejs --harmony ./node_modules/jest-cli/bin/jest.js --runInBand --config="test_utils/jest.json"';

          if (testsRegex) {
            cmd += ' "' + testsRegex + '"';
          }

          return cmd;
        }
      },
      monkeypatchjest: {
        command: 'sed -i.bak s\\/harmonize\\(\\)\\;\\/\\\\/\\\\/wtf\\/g ./node_modules/jest-cli/bin/jest.js'
      },
      unmonkeypatchjest: {
        command: 'sed -i.bak s\\/\\\\/\\\\/wtf\\/harmonize\\(\\)\\;\\/g ./node_modules/jest-cli/bin/jest.js'
      }
    }
  });

  grunt.registerTask('testd', 'Run tests with debugger.', ['shell:monkeypatchjest', 'shell:jestd']);
};
limscoder
  • 3,037
  • 2
  • 23
  • 37