Ron
Ron

Reputation: 1885

Debugging Jest test cases using node-inspector

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?

Upvotes: 41

Views: 13202

Answers (4)

ptaylor
ptaylor

Reputation: 171

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

Upvotes: 5

Dan Abramov
Dan Abramov

Reputation: 268255

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

Upvotes: 14

limscoder
limscoder

Reputation: 3167

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']);
};

Upvotes: 4

Sean Adkinson
Sean Adkinson

Reputation: 8605

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

Upvotes: 16

Related Questions