Тестування: Jest, Playwright, Cypress, k6, Lighthouse
Баг, знайдений у юнит-тесту, коштує хвилину виправлення. Той самий баг у production — години інциденту, компенсації клієнтам, втрата довіри. Це не абстрактний тезис: на проекті інтернет-магазину баг у розрахунку знижки пройшов ручне тестування, потрапив у prod та за 4 години обробив 37 замовлень по нульовій ціні. Автотест на граничні випадки розрахунку коштував би в CI та поймав би його при першому ж push.
Jest та юнит-тестування: де це працює, а де ні
Jest — стандарт для JavaScript/TypeScript. Але юнит-тести мають сенс тільки там, де є ізольована логіка: функції трансформації даних, валідатори, бізнес-правила, утиліти.
Тестування React-компонентів через Jest + Testing Library правильно для поведінкових тестів: "кнопка появляється після завантаження даних", "форма показує помилку при пустому email". Снепшот-тести (toMatchSnapshot) — ловушка: вони ломаються при будь-якій зміні верстки та перетворюються на шум, який розробники оновлюють не глядячи.
Покриття коду (code coverage) — погана метрика якості. 80% coverage можна отримати тестами, які нічого не перевіряють. Coverage показує, що код виконався, не те, що він працює правильно.
Vitest як альтернатива Jest для Vite-проектів: в 10–20 разів швидше за рахунок нативного ES modules без трансформації через Babel. Для монорепозиторіїв з тисячами тестів різниця швидкості відчутна.
Playwright: E2E тестування, яке працює
Cypress довгий час був стандартом E2E, але Playwright обійшов його за ключовими параметрами: нативна підтримка multi-tab, multi-origin, iframe тестування; паралельне виконання на рівні тестів (не тільки файлів); WebKit, Firefox, Chromium з коробки; немає iframe для додатку — тести працюють у реальному браузері.
Playwright codegen записує дії та генерує тест — хороша точка старту, але згенерований код потрібно рефакторити. Локатори за text content хрупкі: getByRole('button', { name: 'Оформити замовлення' }) — стійкіше, ніж locator('.btn-primary').
Page Object Model — стандарт організації E2E тестів. Кожна сторінка — окремий клас з методами замість прямих локаторів у тестах. Коли кнопка переїхала з хедера в сайдбар — змінюємо в одному місці, не шукаємо по всіх тестах.
Типова проблема — flaky tests. Тест іноді падає, іноді проходить. Причини: race condition між запитом та рендером, анімації без очікування завершення, залежність від зовнішніх API. Рішення: page.waitForResponse() замість page.waitForTimeout(), мокування зовнішніх API через page.route().
// Погано
await page.click('#submit');
await page.waitForTimeout(2000);
await expect(page.locator('.success')).toBeVisible();
// Добре
await page.click('#submit');
await page.waitForResponse(resp =>
resp.url().includes('/api/orders') && resp.status() === 201
);
await expect(page.getByRole('alert', { name: /замовлення створено/i })).toBeVisible();
Нагрузкове тестування з k6
k6 — інструмент для нагрузкового тестування з JavaScript API. Сценарії пишуться як код, версіонуються в git, запускаються в CI.
Три основних сценарії нагрузки:
Spike test — різкий рост нагрузки: 0 → 1000 користувачів за 30 секунд. Імітує запуск рекламної кампанії або попадання в топ новин. Показує, як система веде себе при різкому зростанні та умиє ли автоскейлинг відреагувати вовремя.
Soak test — стабільна нагрузка на 2–4 години. Виявляє memory leaks, connection pool exhaustion, деградацію продуктивності часом.
Stress test — нагрузка вище розрахункової (150–200% від очікуваного піку). Показує точку відказу та graceful degradation.
Порогові значення у k6:
thresholds: {
http_req_duration: ['p95<500', 'p99<1000'],
http_req_failed: ['rate<0.01'],
}
p95 < 500ms означає: 95% запитів відповідають швидше 500ms. Якщо поріг не виконується — k6 завершується з кодом помилки, CI-пайплайн падає.
Lighthouse та Core Web Vitals
Google використовує Core Web Vitals у ранжуванні. Lighthouse CLI у CI-пайплайні: при кожному деплою перевіряємо, що LCP < 2.5s, CLS < 0.1, INP < 200ms.
Реальні проблеми, які Lighthouse знаходить:
- Hero image без
width/heightатрибутів: CLS 0.35 при завантаженні (браузер зміщує контент коли завантажується зображення) - JavaScript-бандл 2.1MB синхронно блокує парсинг: INP 450ms
- Шрифти без
font-display: swap: невидимий текст до завантаження шрифту (FOIT) - Неоптимізований hero image 4MB: LCP 8.2s
Lighthouse CI (lhci) зберігає історію метрик та відправляє коментар до PR з деградацією.
Піраміда тестування у проекті
| Рівень | Інструмент | Кількість | Швидкість |
|---|---|---|---|
| Юнит | Vitest/Jest | Много | <5 хв |
| Інтеграція | Vitest + supertest | Середнє | 5–15 хв |
| E2E | Playwright | Немного (happy path) | 10–30 хв |
| Нагрузка | k6 | По розписанню | 30–60 хв |
| Performance | Lighthouse CI | При кожному деплою | 5 хв |
Процес роботи
Аудит поточного покриття, визначення критичних user flows для E2E, настройка CI-пайплайну з паралельним виконанням тестів. Playwright тести запускаємо на sharded workers (4 шарди = 4x швидкість). Нагрузкові тести — окремий stage, не блокують feature деплої, запускаються перед релізами.
Графік
Настройка повного тест-пайплайну (Jest + Playwright + k6 + Lighthouse CI) з нуля: 2–4 тижні. Покриття E2E-тестами існуючого проекту (20–30 сценаріїв): 3–6 тижнів. Нагрузкове тестування з звітом та рекомендаціями: 1–2 тижні.







