Vite + React + Vitest: a simple test setup you can copy in 10 minutes

Published: (February 25, 2026 at 04:30 AM EST)
2 min read
Source: Dev.to

Source: Dev.to

Introduction

If you use Vite + React + TypeScript, the fastest way to add tests is Vitest.
In this post, I will show a clean setup you can copy.

Why this stack?

  • Vite – fast dev server
  • Vitest – test runner that feels like Jest, but faster in Vite projects
  • React Testing Library – test from the user perspective

This setup works well with pnpm and small‑to‑medium frontend apps.

1) Install packages

pnpm add -D vitest jsdom @testing-library/react @testing-library/jest-dom @testing-library/user-event

2) Update vite.config.ts

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

export default defineConfig({
  plugins: [react()],
  test: {
    environment: 'jsdom',
    setupFiles: './src/test/setup.ts',
    globals: true,
  },
})

What this does

  • jsdom provides a browser‑like environment.
  • setupFiles runs once before tests.
  • globals: true lets you use describe, it, expect without importing them each time.

3) Create src/test/setup.ts

import '@testing-library/jest-dom'

This adds helpers like toBeInTheDocument().

4) Add scripts to package.json

{
  "scripts": {
    "test": "vitest run",
    "test:watch": "vitest",
    "test:ui": "vitest --ui"
  }
}

Usage

  • pnpm test – run tests once (CI).
  • pnpm test:watch – run tests in watch mode while coding.

5) Example component test

Component: src/components/Counter.tsx

import { useState } from 'react'

export function Counter() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount((c) => c + 1)}>Increment</button>
    </div>
  )
}

Test: src/components/Counter.test.tsx

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

describe('Counter', () => {
  it('increments count when button is clicked', async () => {
    render(<Counter />)

    await userEvent.click(screen.getByRole('button', { name: /increment/i }))

    expect(screen.getByText('Count: 1')).toBeInTheDocument()
  })
})

This test checks real behavior, not internal state details.

Common beginner mistakes

  • Using the node environment for React tests (use jsdom).
  • Forgetting to set up @testing-library/jest-dom.
  • Testing implementation details instead of visible UI behavior.

Final tip

Start with one test per component for the core user action.
You don’t need 100 tests on day one—small, stable tests are better than many fragile ones.

Next steps could include adding coverage reporting and running Vitest in CI.

0 views
Back to Blog

Related posts

Read more »