# 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, HasPermission - `internal/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** : - `authStore` vs `AuthContext` — cohérence (réduire après unification auth) - `client.ts` — découper puis tester interceptors, retry, offline queue - `optimisticUpdates.ts` — rollback, invalidation - `marketplaceService`, `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 ```yaml # .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 `|| true` des tests frontend (ci.yml) | 5 min | | **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.**