Categories:
Migrate unittest from Jasmine to Jest
How to migrate a component unit tests from Jasmine to Jest
Migration steps
Step 1. Delete references to karma and jasmine
-
Delete the files:
src/karma.conf.jsandsrc/test.ts -
In
package.jsonremove the karma and jasmine packages fromdevDependencies.For example:
"@types/jasmine": "~3.5.0", "@types/jasminewd2": "~2.0.3", "jasmine-core": "~3.6.0", "jasmine-spec-reporter": "~5.0.0", "karma": "~5.0.0", "karma-chrome-launcher": "~3.1.0", "karma-coverage-istanbul-reporter": "~3.0.2", "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "^1.5.0", -
Uninstall these dependencies:
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
Step 2. Install jest packages
Execute the following command:
npm i -D jest @types/jest @angular-builders/jest
Step 3. Configure jest
-
Add a file named
jest.config.js(in the same folder aspackage.json)
More information: https://jestjs.io/es-ES/docs/configuration#opcionesmodule.exports = { preset: 'jest-preset-angular', setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'], collectCoverage: false, coverageDirectory: 'coverage/testing-in-jest', testMatch: [ '<rootDir>/src/**/*.spec.ts', ], coverageReporters: ['lcovonly', 'text-summary', 'cobertura'], coverageThreshold: { global: { statements: 10, lines: 10, branches: 10, functions: 10 } }, reporters: ['default'], }; -
Add file
test-config.helpers.tsimport { TestBed } from '@angular/core/testing'; type CompilerOptions = Partial<{ providers: any[]; useJit: boolean; preserveWhitespaces: boolean; }>; export type ConfigureFn = (testBed: typeof TestBed) => void; export const configureTests = (configure: ConfigureFn, compilerOptions: CompilerOptions = {}) => { const compilerConfig: CompilerOptions = { preserveWhitespaces: false, ...compilerOptions, }; const configuredTestBed = TestBed.configureCompiler(compilerConfig); configure(configuredTestBed); return configuredTestBed.compileComponents().then(() => configuredTestBed); }; -
Add file
setup-jest.ts
More information: https://jestjs.io/es-ES/docs/configuration#setupfiles-arrayimport 'jest-preset-angular/setup-jest'; /* global mocks for jsdom */ const mock = () => { let storage: { [key: string]: string } = {}; return { getItem: (key: string) => (key in storage ? storage[key] : null), setItem: (key: string, value: string) => (storage[key] = value || ''), removeItem: (key: string) => delete storage[key], clear: () => (storage = {}), }; }; Object.defineProperty(window, 'localStorage', { value: mock() }); Object.defineProperty(window, 'sessionStorage', { value: mock() }); Object.defineProperty(window, 'getComputedStyle', { value: () => ['-webkit-appearance'], }); Object.defineProperty(document.body.style, 'transform', { value: () => { return { enumerable: true, configurable: true, }; }, });
Step 4. Change src/tsconfig.spec.json
-
Replace
jasminewithjestin the types array -
Add
module:commonjsto thecompilerOptions -
Remove
test.tsfrom the files array
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jest",
],
"module": "commonjs",
"emitDecoratorMetadata": true,
"allowJs": true
},
"files": [
"src/polyfills.ts"
],
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
Step 5. Edit your angular.json file
-
Change the projects[your-project].architect.test section, so it looks like this:
https://www.npmjs.com/package/@angular-builders/jest"test": { "builder": "@angular-builders/jest:run", "options": {} },
Step 6. Migrate test with jest-codemods
-
Execute the following command:
npx jest-codemods -f ./src/app/*.spec.ts? Which parser do you want to use? TypeScript ? Which test library would you like to migrate from? Jasmine: globals ? Are you using the global object for assertions (i.e. without requiring them) No, I use import/require statements for my current assertion libr ary ? Will you be using Jest on Node.js as your test runner? Yes, use the globals provided by Jest (recommended) Executing command: jscodeshift -t /Users/moasl/.npm/_npx/13840/lib/node_modules/jest-codemods/dist/transformers/jasmine-globals.js ./src/app/app.component.spec.ts --ignore-pattern node_modules --parser ts --extensions=ts Executing command: jscodeshift -t .npm/_npx/14583/lib/node_modules/jest-codemods/dist/transformers/jasmine-globals.js ./src/app/app.component.spec.ts --ignore-pattern node_modules --parser ts --extensions=ts Processing 1 files... Spawning 1 workers... Sending 1 files to free worker... All done. Results: 0 errors 0 unmodified 0 skipped 1 ok Time elapsed: 1.286seconds -
After all of these changes, it is recommended to delete your node_modules folder and run
npm installagain. -
At this stages, you may have to change some test manually, for example, if jest does not have
toBeTrueortoBeFalse.
Interesting library: jest-dom
Common errors
Converting circular structure to JSON
-
If you lose some import or injection in your component test, you will get this error type:
(node:71567) UnhandledPromiseRejectionWarning: TypeError: Converting circular structure to JSON at JSON.stringify (<anonymous>) at process.target._send (internal/child_process.js:735:23) at process.target.send (internal/child_process.js:634:19) at reportSuccess (/Users/moasl/PROYECTOS/AURA/aura-channels-factory/packages/aura-channels-libraries/node_modules/jest-runner/node_modules/jest-worker/build/workers/processChild.js:67:11) (node:71567) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1) (node:71567) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. -
If you run the test with
--detectOpenHandlesoption, you will get more information to solve the error:$ ng test --detectOpenHandles aura-channels-views ..... FAIL projects/aura-channels-views/src/lib/components/alfred/alfred.component.spec.ts ● AlfredComponentComponent › should render title Found the synthetic property @alfredAnimationState. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application. at checkNoSyntheticProp (../packages/platform-browser/src/dom/dom_renderer.ts:269:11) ....
More information: Jest documentation –detectOpenHandles.