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-libraryLinking 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:
- The
postinstall
script automatically runs after eachnpm install.
build lib
is pretty much standard. It compiles the shared library. Angular (andng-packagr
) stores the binaries in a subfolder of the/dist
folder.- Finally, there's another
post
script that's called after eachnpm 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-devUninstall 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.tsConfigure Jest
Find the "test"
section of each sub-project in the angular.json
and replace the Jasmine configuration.
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:
Run Jest from the command line
Now you can run Jest from the command line using ng test
:
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:
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:
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