Migrating From Jest to Vitest
1.a. ๐พ Use Both Jest & Vitestโ
In the rare occurrence where some tests are too coupled to Jest and hard to automatically migrate to Vitest, you can keep the Jest's configuration files and run some specific tests with Jest and others with Vitest. This will help you migrate progressively. Otherwise, you can simply remove the Jest setup.
Backup Jest's test-setup.ts fileโ
git mv {MY_PROJECT}/src/test-setup.ts {MY_PROJECT}/src/test-setup.jest.ts
Update jest.config.ts fileโ
Update the jest.config.ts configuration to use the test-setup.jest.ts file and match test files ending with .jest.spec.ts.
- setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
+ setupFilesAfterEnv: ['<rootDir>/src/test-setup.jest.ts'],
+ testRegex: '(/__tests__/.*|(\\.|/)jest\.(test|spec))\\.[jt]sx?$',
Rename test Targetโ
Rename the test target to jest in project.json (if you are using Nx) or angular.json (if you are using Angular CLI).
"architect|targets": {
- "test": {
+ "jest": {
"builder": "...",
...
}
...
}
You will be able to run the Jest tests with the following command:
nx jest {MY_PROJECT}
# or
ng run {MY_PROJECT}:jest
1.b. ๐๏ธ Remove Jestโ
Remove Jest configuration files:
rm -f {MY_PROJECT}/jest.config.ts {MY_PROJECT}/src/test-setup.ts
Remove the test target from project.json (if you are using Nx) or angular.json (if you are using Angular CLI).
"architect|targets": {
- "test": {...}
...
}
2. ๐ฆ Set Up Vitestโ
For Nx Usersโ
If you are using Nx (>= 20.3.0), you can run the following commands to set up Vitest in your Angular project:
nx add @nx/vite
nx g vitest --project {MY_PROJECT}
For Angular CLI Usersโ
If you are using the Angular CLI (>= 21.0.0), you can use the new unit-test builder to set up Vitest in your Angular project.
Otherwise, if you are using an older Angular CLI version or if you want more control over the setup or more Vitest features, you can use Angular Vitest Generator/Schematic by Analog to set up Vitest in your Angular project.
Using the Angular CLI's unit-test builderโ
Update your angular.json file to use the unit-test builder:
{
...
"targets": {
+ "test": {
+ "builder": "@angular/build:unit-test",
+ }
}
}
Vitest is the default test runner when using the unit-test builder.
Using the Angular Vitest Generator/Schematic by Analogโ
ng g @analogjs/platform:setup-vitest --project {MY_PROJECT}
Note that this does not set up anything specific to Analog. It is just a convenient way to set up Vitest in your Angular project.
The Analog team did an outstanding job of making it easy to use Vitest with Angular projects.
Update src/test-setup.tsโ
You may need to update the src/test-setup.ts file to apply whatever previous setup you had in Jest to Vitest.
3. ๐งณ Migrate Testsโ
Vitest shares a large API surface with Jest, so most of the tests should work without any changes.
However, if your tests are using Jest-specific APIs (e.g. jest.fn()), you may need to update them.
In general, I'd recommend staying as decoupled as possible from the testing framework. For instance, it is better to use fakes than mocks or spies. Cf. ๐บ Fake it till you Mock it.
๐ค Automatic Migrationโ
There is a Jest to Vitest codemod that will automatically transform most Jest-specific API usages to their Vitest equivalent.
You can run it with the following command:
npx codemod jest/vitest -t path/to/the/test/files/you/want/to/migrate
The codemod will make transforms such as:
- test(...);
+ import { test } from 'vitest';
+ test(...);
- jest.mock(...);
+ import { vi } from 'vitest';
+ vi.mock(...);
- jest.fn();
+ import { vi } from 'vitest';
+ vi.fn();
It is not exhaustive but should cover most of the common cases and help you migrate faster.
๐ท Manual Migrationsโ
Replace done callback with a Promiseโ
Vitest does not support the done callback. A quick way to migrate this is to wrap the test body in a Promise like this.
- it('should do something', (done) => {
- // ...
- done();
- });
+ it('should do something', () => new Promise((done) => {
+ // ...
+ done();
+ }));
Ideally, the done callback pattern should be avoided.
Prefer converting any async code to promises:
import { lastValueFrom } from 'rxjs';
test('...', async () => {
const source$: Observable<...> = ...;
const result = await lastValueFrom(source$);
expext(result).toEqual(...);
})
I'll elaborate on other techniques in a future chapter.
4. ๐ Run Testsโ
You can run the tests with the following command:
nx test {MY_PROJECT}
# or
ng test {MY_PROJECT}
๐ F.A.Q.โ
Nx creates a project with Jest by default. How can I change it to use Vitest?โ
This happens when the default unitTestRunner option is set to jest in the nx.json file. You can change it to vitest:
"generators": {
"@nx/angular:application": {
...
- "unitTestRunner": "jest"
+ "unitTestRunner": "vitest"
}
}
I can't see vitest in the list of suggested test runnersโ
The vitest option for Angular projects is available in Nx 20.1.0 or later.
๐ Common Errors & Issuesโ
Error: Expected to be running in 'ProxyZone', but it was not foundโ
This often happens with tests relying on Angular's fakeAsync.
For fakeAsync to work, Angular has to monkey patch the test function to use zones. Analog's Vitest plugin already does this for you.
This is actually what is happening under the hood in the @analogjs/vitest-angular/setup-zone module imported in the test-setup.ts file.
This behavior is broken when we import beforeEach, test, it, and others from vitest instead of using the global ones that are monkey patched.
To fix this, you will have to remove the import and make sure to use the global functions.
- import { describe, it } from 'vitest';
describe('...', () => {
it('...', () => {
// ...
});
});
It is better to avoid using fakeAsync and prefer using Vitest's fake timers instead.
Error: Cannot set base providers because it has already been calledโ
Replace:
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
);
with:
beforeEach(() => {
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
);
});
afterEach(() => {
getTestBed().resetTestEnvironment();
});
