From Jest to Vitest - Migration and Benchmark
Tags: testing, react, vite, performance
Published: 2022-01-21 11:52:20

In this post join me as I migrate my project’s test runner framework from Jest to [Vitest](https://github.com/vitest-dev/vitest), and check if it is really as they claim - “_A blazing fast unit test framework_”.

## Vitest?
I’m pretty sure you’ve already heard about [Vite](https://vitejs.dev/) which is Evan You’s recent promising project for frontend tooling. Benchmarks claim it is super fast in times where bundling and HMR present real challenges for dev velocity. 
It was recently brought to my attention that there is another emerging project called [Vitest](https://github.com/vitest-dev/vitest) which is supposed to bring that same disruption into the realm of test runners. My curiosity obviously could not let this pass.
Although “_Vitest is still in development and not stable yet. It's not recommended to use it in production._” I was eager to find out just how fast we are talking about. 

Here's my path for migrating a project using Jest into using Vitest along with some benchmarking.

## Benchmarking
My guinea pig is (yet again) my React [Word-Search game](https://word-search-react-game.netlify.app/) and its tests, but before I jump in I would like to measure how long it currently takes to run the project’s tests in order to do some comparison at the end.
The Project currently has 4 test files which have 37 tests between them. Not too many, I agree, but I believe it can give a good sense of the difference between Jest and Vitest.

I will measure the tests running time in 2 scenarios: 

- Initial run - where I first lunch the test 
- Watch run - where I change a single file and see how long it takes for the tests to run

For each framework I will run these scenarios a few times (with and without cleaning the cache for Jest for the initial run) to make sure I get the average time.

Here are the results for Jest I got:

- Initial run - 6.5s (without clearing Jest cache its 5.5s)
- Watch run - 5.5s

## Migrating to Vitest
[Vitest](https://github.com/vitest-dev/vitest) has a really comprehensive gitHub repo, with some good documentation (considering its age).
I could look into the code [examples](https://github.com/vitest-dev/vitest/tree/main/examples) for React and React Testing Lib and monkey copy-paste it with fingers crossed, but I would like to know what’s really going on, and what is the exact minimum required for one to make this transition.
Before I even start to npm install anything, I’d like to try it as they suggest by running a single test. This following test is passing with Jest, now let’s try it with Vitest:

```bash
npx vitest src/components/Confirmation/index.test.js
```

After confirming the installation of ‘vitest’ we get our feedback from the test runner - who could have guessed, the first error (I must admit that Vitest has a more clearer way of displaying the errors and failed tests):

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2tippsxuwg80n94u9dfl.png) 

**Error: Failed to parse source for import analysis because the content contains invalid JS syntax. If you are using JSX, make sure to name the file with the .jsx or .tsx extension.**

While Jest has no issue with parsing these files, it appears that Vitest does not know how to parse them, and requires that we change the file names if they contain JSX. 
Before I jump into introducing new configurations I would like to see if just changing the file name will help with this error, and it does - changing the name of my test file from index.test.js to index.test.jsx eliminates that error, but now I’m getting a new one:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gpnw5iz136hnhct9qh3s.png) 

**describe is not defined**

Well, Jest has these globals declared, but it seems that Vitest does not, and we need to import them explicitly. No worries, let’s do that, but before we do, we need to install Vitest. We at least know now that running Vitest just by using npx is not enough when migrating a project to work with it.

```bash
npm i vitest -D
```

Now let’s add the needed imports to our test file:

```javascript
import { it, describe, expect } from 'vitest';
```

Oh my, now all my tests fail with a lot of errors flying, but that’s good. Let’s address them one by one:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hvytvq0glr3t70fcv3cv.png) 

**document is not defined**

This error comes from react-testing-library and it has to do with js-dom support of vitest. I’m going to look for some resources for this… yes, the [docs](https://github.com/vitest-dev/vitest/blob/main/docs/config/index.md#environment) do not fail - it says that adding a docblock or comment specifying the env as js-dom (or dom-happy) will do the trick. I will add it to my test and see how it goes:

```javascript
/**
* @vitest-environment jsdom
*/
 
describe('Confirmation component', () => {
   . . .
```

The tests run again, but still all of them are failing, now with new error:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e57z5qiqlj6wsvh5xypo.png) 

**Invalid Chai property: toBeInTheDocument**

Chai? No, no, no… toBeInTheDocument is not a Chai property. 
toBeInTheDocument is an API of the testing-library’s js-dom, and the part responsible to include it and append its assertions is the test setup file (in create react app it is the testSetup.js file on the project root).

In order to let vitest include this file as its own setup we need to create a vitest config, no escape there. Now is a good time to look at the configuration found on the [example](https://github.com/vitest-dev/vitest/tree/main/examples/react-testing-lib) and check what’s going on in the configuration there. Again, I’m not blindly copy-pasting and so I pick what I know to be relevant to the problem I’m facing.

In order to use the configuration I need to install “vite”. I’m not very keen about it, but if that makes my tests run faster, so be it:

```bash
npm i vite -D
```

I create a configuration file named “vite.config.js” and set the configuration as follows:

```javascript
import {defineConfig} from 'vite';
 
export default defineConfig({
   test: {
       globals: true,
       setupFiles: 'src/setupTests.js',
   },
});
```

As you can see I’m giving the setup file location, which loads the jest-dom needed, and also notice that I have the global property set to “true”. This means that I won’t need to import those global variables Jest comes with like “describe”, “expect” etc. I can remove that import from my test :)
(more information on the configuration can be found [here](https://github.com/vitest-dev/vitest/blob/main/docs/config/index.md))

Good progress, but do our tests pass now? No, some still don’t. We have another error:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ythoeol9ck1uvvb8tuu2.png) 

**jest is not defined**

Well of course it isn’t. We’re using jest in this test for creating spy/stub functions with `jest.fn()`, but Vitest has another way of achieving this - it has the same implementation but under “vi”. So instead we need to use `vi.fn()`

```javascript
import {vi} from 'vitest';
```

```javascript
it('should be able to receive a handler for the "Cancel" button and execute it upon click', () => {
      const onCancellationHandler = vi.fn();
	. . .
});
```

Hurrah! We have a single test migrated into Vitest :)

I will now attempt to run the entire tests with vitest. I will start by changing my npm script for test to run vitest instead of jest:

```json
"scripts": {
       "test": "vitest",
       . . .
},
```

Let's also add the `environment: 'jsdom'` to the configuration file so we can avoid adding the env docblock in each test.
Running npm tests, and as you probably guessed it, many tests fail, but the good news is that there is nothing new to the issues we already bumped into before.
It is time to do some benchmarking 

## Benchmark again and compare 

Now it is time to take our statistics again for Vitest:

- Initial run - 5.30s (nice, but kinda the same as Jest with cache)
- Watch run  1.25s (wow!)

Let’s put it in a nice table:

| Framework | Initial run | Watch run |
|-----------|-------------|-----------|
| Jest      | 6.50s       | 5.5s      |
| Vitest    | 5.30s       | 1.25s     |

From this little benchmarking I did here on my own machine, it appears that although the initial runs are slightly in the favor of Vitest, the watch run is a lot faster!
As I see it, there is no question that once Vitest is ready for production you should really consider replacing your current test runner with it. My Word-Search game already has it ;)

As always, if you have any thoughts or comments about what's written here, please share with the rest of us :)

*Hey! If you liked what you've just read check out <a href="https://twitter.com/mattibarzeev?ref_src=twsrc%5Etfw" class="twitter-follow-button" data-show-count="false">@mattibarzeev</a><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> on Twitter* :beers:

<small><small><small>Photo by <a href="https://unsplash.com/@flo_stk?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Florian Steciuk</a> on <a href="https://unsplash.com/s/photos/speed?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></small></small></small>