automationplaywright

Playwright auto-wait: почему вам не нужны explicit waits

Если ты пришёл в Playwright из Selenium — первое инстинктивное движение писать await page.waitForSelector(...) перед каждым действием. В 90% случаев это лишняя работа: Playwright уже ждёт за тебя. Но многие об этом не знают и тащат привычки из старого мира.

Что такое auto-wait

Каждое действие на Locator (click, fill, type, check) перед выполнением проводит серию actionability checks — проверяет, что элемент:

  • attached в DOM
  • visible
  • stable (не двигается, не анимируется)
  • receives events (не перекрыт другим элементом)
  • enabled

Если условие не выполнено — Playwright ждёт до 30 секунд по дефолту, потом фейлит. Никакого waitFor писать не надо.

Что сломает auto-wait

— Использование старого page.click('selector') вместо page.locator('selector').click(). Работает, но без полного набора actionability checks. Всегда через Locator API.

— Custom-overlay (loading spinner с pointer-events: none) перекрывает кнопку, и Playwright «думает» что элемент кликабельный. Auto-wait не помогает — нужно явно: await page.locator('.spinner').waitFor({ state: 'hidden' }).

— Анимация делает элемент «нестабильным» дольше 30 секунд. Решение: animation: none !important в test environment, либо локальный { timeout: 60_000 }.

Что использовать вместо waitFor

expect(locator).toBeVisible() — встроенный retry до timeout. Чище чем waitForSelector. — expect(locator).toHaveText('...') — ждёт пока текст совпадёт. Polling вручную не нужен. — page.waitForResponse(/api\/data/) — ждать конкретный сетевой ответ. — page.waitForURL('/dashboard') — ждать навигации.

Антипаттерны

page.waitForTimeout(2000) — это Thread.sleep, только в Playwright. В CI всегда либо мало, либо много. Используй только для дебага, удаляй перед коммитом.

❌ Кастомный poll-loop через setInterval — Playwright делает это нативно.

expect(await locator.textContent()).toBe(...) — это синхронная проверка без retry. Заменяй на await expect(locator).toHaveText(...).

Что делать прямо сейчас

✅ Прогрепай проект на waitForSelector и waitForTimeout( — это кандидаты на удаление или замену.

✅ Переходи на web-first assertions (expect(locator)) везде, где есть expect(await locator.x()).

✅ Включи trace: 'on-first-retry' в playwright.config.ts — даёт offline-отладку с timeline всех auto-wait.

Подробнее: Playwright — Auto-waiting, Best Practices.