Recently, I had a chance to participate in migration from Karma and Jasmine to Jest. If you are an Angular developer, you might be wondering why you did so. But give me some time, and in this article, I will tell you why we did that, why you should do it, and our results.
There are several arguments, but the main ones are: Karma had been deprecated since Apr 2023, and we were in the preparation stage to write unit tests for our project.
We thought that it’s better to migrate to Jest now (while we don’t have a huge amount of unit tests) than in the future Angular versions. Let’s look at the steps of migration.
Install all necessary packages:
npm install --save-dev jest @types/jest @jest/globals @angular-builders/jest jest-preset-angular
Create a setup-jest.ts
file, and import this module. This file is necessary if you want to specify some code that runs before all test suits but after Jest has set up its testing environment.
It can be helpful if you have some package, that requires global configuration (ex day.js) or setup mocks:
import 'jest-preset-angular/setup-jest';
// other imports if you need
Create a jest.config.js
file:
module.exports = {
preset: 'jest-preset-angular',
globalSetup: 'jest-preset-angular/global-setup',
setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
transform: {
'^.+\\.(ts|js|html)$': 'jest-preset-angular',
},
globals: {
'ts-jest': {
tsconfig: './tsconfig.spec.json',
stringifyContentPathRegex: '\\.html$',
astTransformers: ['jest-preset-angular/InlineHtmlStripStylesTransformer'],
isolatedModules: true,
preserveSymlinks: true,
},
},
moduleFileExtensions: ['ts', 'html', 'js', 'json'],
moduleDirectories: ['node_modules', 'src'],
modulePaths: ['<rootDir>'],
moduleNameMapper: {
'^@app/(.*)$': ['<rootDir>/src/app/$1'],
},
};
Update your tsconfig.spec.json
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/spec",
"types": ["node", "jest"]
},
"include": ["../src/**/*.spec.ts", "../src/**/*.ts", "../src/**/*.mock.ts"]
}
Remove all files and configurations (and dependencies in package.json
) which depend on Karma and Jasmine - karma.conf.js
, test.ts
(usually located in the src folder)
Update your angular.json
"test": {
"builder": "@angular-builders/jest:run",
},
Update your test scripts in the package.json
"test": "ng test",
"test-coverage": "ng test --coverage=true",
After completion of these steps, you have to slightly edit your existing tests. There are some points that you should revise:
toBeTrue/toBeFalse
). It means that you should use other functions - they exist but have other names (toBe(true)/toBe(false)
)
jest.spyOn(class, ‘functionName’)
instead of spyOn(class, ‘functionName’)
If you want to mock the returning function’s value, you should use the following syntax: jest.fn().mockReturnValue(yourValue)
instead of jasmine.createSpy(‘functionNname’).and.returnValue(yourValue)
The total time spent on these changes depends on the amount of unit tests and can vary from project to project.
Well, it depends, and there is no simple answer. If you just started your new project and don’t have a huge amount of unit tests - yes, you can migrate from the start. If you have a legacy project or just a project without unit tests and you want to start writing them - it’s also a good opportunity to migrate to Jest. If you have a lot of unit tests - it can take some time to migrate all of them
It’s important to mention that Jest requires a lot of your resources. If you want to run your test faster - increase the number of streams (each stream can take around 2 GB of RAM and one core). I want to pay attention to what you have on your CI server, and how much capacity you have.
If you have 8GB of RAM and several cores on your server - it’s not a good idea to run Jest in 4 streams because you can get out of allowed memory allocation.
There are some options to configure your runner in the CI environment:
--maxWorkers
option. This flag determines how many cores can be used for test running (all available cores minus one for the main thread)
Use --runInBand
option. With this flag, your tests will be running serially. Sometimes, it can be faster than with --maxWorkers
If you want to run all your tests fast - just run the jest command for the root directory without any flags. It will take all of your available resources (your workstation can be a little bit laggy at this moment, but your test will pass faster).
What about time comparison? Well, when we have several thousands of tests it can be challenging even to run the karma server (it can take more than several minutes) but when the server has started - all tests are passing quite fast. In Jest's case, we don’t need to wait for a server, but tests running take a lot of resources.
I can say, that on a local machine, it will be faster than with Karma/Jasmine setup, but in CI - it depends on your server. In my case, it becomes worse over several minutes.
I’d like to say that such a kind of migration fully depends on your project setup and needs. There is no silver bullet, and I can’t push you to perform this migration - just think twice, think about your setup, performance perspectives, and future support.
In the next articles, I will tell you about test optimizations and how to increase the speed of your test in your CI environment