Продуктивність та стабільність тестів
Основні принципи
Section titled “Основні принципи”| Принцип | Суть |
|---|---|
| Ізоляція | кожен тест не впливає на інший |
| Детермінізм | однакові результати при кожному запуску |
| Мінімалізм | тестуємо лише те, що потрібно, без зайвої ініціалізації |
| Очищення | після тесту немає “витікань” (таймерів, моків, DOM) |
| Швидкість | локальні прогони ≤ 3 с, CI – паралельні |
Швидкість виконання
Section titled “Швидкість виконання”Вибір середовища
Section titled “Вибір середовища”node- для pure-утиліт, SDK, сервісів → швидкий запуск.jsdom- для компонентів React → лише коли потрібен DOM.
Не використовуйте jsdom там, де достатньо node.
Кешування Vitest
Section titled “Кешування Vitest”- Vitest зберігає результати в
.vitest/.
Для CI кешуємо цю директорію між збірками:
cache: key: vitest-${CI_COMMIT_REF_SLUG} paths: - .vitest/- Використовуй
--changedабо--sinceдля часткових прогонів.
Паралельне виконання
Section titled “Паралельне виконання”- Увімкни
threads: true(за замовчуванням у Vitest 1+). - Великі проєкти ділимо на групи:
test:unit:fast- утиліти/хуки;test:ui- jsdom;test:node- серверні частини.- У CI - шардінг за шаблоном
vitest --shard 1/3.
Мокані ресурси
Section titled “Мокані ресурси”- Мережеві запити - тільки через MSW (жодних реальних HTTP).
localStorage,matchMedia,ResizeObserver- мок уsetupTests.ts.- Уникай великих фікстур > 10 KB: це сповільнює парсер.
Стабільність
Section titled “Стабільність”Контроль часу
Section titled “Контроль часу”- Усі
Date,setTimeout,setInterval- під контролем:
vi.useFakeTimers();vi.setSystemTime('2025-01-01T00:00:00Z');- Не використовуй
await new Promise(r => setTimeout(r, ...)).
Очистка моків
Section titled “Очистка моків”beforeEach(() => { vi.clearAllMocks(); vi.restoreAllMocks(); cleanup(); // from @testing-library/react});Обов’язковий cleanup для jsdom після кожного тесту.
Очікування DOM-змін
Section titled “Очікування DOM-змін”- Використовуй
findBy*абоwaitFor, ніколи - жорсткі таймаути. - Встанови глобальний таймаут у Vitest:
testTimeout: 5000,hookTimeout: 2000,Детермінізм даних
Section titled “Детермінізм даних”- Випадковість через seed:
import seedrandom from 'seedrandom';Math.random = seedrandom('test-seed');- Тестові об’єкти створюй фабриками (
factory()), неMath.random().
Уникнення флейків
Section titled “Уникнення флейків”- Флейк = тест, що іноді падає без змін у коді.
- Дії при флейку:
- Відтворити локально 3—5 разів.
- Якщо причина середовище → ізолювати у
*.flaky.test.ts. - Якщо причина таймінг - використати
waitForабо стабільний хук. - Якщо тест непотрібний - переписати або видалити.
Розподіл навантаження у CI
Section titled “Розподіл навантаження у CI”| Практика | Пояснення |
|---|---|
| Docker-layer cache | образ vitest-env кешується для кожної CI-гілки |
| Паралельні job’и | кожна група тестів — окремий job |
| Артефакти | передаємо тільки reports/ і coverage/, без .vitest/ |
| Retry у GitLab | для флейкових job’ів — retry: 1 максимум |
| Fail-fast | зупиняти pipeline при 1-й невдачі тестів |
Облік часу виконання
Section titled “Облік часу виконання”- Кожен job зберігає час виконання у GitLab → метрика «test duration».
- Якщо тривалість росте > 20 %, створюємо задачу на оптимізацію.
- Vitest має CLI-флаг
--reporter=verboseдля аналізу повільних тестів.
Memory Leaks / jsdom leaks
Section titled “Memory Leaks / jsdom leaks”- Після кожного
renderвикликаєтьсяcleanup(). - Для важких компонентів - lazy import або
beforeAll+afterAll. - Якщо jsdom зависає - встанови
environmentOptions: { resources: 'usable' }. - У CI при системних OOM - перейти на
--runInBandз обмеженням потоків.