Migrating Jest tests to Vitest with minimal code changes

EJEJ
4 min read

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

jestIs it working using Vitest?Notes
jest.mock('...'); ` NoWorkaround: see Workarounds section below
jest.unmock('...');NoWorkaround: see Workarounds section below
jest.clearAllMocks();Yes
jest.restoreAllMocks();Yes
jest.resetAllMocks();Yes
window.gtag = jest.fn()NoWorkaround: 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)NoWorkaround: 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}, () => ...)
0
Subscribe to my newsletter

Read articles from EJ directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

EJ
EJ