Флаки-тесты и таймауты
Нестабильные тесты — главная боль E2E. Разбираем причины и проверенные способы лечения.
Флаки-тест (flaky test) — тест, который иногда проходит, а иногда падает без изменений в коде. Это самая частая и самая дорогая проблема E2E.
Почему флаки так вредны
Один тест, падающий раз в десять прогонов, кажется мелочью. Но когда в наборе сотня тестов и каждый изредка «моргает», красный CI становится нормой. Команда перестаёт доверять тестам и начинает перезапускать их «вслепую» — а это уже путь к тому, что реальные баги проскальзывают незамеченными. Поэтому борьба с флаки — не косметика, а вопрос ценности всего набора тестов.
Главные причины флаки
| Причина | Лечение |
| Ручные паузы вместо ожиданий | убрать waitForTimeout, довериться авто-ожиданиям |
| Мгновенное чтение состояния | использовать web-first assertions |
| Хрупкие локаторы (CSS/XPath по позиции) | перейти на getByRole/getByText |
| Зависимость тестов друг от друга | изоляция: чистый контекст на каждый тест |
| Общие данные между тестами | уникальные данные на каждый прогон |
| Гонки с анимацией | дождаться стабильности (Playwright делает сам) |
Антипаттерн и его исправление
// ФЛАКИ: пауза наугад + чтение «сейчас»
await page.click('#load');
await page.waitForTimeout(1000);
const items = await page.locator('.item').count();
expect(items).toBe(5);
// СТАБИЛЬНО: семантический локатор + web-first assertion
await page.getByRole('button', { name: 'Загрузить' }).click();
await expect(page.getByRole('listitem')).toHaveCount(5);Второй вариант сам дождётся, пока появятся ровно пять элементов — без угадывания времени. Большинство флаки лечатся именно такой заменой: «угадал тайминг» → «дождался состояния».
Изоляция тестов
Тесты не должны зависеть от порядка запуска. Если тест Б ожидает, что тест А что-то создал, то при параллельном или выборочном запуске всё ломается. Playwright по умолчанию даёт каждому тесту чистый контекст браузера — пользуйтесь этим и не оставляйте «хвостов» в общем состоянии.
Ретраи: лечить, а не прятать
Playwright умеет перезапускать упавший тест автоматически. Это настраивается в конфиге.
// playwright.config.ts
export default defineConfig({
retries: 2, // упал — перезапустить до 2 раз
});Ретраи полезны в CI, чтобы случайный сбой инфраструктуры не валил весь прогон. Но это обезболивающее, а не лекарство: если тест проходит только со второй попытки, в нём есть реальная нестабильность, которую надо найти и устранить. Playwright помечает такие тесты как «flaky» в отчёте — это сигнал к разбору, а не повод расслабиться.
Виды таймаутов
В Playwright несколько уровней таймаутов — важно не путать.
| Таймаут | Что ограничивает | По умолчанию |
| Test timeout | весь тест целиком | 30 с |
| Expect timeout | одну web-first проверку | 5 с |
| Action timeout | одно действие (клик и т.п.) | не ограничен |
// playwright.config.ts
export default defineConfig({
timeout: 30_000, // на весь тест
expect: { timeout: 5_000 }, // на каждую проверку
});Увеличивать таймауты стоит осознанно. Если тест стабильно не укладывается в 30 секунд — обычно проблема не в таймауте, а в том, что тест делает слишком много или ждёт чего-то ненадёжного. Раздувание таймаутов — это попытка заглушить симптом.
Итог
- Флаки-тест падает случайно и подрывает доверие к тестам — это главная боль E2E.
- Частые причины: ручные паузы, мгновенные проверки, хрупкие локаторы, зависимость тестов.
- Лечение: авто-ожидания, web-first assertions, семантические локаторы, изоляция.
- Ретраи — обезболивающее: «flaky» в отчёте означает, что причину надо найти.
- Таймауты бывают на тест, на проверку и на действие — увеличивайте их осознанно.