Aller au contenu

Tests natifs de Node.js : couverture et rapports

Fenêtre de terminal
node --test --experimental-test-coverage
ℹ start of coverage report
ℹ ----------------------------------------------------------
ℹ file | line % | branch % | funcs % | uncovered lines
ℹ ----------------------------------------------------------
ℹ src/panier.js | 88.89 | 66.67 | 100.00 | 24-26
ℹ src/somme.js | 100.00 | 100.00 | 100.00 |
ℹ ----------------------------------------------------------
ℹ all files | 92.31 | 80.00 | 100.00 |
ℹ end of coverage report

L’option garde le nom --experimental-test-coverage dans de nombreuses versions : vérifier node --help pour la version installée. La couverture s’appuie sur le moteur V8 : elle mesure les lignes, branches et fonctions exécutées. Elle montre ce qui n’est pas testé, mais ne prouve pas que le code est correct.

Selon la version de Node.js, des options imposent un minimum (la commande échoue sinon) :

Fenêtre de terminal
node --test --experimental-test-coverage \
--test-coverage-lines=80 --test-coverage-branches=70 --test-coverage-functions=80

Choisir des seuils atteignables, puis les relever progressivement : un seuil trop haut encourage des tests sans valeur.

Fenêtre de terminal
node --test --experimental-test-coverage \
--test-coverage-include="src/**" \
--test-coverage-exclude="src/**/*.test.js" \
--test-coverage-exclude="src/main.js"

Par défaut, les fichiers de test et ceux de node_modules sont exclus. Inclure explicitement src/** pour que les fichiers jamais importés par un test apparaissent aussi dans le rapport (sinon la couverture paraît meilleure qu’elle n’est).

/* node:coverage ignore next 3 */
if (process.env.DEBUG) {
console.log('diagnostic');
}
/* node:coverage disable */
function uniquementEnDeveloppement() {}
/* node:coverage enable */

À réserver au code inatteignable ou non testable ; justifier chaque exclusion.

Un rapporteur (reporter) choisit le format de sortie :

Fenêtre de terminal
node --test --test-reporter=spec # lisible (défaut dans un terminal)
node --test --test-reporter=dot # un point par test (compact)
node --test --test-reporter=tap # format TAP (défaut hors terminal selon la version)
node --test --test-reporter=junit # XML pour les outils d'intégration continue
node --test --test-reporter=lcov # couverture au format lcov (avec la couverture activée)
Rapporteur Usage
spec Développement : arborescence lisible
dot Beaucoup de tests, sortie réduite
tap Compatible avec les outils TAP
junit Intégration continue, rapports de tests
lcov Couverture exploitable par des outils de revue

Plusieurs rapporteurs en parallèle, chacun vers une destination :

Fenêtre de terminal
node --test --experimental-test-coverage \
--test-reporter=spec --test-reporter-destination=stdout \
--test-reporter=junit --test-reporter-destination=rapport-tests.xml \
--test-reporter=lcov --test-reporter-destination=lcov.info

Chaque --test-reporter est associé au --test-reporter-destination qui le suit (stdout, stderr ou un fichier).

Convertir lcov.info en rapport navigable :

Fenêtre de terminal
sudo apt install lcov
genhtml lcov.info --output-directory coverage-html

Ouvrir coverage-html/index.html dans le navigateur pour voir les lignes non couvertes. Ajouter coverage-html/ et lcov.info au .gitignore.

{
"scripts": {
"test": "node --test",
"test:ci": "node --test --experimental-test-coverage --test-reporter=spec --test-reporter-destination=stdout --test-reporter=junit --test-reporter-destination=rapport-tests.xml",
"test:watch": "node --test --watch"
}
}

Distinguer le script local (test, rapide, lisible) du script CI (test:ci, couverture et rapports).

Gitea Actions (voir Gitea Actions : écrire un workflow) :

name: Tests
on:
push:
branches: [main]
pull_request:
jobs:
tests:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run test:ci
- uses: actions/upload-artifact@v3
if: always()
with:
name: rapports
path: rapport-tests.xml

upload-artifact@v3 : la version 4 n’est pas prise en charge par Gitea (voir Gitea Actions : cache et artefacts).

Lanceur natif Vitest
Couverture --experimental-test-coverage (V8) @vitest/coverage-v8 ou istanbul
Seuils Options de ligne de commande coverage.thresholds
Rapport HTML Via lcov + genhtml Intégré (html)
Snapshots, mocks de modules, DOM Limités Complets

Voir Vitest : couverture et snapshots.

Symptôme Piste
bad option: --experimental-test-coverage Version de Node.js trop ancienne
Aucune ligne de couverture pour certains fichiers Fichiers non importés par un test, ou exclus : --test-coverage-include
--test-coverage-lines inconnue Version plus ancienne : vérifier node --help
Le rapport JUnit est vide Destination non indiquée ou rapporteur sans test exécuté
Sortie illisible en CI Utiliser spec avec une destination explicite, junit pour les outils
Couverture différente en local et en CI Fichiers inclus différents, tests ignorés par l’environnement

Ubuntu 24.04 et 26.04 : différences à connaître

Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »

Aucune propre à Ubuntu. Le paquet lcov (sudo apt install lcov) fournit genhtml sur les deux versions.