VSCode Newbie: Remote Jest/Node debugging through Docker

Viewed 1746

I've recently switched from Vim to VSCode, and I'm trying to set up VSCode debugging for jest tests run through docker.

The debugging works...sort of. If I want to run jest tests and have breakpoints activate, I need to:

  1. Insert the breakpoints
  2. Start running the relevant jest test(s) via the vscode-jest-tests launch.json task below
  3. Quickly execute Docker: Attach To Node before the test suite hits breakpoints

Obviously not ideal - I'd love to ensure VSCode automatically attaches to the debugger upon running vscode-jest-tests. In short: is there an easy way to attach the VSCode debugger when running Jest tests through Docker?

Here are my current launch.json and package.json files. Any help very appreciated:

launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "attach",
      "name": "Docker: Attach to Node",
      "port": 9229,
      "address": "localhost",
      "localRoot": "${workspaceFolder}",
      "remoteRoot": "/www",
      "protocol": "inspector"
    },
    {
      "type": "node",
      "request": "launch",
      "name": "vscode-jest-tests",
      "runtimeExecutable": "npm",
      "runtimeArgs": [ "run", "test:debug" ],
      "address": "127.0.0.1",
      "port": 9229,
      "breakOnLoad": true,
      "restart": true,
      "timeout": 10000,
      "localRoot": "${workspaceFolder}",
      "remoteRoot": "/www",
      "outFiles": [
        "${workspaceFolder}/dist/**/*.js"
      ],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen"
    }
  ]
}

package.json

#...
"scripts": {
  "test:debug": "docker exec -it kiva_api node --nolazy --inspect-brk=0.0.0.0:9229 node_modules/.bin/jest --runInBand --config=test/jest-e2e.json"
}
#...

PS: If I run npm run test:debug from the command line & have a chrome debugger window open, Chrome's debugger works just fine

3 Answers

Here a shot of my solution, which comes mostly from your same question. Thank you for asking :)

First start jest in watch mode (--watchAll), so the process stays alive. (In the snippet I assume a backend container is running via docker-compose with port 9229 exposed on the host)

docker-compose exec backend \
  node --inspect=0.0.0.0:9229 -r tsconfig-paths/register -r ts-node/register \
  node_modules/.bin/jest --watchAll --runInBand 

Now in VSCode .vscode/launch.json config add a config to attach to the running process. Note: ensure remoteRoot fit your setup.

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
        "type": "node",
        "request": "attach",
        "name": "Docker: Debug tests",
        "address": "127.0.0.1",
        "port": 9229,
        "trace": true,
        "restart": true,
        "timeout": 10000,
        "localRoot": "${workspaceFolder}",
        "remoteRoot": "/app",
        "outFiles": [
            "${workspaceFolder}/dist/**/*.js"
        ],
        "disableOptimisticBPs": true,            
        "internalConsoleOptions": "neverOpen",
        "continueOnAttach": true,
    }]
}

From here on I have been able to develop and debug properly my code.

This is my launch.json configuration for debugging Jest tests with Docker.

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "name": "Docker: Jest Tests",
      "request": "launch",
      "program": "${workspaceFolder}/node_modules/.bin/jest",
      "args": [
        "--runInBand"
      ],
      "cwd": "${workspaceFolder}",
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "disableOptimisticBPs": true,
      "windows": {
        "program": "${workspaceFolder}/node_modules/jest/bin/jest",
      },
      "protocol": "inspector"
    }
  ]
}

The idea is start the docker-compose includes a database (Postgres, MongoDB, etc ...) and an api app before run and debug thru VSCode.

Most of a day later, got it.

VSCode launch.json

{
  "type": "node",
  "name": "docker-jest",
  "request": "attach",
  "address": "0.0.0.0",
  "port": 9229,
  "localRoot": "${workspaceFolder}",
  "remoteRoot": "/app", // Will depend on your setup
  "skipFiles": [
    "<node_internals>/**/*.js",
    "${workspaceFolder}/node_modules/**/*.js"
  ],
  "internalConsoleOptions": "neverOpen",
  "presentation": {
    "reveal": "silent"
  }
},

Ensure your docker container is running with port 9229 open. I used tail -d /dev/null to keep mine running. I wont go into details of a docker setup since there is plenty of online resources on the topic.

Then enter the docker container

$ docker exec -it container_name /bin/bash

And run

$ node --inspect-brk=0.0.0.0:9229 --nolazy -r ./node_modules/ts-node/register ./node_modules/jest/bin/jest.js --config=./jest-config.json --runInBand

The --runInBand flag is key for this to work.

--runInBand causes all tests to be run in the parent process rather than child processes.

You should see something like

root@7a0ba832e7f9:/app# node --inspect-brk=0.0.0.0:9229 --nolazy -r ./node_modules/ts-node/register ./node_modules/jest/bin/jest.js --config=./jest-config.json --runInBand
Debugger listening on ws://0.0.0.0:9229/267bfe8c-dfa8-45e0-a86c-abcadbd97bea
For help, see: https://nodejs.org/en/docs/inspector

Set breakpoints in your Jest .spec.ts files and execute the docker-jest debugger.


If you are continuing to have issues, ensure your app isn't already running in debug mode on the same port. The tests will continue executing with only a brief pause showing the following;

Starting inspector on 0.0.0.0:9229 failed: address already in use

If this happens, just change the debug port used in the node command and launch.json to something else and open the docker port.

Related