QA Interview Hub · База знань · Тести

CI/CD

Пайплайн і quality gates

Що запускати на PR, на merge і вночі

Головна ідея пайплайна для автотестів: чим дорожчий набір, тим рідше й пізніше його запускають. Один «повний регрес на кожен коміт» — найкоротший шлях до 40-хвилинного очікування та розробників, які перестають дивитися на CI.

  • Pull request (мета — фідбек до ~10 хвилин): lint і typecheck, unit, API/контрактні тести, збірка, smoke-набір e2e на критичних шляхах (логін, головна дія продукту). Усе це — required checks: без зеленого статусу merge заборонено;
  • Merge у main: ширший набір (повний API, e2e по основних модулях), деплой на staging і smoke після деплою. Падіння тут означає, що PR-набір щось пропустив, і це привід його доповнити;
  • Nightly / за розкладом: повний регрес, усі браузери, довгі сценарії, візуальні тести, performance-перевірки, прогін з вимкненим карантином. Результат — звіт і сповіщення команді, а не блок merge;
  • Ручний запуск (workflow_dispatch): повторити довгий набір на вимогу, наприклад на певній гілці чи оточенні.

Порядок етапів у межах запуску — fail-fast: дешеві й швидкі перевірки (lint, unit) ідуть першими, повільні e2e — після них. Незалежні етапи виконуються паралельно, а не по черзі.

Quality gate — це набір умов, без яких код не йде далі: усі required checks зелені, немає нових критичних помилок, покриття нового коду не нижче порогу, flaky-тести не в блокуючому наборі. Чим менше gate «на слово», тим краще: умова має перевірятися автоматично.

Flaky у CI: ретраї, карантин, повторний запуск

Flaky-тест — той, що на тому самому коді то проходить, то падає. У CI він коштує двічі: червоний PR без причини і втрата довіри до набору. Тому потрібна політика, а не «перезапустимо ще раз».

Ретраї. Дозволяють 1–2 повторні спроби в CI (у Playwright retries: process.env.CI ? 2 : 0), локально — 0, щоб розробник бачив нестабільність одразу. Ретрай — не лікування, а сенсор: тест, що пройшов лише з повтору, отримує статус flaky, потрапляє в метрики й веде до тікета. На ретраї зручно вмикати trace (on-first-retry).

Карантин. Тест, який нестабільний і блокує інших, виносять із required-набору (тег, окремий проєкт, skip з посиланням на тікет), але не видаляють: у нього є власник, причина і дедлайн. Карантинний набір продовжує бігати вночі, щоб бачити, чи він «одужав».

Повторний запуск. Якщо впала інфраструктура (раннер, мережа, rate limit), у GitHub Actions можна натиснути Re-run failed jobs: перезапуститься лише впала job (наприклад, одна шарда), а не весь пайплайн. Це економить час, але не відміняє аналізу причини.

Чого не робити: ставити глобально retries: 5 (ховає реальні баги з гонками), автоматично перезапускати червоні запуски без запису в метрики, лишати skip без власника.

Як утримати фідбек PR у межах 10 хвилин

Після ~10 хвилин розробник перемикається на іншу задачу, а повернення до червоного PR коштує контексту. Коли пайплайн повільний, спершу міряють, а не оптимізують навмання: розбивка часу по джобах і крокам (checkout, install, build, тести), p50/p90 тривалості, черга на раннер.

Важелі, від дешевих до дорогих:

  1. Паралельні джоби. lint, unit, build, API і e2e не мають чекати одне одного, якщо між ними немає залежності;
  2. Кеш. npm-кеш, браузери Playwright, Docker-шари, результати збірки;
  3. Шардування e2e. --shard=i/N у matrix; тривалість ≈ найповільніша шарда, тому важлива рівномірність;
  4. Селективний запуск. Path filters і аналіз зачеплених пакетів у монорепо: PR, що змінив документацію чи один сервіс, не запускає все. Повний набір лишається на main і вночі як страховка;
  5. Піраміда. Перенести перевірки з e2e в API/компонентні тести; e2e на PR — лише smoke;
  6. Стабільність. Ретраї та перезапуски теж «їдять» час: низький flaky rate прискорює пайплайн;
  7. Сильніші раннери. Остання опція: зазвичай вузьке місце не в CPU.

Ризик селективного запуску — пропустити залежність. Тому потрібен fallback: періодичний повний прогін і правило «зміна спільної бібліотеки запускає все».