Setup Jest for Angular with Debugging in Visual Studio Code

David Würfel - Dec 9 '19 - - Dev Community

This article aims to describe a really fast step-by-step way to setup Jest testing for Angular projects including debugging capabilities of Visual Studio Code.

Overview

I always thought that no one will ever read my blog posts. However, I myself will surely read my own as long as I haven't completely automated the following steps. The upcoming information is already present online but varies and is distributed over several sources*. My goal is to describe everything that is needed in one single post.

Why Jest?

The default test runner for Angular applications is Karma in combination with Jasmine as test framework. In recent times I often prefer Jest as testing framework. In my opinion it has some advantages over the default setup: It is headless out-of-the-box, less configuration is needed and it has some handy features like snapshot testing. Since Jest is headless which means that it won't spawn a browser window where you can open Chrome Dev Tools, it can get cumbersome to use console-logs when trying to debug while testing. The debug logs would spam the terminal and you will probably have to scroll a lot to find the outputs you are looking for. At this point you should think about using the great debugging features of your editor.

Some Prerequisites

This guide assumes that you are using Angular in version 8 (as it uses the new CLI builders). Moreover, I assume that we won't use Protractor as E2E testing framework. We're already living in heaven and may be using Cypress later. Therefore, we can safely remove anything related to Jasmine.

If you don't have an Angular application already, you may create one like you would normally do with the Angular CLI:



ng new <app-name>


Enter fullscreen mode Exit fullscreen mode

The Cleanup

When it comes to source code or configuration, I am a huge friend of less is more. Any code snippet or configuration that is not needed or commented out can be removed. Our plan is to remove any Karma and Jasmine related dependencies and entities to always have a clean project.

Remove Protractor and Jasmine (Optional)

If you really want to use Protractor for your end-to-end tests you can skip this part. Otherwise, we will remove everything related to the E2E tests. If we have done this, we can remove everything related to Jasmine, too.

Remove the following because we won't use it anymore:

  • /e2e folder containing all your end-to-end tests and configuration
  • e2e section from angular.json
  • e2e entry in the README.md
  • e2e command from the scripts in the package.json

Now we can safely uninstall Protractor and Jasmine dependencies:



npm uninstall protractor
npm uninstall jasmine-core jasmine-spec-reporter @types/jasmine @types/jasminewd2


Enter fullscreen mode Exit fullscreen mode

Remove Karma

Since we will use Jest for our entire testing we can now remove everything that is related to Karma.

Uninstall Karma dependencies:



npm uninstall karma karma-chrome-launcher karma-coverage-istanbul-reporter
karma-jasmine karma-jasmine-html-reporter


Enter fullscreen mode Exit fullscreen mode

As we don't use Karma, we can remove the following files:

  • karma.conf.js
  • src/test.ts

The Setup

We cleaned up our project from any unused resources and will now setup our toolchain to run unit tests with Jest.

Add Jest

We can start by installing Jest, it's types and new Angular builder that is used to run the Jest tests:



npm install --save-dev jest @types/jest @angular-builders/jest


Enter fullscreen mode Exit fullscreen mode

Adjust Angular CLI Configuration

Replace the previous Karma builder in the test section of the angular.json with the new Jest builder:



"test": {
  "builder": "@angular-builders/jest:run",
  "options": { 
    // The options and everything in here can be removed.
  }


Enter fullscreen mode Exit fullscreen mode

Adjust TypeScript Configurations

In your configuration for the tests (tsconfig.spec.json) change the entry jasmine in the types array to jest and remove the file src/test.ts from the files array. Set emitDecoratorMetadata and esModuleInterop to true. The first one is needed for Angular's dependency injection to work this Jest, the latter one is suggested by a Jest warning when running your tests.



{
  // ...
  {
    // ...
    "types": [
      "jest",
      "node"
    ],
    "emitDecoratorMetadata": true,
    "esModuleInterop": true
  },
  "files": ["src/polyfills.ts"]
  // ...
}


Enter fullscreen mode Exit fullscreen mode

Lastly in your main base configuration tsconfig.json also change the types entry from jasmine to jest.

Add Minimal Jest Configuration (Optional)

When running Jest it complains that it cannot find a configuration file. Since I don't like such warnings we take this opportunity to add a minimal configuration that also setups up the code coverage format. I want the coverage to output a nice HTML site as an overview. You can use one of the Istanbul reporters here.

You can create the file jest.config.js in the root of your project and add the following contents:



module.exports = {
  coverageReporters: ['html', 'text', 'text-summary']
};


Enter fullscreen mode Exit fullscreen mode

Adjust NPM Test Scripts (Optional)

I like to define two npm scripts to run my tests. The test script runs all tests and produces the code coverage. The test:watch script doesn't produce code coverage but watches for file changes (using the integrated Jest watch mode).

You can add the following to your package.json:



"scripts": {
  // ...
  "test": "ng test --coverage",
  "test:watch": "ng test --watch",
  // ...
}


Enter fullscreen mode Exit fullscreen mode

Configure Debugging in VS Code

As debugging via console-logs can be tedious, especially when your unit tests are running in headless mode, we want to use the great debugging features of Visual Studio Code. The goal is to have two launch scripts to run and debug all tests and only tests that belong to the currently opened file.

If you press F5 or switch to the Debug view in VS Code you will start one of these launch scripts. They are located in the file .vscode/launch.json. You may add as many scripts as you want.

If not already present, create the file .vscode/launch.json and add the following two launch configurations to this file:



{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Jest All",
      "program": "${workspaceFolder}/node_modules/@angular/cli/bin/ng",
      "cwd": "${workspaceFolder}",
      "args": [
        "test",
        "--testMatch=\"**/+(*.)+(spec|test).+(ts|js)?(x)\"",
        "--runInBand"
      ],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "disableOptimisticBPs": true,
    },
    {
      "type": "node",
      "request": "launch",
      "name": "Jest Current File",
      "program": "${workspaceFolder}/node_modules/@angular/cli/bin/ng",
      "cwd": "${workspaceFolder}",
      "args": [
        "test",
        "--testMatch=\"**/+(*.)+(spec|test).+(ts|js)?(x)\"",
        "--testPathPattern=${fileBasenameNoExtension}",
        "--runInBand",
      ],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "disableOptimisticBPs": true,
    }
  ]
}



Enter fullscreen mode Exit fullscreen mode

The first script Jest All will run all tests. The second one Jest Current File will run all specs with a path that matches the filename (without extension) of your currently opened file. This means if you have opened either app.component.ts or app.component.spec.ts it will run the test app.component.spec.ts because both app.component and app.component.spec match the path of your spec. Smart, isn't it? 😉

You can now set breakpoints in your specs or components that will be hit upon running these scripts. It gives you the ability to use the entire toolchain of Visual Studio Code's debugging features. You don't need to console-log all your variables, you can inspect them right inside your editor while stepping through the program execution. 🤯

Animated GIF showing debugging features of Visual Studio Code

(Un)known Issues

It really had some trouble with the launch configurations. Sometimes it worked. Most times it causes Jest not to find any tests. After about half a day of searching, debugging and trying out different parameters, I found out that this is caused by the default testMatch parameter. It appears that VS Code uses the workspaceFolder and injects it into the parameter. However, it appears that the underlying Regex is not evaluated.

The solution was to explicitly set the current working directory ("cwd": "${workspaceFolder}") and overwriting the default testMatch parameter while removing the absolute path that VS Code injects itself ("--testMatch=\"**/+(*.)+(spec|test).+(ts|js)?(x)\"").

Bright Future

As mentioned in the beginning, I will probably look up my own blog post several times. At some point in future and if I have some spare time, I want to create my own Angular Schematic to ng new an Angular project and automate these initial steps. The schematic may then basically do the following:

  1. ng new with parameter --minimal to prevent installing of any Karma or Jasmine related dependencies and files
  2. Remove E2E mentions from the README and npm scripts for now (because they will still be added)
  3. Add Jest dependencies
  4. Add tsconfig.spec.json and adjust the tsconfig.json
  5. Add test section to angular.json
  6. Add jest.config.js
  7. Add test and test:watch npm scripts
  8. Add launch.json

I hope that you will also find some value in this article. If you have any questions or remarks, just let me know. Your feedback is very welcome!

You can find the sources for this guide on GitHub:

GitHub logo MrCube42 / angular-jest-vscode-debugging

Setup Jest for Angular with debugging in Visual Studio Code.

References

*There are schematics like the one from Briebug that add Jest with a single command. However, it does some things a bit different, I wanted to describe the steps to take without a schematic first and wanted to reduce the pain of setup debugging in VS Code.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .