đ„ Guide Complet des Tests E2Eï
Ce guide centralise toutes les informations sur les tests End-to-End avec Playwright et la génération de vidéos de documentation vivante.
đŻ Introductionï
Les tests E2E de KoproGo testent toute la stack :
â Frontend (Astro + Svelte)
â Backend (Rust + Actix-web)
â Base de donnĂ©es (PostgreSQL)
â API REST
â PWA + Mode Offline
Chaque test peut enregistrer une vidéo de démonstration : générez-les localement, puis ajoutez les fichiers .webm dans docs/_static/videos/ pour enrichir la documentation.
đ DĂ©marrage Rapideï
Installation (une seule fois)ï
# Installer les dépendances frontend
cd frontend
npm install
# Installer Playwright et Chromium
npx playwright install chromium
DĂ©marrer les servicesï
# Depuis la racine du projet
make up
# Les services démarrent via Docker Compose + Traefik, sur des ports
# DĂCALĂS pour ne pas entrer en collision avec la dĂ©mo (ADR 0050) :
# Frontend: http://localhost:8090
# API: http://localhost:8090/api/v1
# Traefik: http://localhost:8091
# Postgres: localhost:15432 MinIO: localhost:19000 / 19001
Lancer les testsï
# Le gate, Ă la vitesse
make test-e2e
# La vitrine : le MĂME parcours, en cadence, narrĂ©, avec sa galerie.
# Harnais sĂ©parĂ© â il ne rend aucun verdict et ne touche pas au gate.
make vitrine
Le tĂ©moin dâinterruption backend (#880)ï
Le backend de la pile de recette tourne sous cargo-watch
(backend/Dockerfile.dev:71) : une édition de fichier Rust pendant une
campagne recompile et coupe le service ~90s. Sans témoin, ces échecs sont
indiscernables dâune rĂ©gression â 83 des 95 Ă©checs du 2026-09-13 visaient un
backend mort (cf. issue #880).
make test-e2e encadre désormais la commande Playwright réelle de
scripts/e2e-guarded.sh, qui surveille lâempreinte (PID + heure de
démarrage) du process backend pendant toute la campagne
(scripts/e2e-backend-watch.sh) :
exit <code Playwright> aucun redĂ©marrage dĂ©tectĂ© â verdict inchangĂ©
exit 75 (EX_TEMPFAIL) backend redémarré pendant la campagne :
campagne NON MESURĂE, quel qu'ait Ă©tĂ© le rĂ©sultat
brut â voir frontend/test-results/campaign-verdict.json
et frontend/test-results/backend-restarts.jsonl
Si lâempreinte est indisponible (pas de dĂ©mon Docker, banc distant), le
code de sortie de la commande encadrée est transmis tel quel, mais
campaign-verdict.json porte "monitoring": "unavailable" et
"backend_restarts": null â jamais un zĂ©ro silencieux qui prĂ©tendrait
avoir vérifié.
Tests du tĂ©moin lui-mĂȘme (4 catĂ©gories, sans docker rĂ©el â fixtures rejouant une sĂ©quence dâempreintes) :
make e2e-guard-test
đč Enregistrer de Nouveaux Testsï
MĂ©thode 1 : Playwright Codegen (â RecommandĂ©)ï
Enregistrement interactif - Playwright génÚre le code automatiquement !
# Assurer que l'app tourne
make up
# Lancer l'enregistrement
cd frontend
npm run codegen
# OU pour mobile
npm run codegen:mobile
# Alternative depuis la racine
make codegen
make codegen DEVICE=mobile
Ce qui se passe :
Un navigateur sâouvre sur
http://localhost:8090Une fenĂȘtre âPlaywright Inspectorâ sâouvre Ă cĂŽtĂ©
Vous naviguez dans lâapp (clic, remplissage de formulaires, etc.)
Le code du test apparaĂźt en temps rĂ©el dans lâInspector
Vous copiez le code et le collez dans un fichier
.spec.ts
Sauvegarder le test :
// frontend/tests/e2e/mon-test.spec.ts
import { test, expect } from '@playwright/test';
test('Mon scénario de test', async ({ page }) => {
await page.goto('/login');
await page.fill('input[type="email"]', 'test@test.com');
await page.fill('input[type="password"]', 'test123');
await page.click('button[type="submit"]');
await expect(page.locator('text=Dashboard')).toBeVisible();
});
Lancer le test :
npm run test:e2e -- mon-test.spec.ts
La vidéo sera dans frontend/test-results/ !
MĂ©thode 2 : Ăcrire le Test Manuellementï
Si vous préférez écrire le code directement :
# Créer le fichier
nano frontend/tests/e2e/mon-test.spec.ts
# Ăcrire le test (voir exemple ci-dessus)
# Lancer
npm run test:e2e -- mon-test.spec.ts
đŹ CrĂ©er des VidĂ©os Lisibles â la vitrineï
Les vidĂ©os du gate sont enregistrĂ©es Ă la vitesse des tests : elles servent au diagnostic dâun Ă©chec, pas Ă raconter le produit. Pour une vidĂ©o quâun humain suit, on passe par la vitrine, qui est un harnais sĂ©parĂ© :
make vitrine
Elle rejoue le parcours de rĂ©fĂ©rence en cadence, incruste la narration dans la page pendant lâenregistrement, et assemble une galerie autonome :
frontend/tests/e2e/journeys/vitrine/index.html
Ce qui se passe :
enregistrer-vitrine.mjsrejouetests/e2e/journeys/parcours.tsĂ raison dâune action par seconde (CADENCE_MS, dansscene.ts)Chaque Ă©tape est racontĂ©e Ă lâĂ©cran, donc visible dans la vidĂ©o
assembler-vitrine.mjsproduit la galerie et les chapitres horodatĂ©s (videos/<parcours>.json), pour sauter Ă une Ă©tape au lieu de regarder le film en entierLa CI publie le tout dans lâartefact
vitrine(ci.yml, #873)
Changer la cadence :
VITRINE_CADENCE_MS=2000 make vitrine
Warning
Il a existĂ© jusquâau 2026-09-12 un make test-e2e-slow qui modifiait
les fichiers du gate pour y insérer des pauses, puis les restaurait.
La cible, les deux scripts et leurs commandes nâexistent plus : muter
les specs du gate pour enregistrer confie au gate une responsabilité qui
nâest pas la sienne, et la MĂ©thode Foyer le nomme comme lâanti-patron Ă
éviter (#876). Le harnais de valeur ne touche à aucun fichier du gate.
đ Ajouter les VidĂ©os dans la Documentationï
Une fois les tests exécutés en local, synchronisez et versionnez les vidéos :
# Copie les vidéos + génÚre la page RST automatiquement
make docs-sync-videos
# Générer la documentation Sphinx
make docs-sphinx
# Vérifier le rendu localement
open docs/_build/html/e2e-videos.html
Les fichiers copiĂ©s dans docs/_static/videos/ doivent ĂȘtre commitĂ©s dans Git. Ils seront ensuite publiĂ©s automatiquement par le workflow documentation (.github/workflows/docs.yml).
Le dossier docs/_build/ reste local (ignoré par Git) : ne le commitez pas.
Les vidĂ©os validĂ©es sont listĂ©es dans la page đ„ VidĂ©os Tests E2E (Documentation Vivante).
đŹ Commandes Disponiblesï
Commandes npm (depuis frontend/)ï
# Enregistrement interactif
npm run codegen # Desktop
npm run codegen:mobile # iPhone 13
# Tests
npm run test:e2e # Tous les tests (headless)
PLAYWRIGHT_BASE_URL=http://localhost:8090 npm run test:e2e -- AdminDashBoard.improved.spec.ts # Suite admin
npm run test:e2e -- mon-test.spec.ts # Un test spécifique
npm run test:e2e:ui # Mode UI (interface graphique)
npm run test:e2e:headed # Voir le navigateur
npm run test:e2e:debug # Mode debug pas Ă pas
# Rapports
npm run test:e2e:report # Ouvre le rapport HTML avec vidéos
Commandes make (depuis la racine)ï
# Tests E2E
make test-e2e # Le gate, Ă la vitesse
make vitrine # La preuve de valeur : parcours narré + galerie
# Documentation
make docs-sync-videos # Copier vidéos + générer RST (local)
make docs-with-videos # Helper local pour générer vidéos + doc
make docs-sphinx # Générer doc Sphinx seule
make codegen # Playwright codegen (DEVICE=mobile pour iPhone 13)
Les cibles make test-e2e et make docs-with-videos exportent
PLAYWRIGHT_BASE_URL=$(RECETTE), dont le défaut est http://localhost:8090
â la pile de recette, jamais la dĂ©mo. Pour viser ailleurs, surchargez la
variable plutĂŽt que dâĂ©diter la cible :
make test-e2e RECETTE=http://localhost:3000
Danger
Ne visez jamais ``http://localhost`` sur un hÎte qui porte la démo.
Le port 80 y est tenu par le Traefik de la démo, qui route vers
Host(api.koprogo.com). La suite e2e Ă©crit â 480 appels POST/PUT/
DELETE â et make seed-reset POSTe sur /seed/scenario/world
pendant que make reset-db annonce « SUPPRIME TOUTES LES DONNĂES ».
Ce nâest pas un risque Ă entourer de prĂ©cautions : la prĂ©condition de
reproductibilité de la recette est exactement ce qui détruirait la démo.
Sây ajoutent 130 connexions sur /auth/login contre une limite de
5/minute, qui ont dĂ©jĂ valu un bannissement CrowdSec de lâadresse source
le 2026-09-01.
Câest lâobjet de lâADR 0050 et de lâissue #872.
Viser un hĂŽte distant : deux variables obligatoiresï
Contre localhost, rien Ă faire : la campagne amorce sa propre base et le
mot de passe de repli du seed (admin123) y est lĂ©gitime. Câest aussi le
cas en CI.
Contre un hĂŽte que la campagne nâamorce pas â la dĂ©mo, une prĂ©production â
le superadministrateur est créé par seed_superadmin, qui fait un upsert Ă
chaque dĂ©marrage depuis lâenvironnement de cet hĂŽte. Ce que vaut le repli
dĂ©pend donc de ce que lâexploitant a posĂ© lĂ -bas, et vous ne pouvez pas le
deviner : sans choix explicite, la connexion rend 401 Invalid credentials,
un message qui parle dâidentifiants lĂ oĂč le dĂ©faut est de configuration.
export KOPROGO_SUPERADMIN_EMAIL=...
export KOPROGO_SUPERADMIN_PASSWORD=...
export KOPROGO_CONFIRME_HOTE_DISTANT=1
PLAYWRIGHT_BASE_URL=https://koprogo.com npm run test:e2e
Sans les deux premiĂšres variables, la suite sâarrĂȘte avant la premiĂšre
requĂȘte et nomme celle qui manque (tests/e2e/helpers/identifiants.ts).
Câest dĂ©libĂ©rĂ© : le 2026-09-10, le 401 muet a coĂ»tĂ© une demi-journĂ©e
dâenquĂȘte sur un dĂ©faut produit qui nâexistait pas (#870).
Le garde regarde si la variable est posĂ©e, pas ce quâelle contient. Choisir une valeur faible en connaissance de cause est une dĂ©cision dâexploitation, et le serveur lâavertit dĂ©jĂ de son cĂŽtĂ© au dĂ©marrage. Ce quâil refuse, câest de partir vers un hĂŽte distant sans que personne nâait choisi.
Danger
La troisiĂšme variable existe pour le cas inverse et plus dangereux
(#872) : un identifiant qui FONCTIONNE. Elle se nomme
KOPROGO_CONFIRME_HOTE_DISTANT.
Un mot de passe correct contre un hĂŽte distant ne rend aucun 401 â il
laisse la campagne enchaßner ses écritures, son seed-reset, son
reset-db, sur des données vivantes. Le garde ne peut pas savoir si le
mot de passe est correct sans lâessayer, et lâessayer est justement
lâaction quâil doit empĂȘcher. Il exige donc une confirmation sĂ©parĂ©e de
lâidentifiant, que ce dernier soit correct ou non.
Warning
Corriger le mot de passe en base ne tient pas : lâupsert repart de
lâenvironnement au prochain dĂ©marrage et lâĂ©crase. Câest
KOPROGO_SUPERADMIN_PASSWORD de lâhĂŽte quâil faut changer, pas la ligne.
Note
Sur la démo (api.koprogo.com), la variable porte admin123 depuis le
2026-09-12, par dĂ©cision dâexploitation : le mot de passe survit dĂ©sormais
aux redĂ©ploiements, au prix dâĂȘtre celui que le dĂ©pĂŽt publie. Le backend
lâannonce Ă chaque dĂ©marrage â « SĂCURITĂ : le superadmin utilise le mot de
passe par défaut, lisible dans le dépÎt public ».
Note
Une campagne complÚte contre la production a déjà provoqué un bannissement
CrowdSec de lâadresse source. Une exception existe depuis le 2026-09-02,
mais /api/v1/auth/login reste limitĂ© Ă 5 requĂȘtes par minute et par
adresse : commencer par un parcours étroit, pas par la suite entiÚre.
đ Structure des Fichiersï
Tests E2Eï
frontend/tests/e2e/
âââ config.ts # Helper pour construire les endpoints
âââ AdminDashBoard.improved.spec.ts # Suite complĂšte admin (org/users/buildings)
VidĂ©os GĂ©nĂ©rĂ©esï
frontend/test-results/
âââ admin-dashboard-tour-test-chromium/
â âââ video.webm # â VidĂ©o du test
â âââ trace.zip # Trace Playwright
â âââ test-failed-1.png # (si Ă©chec)
âââ autre-test-chromium/
âââ video.webm
Documentation VidĂ©osï
docs/_static/videos/
âââ admin-dashboard-tour.webm
âââ login-success.webm
âââ *.webm # Toutes vos vidĂ©os
docs/e2e-videos.rst # Page auto-générée
âïž Configuration Playwrightï
Le fichier frontend/playwright.config.ts configure :
Enregistrement vidéo :
video: { mode: 'on', size: { width: 1280, height: 720 } }Base URL :
baseURL: 'http://localhost:3000'WebServer : Démarre automatiquement
npm run devTimeouts : 10s par action, 30s par page
Screenshots : Uniquement en cas dâĂ©chec
đ Debuggingï
Mode UI (RecommandĂ©)ï
cd frontend
npm run test:e2e:ui
Cela ouvre une interface graphique oĂč vous pouvez :
â Voir tous vos tests
â Les lancer un par un
â Voir les vidĂ©os/screenshots
â Inspecter chaque Ă©tape
â Voir les timings
Mode Debugï
npm run test:e2e:debug
Le test sâarrĂȘte Ă chaque Ă©tape, vous pouvez :
Inspecter le DOM
Exécuter du code dans la console
Avancer pas Ă pas
đ ProblĂšmes Courantsï
â Lâapp nâest pas accessibleï
# VĂ©rifier que les services tournent â sur le port de la RECETTE.
# Un curl sur le port 80 nu interrogerait la démo et répondrait 200,
# ce qui ferait croire que votre pile tourne alors qu'elle est éteinte.
curl http://localhost:8090
curl http://localhost:8090/api/v1/health
# Si pas de réponse, démarrer :
make up
â Timeout lors des testsï
Augmentez les timeouts dans playwright.config.ts :
use: {
actionTimeout: 20000, // 20s au lieu de 10s
navigationTimeout: 60000, // 60s au lieu de 30s
}
â Les vidĂ©os ne sont pas gĂ©nĂ©rĂ©esï
Vérifiez dans playwright.config.ts :
video: {
mode: 'on', // Doit ĂȘtre 'on', pas 'retain-on-failure'
}
â âTarget page has been closedâï
Votre app redirige trop vite. Ajoutez des attentes :
await page.click('button');
await page.waitForURL('/dashboard');
đ Best Practicesï
Noms de tests explicites
// â Bon test('Login admin et navigation vers dashboard organisations', ...) // â Mauvais test('test', ...)
Utiliser les rĂŽles ARIA
// â Bon (plus robuste) await page.getByRole('button', { name: 'Se connecter' }).click(); // â Ăviter (fragile) await page.click('.btn-login');
Attentes explicites
// â Bon await expect(page.getByText('Dashboard')).toBeVisible(); // â Ăviter await page.waitForTimeout(5000);
One test, one scenario
Chaque test doit tester UN scénario utilisateur complet.
Vidéos lisibles
Utilisez
make test-e2e-slowpour créer des vidéos de documentation.
đ IntĂ©gration CI/CDï
Les vidĂ©os ne sont plus gĂ©nĂ©rĂ©es dans la CI : elles doivent provenir dâun run local fiable, puis ĂȘtre ajoutĂ©es au dĂ©pĂŽt.
Le workflow .github/workflows/docs.yml se charge ensuite de publier la documentation Sphinx (et toutes les vidéos déjà présentes dans docs/_static/videos/) vers GitHub Pages.
đ Ressourcesï
Documentation Playwright : https://playwright.dev
Page vidĂ©os : đ„ VidĂ©os Tests E2E (Documentation Vivante)
Scripts :
.claude/scripts/README.mdConfiguration :
frontend/playwright.config.tsMakefile : đ ïž Guide des Commandes Make
đ€ Guide maintenu avec Claude Code
KoproGo ASBL - Tests E2E et Documentation Vivante
Pattern silent-refresh single-flight (frontend)ï
(Voir aussi docs/backend/JWT_REFRESH_TOKENS.md §âAmendment 2026-05-19â.)
frontend/src/stores/auth.ts coalesce les appels concurrents Ă
refreshAccessToken() via une promesse partagée au scope du module :
let inflightRefresh: Promise<boolean> | null = null;
refreshAccessToken: async (): Promise<boolean> => {
if (inflightRefresh) return inflightRefresh; // dedup
inflightRefresh = doRefresh();
try { return await inflightRefresh; }
finally { inflightRefresh = null; }
}
Pourquoi câest critique : RouteGuard.svelte et
Navigation.svelte sâhydratent comme deux Ăźlots Astro client:load
parallĂšles ; sans dedup, deux POST /auth/refresh concurrents
rĂ©utilisent le mĂȘme cookie â la rotation backend en rĂ©voque un â 401 â
clearSession() â dĂ©connexion. Câest un bug prod rĂ©el (#550), pas
seulement de test.
Spec Playwright de rĂ©fĂ©rence (4-cat)ï
frontend/tests/e2e/smoke/AuthCookie.spec.ts :
@securityaccess token absent delocalStorage+ cookie illisibledocument.cookie(HttpOnly).@edgeattributs du cookie (HttpOnly, SameSite=Strict, Path, Secure).@happyreload conserve la session via silent-refresh cookie.@negativesans cookie â redirige/login.
à utiliser comme modÚle pour toute nouvelle spec testant un flow authentifié.