340 lines
13 KiB
Markdown
340 lines
13 KiB
Markdown
|
|
# 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.**
|