Integrating Jest with your Angular CLI Application

Deepak Choudhary
4 min readJun 7, 2019

Unit testing your Angular application in the browser takes time and if you do not want to deal with PhantomJS or Chrome Headless then Jest is the solution you need.

WHAT IS JEST?

According to its website,

Jest is a delightful JavaScript Testing Framework with a focus on simplicity.

It works with projects using: Babel, TypeScript, Node, React, Angular, Vue and more!

Yes, Facebook. Jest is a testing framework developed by Facebook. It does not run in the browser and instead uses the jsdom. It aims to be zero-configuration, although that statement is only applicable for testing React applications.

WHY SHOULD YOU MOVE AWAY FROM KARMA JASMINE?

Because of the popular saying which goes something like this :

Karma is a b**ch.

Jokes aside. To each his own. I like my tests not having a dependency on the browser. Even if it’s a headless one.

OK, BUT WHY JEST?

For the following reasons :

  • The tests are not run in a browser, not even a headless one — it’s run in a virtual DOM (using jsdom) — and that makes it blazingly fast.
  • Since there’s little to no overhead, nor any limitations when using jsdom, tests are run in parallel.
  • Jest also executes failed tests first so you don’t
  • Jest introduces the feature of Snapshot Testing, to write “no-nonsense” tests which help you avoid writing cumbersome test setup-routines.

CONVINCED YET? HERE’S HOW TO DO IT

Here are the things I need you to have installed on your machine:

  • Node.js (use an LTS, unless you’re feeling adventurous — I used 10.x).
  • Angular CLI (the latest version will do — I used v7.x).

Here are the steps you need to follow now that you are ready:

  • Create a new angular-cli project with the following:
ng new jest-test
  • Remove all dependencies for Karma and Jasmine by executing the following command in your project root:
npm uninstall @types/jasmine @types/jasminewd2 jasmine-core jasmine-spec-reporter karma karma-chrome-launcher karma-coverage-istanbul-reporter karma-jasmine karma-jasmine-html-reporter --save-dev
  • Remove karma.conf.js and test.ts from your project folder.
  • Next, we modify our tsconfig.spec.json file to look like this:
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/spec",
"module":"commonjs",
"types": [
"node",
"jest",
"jsdom"
]
},
"files": [
"polyfills.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}
  • We will now install the packages required to run your existing test cases with Jest using:
npm install --save-dev jest jest-createspyobj jest-preset-angular babel-preset-env @types/jest @types/jsdom
  • Now that the packages are installed we need to update our npm scripts in package.json so that we can run our test cases. Update your test scripts as follows :
"test": "jest",
"test:watch": "jest --watch",
"test:ci": "jest -ci --runInBand",
"test:coverage": "jest --coverage",
  • Now we add the Jest definition in our package.json. Insert the following at the base of your package.json :
"jest": {
"preset": "jest-preset-angular",
"setupFilesAfterEnv": [
"<rootDir>/src/setupJest.ts"
]
}
  • In the previous step we mentioned that Jest needs to pick up a setupJest.ts file which we will now create in our src directory with the following content:
import 'jest-preset-angular';
import './jestGlobalMocks.ts';
  • We now need to create the jestGlobalMocks.ts file at the same level as our setupJest.ts with the following content :
global['CSS'] = null;const mock = () => {
let storage = {};
return {
getItem: key => key in storage ? storage[key] : null,
setItem: (key, value) => storage[key] = value || '',
removeItem: key => delete storage[key],
clear: () => storage = {},
};
};
Object.defineProperty(window, 'localStorage', {value: mock()});
Object.defineProperty(window, 'sessionStorage', {value: mock()});
Object.defineProperty(document, 'doctype', {
value: '<!DOCTYPE html>'
});
Object.defineProperty(window, 'getComputedStyle', {
value: () => {
return {
display: 'none',
appearance: ['-webkit-appearance']
};
}
});
/**
* ISSUE: https://github.com/angular/material2/issues/7101
* Workaround for JSDOM missing transform property
*/
Object.defineProperty(document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true,
};
},
});
  • Create a .babelrc file in your project root with the following content:
{
"presets": ["env"]
}
  • Run the following command in your project root and see your test cases get executed without the need of a browser :
npm run test

NOTE: Know that since Jest does not run in the browser we do not have access to things like localStorage which is why we mock that in our jestGlobalMocks.ts file. Jest also does not have a createSpyObject method available like jasmine which is why we are using a 3rd party package[i.e. jest-createspyobject] to let us use this.

CONCLUSION

Although Jest does not run in the browser and has a few limitations, they are quite easy to overcome. Jest is a powerful tool for unit testing and is helping developers across the globe MAKE UNIT TESTING GREAT AGAIN.

Related Articles :

This article has been inspired by Anders Skarby’s guide to migrating from Karma and Jasmine to Jest for Angular applications. You can find other links for more info below :

If you loved this article and want more articles like these, please leave comments and claps as a sign of your appreciation.

--

--

Deepak Choudhary

Technology evangelist engineering solutions on weekdays and exploring life on the weekends. The joy of life lies in the gray zone.