- 7 minutes read

Since Angular 16, we've got native support for Jest! It's experimental, but that didn't stop me. I took it for a test ride.

TL;DR: Angular's native Jest integration works surprisingly well. However, it's a technology preview, so several limitations stop me from adopting it. For example, it doesn't support multi-projects, and there is no support for Visual Studio Code.

Why do we need native support?

There are a couple of community projects adding Jest support to Angular. For example, there's the "Just Jeb" project. Another popular option is using Nx, especially if you're using a monorepo. Another option is configuring Jest manually.

Until recently, the community projects and the manual configuration did their job without problems. Then Angular migrated to the ESM module system.

Suddenly, it becomes evident that Jest doesn't use the Angular compiler. Instead, it compiles the source code with help from the jest-preset-angular/setup-jest plugin. In a nutshell, this plugin adds the same functionality that the Angular compiler adds to the TypeScript compiler. But the plugin can't change the module system used by Jest. It converts the ESM modules to the CommonJS format. So you end up with double compilation plus a time-consuming conversion between module systems. Rainer Hahnekamp has an article covering the problem in depth.

Native support for Jest aims to fix both problems.

Activating the native support of Jest

It's time to get our feet wet. All you have to do is to replace the Karma builder with the Jest builder. Open the angular.json file and replace the test section with the following:

"test": { "builder": "@angular-devkit/build-angular:jest", "options": { "tsConfig": "tsconfig.spec.json", "polyfills": ["zone.js," "zone.js/testing"] } }

Next, you'll have to install Jest and the Angular builder for Jest:

npm install jest @types/jest jest-environment-jsdom --save-dev

Now it's time to update your tsconfig.*.json files. Locate the compilerOptions/types section and replace jasmine with jest:

..., "compilerOptions": { "outDir": "../../out-tsc/spec", "types": [ "jest", "node" ] }, ...

That's it. Optionally, you can remove Karma and Jasmine from your project, but I don't think that's mandatory. You can now run your tests with ng test.

What about fine-tuning Jest?

I haven't mentioned any configuration files like jest.config.js or setup-jest.ts yet, and that's no coincidence. Angular aims to be a carefree package. Plus, the Angular team needs a certain level of control. So they decided not to expose the Jest configuration. Granted, at the time of writing, the GitHub ticket is still open, so maybe that's subject to change, but it'd match the general philosophy of Angular.

Running the tests

If everything goes according to plan, this is a bit anticlimactic. You can run the tests with ng test, and the tests run unless you've got an advanced project.

Most of you (including me) have a more advanced project, so you'll have to adjust a thing or two, but if you're familiar with Jest, you'll manage. If you aren't, ask ChatGPT, Bard, or GitHub Copilot. They'll help you. Please anonymize your code before sending it to the server. Otherwise, you're giving your employer's (or even your) intellectual property to a foreign company for free.

The anticlimactic part is that the tests run without further ado. That's it.

At a second glance, there's no Karma server. There's no annoying browser window popping up. Even better, the tests run faster. You'll love it!

IDE integration

It's time to cover the rough edges. There are quite a few; I'm sure I've missed some. However, I was particularly frustrated by the lack of IDE integration. I've managed to get it working, but only just. Maybe it's more honest to say I've failed, but only by a margin.

Some time ago, I suggested using Orta's Jest plugin. It didn't work out of the box. I think I've found the reason by now, but I suspected the plugin to be incompatible, so I opted for the second-most popular Jest plugin: Jest Runner.

I prefer Jest Runner because of its limited focus: it allows me to run and debug tests with a single click in the IDE - nothing more and nothing less. Orta's plugin is more ambitious.

The long period of trial and error told me that the Jest Runer plugin requires you to add these lines to your package.json:

"jest": { "preset": "jest-preset-angular", "setupFilesAfterEnv": [ "/setupJest.ts" ] }

This configuration, in turn, refers to the setupJest.ts file, so you'll have to add it:

import 'jest-preset-angular/setup-jest'; import 'zone.js'; import 'zone.js/testing';

That's it. Now, you can run your tests from your IDE. The plugin adds a "run/debug" line above your tests so you can start or debug your tests with a single click. Hooray!

There's only one little problem: both ng test and npm run test are broken.

At the moment, I haven't found a solution. I ended up renaming the jest section of my package.json to deactivated-jest, renaming it to jest each time I want to run the tests from the IDE, and renaming it back to deactivated-jest when I want to run the tests from the command line.

I'm not happy with this solution. But then, it's a technology preview. When I started the test ride, I didn't expect it to be smooth.

What about the "import is not defined" message?

If you run into this method, your module system is configured badly in one of your tsconfig.json files. I know of two possible reasons:

  • If you want to use the IDE integration and you run into this error, activate the jest section of your package.json. When jest-preset-angular is active, it overrides the module settings of your tsconfig.json.
  • If you encounter this error when running the ng test, you must configure the module setting in the tsconfig.json file. If you've got multiple tsconfig.*.json files in your project, it's the one you've referred to in the angular.json file. The correct setting seems to be "module": "es2022".

Monorepos

This is a short section: The Angular CLI does not support Jest in monorepos. More to the point, monorepos aren't supported in Angular 17. The good news is the Angular team has it on their roadmap.

In the meantime

If you're unhappy with Jasmine and Karma or curious, you don't have to wait until the Angular team delivers. Read my follow-up articles to learn how to configure an Angular monorepo manually or how to do it using the @angular-builders/jest plugin.

Wrapping it up

At the time of writing, Angular's native support for Jest is a technology preview - nothing more and nothing less.

On the plus side, it works surprisingly well, as long as you respect its limitations: there's no IDE support or monorepo support.

My gut feeling tells me the Angular team won't abandon Jest. But that's just my gut feeling, backed by awfully little insight, apart from my experience that Jest is superior. However, whether the Angular team shares my feelings is different story.

Nonetheless, I'd encourage you to migrate to Jest, using either the manual configuration, Just Jeb's plugin, or Nrwl Nx Jest builder.

Dig deeper

Introducing Angular v17 by Minko Gechev

The original pull request adding Jest to the Angular CLI

Moving Angular CLI to Jest and Web Test Runner by Doug Parker

What's new in Angular CLI 16.0 by Ninja Squad

Angular Testing in 2023: Past, Present, and Future by Rainer Hahnekamp

Angular's Jest builder at NPM

Setup Jest in Angular Application by Scott Junk


Comments