1. Why switch from Karma+Jasmine
to Jest
?
The official recommended unit testing framework for Angular is Karma + Jasmine
by default.
Karma
is used to execute unit tests in a real browser environment by launching the Chromium browser.
Jest
specifies the runtime environment through configuration, usually jsdom
, and each test file is executed in a separate runtime environment.
The main problems with Karma
currently are the following.
- the need to launch the browser, compile the entire project and execute the unit test cases in the browser
- The result is unstable due to side effects of test case execution as it is executed in the browser and shared runtime environment.
- No support for single-file testing, so the unit test development and debugging experience is relatively weak.
- The CI execution environment requires chromium browser to be installed, which is relatively cumbersome
Advantages of replacing Jest
with
- The runtime environment is based on
jsdom
, no need to start a browser - Support single-file testing and caching of file compilation results
- Supports parallel execution on multi-core CPUs
- Exceptions are presented as a single-file call stack, with clear hints and easy to locate and analyze.
- A generic Node.js docker image is sufficient for execution on CI
Jest
should be chosen carefully for the following scenarios: CI Runner is a single-core, low-performance virtual machine. The main reason is that the single-file standalone environment ofJest
, which can be executed in parallel, has no advantage in terms of execution efficiency. Since each test file needs to start the environment when running, file preloading and processing is extremely time-consuming for large projects with deep file dependency chains. Because single-core can only execute serially, the final execution time can be very long and almost unacceptable.This is where
karma+jasmine
’s compile once, execute centrally in the browser approach comes into its own.
In general, the main purpose of migrating to Jest
is to get a better single-file test writing development experience. However, for large projects, the Jest single-file standalone environment requires multi-core processors to get better execution efficiency, while karma+Jasmine
requires less machine performance.
2. Options for Angular using Jest
The main popular solutions in the community are @angular-builders/jest and jest-preset-angular. Based on npm
download trends, jest-preset-angular
clearly has a definite advantage, so it is chosen.
Also, since the project already has a lot of unit tests written based on jasmine
, the API calls need to be migrated, although Jest
is compatible with its unit test writing style. You can use the tool jest-codemods.
3. Process reference for migrating from Karma to Jest
3.1. Jest dependency installation
Add Jest-related dependencies by executing the following command.
|
|
3.2. Configuring Jest
Create a new file src/jest-setup.ts
with the following reference.
Create a new file __mocks__/jestGlobalMocks.ts
with the following reference.
|
|
Create a new jest.config.js
file with the following content reference.
|
|
The contents of the tsconfig.spec.json
file are adjusted with the following reference.
3.3. Migrating unit test code using jest-codemods
First test the effect by executing the following command.
|
|
If no exceptions are reported, the actual migration command can be executed as follows (remember to commit all modified code in advance so that it can be reset and rolled back at any time).
|
|
jest-codemods
can help update the application of the more standardized jasmine
API by replacing it with the implementation corresponding to the jest
API. However, there will still be some less standardized writings that need to be confirmed and manually fixed based on the results of unit test execution feedback on a case-by-case basis.
3.4. Removing Karma
If the migration process described above is complete and all unit tests are running smoothly with jest, then the karma dependency can be removed.
- Remove karma and
jest
dependencies frompackage.json
. - Remove the karama configuration file
4. Problems encountered and solutions
4.1. Global object mock
Since karma compiles all files and launches tests in the browser, while jest executes tests based on jsdom as a single file, there is a big difference in its initialization environment, and some APIs not supported by jsdom and global APIs predefined by the application do not exist in the jest unit test environment. This can be solved by mocking the relevant APIs.
If the window.getComputedStyle
API is not implemented in jsdom, you can create the file jestGlobalMocks.ts
and implement its basic API, then introduce it in jest-setup.ts
(see the jestGlobalMocks.ts
file example above).
The string prototype is extended in utils/global.ts
as in the application: String.prototype.isGb = () => {...}
. Then you can introduce it in the jest-setup.ts
file.
If you call location
, jsdom
will report the following exception.
Error: Not implemented: navigation (except hash changes)
This can be solved by mocking the location
object.
|
|
4.2. Jasmine and Jest API modification and comparison
-
jasmine.createSpyObj
->jest.fn
. The example is shown below.moreā¦
4.3. transform related issue: Cannot find module ‘@angular/common/locales/xxx’
The main problem is that the module provides output of commonjs and esmodule types, and there are problems such as dependency library entry finding exceptions and transform exceptions.
For the default use of esm mode to execute jest, you can configure transformIgnorePatterns
to filter the translation of esm modules, configure moduleNameMapper
to relocate the exception module to the corresponding esm
type file entry, etc.
|
|
Reference :https://github.com/thymikee/jest-preset-angular/issues/1147
5. Summary and reference
To summarize the above practice process, we can summarize its main process as follows.
- add
jest
dependencies - remove
karma
andjasmine
dependencies - configure
jest
. Depending on the exceptions from the unit test execution, you may need to add some compatibility configurations, such asesm
module path mapping, global variable compatibility, etc. - execute
npx jest-codemods src -f
to help migrate the unit test code - Execute
pnpm jest
to confirm and manually handle compatibility with unit test exceptions on a case-by-case basis.
Finally, compared to jasmine
and created jest
, jest
is also disliked too bloated and appeared vitest
, there is time to do the Angular project unit testing framework switch to vitest
attempt.