HappyA beginner-friendly, practical setup for testing React components in a Vite + TypeScript project with Vitest.
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.
This setup works well with pnpm and small-to-medium frontend apps.
pnpm add -D vitest jsdom @testing-library/react @testing-library/jest-dom @testing-library/user-event
vite.config.ts
/// <reference types="vitest" />
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 gives a browser-like environmentsetupFiles runs once before testsglobals: true lets you use describe, it, expect without importing every timesrc/test/setup.ts
import '@testing-library/jest-dom'
This adds helpers like toBeInTheDocument().
package.json
{
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:ui": "vitest --ui"
}
}
Use:
pnpm test for CIpnpm test:watch while codingsrc/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>
)
}
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.
node environment for React tests (use jsdom)@testing-library/jest-dom setupStart with one test per component for the core user action.
You do not need 100 tests on day one.
Small, stable tests are better than many fragile tests.
If you want, next step is adding coverage and running Vitest in CI.