Brian Love
Google Developer Expert in Angular, software engineer and skier located in Denver, CO

Angular + Jest

Reading time ~3 minutes

Learn how to write unit tests for Angular using Jest. 🚀

Download

In this post I’ll be referencing code in a demo application that uses Jest. You can clone the repository or download a zip file of the source code:

Angular 6

We’ll be using Angular 6. However, much of what is demonstrated here should be applicable for Angular 2+.

We will not be using Jasmine or Karma. While we are not using Jasmine, we will learn that Jest is Jasmine-like and follows much of the same patterns, using many of the same functions to build test suites, tests and assert values and expected outcomes.

As such, you can remove the following files from a generated Angular application:

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

You can also remove the following dev dependencies in package.json:

  • jasmine-core
  • jasmine-spec-reporter
  • karma
  • karma-chrome-launcher
  • karma-coverage-istanbul-reporter
  • karma-jasmine
  • karma-jasmine-html-reporter

Why Jest?

Simple. It’s fast.

It's fast

The jest test runner uses jsdom and executes tests in parallel. Together, this makes jest a really fast test runner.

Install Jest

Install jest and the jest-preset-angular modules into your project using npm:

$ npm i -D jest jest-preset-angular

Or, with yarn:

$ yarn add -D jest jest-preset-angular

The jest-preset-angular module provides a preset configuration of Jest for Angular. After installing this, there are a few things that we need to do.

Configuration

With Jest and jest-preset-angular installed, let’s configure Jest for our Angular 6 project. First, create a jest.config.js file in the root of your project:

module.exports = {
  preset: "jest-preset-angular",
  roots: ['src'],
  setupTestFrameworkScriptFile: "<rootDir>/src/setup-jest.ts"
}

In our configuration:

  • First, we are using a preset base configuration that we installed previously.
  • Next, we instruct Jest to look for tests in the src directory.
  • Finally, we are using the src/setup-jest.ts module which will be executed before each test.

Then, create src/setup-jest.ts:

import 'jest-preset-angular';
import './jestGlobalMocks';

In this module we import the preset module as well as the src/jestGlobalMocks.ts file where we will define any necessary browser mocks. You can download the jestGlobalMocks.ts file from the example app for jest-preset-angular.

Test Scripts

The last step is updating the test scripts in the package.json file:

{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:ci": "jest --runInBand",
    "test:coverage": "jest --coverage",
  }
}

Path Mappings

If you are using path mappings for importing modules in your projet’s tsconfig.json file then you will need to add some configuration to the src/setup-jest.ts file (below).

For example, you may have path mappings configured in tsconfig.json such as:

{
  "compilerOptions": {
    baseUrl: "./",
    "paths": {
      "@core/*": ["src/app/core/*"],
      "@state/*": ["src/app/state/*"],
    }
  }
}

This allows for shortened namespace imports in your Angular project. For example, instead of this:

import { User } from '../../../../state/user/user.model';

You can use the following import statement:

import { User } from '@state/user/user.model';

In order to instruct Jest about the path mappings you must specify the moduleNameMapper configuration in the src/setup-jest.ts file to match:

module.exports = {
  preset: 'jest-preset-angular',
  setupTestFrameworkScriptFile: '<rootDir>/src/setup-jest.ts',
  moduleNameMapper: {
    '@core/(.*)': '<rootDir>/src/app/core/$1',
    '@state/(.*)': '<rootDir>/src/app/state/$1'
  }
};

Jasmine diff

As I indicated above, Jest uses an API that is very similar to Jasmine. If you find that your tests are not running with Jest, try using jest-codemods to migrate your code to Jest.

To create spies in Jest we use the jest.fn() mock function. For example, in Jasmine you might create a spy on a property in an object using the createSpyObj() method:

jasmine.createSpyObj('name', ['key'])

In Jest we simply create a mock:

jest.fn({key: jest.fn()})

Run Tests

With Jest installed and configured run the tests via:

$ npm test

Test Result

Debug in VS Code

If you’re using VS Code you can easily configure the debugger to run your Jest tests. This is helpful for debugging your tests using breakpoints.

In VS Code, open the Debug view, and then click the gear icon. This will open the .vscode/launch.json file.

Add the following configuration:

{
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Jest Test",
      "program": "${workspaceFolder}/node_modules/jest/bin/jest",
      "args": ["--runInBand"],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen"
    }
  ]
}

Select the newly created “Jest Test” configuration, set any necessary breakpoints, and then click Start Debugging (play icon).

Conclusion

I love Karma, and if you’re not writing any unit tests for your Angular applications today, start there; start writing unit tests and strive towards achieving TDD blissfulness. 🧘‍🙇

While Karma is the default test runner when creating a new Angular application using the CLI, you can easily swap this out with Jest. 🚀

Brian Love

Hi, I'm Brian. I am interested in TypeScript, Angular and Node.js. I'm married to my best friend Bonnie, I live in Denver and I ski (a lot).