How to use Jest in Angular aka make unit testing great (again)

Make unit testing in Angular fun again with Jest, the spectacular test runner from Facebook

Ali Kamalizade
Published in
4 min readApr 1, 2019

--

Angular is a powerful framework for creating web applications. The Angular team has put a great emphasis on providing a good testing experience. In fact, I like to write unit tests not only for simple functions but whole components. In smaller projects with few dependencies, I can easily follow a TDD-style approach.

However, the testing experience is far worse to me (and others, just google it) when the projects are fairly large:

  • (Initial) build times are slow
  • Recompiling often does not work reliably
  • The productivity is lower than it should be. Especially for components which import lots of other components and modules, running those tests becomes cumbersome.

Facebook created a great testing framework called Jest. Jest is using jsdom under the hood and thereby supports most of the DOM API you need for testing your web app. Jest is supposed to be faster than other test runners by parallelizing tests. The killer feature is the CLI which improves the testing experience a lot. Compared to Jasmine or other JavaScript frameworks, the configuration effort is greatly reduced. Additionally, you can generate code coverage out-of-the-box.

Fortunately, Jest is not only usable in React projects but also in Angular, Vue.js and basically every JS framework. In this tutorial, I want to show how you can replace the default Angular testing with Jest.

How to setup Jest in an Angular project

  1. Create an Angular CLI project if you have not created one yet.
  2. We need to install Jest and typings: npm install jest @types/jest --only=dev.
  3. To make Jest know how to work in an Angular environment, we need to install the following NPM package: npm install jest-preset-angular.
  4. Add the Jest configuration to your package.json. Alternatively, you can create a JavaScript file to configure Jest.
  5. Adjust your test scripts: replace any ng test usage with Jest commands.
  6. Replace "jasmine" with "jest" in your tsconfig.json files.
  7. Remove Jasmine and its typings: npm uninstall jasmine @types/jasmine.
  8. Remove any karma related packages and test.ts if you do not need to test in real browsers.

Here’s a sample package.json which includes scripts for Jest and a way to tell Jest where to find our configuration.

{
"name": "my-package",
"version": "0.0.1",
"license": "MIT",
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:cc": "jest --coverage"
},
"dependencies": {
"@angular/common": "7.2.1",
"@angular/compiler": "7.2.1",
...
},
"devDependencies": {
"@types/jest": "^24.0.6",
"jest": "^24.1.0",
"jest-preset-angular": "^6.0.2",
"ts-node": "~7.0.1",
"typescript": "3.2.4"
},
"jest": {
"preset": "jest-preset-angular",
"setupTestFrameworkScriptFile": "<rootDir>/setupJest.ts"
}
}

setupJest.ts (which is imported in package.json, you can name it differently) can be as simple as:

import 'jest-preset-angular';

Benefits of Jest (compared to Karma + Jasmine)

  • CLI: filter by a filename or test name regex pattern (reducing the need for fdescribe) and rerun tests
  • Executing tests without building the whole app allows to run our tests faster
  • Low configuration needed to get started
  • Clear documentation which makes it easy to adjust Jest to your needs
  • Testing is stable: no more sudden test runner failures while writing tests
  • You can keep most of the Jasmine syntax because Jest includes most of the Jasmine API in addition to its own API
  • Snapshot testing, a useful feature which is not available in Jasmine
  • More active community which will make Jest even better

Gotchas when switching from Karma+Jasmine to Jest

  • Some properties or functions do not exist in jsdom. For example: the innerText property is unsupported in jsdom. The primary issue is the fact that innerText (like some other properties and functions) leans on the layout engine for guidance, and jsdom has no layout engine. Instead, you can use textContent and optionally call trim() to get rid of whitespaces.
  • Importing of third-party libraries like jQuery can be tricky. If you use jQuery and expect it to be globally available, you need to add jQuery to the window object. You can do that in your setupJest.ts file.
  • Cross-browser testing is currently not well supported by Jest. If you want to do cross-browser unit testing though, you can keep all Karma related files since Jest currently does not support running in a browser (aside from Chrome using Puppeteer).
  • If you are using TypeScript paths for cleaner imports and Jest is not understanding your imports, then you need to provide Jest a paths mapping.

Bonus: run Jest tests using your IDE

Jetbrains (the maker of IntelliJ/WebStorm…) has created a Jest plugin which allows you to run tests directly from your IDE. If you are using Visual Studio Code, you can easily create a launch configuration which you can execute from inside it. All you need to do is to create a launch.json file in your .vscode folder and add the following configurations:

{
"type": "node",
"request": "launch",
"name": "Jest: Run all",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": [],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true
},
{
"type": "node",
"request": "launch",
"name": "Jest: Run current File",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": [
"${relativeFile}"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true
}
}

Conclusion

Thanks for reading this article about how to use Jest to improve your testing experience in Angular by a wide margin. Jest has become my favorite JavaScript testing solution no matter which framework I use. What are your experiences with Jest and JavaScript testing frameworks? Let me know in the comments.

--

--

Co-founder of Sunhat. Posts about software engineering, startups and anything else. 有難うございます。🚀