Надёжность сквозных тестов

Что это такое

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

Почему это важно

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

Ключевые идеи

Ждите условий, а не времени

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

await expect(page.getByRole("status")).toHaveText("Saved");   // условие
await page.waitForTimeout(3000);                              // ставка наугад

Начинайте с чистого листа и оставляйте его чистым

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

id прогона: e2e-20260301-7f3a
каждое имя, созданное этим прогоном, содержит его

Прогоняйте одни и те же тесты против одной и той же сборки

Продвигайте одну сборку по средам, а не собирайте заново под каждую среду. Тест, который проходит против артефакта, действительно запускаемого в продакшене, даёт доказательство, тогда как тест против отдельно собранного почти такого же артефакта даёт лишь надежду. Данные, от которых зависят тесты, заморозьте, а часы зафиксируйте там, где проверка чувствительна ко времени.

Делайте отказы диагностируемыми

Когда тест падает в конце конвейера, уликами становится только то, что тест сохранил: снимок экрана, видео, трассировка, лог консоли, сетевые запросы. Настройте раннер собирать их при отказе и называйте артефакты по имени теста. Повторная попытка, которая ничего не сохраняет, хуже отказа: она уничтожает и улики.

при отказе: снимок экрана + трассировка + лог сервера, загружаются с id прогона

Считайте повторную попытку сообщением об ошибке

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

Практика

Уберите паузу

Найдите фиксированную задержку в сквозном тесте и замените её проверкой, которая ждёт появления нужного состояния.

Готово, когда: тест зелёный, измеримо быстрее и падает с понятным сообщением, когда ожидаемое состояние так и не наступает.

Докажите, что два прогона независимы

Прогоните весь набор сквозных тестов дважды подряд против одной среды, а затем ещё раз в перемешанном порядке.

Готово, когда: все три прогона дают одинаковый результат и ни один тест не зависит от данных, созданных другим.

Частые ошибки

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

Что читать дальше