Supercharge Your Angular 17+ Testing with Jest: A Modern Configuration Guide

Angular 17 has landed, bringing with it a wave of exciting features: a new declarative control flow, simplified standalone APIs as the default, and the blazing-fast Vite + esbuild development server. This new era of Angular is all about improving developer experience and performance.
As we modernize our development workflow, it's also the perfect time to re-evaluate our testing strategy. While the default Karma and Jasmine setup has served the community well, many developers prefer the speed, powerful features, and streamlined experience offered by Jest.
But here's the catch: with the shift to Vite and esbuild in Angular 17+, the old ways of configuring Jest might not work as expected. Don't worry, we've got you covered. This guide will walk you through setting up Jest in a modern Angular 17+ project, step-by-step.
Why Bother with Jest?
If you're new to Jest, you might be wondering why you should switch. Here are a few compelling reasons:
- Incredible Speed: Jest runs tests in parallel, sandboxed processes, which can dramatically reduce your test suite's execution time.
- Zero-Config Philosophy: While we need some config for Angular, Jest aims to work out of the box for most JavaScript projects.
- Snapshot Testing: Easily track changes to your UI components by saving snapshots of their rendered output.
- Rich Mocking Library: Jest's built-in mocking capabilities are intuitive and powerful, making it easy to isolate your code for unit testing.
- All-in-One: Jest comes with everything you need: a test runner, assertion library (
expect), and mocking support. No need to install multiple packages.
The Challenge: Angular 17+ and the New Build System
The biggest change affecting Jest configuration is Angular's move away from Webpack (for development) to Vite and esbuild. This new tooling relies heavily on modern JavaScript features like ECMAScript Modules (ESM).
Jest has traditionally had a rocky relationship with ESM. Many community presets and transformers were built for the CommonJS world of Webpack. Fortunately, the brilliant maintainers of jest-preset-angular have updated the library to seamlessly handle Angular's new architecture.
The key is to use the right preset. Let's get started!
Step-by-Step Guide to Configuring Jest
We'll assume you have a fresh Angular 17+ project. If not, create one now:
ng new my-awesome-app --standalone --ssr=false
cd my-awesome-app
Step 1: Install Jest Dependencies
First, let's install Jest and its essential sidekicks. The star of the show here is jest-preset-angular, which does the heavy lifting of teaching Jest how to understand Angular components, templates, and dependency injection.
npm install --save-dev jest jest-preset-angular @types/jest
Step 2: Create the Jest Configuration File
Next, create a Jest configuration file in the root of your project. We'll name it jest.config.ts. This TypeScript file gives us type safety for our configuration.
Create jest.config.ts in your project's root directory and add the following content:
// jest.config.ts
import type { Config } from 'jest';
const config: Config = {
// The preset is the key to making Jest work with Angular.
preset: 'jest-preset-angular',
// A list of paths to modules that run some code to configure or set up the testing framework before each test.
setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
// A recommended configuration for CI environments to prevent resource exhaustion.
// This tells Jest to use a maximum of 40% of the available CPU cores.
// Using a percentage is ideal for portability across different machines.
// For local development, you might want to comment this out to use Jest's faster default (all cores - 1).
maxWorkers: '40%',
// A map from regular expressions to module names that stub out non-JavaScript files.
moduleNameMapper: {
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
},
// The test environment that will be used for testing.
testEnvironment: 'jsdom',
// By default, Jest will not transform any modules in `node_modules`.
// Here we're telling it to transform specific ES Modules that are commonly used in the Angular ecosystem.
transformIgnorePatterns: [
'node_modules/(?!.*\\.mjs$|@angular|@ng-bootstrap|@ngrx|ngx-socket-io)'
],
};
export default config;
What's happening here?
preset: 'jest-preset-angular': This is the magic wand. It configures Jest with all the necessary transformers and settings to compile and run tests for Angular code.setupFilesAfterEnv: This points to a file that will run before every test suite, which we'll create next.maxWorkers: '40%': This is a crucial setting for performance and stability, especially in CI/CD environments. It limits Jest to using a maximum of 40% of the available CPU cores to run tests in parallel. This prevents it from overloading the machine and ensures smooth operation, even on shared runners.transformIgnorePatterns: This is a key piece for the modern ecosystem. It tells Jest that it should transform certain packages insidenode_modules, as many are now published as ESM.
Step 3: Create the Jest Setup File
As referenced in our config, we need a setup file. This file imports the global setup from jest-preset-angular, which handles things like DOM serialization and setting up the testing module.
Create setup-jest.ts in your project's root directory:
// setup-jest.ts
import 'jest-preset-angular/setup-jest';
That's it! This one line is all you need.
Step 4: Update tsconfig.spec.json
Now, we need to tell TypeScript's test configuration about our new setup. Open tsconfig.spec.json and modify it to look like this:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jest" // <-- Add "jest" here
]
},
"files": [
// Add these two files to ensure TypeScript knows about them
"src/polyfills.ts",
"setup-jest.ts" // <-- Add this line
],
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
Changes:
- We added
"jest"to thetypesarray so TypeScript recognizes Jest's global functions likedescribe,it, andexpectwithout needing to import them in every file. - We added
setup-jest.tsto thefilesarray.
Step 5: Add Test Scripts to package.json
Finally, let's make running our tests easy. Open package.json and update the scripts section. You can replace the existing "test" script.
// package.json
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "jest",
"test:watch": "jest --watch",
"test:ci": "jest --runInBand --coverage"
},
Now you can run your tests with these simple commands:
npm test: Runs all tests once.npm run test:watch: Runs tests in watch mode, re-running on any file change.npm run test:ci: A good script for continuous integration, which runs tests sequentially and generates a coverage report.
Let's Write a Test!
Your existing tests should work with minimal changes. jest-preset-angular ensures that Angular's TestBed works just as you expect. Here’s what the default app.component.spec.ts might look like:
// src/app/app.component.spec.ts
import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
// Jest uses `describe`, `it` (or `test`), and `expect`
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AppComponent],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
// `expect` is from Jest, but the syntax is familiar!
expect(app).toBeTruthy();
});
it(`should have the 'my-awesome-app' title`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('my-awesome-app');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, my-awesome-app');
});
});
Run npm test, and you should see your tests passing with flying colors!
Conclusion
You've successfully replaced Karma and Jasmine with the modern, fast, and feature-rich Jest test runner in your Angular 17+ project.
By leveraging the power of jest-preset-angular and a modern configuration, you get the best of both worlds: Angular's powerful component framework and Jest's delightful testing experience. This setup not only speeds up your feedback loop but also unlocks powerful features like snapshot testing and sophisticated, portable performance management with options like maxWorkers.
Happy testing