Setup Jest in Angular application
I had Angular applications and wanted to test and collect coverage with Jest. There are various ways to integrate Jest into Angular and I found jest-preset-angular worked well for me.
- https://www.xfive.co/blog/testing-angular-faster-jest/
- https://github.com/thymikee/jest-preset-angular
This document is a step-by-step execution note.
1. Create an Angular Application
Create an angular app and run npm install. The angular version is 12 in the laptop at the time of writing this document.
$ ng --version
...
Package Version
------------------------------------------------------
@angular-devkit/architect 0.1202.12 (cli-only)
@angular-devkit/core 12.2.12 (cli-only)
@angular-devkit/schematics 12.2.12 (cli-only)
@schematics/angular 12.2.12 (cli-only)$ ng new new-app
...
$ cd new-app
$ npm install
2. Install jest packages
Install jest, jest-preset-angular and @types/jest in devDependencies.
$ npm install -D jest jest-preset-angular @types/jest
3. Uninstall karma and jasmine packages
Open package.json and find all karma and jasmine packages. Remove them using npm remove command.
$ npm remove @types/jasmine jasmine-core karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter
4. Create 2 jest setup files
4.1 /jest.config.js
In your project root, create /jest.config.js (.js javascript file) with the following contents.
(NOTE: The file name is reserved by jest, and jest looks up this file for configuration.)
// jest.config.js (javascript file)
module.exports = {
preset: 'jest-preset-angular',
setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
};
4.2 /setup-jest.ts
In your project root, create /setup-jest.ts with the following contents.
(INFO: You may change the filename with your preference as long as the file name is matched in the jest.config.js)
// setup-jest.ts
import 'jest-preset-angular/setup-jest';
5. Update files
5.1 /tsconfig.spec.json
(1) Change types from “jasmine” to “jest”.
(2) Remove files.
// Original file created by 'ng new' command.
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": ["jasmine"]
},
"files": ["src/test.ts", "src/polyfills.ts"],
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}
The following is after the changes.
// After the changes
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": ["jest"]
},
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}
5.2 /tsconfig.json
Add “esModuleInterop”: true in the CompilorOptions to remove a warning message. (See the warning message in Appendix)
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2017",
"module": "es2020",
"lib": ["es2018", "dom"],
"esModuleInterop": true
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
},
"types": ["jest"]
}
5.3 /package.json
Change the test script from ng test to jest
"scripts": {
"test": "ng test"
},==>"scripts": {
"test": "jest --coverage"
},
6. Remove 2 files
Remove “/src/test.ts” and “/karma.config.js”.
7. Run jest with coverage option
Run npm run test, which invokes the script “jest --coverage”
$ npm run test> new-app@0.0.0 test C:\new-app
> jest --coveragePASS src/app/app.component.spec.ts
AppComponent
√ should create the app (140 ms)
√ should have as title 'new-app' (82 ms)
√ should render title (57 ms)--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
app.component.html | 100 | 100 | 100 | 100 |
app.component.ts | 100 | 100 | 100 | 100 |
--------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 3.214 s
Ran all test suites.
A. Appendix (Troubleshooting)
A1. ts-jest[config] (WARN) message TS151001:
- When you run jest, if you see this warning message,
$ jest --coveragets-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
in the /tsconfig.json file, set “esModuleInterop” to true.
// tsconfig.json
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2017",
"module": "es2020",
"lib": ["es2018", "dom"],
"esModuleInterop": true
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
},
"types": ["jest"]
}
A2. If you create /jest.config.js incorrectly with .ts extension.
$ jest --coverageError: Jest: Failed to parse the TypeScript config file C:\new-app\jest.config.ts
Error: Jest: 'ts-node' is required for the TypeScript configuration files. Make sure it is installed
Error: Cannot find module 'ts-node'
Require stack:
- C:\new-app\node_modules\jest-config\build\readConfigFileAndSetRootDir.js
- C:\new-app\node_modules\jest-config\build\index.js
- C:\new-app\node_modules\jest\node_modules\jest-cli\build\init\index.js
- C:\new-app\node_modules\jest\node_modules\jest-cli\build\cli\index.js
- C:\new-app\node_modules\jest\node_modules\jest-cli\bin\jest.js
- C:\new-app\node_modules\jest\bin\jest.js
at readConfigFileAndSetRootDir (C:\new-app\node_modules\jest-config\build\readConfigFileAndSetRootDir.js:118:13)
at async readConfig (C:\new-app\node_modules\jest-config\build\index.js:233:18)
at async readConfigs (C:\new-app\node_modules\jest-config\build\index.js:420:26)
at async runCLI (C:\new-app\node_modules\@jest\core\build\cli\index.js:132:59)
at async Object.run (C:\new-app\node_modules\jest\node_modules\jest-cli\build\cli\index.js:155:37)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! new-app@0.0.0 test: `jest --coverage`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the new-app@0.0.0 test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
Change the filename “jest.config.ts” to “jest.config.js” (javascript file)