13 KiB
STRATÉGIE DE COUVERTURE & ORCHESTRATION TMT — VEZA
Date : 2025-02-10
Mandat : Architecte qualité — redressement de la base de tests
Audits de référence : AUDIT_TESTS_ET_COUVERTURE_2025_02.md, AUDIT_FRONTEND_EXHAUSTIF_2025_02.md
Objectif : « Une régression significative ne peut plus passer inaperçue. »
0. POSTURE
Décisions appliquées. Pas de pédagogie. Pas de généralités.
1. REDÉFINITION DE LA COUVERTURE
1.1 Définition opérationnelle
Couverture = probabilité que le système se comporte correctement lorsqu'il est modifié.
Trois axes :
| Axe | Signification | Mesure |
|---|---|---|
| Logique critique | Auth, RBAC, commerce, upload, webhooks | Branches exercées sur chemins nominaux ET erreurs |
| Branches d'erreur | catch, retry, fallback, validation | % branches catch/error couvertes |
| Contrats implicites | API, auth, invariants métier | Tests contractuels, assertions sur schémas |
1.2 Cibles chiffrées (différenciées)
| Domaine | Cible branches | Cible lignes | Bloquant |
|---|---|---|---|
| Auth / RBAC | ≥ 90% | ≥ 85% | Oui |
| Commerce / Marketplace | ≥ 85% | ≥ 80% | Oui |
| Upload / Tracks | ≥ 85% | ≥ 80% | Oui |
| Services API (client.ts, interceptors) | ≥ 80% | ≥ 75% | Oui |
| Handlers / Services Go critiques | ≥ 90% | ≥ 85% | Oui |
| Hooks / utils frontend | ≥ 80% | ≥ 80% | Oui |
| Logique utilitaire | ≥ 80% | ≥ 80% | Non (warning) |
| UI pure (composants) | Indicateur | Indicateur | Non |
Pourquoi un seuil global unique est architecturalement débile :
Un seuil global (ex. 80%) masque les zones critiques sous-testées. Le client API (2238 lignes) peut être négligé tandis que des utils triviales gonflent le pourcentage. Les domaines à fort risque (auth, RBAC) doivent avoir des seuils plus élevés et être vérifiés séparément.
2. STRATÉGIE PAR COUCHE
2.1 Backend (Go)
Fonctions critiques identifiées (à couvrir en priorité) :
internal/core/auth/service.go— ValidateSession, HasRole, HasPermissioninternal/api/router.go— Middleware auth, RBAC- Handlers : auth, tracks, playlists, marketplace, webhooks
internal/database/— Migrations, prepared statements (chemins erreur)
Tests à écrire/corriger :
| Type | Action | Justification |
|---|---|---|
| Chemins nominaux | Corriger mocks auth middleware | Échec actuel : 0 out of 1 expectation(s) were met |
| Erreurs métier | Ajouter tests sur erreurs 401, 403, 404 | RBAC non validé |
| Erreurs infra | Simuler DB down, timeout | Branches jamais exercées |
Interdictions :
- Mocks non alignés avec les interfaces réelles (signatures Go)
- Tests dépendants du timing (supprimer ou utiliser
testify/assert.Eventually)
2.2 Frontend
| Couche | Rôle | Outil | Couverture |
|---|---|---|---|
| Unitaire | Hooks, helpers, utils, services purs | Vitest | branches ≥ 80% sur features/*, hooks, services |
| Intégration | Pages, flows (MSW) | Vitest + MSW | Pas de logique métier significative non testée hors E2E |
| E2E | Flux critiques (auth, playlists, search) | Playwright | Smoke obligatoire |
Objectif : Zéro logique métier significative non testée hors E2E.
Zones prioritaires :
authStorevsAuthContext— cohérence (réduire après unification auth)client.ts— découper puis tester interceptors, retry, offline queueoptimisticUpdates.ts— rollback, invalidationmarketplaceService,webhookService— peu couverts
2.3 Rust (Chat, Stream)
- Clippy : 0 warnings (déjà vital)
- Tests : Déjà dans TMT vital
- Pas de changement structurel prévu
3. ÉLIMINATION DES FAUX POSITIFS
| Élément | Action | Argument |
|---|---|---|
npm run test -- --run || true |
Supprimer | Tests qui passent malgré régression = illusion |
| Snapshots sans assertion sémantique | Supprimer ou remplacer | Snapshots décoratifs ; ajouter expect sur comportement |
| Tests qui ne testent que React/framework | Supprimer | Redondants avec tests framework |
PlaylistErrorBoundary.test.tsx (jest.spyOn) |
Remplacer par vi.spyOn |
Incohérence Vitest |
| Tests Go auth/RBAC avec mocks cassés | Réparer | Sinon les exclure explicitement (documenté) |
4. RÉDUCTION DU MOCKING
Objectif : remplacer le mocking par de la composition testable.
| Action | Détail |
|---|---|
| Extraction de ports/adapters | Interfaces pour authService, apiClient — injection en tests |
| MSW ciblé | Garder MSW pour les handlers HTTP ; ne pas mocker 10+ modules par test |
| Doubles de test minimaux | Backend : interfaces Go déjà présentes ; utiliser des implémentations stub |
| Unifier auth | Une source (Store) → un mock au lieu de deux |
Critère : si un test nécessite > 5 mocks, le design est toxique.
5. ORCHESTRATION TMT
5.1 État actuel (diagnostic)
| Aspect | État | Détail |
|---|---|---|
| TMT utilisé en CI | ❌ Non | La CI n'appelle jamais tmt run |
| Types de tests TMT | Partiel | Build, bundle_size, build_perf, no_critical_js ; Go unit (internal) ; Rust clippy/test |
| Vitest | ❌ Hors TMT | Exécuté directement dans ci.yml avec || true |
| Playwright | ❌ Hors TMT | Workflow séparé, sans working-directory: apps/web |
| Contournement | CI directe | go test, npm run test, npx playwright test sans TMT |
Conclusion : TMT est une couche déclarative sous-exploitée. La CI est une projection ad-hoc, pas fidèle à TMT.
5.2 Rôle cible de TMT
TMT devient :
- Point d'entrée unique pour tous les tests
- Garant de l'ordre, des dépendances, des profils (local / CI / nightly)
5.3 Modélisation TMT cible
tmt/
├── plans/
│ ├── vital.fmf # Tier 1 — bloque tout
│ ├── integration.fmf # Tier 2 — nécessite infra (DB, Redis)
│ └── nightly.fmf # Tier 3 — E2E, contract, visuels
├── tests/
│ ├── frontend/
│ │ ├── build.sh
│ │ ├── build_perf.sh
│ │ ├── bundle_size.sh
│ │ ├── no_critical_js.sh
│ │ └── unit.sh # NOUVEAU — npm run test -- --run
│ ├── frontend-e2e/
│ │ └── playwright.sh # NOUVEAU — npx playwright test
│ ├── backend/
│ │ ├── unit.sh
│ │ ├── integration.sh
│ │ ├── core_isolation.sh
│ │ ├── startup_time.sh
│ │ └── memory_budget.sh
│ └── services/
│ ├── rust_clippy.sh
│ └── rust_test.sh
└── README.md
Variables d'environnement explicites :
| Variable | Valeur | Rôle |
|---|---|---|
GOMAXPROCS |
1 | Low-power backend |
LIBGL_ALWAYS_SOFTWARE |
1 | GPU désactivé |
RUST_BACKTRACE |
0 | Bruit minimisé |
VEZA_TEST_DB_URL |
(optionnel) | Intégration |
VEZA_E2E_API_URL |
(optionnel) | E2E |
Artefacts de sortie :
| Artefact | Emplacement | Usage |
|---|---|---|
| Coverage Go | veza-backend-api/coverage.out |
Rapport, seuils |
| Coverage Vitest | apps/web/coverage/ |
Rapport, seuils |
| Playwright report | apps/web/playwright-report/ |
Debug E2E |
5.4 Plans TMT
| Plan | Tier | Contenu | Bloquant |
|---|---|---|---|
| vital | 1 | build, bundle_size, build_perf, no_critical_js, backend unit, rust clippy/test, frontend unit | Oui |
| legacy | 2 | integration (backend), startup_time, memory_budget | Non (warning) |
| nightly | 3 | E2E Playwright, contract, Storybook audit | Non |
Changement majeur : frontend/unit.sh ajouté au plan vital. Exécute npm run test -- --run sans || true.
6. COUVERTURE & TMT
| Plan | Couverture produite | Agrégation | Seuils |
|---|---|---|---|
| vital | vitest run --coverage, go test -coverprofile |
Rapports séparés par composant | Évalués en CI ; échec si seuils non atteints |
| legacy | Idem | Idem | Indicateur |
| nightly | E2E (pas de coverage classique) | Playwright HTML report | Binaire (pass/fail) |
Agrégation : pas de rapport global unique. Chaque composant (frontend, backend) a ses seuils. CI échoue si un seuil est violé.
Aucun || true. Aucune exception silencieuse.
7. INTÉGRATION CI
Principe : La CI est une projection fidèle de l'exécution TMT.
7.1 Règle
La CI ne doit jamais appeler directement vitest, go test, playwright.
Elle appelle toujours tmt run plan --name /vital (ou équivalent).
7.2 Schéma cible
# .github/workflows/ci.yml (simplifié)
jobs:
test:
steps:
- uses: actions/checkout@v4
- name: Install TMT
run: pip install tmt
- name: Run Vital Tests
run: tmt run plan --name /vital
# Plus de go test, npm test, etc. directs
7.3 Workflows à corriger/supprimer
| Workflow | Action | Raison |
|---|---|---|
ci.yml |
Remplacer jobs par tmt run |
Point d'entrée unique |
frontend-ci.yml |
Supprimer | Chemin apps/web-frontend inexistant |
backend-ci.yml |
Supprimer | Chemin apps/backend-api inexistant |
playwright.yml |
Intégrer dans TMT nightly ou garder séparé avec working-directory: apps/web |
E2E nécessite runtime différent |
8. FEUILLE DE ROUTE
Phase 1 — Rétablissement de la vérité (1–2 semaines)
| Priorité | Action | Effort |
|---|---|---|
| P0 | Supprimer ` | |
| P0 | Corriger playlist_duplicate_transaction_test.go:80 (compile) |
2 h |
| P0 | Exclure/corriger tests Go qui paniquent (testutils, RoomService) | 4 h |
| P1 | Ajouter working-directory: apps/web à playwright.yml |
15 min |
| P1 | Supprimer frontend-ci.yml, backend-ci.yml (ou corriger chemins) | 15 min |
Objectif : tests qui échouent = build rouge assumé.
Phase 2 — Couverture ciblée (1–3 mois)
| Priorité | Action | Effort |
|---|---|---|
| P1 | Réparer tests auth middleware (Go) | 8 h |
| P1 | Ajouter tmt/tests/frontend/unit.sh et l'intégrer au plan vital |
2 h |
| P1 | Faire appeler la CI tmt run plan --name /vital |
4 h |
| P2 | Validation seuils coverage en CI (par domaine) | 8 h |
| P2 | Remplacer jest.spyOn par vi.spyOn | 2 h |
| P2 | Tests branches d'erreur sur auth, RBAC, client API | 24 h |
Objectif : ajout de tests uniquement sur zones critiques ; suppression de tests toxiques.
Phase 3 — Stabilisation (2–4 semaines)
| Priorité | Action | Effort |
|---|---|---|
| P2 | Temps d'exécution suite unitaire < 2 min (frontend) | Variable |
| P2 | Flakiness = 0 (audit, correction) | Variable |
| P3 | Découper client.ts (modules testables) | 40 h |
| P3 | Unifier auth (Context → Store) | 24 h |
Objectif : temps maîtrisé ; zéro tolérance au flaky.
9. LIVRABLE — LISTE PRIORISÉE
9.1 Tests à écrire
| Domaine | Fichier / Zone | Type | Priorité |
|---|---|---|---|
| Auth | internal/core/auth |
Unit (chemins erreur) | P0 |
| RBAC | rbac_auth_middleware_test.go |
Corriger mocks | P0 |
| Client API | client.ts (après découpage) |
Interceptors, retry | P1 |
| Commerce | marketplaceService, cartStore |
Unit | P1 |
| Webhooks | webhookService, handlers |
Unit + integration | P1 |
| Optimistic | optimisticUpdates.ts |
Rollback, invalidation | P2 |
9.2 Tests à corriger
| Test | Action | Priorité |
|---|---|---|
auth_middleware_test.go |
Aligner mocks avec ValidateSession | P0 |
rbac_auth_middleware_test.go |
Aligner mocks HasRole/HasPermission | P0 |
PlaylistErrorBoundary.test.tsx |
jest → vi | P1 |
auth.integration.test.tsx |
Réduire mocks, scinder | P2 |
9.3 Tests à supprimer
| Test | Raison | Priorité |
|---|---|---|
| Snapshots sans assertion sémantique | Illusion de couverture | P2 |
| Tests redondants (framework only) | Aucune valeur métier | P2 |
Tests orphelins (jest.config.js si Jest inutilisé) |
Nettoyage | P3 |
10. RÉSUMÉ EXÉCUTIF
| Principe | Décision |
|---|---|
| Couverture | Différenciée par domaine ; domaines critiques ≥ 90% branches |
| Faux positifs | Suppression de || true ; tests cassés = build rouge |
| Mocking | Réduction ; composition testable ; ≤ 5 mocks par test |
| TMT | Point d'entrée unique ; CI appelle tmt run |
| Phases | 1. Vérité → 2. Couverture ciblée → 3. Stabilisation |
Phrase de clôture : Une régression significative ne peut plus passer inaperçue — à condition que les phases 1 et 2 soient exécutées sans compromis.
Fin du document.