- 6 minutes read

Using a Jest builder is an attractive option for using Jest in an Angular project. @angular-builders/jest:run is a production-ready solution. The name is a bit cumbersome, so let's call it the "Just Jeb" plugin because the author has published it on his website JustJeb.com.

In a few years, we'll probably prefer Angular's native builder, but it's not fit for production yet. I'm covering it here.

Setting up the monorepo

Before setting up Jest, let's look at the project structure. My use case is a shared library used by two applications, so the first step is to set up a monorepo. If you already have a project, compare my approach to your project. Chances are they're not very different, but minor differences often result in a broken setup. To avoid this, I've uploaded a working project on GitHub. You can use it as a reference.

Angular is an opinionated framework, so I set up my monorepo the Angular way. Probably the most future-proof option is using the Angular CLI commands. Using a workspace with subprojects sounds like the way to go:

ng new my-workspace --create-application=false cd my-workspace ng generate application app1 ng generate application app2 ng generate library my-favorite-library

Linking the library to your node_modules folder

Now, you can start implementing code in your library and using it in the applications. Most of the time, this works without further ado. However, I learned it's a good idea to treat the library like a proper library you publish to and download from npm. In particular, Jest requires you to do so.

Most other tutorials tell you to add paths to the tsconfig.json file and module_mappers to the Jest configuration, but that's tedious and poorly documented. Using npm link is easier.

In my projects, I've added a couple of scripts to the package.json to make the library available to the apps:

"scripts": { "postinstall": "npm run build:lib", "build:lib": "ng build -c production my-favorite-library," "postbuild:lib": "cd dist/my-favorite-library && npm link && npm link my-favorite-library"
  • The postinstall script automatically runs after each npm install.
  • build lib is pretty much standard. It compiles the shared library. Angular (and ng-packagr) stores the binaries in a subfolder of the /dist folder.
  • Finally, there's another post script that's called after each npm run build:lib. It makes the compiled binaries of the library available to the apps.

If you want to dive deeper, read my article about npm-link.

Running Jest on the command line

The advantage of using a build is you don't have to care much about the configuration. It reads the configuration files if they're there, but you don't need them to get started. So you're finished in a few minutes.

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

Uninstall Karma and Jasmine

If your installation contains Karma and Jasmine, you can now remove both. By default, Angular 17 doesn't install any test framework. So, this step is primarily an issue if you've got an older project.

npm uninstall karma karma-chrome-launcher karma-coverage-istanbul-reporter karma-jasmine karma-jasmine-html-reporter karma-coverage jasmine-core rm karma.config.js rm src/test.ts

Configure Jest

Find the "test" section of each sub-project in the angular.json and replace the Jasmine configuration.

"test": { "builder": "@angular-builders/jest:run", "options": { "polyfills": [ "zone.js", "zone.js/testing" ], "modulePathIgnorePatterns": [ "/projects/my-favorite-library/" ] } }

If you don't add the modulePathIgnorePatterns in the app configuration, Jest may fail because if finds the library in the dist folder and the source code. After setting the modulePathIgnorePatters, Jest finds it in the node_modules folder (unless you've forgotten to run npm link). You should omit the setting in the configuration of the library itself.

Does this sound confusing? Here's my configuration on GitHub.

Configure the tsconfig.js

The following (and final) step is configuring the tsconfig.spec.js files. Replace "jasmine" with "jest" in the types array.

Modify the tsconfig.spec.json in each sub-project:

// projects/*/tsconfig.spec.json /* To learn more about this file, see: https://angular.io/config/tsconfig. */ { "extends": "./tsconfig.app.json", "compilerOptions": { "outDir": "../../out-tsc/spec", "types": [ "jest" ] }, "include": [ "src/**/*.spec.ts", "src/**/*.d.ts" ] }

Run Jest from the command line

Now you can run Jest from the command line using ng test:

ng test my-favorite-library ng test app1 ng test app2

Adding IDE support

Currently, I'm using Visual Studio Code with the Jest Runner plugin. It allows you to run tests and test suites with a single click in the IDE.

Unfortunately, the plugin doesn't know the JustJeb builder. So you have to configure Jest manually.

Add the file setup-jest.ts to the root folder of your workspace and to the root folder of every project:

// setup-jest.ts import 'jest-preset-angular/setup-jest';

Putting the file both into the root folder and every project sounds weird. The reason is that the JustJeb builder and the IDE plugin define <rootDir> differently.

Now, add a file called config-jest.js to the root folder of every project. Note that this file has to be a JavaScript file (as opposed to the setup-jest file, which may be both JavaScript or TypeScript). Here we go:

// projects/*/config-jest.js // This file is required by the IDE plugin. If you only // need ng test to work; you can delete it. // The JustJeb plugin only needs the configuration in // the angular.json. globalThis.ngJest = { skipNgcc: true, tsconfig: 'tsconfig.spec.json', // this is the project root tsconfig }; /** @type {import('@jest/types').Config.InitialOptions} */ module.exports = { preset: 'jest-preset-angular', setupFilesAfterEnv: ['/setup-jest.ts'], };

For some reason unknown, this configuration differs from the all-manual configuration. I tried using the same configuration, but using the Angular builder seems to change a thing or two.

Wrapping it up

If you don't need IDE support, the JustJeb builder is a straightforward way to get Jest up and running. However, the IDE plugin I'm using ruins the simplicity, so I think it's better to configure Jest manually. As a side effect, you're closer to the standard, so the documentation is better (although I have to admit the JustJeb documentation is excellent).

I didn't test my setup with Webstorm yet, so I can't say anything about it yet. However, I suspect it doesn't know the JustJeb builder, so you'll need the same configuration you need for the Visual Studio Code Jest Runner plugin.

I've uploaded a working project on GitHub. The repository also contains a monorepo configured without any Angular builder and a project using the preview of Angular's native Jest builder.

Dig deeper

Jeb's article about his plugin.


Comments