You can debug your Jest tests using the Node.js inspector, which integrates seamlessly with VSCode, by launching Jest with the --inspect-brk flag.
Here’s how to set it up:
First, in your package.json file, add a new script that uses the --inspect-brk flag:
{
"scripts": {
"test": "jest",
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand"
}
}
The --inspect-brk flag tells Node.js to start the inspector agent and pause execution on the very first line of code. The --runInBand flag for Jest is crucial here; it ensures that each test runs serially in a single process, making debugging much more predictable than with Jest’s default parallel test execution.
Now, open your project in VSCode. Go to the "Run and Debug" view (the icon with a play button and a bug). Click "create a launch.json file" if you don’t have one, or open your existing launch.json. Add the following configuration to your launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Jest: Debug All Tests",
"type": "node",
"request": "launch",
"runtimeArgs": [
"--inspect-brk",
"${workspaceRoot}/node_modules/.bin/jest",
"--runInBand"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"port": 9229
}
]
}
This configuration tells VSCode to launch Node.js with the inspector enabled on port 9229, executing your Jest tests. The runtimeArgs directly mirror the command you’d run in the terminal.
To start debugging, open your terminal, run npm run test:debug (or yarn test:debug), and then in VSCode, select the "Jest: Debug All Tests" configuration from the dropdown in the "Run and Debug" view and click the green play button.
VSCode will attach to the Node.js inspector. Because of --inspect-brk, execution will pause at the very beginning of your test runner. You can then set breakpoints in your test files or the code they are testing.
Let’s look at an example. Suppose you have a simple function and a test for it:
src/math.js:
export function add(a, b) {
const result = a + b; // Let's set a breakpoint here
return result;
}
src/math.test.js:
import { add } from './math';
describe('Math functions', () => {
test('should add two numbers correctly', () => {
const sum = add(5, 3);
expect(sum).toBe(8);
});
});
After starting the debug session, the execution will pause at the first line of the jest executable. You can then step through the code using the debug controls in VSCode (step over, step into, step out).
To make debugging easier, you can also configure VSCode to automatically launch the debugger when you start your debug script. Modify your launch.json like this:
{
"version": "0.2.0",
"configurations": [
{
"name": "Jest: Debug Current File",
"type": "node",
"request": "launch",
"runtimeArgs": [
"--inspect-brk",
"${workspaceRoot}/node_modules/.bin/jest",
"--runInBand",
"${relativeFile}" // This will run only the current file
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"port": 9229,
"skipFiles": [ // These are common Node.js internal modules you don't want to step into
"<node_internals>/**"
]
}
]
}
And then, in your package.json:
{
"scripts": {
"test": "jest",
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand"
}
}
Open the test file you want to debug (e.g., src/math.test.js), select "Jest: Debug Current File" from the VSCode debug dropdown, and click the play button. This will launch Jest, run only the tests in the currently open file, and break on the first line.
The --runInBand flag is essential because Jest by default runs tests in parallel worker processes. When debugging, you want a single process to attach to, and --runInBand ensures this. The inspector agent needs a single process to hook into.
If you’re using a test runner that starts multiple processes (like Jest’s default worker setup), the --inspect-brk flag on the main Node.js process won’t help you debug code running in the worker processes. --runInBand solves this by forcing Jest to use a single process.
The skipFiles option in launch.json is a quality-of-life improvement. It prevents the debugger from automatically stepping into Node.js’s internal modules, allowing you to focus on your application’s code and tests.
Once the debugger is attached and paused, you can inspect variables, step through your code line by line, and evaluate expressions in the VSCode debug console. This allows you to understand the exact state of your application at any point during the test execution, making it much easier to pinpoint the root cause of failing tests.
The next hurdle you’ll likely face is debugging asynchronous code within your tests, which requires understanding how to set breakpoints within promises or async functions and how to step through them correctly.