Migrating Jest tests to Vitest with minimal code changes

As part of modernising an app that I was working on, I am trying to improve our toolset by trying and using a better tool.
Jest has been one of my team pain points during development, especially for those of us who write a lot of tests as part of our Ways of Working (i.e. Test Driven Development)
Jest tests are slow to run (just Google “jest slow”)
Vitest is a logical upgrade for various reasons and one of them is:
Vitest has been designed with a Jest compatible API, in order to make the migration from Jest as simple as possible.
The above is quoted from https://vitest.dev/guide/migration.html
Migration
With that in mind, these are the steps that I took to minimise the code changes when migrating from Jest to Vitest.
Create an “alias” of “jest” to “vi”
Vitest adopt the same method names as Jest. So Vitest provides functions such as vi.restoreAllMocks()
that works just like jest.restoreAllMocks()
, etc
But that means for existing tests (could be hundreds of them), we need to modify them all (replace jest. with vi. which could make the merge request unseemly.
Fortunately, the internet provides an example how to create an “alias” so the code changes are minimal.
In the vitest.config.ts
file, define a setup file that will be executed before the tests run
// vitest.config.ts (or .mjs depends on your preference)
export default defineConfig({
test: {
setupFiles: ["./tests/setup.ts"]
}
})
And in the setup.ts
file,
import {vi} from "vitest";
Object.assign(globalThis, {jest: vi})
As per doco:
The Object. assign() static method copies all enumerable own properties from one or more source objects to a target object. It returns the modified target object.
Once that is done, you can:
Remove Jest from you project
Import the test infrastructure such as
describe
,it
,beforeEach
, etc
import {describe, it, expect, vi, Mock, beforeEach} from "vitest";
- Leave the tests untouched (mostly - keep reading for more details)
Below are the list of Jest related function/features that we use in our project, and as of today, they can run untouched except for jest.mock(...).
List of Changes
jest | Is it working using Vitest? | Notes |
jest.mock('...'); ` | No | Workaround: see Workarounds section below |
jest.unmock('...'); | No | Workaround: see Workarounds section below |
jest.clearAllMocks(); | Yes | |
jest.restoreAllMocks(); | Yes | |
jest.resetAllMocks(); | Yes | |
window.gtag = jest.fn() | No | Workaround: see Workarounds section below |
= jest.fn().mockRejectedValue(...) | Yes | |
= jest.fn().mockResolvedValue(...) | Yes | |
= jest.fn().mockImplementation(...) | Yes | |
(<jest.Mock>Something.anything).mockRejectedValue(...) | Yes | |
(<jest.Mock>Something.anything).mockResolvedValue(...) | Yes | |
(<jest.Mock>Something.anything).mockImplementation(...) | Yes | |
jest.spyOn(...).mockRejectedValue(...) | Yes | |
jest.spyOn(...).mockResolvedValue(...) | Yes | |
jest.spyOn(...).mockImplementation(...) | Yes | |
jest.useFakeTimers(); | Yes | |
jest.runAllTimers(); | Yes | |
jest.advanceTimersByTime(...); | Yes | |
expect(...).toHaveBeenCalledTimes(...); | Yes | |
expect(...).toHaveBeenCalledWith(...) | Yes | |
expect(...).toBe(...); | Yes | |
expect(...).toEqual(...); | Yes | |
expect(...).toBeTruthy(); | Yes | |
expect(...).toBeFalsy(); | Yes | |
expect(...).toContain(...) | Yes | |
mockedObject.mock.calls[0][1] | Yes | |
jest.setTimeout(20000) | No | Workaround: see Workarounds section below |
Workarounds
Workaround for jest.mock()
and jest.unmock('...')
When attempting to mock result of function mocked with jest.mock(...), will error:
v1.mockReturnValue is not a function
TypeError: __vite_ssr_import_1__.v1.mockReturnValue is not a function
Workaround (code changes needed ) is to simply replace it with:
vi.mock(...)
Workaround for window.gtag = jest.fn()
Error: window.gtag is not a function in both test and .vue
Workaround:
Create a thin wrapper around window.gtag
How about vi.spyOn(window, 'gtag')
?
Not working with error:
Error: gtag does not exist
See: How to spy on inline declared functions
Workaround for jest.setTimeout(20000)
Workaround:
describe('something', {timeout: 20000}, () => ...)
Subscribe to my newsletter
Read articles from EJ directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
