Aller au contenu

Vitest : couverture et snapshots

La couverture indique quelles lignes, branches et fonctions sont exécutées par les tests.

Fenêtre de terminal
npm install -D @vitest/coverage-v8
npx 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.

vitest.config.ts
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.

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.

Fenêtre de terminal
npx vitest run --coverage # code de sortie non nul si un seuil n'est pas atteint
/* 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.

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.

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.

Fenêtre de terminal
npx vitest run -u # met à jour tous les snapshots obsolètes ou modifiés

Relire le diff (git diff) avant de valider : mettre à jour sans lire revient à supprimer le test.

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.

Fenêtre de terminal
npx vitest run --coverage --reporter=default --reporter=junit --outputFile.junit=./rapport-tests.xml

Le format junit est lisible par la plupart des outils d’intégration continue, dont Gitea Actions (voir Gitea Actions : exemples).

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.