Структура файлів і неймінг
Базовий принцип: co-locate
Section titled “Базовий принцип: co-locate”- Тест розміщується поруч із модулем, який він перевіряє.
- Це спрощує навігацію, рефакторинг і видимість покриття.
Directorycomponents
- Button.tsx
- Button.test.tsx ← поруч
Directoryhooks
- useToggle.ts
- useToggle.test.ts
Directoryutils
- formatDate.ts
- formatDate.node.test.ts
Directoryservices
- api.ts
- api.node.test.ts
Дозволено окремі папки __tests__ лише для великих модулів або коли тестів багато:
Directorycomponents
DirectoryModal
- Modal.tsx
Directory__tests__
- Modal.open-close.test.tsx
- Modal.a11y.test.tsx
Суфікси та маски файлів
Section titled “Суфікси та маски файлів”| Призначення | Формат файлу | Приклад |
|---|---|---|
| Звичайні юніт-тести (UI/хуки) | *.test.tsx, *.test.ts | Button.test.tsx |
| Node-тести (SDK/утиліти) | *.node.test.ts | formatDate.node.test.ts |
| Снепшоти (лише малі) | автоматично у __snapshots__ | Button.test.tsx.snap |
| Моки для модуля | *.mock.ts поруч із модулем | api.mock.ts |
| Тести на типи (TS) | *.dtest.ts (doc-test style) | types.dtest.ts |
Іменування файлів тестів
Section titled “Іменування файлів тестів”-
Віддзеркалюй ім’я модуля:
X.ts→X.test.ts,X.tsx→X.test.tsx. -
Якщо кейсів багато — додавай короткий дескриптор:
Modal.open-close.test.tsx,Modal.a11y.test.tsx. -
Для параметризованих утиліт — дозволено групувати:
currencyFormat.edge-cases.test.ts.
Структура каталогу tests
Section titled “Структура каталогу tests”Локальні тести — поруч із кодом. Спільні хелпери/фікстури — у tests.
Directorytests
Directorysetup ← допоміжні речі (не плутати з setupTests.ts)
- renderWithProviders.ts ← хелпер для провайдерів/роутера
- timers.ts ← зручності для fake timers
Directoryfixtures
- users.json
- orders.small.json
Directoryfactories
- userFactory.ts
- orderFactory.ts
Directorymsw
- handlers.ts ← REST/GraphQL обробники
- server.ts ← (необов’язково) окремий запуск MSW для інтеграцій
Усередині тестового файлу
Section titled “Усередині тестового файлу”Рекомендований каркас:
import { render, screen } from '@testing-library/react'import userEvent from '@testing-library/user-event'import { describe, it, expect } from 'vitest'import { MyComponent } from './MyComponent'
describe('<MyComponent />', () => { it('shows initial state', () => { /* Arrange-Act-Assert */ }) it('responds to user click', async () => { /* ... */ }) it.each([ ['admin', 'can see button'], ['viewer', 'cannot see button'], ])('variant: %s → %s', async (role, expectation) => { /* ... */ })})Де зберігаємо снепшоти
Section titled “Де зберігаємо снепшоти”- Автоматично створюються у
__snapshots__поруч із тестом. - Дозволені лише малі та стабільні снепшоти (наприклад, серіалізовані об’єкти або невеликі DOM-гілки).
- Великі DOM-снепшоти — заборонені (ламані при будь-якому рефакторингу).
Моки, стаби й адаптери
Section titled “Моки, стаби й адаптери”- Мок для модуля клади поруч:
api.mock.ts,useAuth.mock.ts. - Якщо мок використовується у різних місцях — у
tests/mocks/. - Браузерні API, яких немає в jsdom (
matchMedia,ResizeObserver,IntersectionObserver), оголошуються вsetupTests.ts(глобально).
Розміщення setupTests.ts і конфігів
Section titled “Розміщення setupTests.ts і конфігів”setupTests.tsлежить у корені src або в корені репо (залежно від збірки) і підключений уvitest.config.ts→test.setupFiles.- Не змішуй
setupTests.tsзі спільними хелперами — для них єtests/setup/.
Імпорт-алиаси та стабільність шляху
Section titled “Імпорт-алиаси та стабільність шляху”- Використовуй алиаси з
tsconfig.json(іvite-tsconfig-paths) — жодних глибоких відносних шляхів типу../../../. - Для тестів, що сидять поруч, імпортуй відносно:
import { X } from './X'— це спрощує рефакторинг.
Виключення з покриття (coverage)
Section titled “Виключення з покриття (coverage)”Глобально у vitest.config.ts → coverage.exclude
**/e2e/**, **/stories/**, **/*.d.ts, **/msw/**, **/fixtures/**, **/factories/**, **/.next/**, **/dist/**, **/build/**...За потреби можна точково помітити файл:
/* istanbul ignore file */ — наприклад, чисті re-export index.ts.
Нейминг тестових сутностей
Section titled “Нейминг тестових сутностей”describe: що ми тестуємо — ім’я компонента/модуля.it/test: поведінка користувача/наслідок, не внутрішня імплементація.
Приклад:- ✅
it('disables submit while request is in flight') - ❌
it('sets isLoading to true')
- ✅
- Табличні тести:
it.eachдля наборів вхідних даних/ролей/локалей.
Правила для index.ts
Section titled “Правила для index.ts”- Якщо
index.tsлише ре-експортує — не пишемо окремий тест. - Якщо там є логіка (наприклад, конфіг/фабрика) — тестуємо файл, назвавши наприклад
index.node.test.ts.
Чек-ліст рев’ю структури тестів
Section titled “Чек-ліст рев’ю структури тестів”Розміщення файлів
Section titled “Розміщення файлів”- Тест поруч із модулем (
*.test.ts(x)), а не у випадковій директорії. - Для Node-модулів використано суфікс
.node.test.ts. - Великі набори тестів згруповані у
__tests__. - Спільні фікстури, фабрики, моки розташовані у
tests/fixtures/tests/factories/tests/mocks. - Всі шляхи імпорту — через алиаси, немає
../../../.
Іменування
Section titled “Іменування”- Ім’я тестового файлу віддзеркалює назву модуля (
Button.tsx→Button.test.tsx). -
describe()— містить ім’я компонента або функції. -
it()/test()— описує поведінку, а не реалізацію
(✅ “renders loading state”, ❌ “sets isLoading to true”). - Табличні тести оформлені через
it.each, а не дублікатами блоків.
Зміст тестів
Section titled “Зміст тестів”- Тест перевіряє публічну поведінку (UI, ефекти, вихід), а не внутрішній state.
- Враховано основні стани/гілки логіки (loading, success, error, disabled, edge-cases).
- Не перевіряються тривіальні речі (“рендерить children”, “виводить title”), якщо це не умовна логіка.
- Є хоча б один тест на негативний сценарій (помилка, невалідні дані).
- Тести детерміновані - без
setTimeout,random, “магічних”waitFor. - Для асинхронщини використовуються
await findBy...абоwaitFor. - Немає реальних мережевих запитів - усі через моки або MSW.
- Покриття реальне, не “snapshot-спам”.
Структура файлу
Section titled “Структура файлу”- Імпорти впорядковані (спочатку бібліотеки, потім локальні).
- Є логічні групи
describe(), тестові кейси короткі. - Є Arrange-Act-Assert або Given-When-Then структура.
- Немає зайвих консольних логів, дебагів, коментів.
- Якщо є снепшоти - вони малі й стабільні.
-
beforeEach/afterEachне дублюють setup зsetupTests.ts.
Стандарти середовища
Section titled “Стандарти середовища”- Не використовується нестандартне середовище - все під
jsdomабоnode. - Тестові файли розпізнаються
vitest projectsправильно. - Немає хардкоджених шляхів до
distабо продакшн-файлів. - Використовуються стандартні хелпери (
renderWithProviders, фабрики, фікстури).
Coverage і артефакти
Section titled “Coverage і артефакти”- Файл не виключено з покриття без причини (
/* istanbul ignore file */). - Нові тести реально підвищують або утримують рівень покриття.
- Генерує артефакти у стандартну папку
reports/coverage/reports/junit-*.xml.
Загальна якість
Section titled “Загальна якість”- Тести читаються без додаткових пояснень (самодокументовані).
- Імена кейсів і даних описові.
- Тест не залежить від порядку виконання інших тестів.
- При падінні тесту повідомлення зрозуміле (очікування vs результат).
- Тест не дублює вже існуючий сценарій.