Debug Jest TypeScript in VS Code, Monorepo Edition

August 17, 2022
Two ants, fighting

Wouldn’t it be great if you could just push one button and start stepping through a Jest test script, line by line?

Writing test cases for the Jest testing framework is typically straightforward, but there can be exceptions. If Jest is being particularly persnickety with a test case you’ve written, the fastest path to getting to a solution is through debugging.

In this article, you’ll learn about setting up VS Code to debug your TypeScript Jest test cases. By the end, you’ll have a VS Code launch configuration that you can use in your projects time and time again.

Launch Configuration

Let’s start with what you’re after here: the launch configuration. Afterward, you’ll learn some fundamental properties that are being set and why.

Put this launch.json at the root of your project inside a folder named .vscode

{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Test Spec File", "protocol": "inspector", "program": "${workspaceRoot}/node_modules/jest/bin/jest.js", "args": [ "--collectCoverage=false", "--colors", "--config", "${workspaceRoot}/jest.config.js", "--runInBand", "--runTestsByPath", "${relativeFile}", "--testPathPattern=${fileDirname}", "--testTimeout=10000000" ], "outputCapture": "std", "internalConsoleOptions": "openOnSessionStart", "envFile": "${workspaceRoot}/.env", "skipFiles": [ "${workspaceRoot}/../../node_modules/**/*", "<node_internals>/**/*" ], "windows": { "skipFiles": ["C:\\**\\node_modules\\**\\*", "<node_internals>/**/*"] }, "disableOptimisticBPs": true } ] }

This file is adapted from:

vscode-recipes/debugging-jest-tests at master · microsoft/vscode-recipes

⛔️ The example provided above however does not work well in a monorepo environment, especially with generic file naming conventions relying mostly on folder names (e.g. /src/services/orders/service.ts ) for structure.

⛔ If your jest configuration is looking for files ending in a specific pattern such as *.spec.ts, the example provided above will not work because ${fileBasenameNoExtension} does not (naturally) include the extension.

Program

The program property defines what is the entry point script for Node.js. To successfully debug a Jest test case, you must debug Jest itself. Thus, set program to the absolute location of the jest dependency in your project.

To do this, the replacement variable ${workspaceRoot} is used to identify the directory containing the jest dependency.

✔ You can use a mixture of Windows and POSIX-style paths here. For cross-platform compatibility, always use / as the path separator, as Windows intrinsically handles a mixture of the two paths, while POSIX systems handle paths with only the / separator.

Args

The args property specifies the set of arguments passed to Node.js:

  • --collectCoverage=false During debug, you want to turn off code coverage

  • --colors Enable colors

  • --config ${workspaceRoot}/jest.config.js Specify the configuration for jest

  • --runInBand Ensure test cases run in the current process; not a sub-process

  • --runTestsByPath ${relativeFile} This, combined with --testPathPattern=${fileDirname} makes it possible to isolate a single test script

  • --testTimeout=10000000 Sets a much-longer timeout, allowing you to debug a test case without jest throwing a timeout error

The real magic is the combination of --runTestsByPath ${relativeFile} and --testPathPattern=${fileDirname}

📝 Both ${relativeFile} and ${fileDirname} are replacement variables you can use in your VS Code launch configuration.

📝 runTestsByPath tells jest to run test cases that match the file named ${relativeFile} — that is the relative path (from the currently open folder in VS Code) to the file having the current active focus in the VS Code editor!

📝 testPathPattern tells jest to run test cases in the directory identified by ${fileDirname} — that is the absolute directory of the same currently focused file.

The reason why you want to use both is to remove any ambiguity between two commonly named files in a monorepo project. By combining both the absolute directory and the relative path, you guarantee only the test cases in the script having the current active focus in VS Code are executed.

What makes this so powerful is that you simply put your cursor in the Jest test case you want to debug, ensure that the "Test Spec File" launch configuration is selected and press F5 to launch debug.

🚀 As an added bonus, this works on both Windows and POSIX systems. testPathPattern accepts both Windows and POSIX formats.

Output Capture

By default, VS Code does not send everything from stdout to the console. If your application executes console.log for example, it will not appear in the console.

While this seems wildly counterintuitive, simply set outputCapture to std to get past this.

Additional Options

You can also set the following additional options:

  • disableOptimisticBPs Successfully maps breakpoints to the code generated by the just-in-time transpilation of TypeScript to JavaScript

  • envFile Specify the .env file to inject environment variables into the test cases

  • skipFiles Useful to prevent the debugger from “falling into” internal Node.js code and node_modules source

See it in Action

Whether you’re working in a mono- or a microrepo, writing and debugging jest test cases in VS Code can be a breeze.

  1. Setup your launch.json file
  2. Put your cursor in the test script you want to debug
  3. Set some breakpoint(s)
  4. Press F5

Here’s a walkthrough! Thumbnail for walkthrough video

Related Posts

Implementing a Distributed Lock State Machine

December 17, 2018
A complex distributed computing problem application developers may encounter is controlling access to a resource or entity in a multi-user, concurrent environment. How can we guard against an arbitrary number of concurrent processes from potentially mutating or even having any access to an entity simultaneously?

Narrowing Types in TypeScript

April 13, 2022
Type narrowing is just what it sounds like—narrowing down a general type into something more precise. Here's how to do it.
Trey Hoover

A Deep Dive into Debugging Cypress, iframes, & Runtime Code Modification

February 18, 2021
As software engineers, a large portion of our time is spent researching, reproducing, and fixing bugs. Being able to effectively discover, track down, and resolve bugs is one of the most important skills in our toolboxes.
Dillon Mulroy