# Flaky tests

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

## Определение

**Flaky-тест (Flaky Test)** — тест, который при одинаковом состоянии системы и одинаковом коде иногда проходит, иногда падает. Само слово «flaky» (хлопчатый, рассыпающийся) передаёт непредсказуемость результата.

## Причины

### Асинхронность и тайминги

Самая распространённая причина: тест ожидает элемент или результат асинхронной операции с фиксированным `sleep()` вместо умного ожидания готовности. Решение — использовать встроенные механизмы ожидания фреймворка.

### Неправильная инициализация и очистка данных

Тест зависит от состояния, которое оставил предыдущий тест. При параллельном запуске это проявляется особенно часто. Каждый тест должен самостоятельно создавать нужные данные и очищать состояние после себя.

### Неустойчивые локаторы

XPATH-локаторы, зависящие от позиции элемента в DOM, ломаются при изменении разметки. Предпочтительны `data-testid`, `aria-label`, `role`-атрибуты.

### Параллельное выполнение и shared state

Тесты, изменяющие одни и те же данные в БД или одного тестового пользователя, конфликтуют при параллельном запуске.

### Внешние зависимости

Нестабильное сетевое соединение, медленный внешний API, недоступная база данных. Идеальная тестовая среда — «герметичная»: без внешних зависимостей (моки, Testcontainers, WireMock).

### Аппаратные и системные проблемы

Нехватка памяти, медленный диск, неправильно настроенные ресурсы фреймворка.

## Автоматическое ожидание как профилактика

Современные фреймворки устраняют целый класс timing-проблем через умное ожидание:

**Playwright auto-waiting** — перед каждым действием Playwright автоматически проверяет actionability: элемент должен быть visible, enabled, stable (не анимируется), attached to DOM. `sleep()` для ожидания элементов не нужен.

**Cypress retry-ability** — assertion-команды автоматически ретраят до тех пор, пока условие не выполнится или не истечёт timeout. `cy.get('.button').should('be.visible')` не упадёт при анимации появления.

```typescript
// Playwright: не нужен sleep(), фреймворк ждёт сам
await page.click('.submit-btn');  // ждёт пока кнопка станет visible + enabled + stable

// Явное ожидание для нестандартных случаев
await page.waitForResponse(resp => resp.url().includes('/api/data'));
await expect(page.locator('.result')).toBeVisible({ timeout: 10000 });
```

## Диагностика

1. Документировать нестабильный тест: когда падает, как часто, в каком окружении
2. Проверить логи, скриншоты, видео прогона (Playwright автоматически записывает при падении)
3. Запустить тест 10–20 раз изолированно — воспроизвести нестабильность
4. В 90% случаев причина ясна из артефактов прогона

## Управление flaky-тестами в CI

### Паттерн quarantine

Нестабильный тест помечается как карантинный: он продолжает запускаться, но не блокирует пайплайн. Команда получает уведомление и разбирает проблему по расписанию, не в режиме блокировки PR.

### BuildPulse

SaaS-сервис для автоматического отслеживания flaky-тестов. Интегрируется с GitHub Actions/CircleCI/Jenkins через upload junit-xml артефактов. Определяет нестабильные тесты по истории 50+ запусков, автоматически создаёт GitHub Issues.

```yaml
# GitHub Actions: upload результатов в BuildPulse
- name: Upload test results to BuildPulse
  uses: buildpulse/buildpulse-action@main
  if: always()
  with:
    account: ${{ secrets.BUILDPULSE_ACCOUNT_ID }}
    repository: ${{ secrets.BUILDPULSE_REPOSITORY_ID }}
    path: test-results/*.xml
    key: ${{ secrets.BUILDPULSE_ACCESS_KEY_ID }}
    secret: ${{ secrets.BUILDPULSE_SECRET_ACCESS_KEY }}
```

### Currents.dev

Платформа оркестрации для Playwright и Cypress. Dashboard с историей тестов, flakiness score, аналитика по веткам и воркерам. Поддерживает quarantine mode из коробки.

## Статистика

По данным тестировщиков, основные причины нестабильности по «сложности разбора»:

1. Асинхронные операции (async wait)
2. Многопоточность и shared state
3. Неправильный порядок запуска тестов
4. Аппаратные проблемы (сеть, память)

Как говорил вице-президент Unity3D Алан Берд: «Нестабильные тесты хуже, чем вообще без тестов» — они создают ложный сигнал и убивают доверие к автоматизации.

## Источники

* [Нестабильные тесты. Почему они существуют и что с ними делать](https://testengineer.ru/nestabilnye-testy-pochemu-oni-sushchestvuyut-i-chto-s-nimi-delat/)
* [Playwright: Auto-waiting](https://playwright.dev/docs/actionability)
* [BuildPulse — flaky test detection](https://buildpulse.io)
* [Currents.dev — Playwright analytics](https://currents.dev)

### Дополнительные материалы

* [Flaky-тесты: Откуда ноги растут. Опыт Uber](https://habr.com/ru/post/565806/) — кейс масштабной диагностики
* [Blog: Flaky Testing](https://www.developsense.com/blog/2021/02/flaky-testing/) — системный взгляд на проблему


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://vladislaveremeev.gitbook.io/qa_bible/avtomatizaciya-testirovaniya/tekhniki-i-patterny/chto-takoe-flaky-tests.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
