React
Vitest: setting up a React project in ten minutes
Vitest joins a React project with three packages and one block in vite.config.js: jsdom, jest-dom and a single command for CI.
Key points
- Three packages and one test block in vite.config.js are enough to start.
- setupFiles loads jest-dom once for the whole suite.
- npx vitest run is the CI form; npx vitest stays in watch mode.
A React project moves to Vitest with three packages and one config block: jsdom as the environment, jest-dom as the setup and a single command for local runs and CI.
The packages
npm i -D vitest jsdom @testing-library/react @testing-library/jest-dom
Vitest, Vite and jsdom ship under the MIT licence. The config lives in vite.config.js: no second bundler and no separate file.
The config block
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
test: {
environment: "jsdom",
globals: true,
setupFiles: "./src/test/setup.js",
},
});
Only Vitest reads the test block; Vite skips it in a build. setupFiles loads jest-dom once for every test, instead of importing it in each file.
The setup file
import "@testing-library/jest-dom/vitest";
import { cleanup } from "@testing-library/react";
import { afterEach } from "vitest";
afterEach(() => cleanup());
The jest-dom import adds matchers such as toBeInTheDocument; with globals: true the test files skip importing test and expect.
The first test
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { LoginForm } from "./LoginForm";
test("mostra l'errore con email vuota", async () => {
render( {}} />);
await userEvent.click(screen.getByRole("button", { name: "Accedi" }));
expect(screen.getByRole("alert")).toHaveTextContent("Email obbligatoria");
});
The npx vitest run command runs once and exits with zero or one: that is the CI form, while npx vitest keeps watching.
Live records in the catalogue
Three components worth a first suite: login-form, input and multistep-form. To browse by category start from 111,985 components.
The limitation
jsdom applies no CSS and computes no layout: a green test does not tell you whether the component is visible. That takes a real browser, with Playwright.
Where to continue
The five-test picture is in Testing Library: five tests; how to read documentation is in React documentation; the measured comparison of React libraries is in React libraries 2026.
Frequently asked questions
How long does the setup take?
Ten minutes on a Vite project: three packages, one config block and one setup file.
Do I need jsdom?
Yes for React components, which use the DOM. Pure functions run in the node environment.
Does Vitest replace Jest?
In practice yes: the same test API, but it runs on Vite and reads the project config.
How does it run in CI?
With npx vitest run: it runs once, leaves no watcher behind and returns an exit code.
Can tests sit next to components?
Yes, that is the default convention: Vitest looks for files with a test or spec suffix.