Setting Up Vitest

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.

vite.config.js with a test blockJavaScript
/// <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.

Output of 120
 ✓ 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.