Vitest 5.0.1 102,989 is the default choice for a Vite 25,978 project because it is not a second toolchain: it reads the same vite.config.js, so the JSX transform, path aliases and plugins that build your app also build your tests. Six development dependencies cover a React 7,897 project — vitest, @vitejs/plugin-react 6.1.1, jsdom 30.1.0 21,691 , and @testing-library/react 16.3.3, /jest-dom 7.0.1 and /user-event 14.6.7.
/// <reference types="vitest/config" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom', // give every test file a document
globals: true, // test/expect/vi without importing them
setupFiles: './src/setupTests.js',
},
});The triple-slash reference matters only in TypeScript projects, so the test key type-checks. globals: true is what lets an existing Jest 62,362 suite run unchanged; without it every file starts with import { test, expect, vi } from 'vitest'.
The setup file's whole job is one line — import '@testing-library/jest-dom/vitest' — which turns toBeInTheDocument, toHaveTextContent, toBeDisabled and thirty siblings into real assertions. The /vitest entry point exists because expect.extend has to be called on the right expect; importing plain @testing-library/jest-dom is the usual reason those matchers appear to be missing.
✓ src/Counter.test.jsx > starts at zero 26ms ✓ src/Counter.test.jsx > counts clicks 195ms Duration 1.81s (environment 64%, tests 14%, setup 11%, import 7%, transform 3%)
Per-file lines come from --reporter=verbose; "test": "vitest" gives watch mode, "test:run": "vitest run" a single pass for continuous integration. Read the duration breakdown when a suite feels slow: environment 64% means the time went into a fresh jsdom per worker, not your assertions.