What is Vitest and Why Use It?
Vitest is a fast, Vite‑powered testing framework that runs tests in a Node environment using Vite’s plugin pipeline. It offers:
- Speed: Parallel worker threads and Vite’s caching make it several times faster than Jest.
- Zero configuration: Reuses the existing Vite config, eliminating a separate build step.
- Native TypeScript/JSX/ESM support: No Babel or ts‑jest needed.
- Jest‑compatible API: Familiar
describe,it,expectsyntax. - Watch mode: Reruns only affected tests on file changes.
These features reduce friction, improve developer experience, and keep test code in sync with application code.
How to Set Up Vitest in a React Project
Follow these steps to add Vitest to a Vite‑based React app.
- 1. Create a React project (if you don’t have one):
npm create vite@latest my-react-app -- --template reactcd my-react-app && npm install - 2. Install testing dependencies:
npm install --save-dev vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom - 3. Add a Vitest config file (
vitest.config.js):import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { environment: 'jsdom', globals: true, setupFiles: './src/test/setup.js', css: true } }); - 4. Create a test‑setup file (
src/test/setup.js) to register matchers:import '@testing-library/jest-dom'; - 5. Add test scripts to
package.json:"scripts": { "test": "vitest", "test:watch": "vitest --watch" }
How to Write Your First Test
Create a simple test file to verify the setup.
// src/sum.test.js
import { describe, it, expect } from 'vitest';
describe('sum utility', () => {
it('adds two numbers', () => {
const sum = (a, b) => a + b;
expect(sum(2, 3)).toBe(5);
});
});
Run npm test. The test should pass, confirming Vitest works.
How to Test React Components
Use React Testing Library together with Vitest.
- Render the component:
render() - Query the DOM:
screen.getByRole,screen.getByText, etc. - Assert visibility and content:
expect(element).toBeInTheDocument()
Example:
// src/components/Greeting.test.jsx
import { render, screen } from '@testing-library/react';
import Greeting from './Greeting';
test('renders greeting with name', () => {
render( );
expect(screen.getByText('Hello, Alice!')).toBeInTheDocument();
});
How to Test User Interactions
Simulate real user behaviour with @testing-library/user-event.
- Import
userEventand useawait user.type(...)orawait user.click(...). - Assert resulting UI changes, not internal state.
Example:
// src/components/Counter.test.jsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Counter from './Counter';
test('increments and decrements count', async () => {
render( );
const incBtn = screen.getByRole('button', { name: /increment/i });
const decBtn = screen.getByRole('button', { name: /decrement/i });
const count = screen.getByTestId('count');
await userEvent.click(incBtn);
expect(count).toHaveTextContent('Count: 1');
await userEvent.click(decBtn);
expect(count).toHaveTextContent('Count: 0');
});
How to Test Custom Hooks
Use renderHook from @testing-library/react (or @testing-library/react-hooks if preferred).
// src/hooks/useFetch.test.jsx
import { renderHook, waitFor } from '@testing-library/react';
import { vi } from 'vitest';
import useFetch from './useFetch';
import axios from 'axios';
vi.mock('axios');
test('returns data after successful fetch', async () => {
axios.get.mockResolvedValueOnce({ data: { message: 'ok' } });
const { result } = renderHook(() => useFetch('/api/hello'));
await waitFor(() => expect(result.current.data).toEqual({ message: 'ok' }));
});
How to Mock API Calls
Vitest does not auto‑mock modules, so you manually mock them with vi.mock.
- Mock the module at the top of the test file.
- Provide
mockResolvedValueormockRejectedValuefor the functions you need.
Example with Axios:
// src/components/PostsList.test.jsx
import { render, screen, waitFor } from '@testing-library/react';
import { vi } from 'vitest';
import axios from 'axios';
import PostsList from './PostsList';
vi.mock('axios');
test('displays posts after fetch', async () => {
const mockPosts = [{ id: 1, title: 'First' }];
axios.get.mockResolvedValueOnce({ data: mockPosts });
render( );
await waitFor(() => expect(screen.getByText('First')).toBeInTheDocument());
});
Best Practices for Testing React Components
- Test user behaviour, not implementation details: Prefer
getByRole,getByLabelText, and visible text overdata-testid. - Keep tests focused: One assertion per logical outcome; split complex scenarios into separate tests.
- Clean up after each test: Vitest’s jsdom environment handles this automatically when
globals: trueis set. - Use descriptive test names: Clearly state the action and expected result.
- Leverage watch mode: Run
npm run test:watchduring development to get instant feedback.