How to test React apps with Vitest and Vite

How to test React apps with Vitest and Vite

A few weeks ago, I began creating small applications for my upcoming course on Testing React applications. I aimed to make the setup simple and easy for students to follow.

I started with the Babel/Jest setup, which I've used for years, but people have asked why I'm not using Vitest already.

So I tried Vitest, and it blew my mind.

If I have to summarize in one sentence why Vitest is so good compared to Jest, it is that you don't need a PhD to configure all these things. You use the existing Vite configuration file and add a couple of lines to it, and that's it. Your tests are working.

In this blog post, I will walk you through setting up a new Vitest project inside a new Vite project. If you have an existing Vite project, that's fine because the steps will be pretty much the same. Just skip Set up Vite and jump straight to Set up Vitest.

If you're looking for the video version of this, you can watch it here:

Let's jump into it!

Set up Vite

Let's get started by creating a new Vite project:

$ npm create vite@latest vitest-demo-1 --template react-ts

This command will generate a new Vite project with React and TypeScript set up. Now jump into the folder that the previous command created:

$ cd vitest-demo-1

Install the dependencies and finally start the scaffolded app:

$ npm i
$ npm run dev

The app should be running on localhost:5173, and you should be seeing something like this:

Set up Vitest

Go to your project's root folder and install Vitest as a development dependency:

npm install -D vitest

To create a smoke test and verify that the test runner works, create a sum.ts file in your project's root:

// sum.ts
export function sum(a: number, b: number) {
  return a + b
}

and also create a sum.test.ts file:

// sum.test.ts
import { expect, test } from 'vitest'
import { sum } from './sum'

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3)
})

Now open the package.json file:

and inside scripts add a new script test:

{
  "name": "vitest-demo-1",
  ....
  "scripts": {
    ....
    "test": "vitest"
  }
}

If you set up everything correctly, you should be able to run:

npm run test

in your terminal, and you should see something like this:

Set up testing-library/react

We'll use testing-library/react to test the App.tsx component so let's install all the dependencies needed:

npm i -D @testing-library/jest-dom @testing-library/react @testing-library/user-event jsdom

To be able to do testing library assertions inside our test files, we have to import '@testing-library/jest-dom'. We'll do this in a ./src/test/setup.ts file. Go ahead and create it:

// ./src/test/setup.ts

import '@testing-library/jest-dom'

Update tsconfig.json

Now open tsconfig.json and make the following changes:

{
  "compilerOptions": {
    // existin compiler options, no change

    // this is the new configuration
    "types": ["vitest/globals"],
  },

  // also include the file we just created:
  "include": ["src", "./src/test/setup.ts"]
}

Update vite.config.ts

As we mentioned in the beginning, the Vitest configuration will happen in the existing file, so open vite.config.ts and add the triple-slash imports at the top of the file:

// vite.config.ts
/// <reference types="vitest" />
/// <reference types="vite/client" />

and also add the necessary Vitest configuration to defineConfig. Here's the final vite.config.ts for reference:

/// <reference types="vitest" />
/// <reference types="vite/client" />

import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],

  // <add this part>
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/test/setup.ts',
    css: true,
  },
})

Add a unit test

Now we have everything ready to write and run React component tests with Vitest.

Create a file named App.test.tsx with the following contents:

import App from './App'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'

describe('Simple working test', () => {
  it('the title is visible', () => {
    render(<App />)
    expect(screen.getByText(/Vite \+ React/i)).toBeInTheDocument()
  })

  it('should increment count on click', async () => {
    render(<App />)
    userEvent.click(screen.getByRole('button'))
    expect(await screen.findByText(/count is 1/i)).toBeInTheDocument()
  })
})

Use the npm test or npm run test command we used earlier to run all tests. If you followed the tutorial, this is what you should be seeing:

Congratulations!

You have Vitest handling your React unit tests! 👏

If you want to write more and better tests, check out my series on unit testing React components with testing-library/react here: https://akoskm.com/series/react-testing

Did you find this article valuable?

Support Ákos Kőműves by becoming a sponsor. Any amount is appreciated!