Надёжность сквозных тестов — Примеры

Пример 1 — Пауза вместо неизвестного объёма работы

Сквозной тест делает паузу после сохранения, а затем проверяет результат, поэтому на ноутбуке он проходит, а в конвейере падает. Скажите, что эта задержка на самом деле угадывает, а затем замените её.

await page.getByRole("button", { name: "Save" }).click();
await page.waitForTimeout(3000);                       // ставка на быструю машину
await expect(page.getByText("Saved")).toBeVisible();
// конвейер: FAIL — иногда запись занимает 3.2s

Решение

await page.getByRole("button", { name: "Save" }).click();
await expect(page.getByText("Saved")).toBeVisible({ timeout: 15_000 });
// проходит, как только состояние наступает; чётко падает, когда оно так и не наступает

Фиксированная пауза угадывает, сколько времени занимает работа, и терпит неудачу именно на более медленных машинах, где результат важнее всего. Ожидание условия и быстрее, и надёжнее: оно возвращается в тот момент, когда состояние появляется, вместо того чтобы каждый раз сжигать задержку, а если состояние так и не наступает, падает с сообщением, в котором названо пропущенное. Современные браузерные инструменты ждут автоматически для своих действий, однако любое состояние, которое создаёт ваше приложение, всё равно требует явной проверки, на которой можно ждать, — пауза обычно и есть знак, что такой проверки нет.

Пример 2 — Прогон, зависящий от данных предыдущего прогона

Тесты входят под пользователем, подготовленным однажды в общей тестовой среде, поэтому при параллельном запуске они сталкиваются, а повторная попытка скрывает отказ, не сохраняя улик. Сделайте набор независимым, а его отказы — диагностируемыми.

подготовка: test-user@example.test / password
тест A: меняет отображаемое имя на "Ada"
тест B: проверяет, что отображаемое имя — "Test User"     -> падает при запуске с A
повтор: при отказе запускается снова -> зелёный -> ничего не сохранено

Решение

id прогона: e2e-20260301-7f3a
каждый аккаунт, созданный этим прогоном, содержит id прогона
при отказе: снимок экрана + трассировка + лог сервера, загружаются с id прогона

Уникальные для прогона данные делают два прогона независимыми, выполняются ли они параллельно или в любом порядке, а идентификатор прогона делает очистку дешёвой, а отказ — проще для отслеживания. Повторная попытка — вторая половина проблемы: тест, которому она нужна дважды в неделю, имеет невыявленную гонку, поэтому собирайте улики при каждом отказе, повторялся он или нет. Отношение к частоте повторных попыток как к метрике ошибок — и к самому нестабильному тесту как к ошибке, которую нужно починить, а не как к помехе, которую нужно отложить в карантин, — вот что мешает зелёному цвету набора стать цветом, которому никто не верит.