Skip to content
Learni
Voir tous les tutoriels
Tests & Qualité

Comment configurer et maîtriser Vitest en 2026

Read in English

Introduction

Vitest est l'outil de test moderne par excellence en 2026, conçu spécifiquement pour Vite. Il offre des performances fulgurantes grâce au support natif des modules ESM, à la résolution rapide des dépendances et à une API familière inspirée de Jest. Contrairement aux outils traditionnels comme Jest qui peuvent être lents sur les gros projets, Vitest parallelise les tests par défaut et intègre parfaitement les environnements comme JSDOM pour les composants React ou Vue.

Pourquoi l'adopter ? Dans un monde où les CI/CD exigent des feedbacks rapides, Vitest réduit les temps de test de 50-80% par rapport à Jest. Il gère les snapshots, les mocks, la couverture de code et même un UI de test interactif. Ce tutoriel intermediate vous guide pas à pas pour créer un projet Vite + React + TypeScript, configurer Vitest, écrire des tests avancés (mocks, async, snapshots) et mesurer la couverture. À la fin, vous aurez un setup production-ready que vous bookmerez pour vos futurs projets. Prêt à tester comme un pro ? (128 mots)

Prérequis

  • Node.js 20+ installé
  • Connaissances de base en Vite, React et TypeScript
  • Un éditeur comme VS Code avec extension Vitest
  • Git pour versionner le projet

Créer le projet Vite de base

terminal
npm create vite@latest vitest-tutorial -- --template react-ts
cd vitest-tutorial
npm install

Cette commande initialise un projet Vite avec template React + TypeScript. Elle installe toutes les dépendances de base. Évitez les templates vanilla pour ce tutoriel, car React permet des tests DOM réalistes ; relancez npm install pour valider.

Installer Vitest et dépendances de test

terminal
npm install -D vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom @vitest/ui happy-dom happy-dom/test-environment
npm install -D @types/node @vitest/coverage-v8

On ajoute Vitest comme devDependency, avec RTL pour tester React, JSDOM/HappyDOM pour simuler le navigateur, et coverage-v8 pour les rapports. @vitest/ui apporte une interface web interactive. Le piège : oublier les types Node pour les imports fs/path.

Configurer vitest.config.ts

vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';

import { resolve } from 'path';

export default defineConfig({
  plugins: [react()],  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/test-setup.ts',
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      exclude: ['node_modules', 'dist', '**/*.config.*'],
    },
  },
  resolve: {
    alias: {
      '@': resolve(__dirname, './src'),
    },
  },
});

Ce fichier étend la config Vite pour les tests : globals active describe/it/expect sans imports, jsdom simule le DOM, coverage génère des rapports. Ajoutez un alias '@/' pour importer src facilement. Piège : sans plugins: [react()], les JSX ne compilent pas en test.

Créer le setup global des tests

src/test-setup.ts
import '@testing-library/jest-dom';

Ce fichier s'exécute avant chaque test suite, étendant expect avec des matchers DOM comme toBeInTheDocument. Court et efficace, il évite les imports répétitifs. Piège : l'oublier casse les assertions RTL.

Ajouter les scripts de test dans package.json

package.json
{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview",
    "test:unit": "vitest",
    "test:ui": "vitest --ui",
    "test:coverage": "vitest run --coverage"
  }
}

On ajoute des scripts npm pour lancer les tests (vitest), l'UI (--ui), et la coverage. vitest run pour CI. Copiez juste la section scripts dans votre package.json existant. Piège : utiliser npm test sans le définir pointe sur Vitest.

Créer un composant à tester (compteur)

src/Counter.tsx
import { useState } from 'react';

type CounterProps = {
  initialValue?: number;
};

export function Counter({ initialValue = 0 }: CounterProps) {
  const [count, setCount] = useState(initialValue);

  return (
    <div>
      <h2>Compteur: {count}</h2>
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
      <button onClick={() => setCount(initialValue)}>Reset</button>
    </div>
  );
}

Ce composant simple utilise useState pour un compteur incrémentable. Props optionnelles pour flexibilité. Idéal pour tester renders, events et state. Piège : sans key sur boutons, React peut warn en tests batchés.

Écrire des tests unitaires basiques

src/Counter.test.tsx
import { describe, it, expect } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { Counter } from './Counter';

describe('Counter', () => {
  it('affiche le compteur initial à 0', () => {
    render(<Counter />);
    expect(screen.getByText('Compteur: 0')).toBeInTheDocument();
  });

  it('incrémente le compteur', async () => {
    render(<Counter />);
    fireEvent.click(screen.getByText('+'));
    expect(screen.getByText('Compteur: 1')).toBeInTheDocument();
  });

  it('réinitialise avec prop initialValue', () => {
    render(<Counter initialValue={5} />);
    fireEvent.click(screen.getByText('Reset'));
    expect(screen.getByText('Compteur: 5')).toBeInTheDocument();
  });
});

Ces tests vérifient render initial, interactions userEvent et props. fireEvent simule clics. Avec globals: true, pas d'import describe/it. Piège : utiliser await sans act() pour useState updates ; ici async pour cohérence.

Tests avancés avec mocks et snapshots

src/Counter.test.tsx
import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { Counter } from './Counter';

const mockConsole = vi.fn();

describe('Counter avancés', () => {
  it('utilise un mock pour console.log', () => {
    vi.spyOn(console, 'log').mockImplementation(mockConsole);
    render(<Counter initialValue={10} />);
    fireEvent.click(screen.getByText('-'));
    expect(mockConsole).toHaveBeenCalledWith('Compteur décrémenté');
    vi.restoreAllMocks();
  });

  it('snapshot du rendu initial', () => {
    const { asFragment } = render(<Counter initialValue={42} />);
    expect(asFragment()).toMatchSnapshot();
  });
});

On mocke console avec vi.spyOn (API Vitest native), teste appels, et snapshot pour valider JSX. vi.restoreAllMocks() nettoie. Ajoutez ceci après les tests basiques. Piège : snapshots changent avec props ; updatez avec vitest -u.

Lancer et déboguer les tests

Exécutez npm run test:unit pour watch mode (tests relancent auto). npm run test:ui ouvre http://localhost:51204 pour filtrer/focus tests. Pour coverage : npm run test:coverage génère coverage/coverage-final.json et index.html. Utilisez --reporter=verbose pour traces détaillées.

Bonnes pratiques

  • Utilisez vi.mock pour modules externes : Mockez fetch/API avant imports avec chemin dynamique (vi.mock('./api')).
  • Activez coverage thresholds dans vitest.config.ts : { lines: 80, functions: 80 } pour CI fails.
  • Préférez userEvent à fireEvent pour events réalistes (type, hover).
  • Tests isolés : Un it par comportement, max 10 assertions.
  • Workspace multi-projets : Vitest supporte projects: ['./packages/*'] pour monorepos.

Erreurs courantes à éviter

  • JSDOM non configuré : Erreurs 'document is undefined' → ajoutez environment: 'jsdom'.
  • Imports manquants en non-globals : Si globals:false, importez describe/it/expect explicitement.
  • Mocks non restaurés : Polue tests suivants → toujours vi.restoreAllMocks() ou afterEach.
  • Coverage inexacte : Excluez node_modules/dist explicitement, utilisez provider: 'v8' pour ESM.

Pour aller plus loin