I recently migrated from create-react-app (CRA) to ViteJS, and as part of that, I switched my test runner from Jest to Vitest.
In this article, I go through all the steps I took as part of the migration, in the hope that it might help others who are going through the same process.
Why switch?
I had originally planned to keep using Jest during the migration of CRA to ViteJS, but I kept running into issues, mainly because Jest support for ES Modules is still experimental. There is a Vite plugin called vite-jest but it's still very much a work in progress.
Vitest is also pretty early in its development stages, but I felt that it was stable enough to give it a try, and I'm sure glad I did. It has many advantages but one thing I really like about it compared to other test runners is that it shares the same config file and plugins as Vite itself, so there's only one single pipeline to worry about.
Migration steps
Here are all of the steps I took to migrate from Jest to Vitest.
Note: These steps are unique to the way Jest was installed within CRA, so they may vary if you installed and configured Jest manually.
Let's get started!
1. Install dependencies
We need to install 3 dependencies:
- Vitest: Our test runner.
- jsdom: To mimic the browser while running tests.
- c8: To generate our code coverage reports.
To install these dev dependencies, run the following command:
npm install --save-dev vitest jsdom c8
2. Update vite.config.ts
As I mentioned previously, the beauty of using Vitest is that it integrates seamlessly with Vite, so all we have to do is update the vite.config.ts
file.
You'll also need to add a reference to the Vitest types using a triple slash command at the top of your config file.
/// <reference types="vitest" />
import { defineConfig } from 'vite'
export default defineConfig({
test: {
// ...
},
})
You may have different requirements, but here's what mine ended up looking like:
/// <reference types="vitest" />
import { defineConfig } from 'vite'
export default defineConfig({
test: {
globals: true,
environment: 'jsdom',
setupFiles: './src/setupTests.ts',
coverage: {
reporter: ['text', 'html'],
exclude: [
'node_modules/',
'src/setupTests.ts',
],
},
},
});
Here's the full list of config options, but I'll briefly explain each one I used:
-
globals
: Setting this totrue
allows you to reference the APIs globally (describe, expect, it, should etc.), just like Jest. -
environment
: This is where you choose what browser-like environment you want to use. -
setupFiles
: This is the path to the setup files which run before each test file. In CRA, this file (setupFiles.ts) is included by default, so I left it as is. -
coverage
: This is the configuration I use for the c8 reporter. I also specify the folders that I exclude from the report.
3. Convert tests
Vitest has been designed with a Jest compatible API (describe, expect, it, should etc.), so migrating tests was an absolute breeze. Unless you mock modules or methods, you probably won't need to do anything here.
I was making use of Jest method mocking, but all I had to was change jest.fn()
to vi.fn()
. You'll have to import vi
in your test if you want to do the same: import { vi } from 'vitest';
4. Update package.json
Let's update the package.json
scripts to reference vitest
instead of react-scripts
.
"scripts": {
...
"test": "vitest watch",
"test:no-watch": "vitest run",
"test:coverage": "vitest run --coverage"
},
You'll notice I also added a new entry to run code coverage and provided a way to run tests without a watcher, this comes in handy when running tests in a CI/CD pipeline.
We can npm uninstall @types/jest
since we won't need it anymore. I have kept @testing-library/jest-dom
around though as it's required by React Testing Library.
Finally, I removed any "jest" configuration I had in this file:
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,ts,tsx}",
"!/node_modules/",
]
},
5. Update tsconfig.json
To get TypeScript working with the global APIs, add vitest/globals
to the types field in your tsconfig.json
file.
"types": ["vitest/globals", .....]
You may also run into an error like this:
../node_modules/@types/jest/index.d.ts:34:1 - error TS6200: Definitions of the following identifiers conflict with those in another file: test, describe, it, expect, beforeAll, afterAll, beforeEach,
At the time of writing this article, it still seems to be an open issue. However, a workaround I found is to add "skipLibCheck": true,
to your tsconfig.json
file.
6. Run tests
Hopefully the migration worked for you and all that's left to do now is to run npm test
. 🎉
Final thoughts
Overall I'm extremely happy with Vitest, they've really made the migration so easy. I'm even more impressed with their docs given it's still pretty new, especially the number of examples they have. If you found this article helpful or have suggestions, please leave a comment below. 🙂
Want to see more?
I mainly write about real tech topics I face in my everyday life as a Frontend Developer. If this appeals to you then feel free to follow me on Twitter: https://twitter.com/cmacdonnacha
Bye for now 👋
Top comments (2)
Cool I have heard so many good things about Vite and Vitest. It has surpassed parcel.js imo.
It's really excellent. The maintainers behind it are gifted and you can tell they care about the DX.