Doctests
Tous les articles
Flaky · Debug · Playwright
Mouhamed Sané
  • playwright
  • flaky
  • locators
  • ci
  • debug

Pourquoi vos tests Playwright deviennent flaky (et comment les arrêter)

waitForTimeout, locators fragiles, animations, API lentes, données instables, parallélisation — les 6 causes les plus fréquentes et comment Doctests les détecte automatiquement.

Tu lances la CI : vert. Tu relances sans rien changer : rouge. Tu relances encore : vert. Toute l’équipe connaît ce test « connu pour être flaky » — et personne ne le corrige parce que « on n’a pas le temps ».

Ce n’est pas de la malchance. C’est structurel. Presque toujours, la flakiness vient d’un petit nombre de patterns répétés. Les identifier, c’est déjà la moitié du chemin pour les arrêter.

Voici les 6 causes que je vois le plus souvent en audit — et comment les détecter automatiquement avant qu’elles ne bloquent ta prochaine MEP.

1. waitForTimeout — le flaky factory

await page.waitForTimeout(3000);
await expect(page.locator('.success')).toBeVisible();

Tu supposes que 3 secondes suffisent. Parfois oui. Parfois l’API met 3,5 s. Parfois 800 ms suffisent et tu perds du temps. Parfois la CI est chargée et 3 s ne suffisent pas.

Playwright auto-retry les assertions — pas les waitForTimeout. C’est la cause #1 de tests structurellement flaky.

Fix : remplace par une assertion sur l’état UI :

await expect(page.getByRole('alert')).toBeVisible({ timeout: 10_000 });

Doctests remonte ce pattern en scan statique (waitForTimeout dans les specs) — souvent classé RACE dans les rapports d’audit.

2. Mauvais locators — CSS, nth-child, texte instable

await page.locator('div > span:nth-child(3)').click();
await page.locator('.btn-primary').click();

Ces sélecteurs cassent à chaque refacto CSS, à chaque traduction, à chaque A/B test. Playwright retry — parfois le DOM est « presque » bon, parfois non. Flaky garanti à moyen terme.

Fix :

  • getByRole('button', { name: /confirmer/i })
  • getByTestId('checkout-submit')
  • Page Object Model pour centraliser les changements

En audit, Doctests flaggue les locators CSS fragiles, les xpath non justifiés et les bypass POM (locator inline dans 40 specs au lieu d’un page object).

3. Animations et transitions non attendues

Un bouton devient cliquable après une animation de 400 ms. Ton test clique à 200 ms. Parfois ça passe (animation skip en CI headless), parfois non.

Autres cas :

  • overlay / modal qui fade-in
  • skeleton loader qui masque le vrai contenu
  • scroll virtuel qui déplace l’élément cible

Fix :

  • await expect(locator).toBeVisible() avant interaction
  • await expect(locator).toBeEnabled() si pertinent
  • désactiver les animations en env test seulement si tu contrôles le front (feature flag), pas en contournement aveugle

Le scan Doctests détecte les interactions sans assertion préalable sur l’élément (click direct après navigation sans wait explicite sur l’état).

4. API lentes ou non mockées

Ton test remplit un formulaire, clique « Valider », assert le succès — mais l’API met 8 s un jour sur deux (charge, cold start, rate limit).

Sans mock réseau ou timeout explicite sur l’assertion finale, tu joues à la roulette.

Fix :

  • page.route() pour stabiliser les réponses en E2E
  • expect(..., { timeout: 15_000 }) sur l’état post-API
  • tag @slow pour isoler ces specs du smoke PR

Doctests analyse les patterns de wait implicite et les specs sans fixtures de données ni isolation réseau documentée.

5. Données instables — le même user, le même panier

test('ajoute un produit', async ({ page }) => {
  await login(page, 'test@example.com');
  // ...
});

Deux workers parallèles, même compte, même panier, même commande #42 — collision. Le test A échoue parce que le test B a vidé le stock.

Autres pièges :

  • date du jour hardcodée (2024-01-15)
  • IDs auto-incrémentés supposés fixes
  • état partagé entre tests (pas de cleanup)

Fix :

  • factory par test (createUser(), createOrder())
  • fixtures Playwright avec scope test
  • base de test reset ou transactions rollback

Le scan remonte l’absence de factories, les emails hardcodés répétés et les specs sans isolation (test.describe.configure({ mode: 'serial' }) utilisé comme pansement).

6. Parallélisation — quand fullyParallel: true expose la dette

Playwright parallelise par défaut. C’est une feature — sauf si ta suite suppose un ordre implicite ou un état global.

Signaux :

  • test.describe.serial partout (tu masques le problème)
  • fichiers qui passent seuls en local, flaky en CI (4 workers)
  • storageState partagé et écrasé entre tests

Fix :

  • isolation données + auth par worker
  • tags pour séparer smoke (parallel safe) vs regression (serial si unavoidable)
  • workers: 1 temporaire le temps de corriger — pas comme solution permanente

Sur l’Audit Flakiness approfondi, Doctests ingère tes runs CI et calcule le flake rate par test — souvent corrélé aux specs qui échouent uniquement en parallèle.

Comment Doctests détecte ces problèmes automatiquement

Je ne devine pas ces patterns à la main sur 200 specs. Doctests, mon moteur interne, scanne le repo et produit un rapport actionnable.

Scan gratuit (2 min)

Sur /services/devis : tu colles l’URL GitHub → score 0–100, dimensions (locators, waits, structure POM, CI), signaux d’anti-patterns. Aperçu immédiat sans engagement.

Audit Flash 490 € (48 h)

Scan code-only approfondi sur ton repo :

  • 20+ règles statiques (waitForTimeout, locators CSS, bypass POM, fixtures manquantes…)
  • Score de maturité + top findings priorisés
  • PDF 8–12 pages + plan de remédiation
  • Exemple de livrable : /services/exemple-audit-flash

Aucune modification de ton code — diagnostic only.

Audit Flakiness approfondi

Ingestion de tes derniers runs CI (JUnit, report JSON) :

  • flake rate par test sur 30 jours
  • corrélation flake × anti-patterns dans le spec / POM
  • priorisation : impact = flake_rate × fréquence × sévérité patterns

Tu sais quels 5 tests corriger en premier — pas « toute la suite est flaky ».

Ce que le scan remonte concrètement

ProblèmeSignal Doctests
waitForTimeoutRègle RACE — comptage + extrait de code
Locators CSS fragilesRègle LOCATOR — fichier + ligne
Bypass POMInteraction inline hors page objects
Données partagéesEmails / IDs dupliqués, pas de factory
CI opaquePas de config retry / artefacts / shards documentés
Flaky runtimeCorrélation CI (audit approfondi)

Ce n’est pas un linter générique. Ce sont des règles calibrées Playwright + TypeScript, enrichies par ce que je vois sur les missions réelles.

Par où commencer cette semaine

  1. Lance le scan gratuit — tu verras si waitForTimeout et locators CSS dominent
  2. Note le top 3 findings — ce sont tes quick wins
  3. Si la CI est rouge plusieurs fois par semaine → Audit Flash pour un plan PDF priorisé
  4. Si tu as 100+ specs et des runs CI → audit approfondi pour la liste flaky corrélée

Tu n’as pas besoin de réécrire 200 tests. Tu as besoin de tuer les 20 % qui causent 80 % du bruit.

Conclusion

Les tests Playwright ne deviennent pas flaky « tout seuls ». Ils héritent de waits arbitraires, locators fragiles, données partagées et API non maîtrisées — amplifiés par la parallélisation.

Doctests existe pour rendre ces causes visibles en minutes, pas en semaines de debug. Scan, score, top findings, plan — puis tu choisis si tu corriges en interne ou si on enchaîne sur un Sprint de stabilisation.

Le bloc en bas de page te montre comment réserver un Audit Flash ou lancer un diagnostic sur ton repo.