metalfrom.eu/vitest.mutation.full.config.js
Nicolas Fryder 366bb8630d
Some checks are pending
CI / javascript (push) Waiting to run
CI / python (push) Waiting to run
CI / mutation (push) Waiting to run
perf(tests): porte de qualité 17 s → 6 s, mutation complète 5 min → 3 min 40
Passe de performance guidée par la mesure, pas par l'intuition.

Porte de qualité (`npm run check`) — la commande qui tourne des dizaines de
fois par jour :
- Les 5 vérifications sont indépendantes : exécutées en parallèle via
  scripts/check.mjs au lieu d'un enchaînement `&&` qui imposait la somme des
  durées ET 7 démarrages npm imbriqués.        14 s → 6 s
- Cache ESLint (--cache) et compilation incrémentale tsc.  16 s → 14 s
- Chemin critique restant : vitest 4,9 s, dont ~2 s de mise en place jsdom.

Tests de mutation :
- Config Vitest dédiée en pool `threads` sans ré-isolation. Mesuré sur le
  dry-run Stryker : overhead d'amorçage 12 844 ms → 1 592 ms, soit ~90 % du
  cycle par mutant.                             5 min 02 → 3 min 40
- Le mode incrémental ramène le profil complet à 12 s après une édition.

Pistes mesurées puis REJETÉES (documentées dans README-CI.md pour éviter
qu'on les retente) :
- Découper la mutation en 5 processus Stryker parallèles : 262 s contre 235 s.
  Chaque processus repaie son bac à sable et son dry-run.
- Monter `concurrency` de 6 à 16 : aucun effet (~8,5 mutants/s partout), le
  débit est borné par l'orchestration mono-processus de Stryker.
- Séparer vitest API/frontend en deux processus : aucun gain, jsdom domine.
- Pool `threads` sur la suite complète : 18,8 s contre 3,5 s. Le bon réglage
  dépend du jeu de fichiers (jsdom ou non) — d'où deux configs distinctes.

Le périmètre muté est inchangé (1511 mutants) : un score obtenu en retirant
les mutants gênants vaudrait moins que pas de score.

Corrections au passage :
- scripts/*.mjs n'était couvert par aucune section ESLint
- Les deux suites pytest ont chacune un paquet `src` : réunies dans un seul
  processus, le premier importé masquait l'autre. Séparées (et parallèles).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-18 13:49:54 +02:00

38 lines
1.7 KiB
JavaScript

import { defineConfig } from "vitest/config";
/**
* Config Vitest du profil de mutation COMPLET (`npm run test:mutation:full`).
*
* Deux réglages, tous deux mesurés sur l'overhead d'amorçage que Stryker paie
* à CHAQUE activation de mutant (ligne « net / overhead » du dry-run) :
*
* 1. Ne charger que les tests API. Le fichier a11y initialise jsdom (~2 s) et
* ne couvre aucune ligne de l'API : le charger reviendrait à payer ce coût
* 1500 fois.
*
* 2. Workers `threads` sans ré-isolation. Mesuré sur ce jeu de fichiers :
* forks, isolate:true (défaut) : overhead 12 844 ms
* forks, isolate:false : overhead 7 064 ms
* threads, isolate:false : overhead 1 592 ms ← retenu
* Le temps net des tests, lui, ne bouge presque pas (~1 s) : l'amorçage
* représentait 90 % du cycle.
*
* À NE PAS reporter dans vitest.config.js : la suite complète contient le
* test a11y, et sous jsdom ce même réglage est nettement PLUS lent (18,8 s
* contre 3,5 s). Le bon réglage dépend du jeu de fichiers — re-mesurer.
*
* L'isolation ne protège de rien ici : chaque fichier de test construit sa
* propre app et son propre faux pool, il n'y a aucun état global mutable.
*/
export default defineConfig({
test: {
environment: "node",
pool: "threads",
poolOptions: { threads: { isolate: false, singleThread: true } },
// Stryker parallélise déjà entre mutants (concurrency) : paralléliser aussi
// les fichiers à l'intérieur d'un worker ne ferait que se disputer les cœurs.
fileParallelism: false,
include: ["apps/api/test/**/*.test.js"],
reporters: ["default"],
},
});