Skip to content

Продуктивність та стабільність тестів

ПринципСуть
Ізоляціякожен тест не впливає на інший
Детермінізмоднакові результати при кожному запуску
Мінімалізмтестуємо лише те, що потрібно, без зайвої ініціалізації
Очищенняпісля тесту немає “витікань” (таймерів, моків, DOM)
Швидкістьлокальні прогони ≤ 3 с, CI – паралельні
  • node - для pure-утиліт, SDK, сервісів → швидкий запуск.
  • jsdom - для компонентів React → лише коли потрібен DOM.

Не використовуйте jsdom там, де достатньо node.

  • Vitest зберігає результати в .vitest/.
    Для CI кешуємо цю директорію між збірками:
gitlab-ci.yml
cache:
key: vitest-${CI_COMMIT_REF_SLUG}
paths:
- .vitest/
  • Використовуй --changed або --since для часткових прогонів.
  • Увімкни threads: true (за замовчуванням у Vitest 1+).
  • Великі проєкти ділимо на групи:
  • test:unit:fast - утиліти/хуки;
  • test:ui - jsdom;
  • test:node - серверні частини.
  • У CI - шардінг за шаблоном vitest --shard 1/3.
  • Мережеві запити - тільки через MSW (жодних реальних HTTP).
  • localStorage, matchMedia, ResizeObserver - мок у setupTests.ts.
  • Уникай великих фікстур > 10 KB: це сповільнює парсер.
  • Усі Date, setTimeout, setInterval - під контролем:
vi.useFakeTimers();
vi.setSystemTime('2025-01-01T00:00:00Z');
  • Не використовуй await new Promise(r => setTimeout(r, ...)).
beforeEach(() => {
vi.clearAllMocks();
vi.restoreAllMocks();
cleanup(); // from @testing-library/react
});

Обов’язковий cleanup для jsdom після кожного тесту.

  • Використовуй findBy* або waitFor, ніколи - жорсткі таймаути.
  • Встанови глобальний таймаут у Vitest:
testTimeout: 5000,
hookTimeout: 2000,
  • Випадковість через seed:
import seedrandom from 'seedrandom';
Math.random = seedrandom('test-seed');
  • Тестові об’єкти створюй фабриками (factory()), не Math.random().
  • Флейк = тест, що іноді падає без змін у коді.
  • Дії при флейку:
    1. Відтворити локально 3—5 разів.
    2. Якщо причина середовище → ізолювати у *.flaky.test.ts.
    3. Якщо причина таймінг - використати waitFor або стабільний хук.
    4. Якщо тест непотрібний - переписати або видалити.

Розподіл навантаження у CI

Section titled “Розподіл навантаження у CI”
ПрактикаПояснення
Docker-layer cacheобраз vitest-env кешується для кожної CI-гілки
Паралельні job’икожна група тестів — окремий job
Артефактипередаємо тільки reports/ і coverage/, без .vitest/
Retry у GitLabдля флейкових job’ів — retry: 1 максимум
Fail-fastзупиняти pipeline при 1-й невдачі тестів
  • Кожен job зберігає час виконання у GitLab → метрика «test duration».
  • Якщо тривалість росте > 20 %, створюємо задачу на оптимізацію.
  • Vitest має CLI-флаг --reporter=verbose для аналізу повільних тестів.
  • Після кожного render викликається cleanup().
  • Для важких компонентів - lazy import або beforeAll + afterAll.
  • Якщо jsdom зависає - встанови environmentOptions: { resources: 'usable' }.
  • У CI при системних OOM - перейти на --runInBand з обмеженням потоків.