Vitest : couverture et snapshots
Couverture de code
Section intitulée « Couverture de code »La couverture indique quelles lignes, branches et fonctions sont exécutées par les tests.
npm install -D @vitest/coverage-v8npx vitest run --coverage % Coverage report from v8--------------|---------|----------|---------|---------|-------------------File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s--------------|---------|----------|---------|---------|-------------------All files | 92.31 | 80 | 100 | 92.31 | panier.ts | 88.89 | 66.67 | 100 | 88.89 | 24-26 somme.ts | 100 | 100 | 100 | 100 |--------------|---------|----------|---------|---------|-------------------| Colonne | Mesure |
|---|---|
% Stmts / % Lines |
Instructions ou lignes exécutées |
% Branch |
Branches (if, ?:, &&) parcourues dans chaque sens |
% Funcs |
Fonctions appelées |
Uncovered Line #s |
Lignes jamais exécutées |
Une couverture de 100 % ne prouve pas que le code est correct : elle montre seulement qu’il a été exécuté. Les lignes non couvertes sont plus instructives que le pourcentage global.
Configuration
Section intitulée « Configuration »import { defineConfig } from 'vitest/config';
export default defineConfig({ test: { coverage: { provider: 'v8', reporter: ['text', 'html', 'lcov'], include: ['src/**/*.{ts,tsx}'], exclude: ['src/**/*.test.*', 'src/**/*.d.ts', 'src/main.tsx'], thresholds: { lines: 80, branches: 70, functions: 80, statements: 80, }, }, },});| Option | Rôle |
|---|---|
provider |
v8 (rapide, intégré à Node.js) ou istanbul (instrumentation, plus précis sur certains cas) |
reporter |
text (terminal), html (rapport navigable), lcov (outils externes), json-summary |
include / exclude |
Fichiers pris en compte (inclure aussi le code non testé pour le voir apparaître) |
thresholds |
Seuils minimaux : la commande échoue s’ils ne sont pas atteints |
reportsDirectory |
Dossier du rapport (coverage/ par défaut) |
Ajouter coverage/ au .gitignore. Ouvrir coverage/index.html dans un navigateur pour voir les lignes non couvertes en rouge.
Seuils et intégration continue
Section intitulée « Seuils et intégration continue »Choisir un seuil atteignable et le relever progressivement. Un seuil trop élevé encourage des tests sans valeur écrits pour gagner des points. Pour les projets existants, appliquer le seuil seulement aux fichiers modifiés (rapports lcov avec un outil de revue) plutôt qu’à l’ensemble.
npx vitest run --coverage # code de sortie non nul si un seuil n'est pas atteintIgnorer volontairement des lignes
Section intitulée « Ignorer volontairement des lignes »/* v8 ignore next 3 */if (process.env.DEBUG) { console.log('diagnostic');}
/* v8 ignore start */function uniquementEnDeveloppement() {}/* v8 ignore stop */À réserver au code inatteignable ou non testable (diagnostic, garde-fous) : chaque ignorance doit être justifiée.
Snapshots
Section intitulée « Snapshots »Un snapshot enregistre une valeur de sortie lors du premier lancement, puis vérifie qu’elle ne change pas.
import { expect, it } from 'vitest';
it('formate la facture', () => { const facture = formaterFacture({ numero: 'F-1', lignes: [{ article: 'A', quantite: 2 }], }); expect(facture).toMatchSnapshot();});Au premier lancement, Vitest écrit __snapshots__/fichier.test.ts.snap. Aux suivants, il compare : toute différence fait échouer le test.
Snapshot en ligne
Section intitulée « Snapshot en ligne »it('construit le message', () => { expect(construireMessage('Alice')).toMatchInlineSnapshot(`"Bonjour Alice !"`);});Vitest écrit la valeur dans le fichier de test : plus lisible pour de petites valeurs, et la revue de code voit directement la valeur attendue.
Mettre à jour
Section intitulée « Mettre à jour »npx vitest run -u # met à jour tous les snapshots obsolètes ou modifiésRelire le diff (git diff) avant de valider : mettre à jour sans lire revient à supprimer le test.
Quand utiliser des snapshots
Section intitulée « Quand utiliser des snapshots »| Bon usage | Mauvais usage |
|---|---|
| Sorties structurées stables (message d’erreur, JSON de réponse, document généré) | Grosses sorties que personne ne relit (arbres HTML entiers) |
| Empêcher une régression involontaire d’un format | Remplacer des assertions précises |
| Petits snapshots en ligne | Valeurs variables (dates, identifiants aléatoires) sans les neutraliser |
Neutraliser les valeurs variables :
expect({ id: crypto.randomUUID(), nom: 'Alice' }).toMatchSnapshot({ id: expect.any(String),});Commiter les fichiers __snapshots__/ avec le code. Un snapshot trop gros ou trop souvent mis à jour est un signal : le remplacer par des assertions explicites.
Rapport pour les revues
Section intitulée « Rapport pour les revues »npx vitest run --coverage --reporter=default --reporter=junit --outputFile.junit=./rapport-tests.xmlLe format junit est lisible par la plupart des outils d’intégration continue, dont Gitea Actions (voir Gitea Actions : exemples).
Dépannage
Section intitulée « Dépannage »| Symptôme | Piste |
|---|---|
Cannot find package '@vitest/coverage-v8' |
npm install -D @vitest/coverage-v8 (même version que Vitest) |
| Couverture à 0 % ou fichiers absents | include manquant, fichiers exclus, tests ne les importent pas |
| Seuil non atteint en CI mais atteint en local | Fichiers différents (include), tests ignorés par l’environnement |
Snapshot mismatched |
Sortie modifiée : relire le diff, puis -u si le changement est voulu |
| Snapshot qui change à chaque exécution | Valeur variable : la neutraliser |
obsolete snapshot |
Test supprimé ou renommé : -u pour nettoyer |
Couverture différente entre v8 et istanbul |
Méthodes de mesure différentes : choisir un fournisseur et s’y tenir |
Ubuntu 24.04 et 26.04 : différences à connaître
Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »Aucune.