Article 41·playwright·2 min de lecture
Playwright auto-wait : la fin des waits flaky
Pourquoi chaque commande Playwright attend "actionability".
Avant Playwright, l'écriture de tests E2E demandait une discipline maniaque sur les attentes (waits). En Selenium classique, un test typique ressemble à : `driver.findElement(By.id('btn')).click()` — et ça échoue 1 fois sur 10 parce que l'élément vient d'apparaître mais n'est pas encore "cliquable" (animation en cours, overlay devant, etc.). La solution Selenium est `WebDriverWait` avec des conditions explicites : `element_to_be_clickable`, `presence_of_element_located`, `visibility_of_element_located`, `text_to_be_present_in_element`. Le code finit truffé d'attentes, parfois 30 % du volume du test.
Playwright résout ce problème par défaut. Chaque action (click, fill, hover) attend automatiquement que l'élément soit dans un état "actionable" — c'est-à-dire qu'il satisfasse 5 conditions : (1) attached to DOM, (2) visible (display !== none, opacity > 0, viewport), (3) stable (pas en train d'animer/scroller), (4) enabled (pas disabled), (5) receives events (pas couvert par un autre élément). Si dans le timeout (30 s par défaut), une de ces conditions n'est pas remplie, le test échoue avec un message explicite ("Element is not visible" ou "Element is outside of viewport"). Sinon, l'action s'exécute dès que tout est OK.
Conséquence pratique : sur la suite SallyCards Playwright (312 tests), on a ZÉRO `waitForTimeout` ou `sleep` manuel. La règle équipe : si tu as besoin de `page.waitForTimeout(1000)`, c'est qu'il y a un bug. Soit le test ne sait pas vraiment ce qu'il attend (waitForResponse, waitForSelector spécifique), soit l'app a un vrai race condition à fixer.
L'auto-wait s'étend aussi aux assertions. `expect(page.locator('.toast')).toHaveText('Saved')` attend jusqu'à 5 secondes (configurable) que le texte apparaisse. Pas besoin de `waitForSelector` séparé. Si l'assertion timeoute, le rapport montre quel texte était présent au moment du timeout — diagnostic immédiat.
La granularité du timeout est ajustable par test ou par action. `page.click('.btn', { timeout: 2000 })` raccourcit l'attente si l'élément doit être instantané. À l'inverse, pour un test E2E qui attend une exécution serveur lente (génération PDF, signature crypto), on peut bumper à `{ timeout: 30000 }`. La default de 30 s couvre 98 % des cas.
Migration depuis Selenium : la plupart des explicits waits disparaissent automatiquement. `WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, 'submit'))).click()` devient `page.locator('#submit').click()`. Le gain en lisibilité est massif. Sur 200 tests migrés sur 6 semaines, la suite est passée de 3 800 lignes à 2 100 lignes, et le temps moyen par test de 8.2 s à 2.4 s.
Mais attention : l'auto-wait n'absorbe PAS les bugs racines. Si ton app affiche un toast 5 secondes après une action sans état intermédiaire visible, c'est probablement un bug UX (l'utilisateur ne sait pas si son clic a marché). Le test va passer (auto-wait attend), mais l'utilisateur réel souffre. Donc : utilise les outils de profiling (Lighthouse, Web Vitals) en parallèle des tests E2E pour catcher ces cas.
playwrightauto-wait