Skip to content

Структура файлів і неймінг

  • Тест розміщується поруч із модулем, який він перевіряє.
  • Це спрощує навігацію, рефакторинг і видимість покриття.
  • 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.tsButton.test.tsx
Node-тести (SDK/утиліти)*.node.test.tsformatDate.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.tsX.test.ts, X.tsxX.test.tsx.

  • Якщо кейсів багато — додавай короткий дескриптор:
    Modal.open-close.test.tsx, Modal.a11y.test.tsx.

  • Для параметризованих утиліт — дозволено групувати:
    currencyFormat.edge-cases.test.ts.

Локальні тести — поруч із кодом. Спільні хелпери/фікстури — у 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 “Усередині тестового файлу”

Рекомендований каркас:

example.test.ts
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-снепшоти — заборонені (ламані при будь-якому рефакторингу).
  • Мок для модуля клади поруч: 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.tstest.setupFiles.
  • Не змішуй setupTests.ts зі спільними хелперами — для них є tests/setup/.

Імпорт-алиаси та стабільність шляху

Section titled “Імпорт-алиаси та стабільність шляху”
  • Використовуй алиаси з tsconfig.jsonvite-tsconfig-paths) — жодних глибоких відносних шляхів типу ../../../.
  • Для тестів, що сидять поруч, імпортуй відносно: import { X } from './X' — це спрощує рефакторинг.

Виключення з покриття (coverage)

Section titled “Виключення з покриття (coverage)”

Глобально у vitest.config.tscoverage.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 лише ре-експортує — не пишемо окремий тест.
  • Якщо там є логіка (наприклад, конфіг/фабрика) — тестуємо файл, назвавши наприклад index.node.test.ts.

Чек-ліст рев’ю структури тестів

Section titled “Чек-ліст рев’ю структури тестів”
  • Тест поруч із модулем (*.test.ts(x)), а не у випадковій директорії.
  • Для Node-модулів використано суфікс .node.test.ts.
  • Великі набори тестів згруповані у __tests__.
  • Спільні фікстури, фабрики, моки розташовані у tests/fixtures / tests/factories / tests/mocks.
  • Всі шляхи імпорту — через алиаси, немає ../../../.
  • Ім’я тестового файлу віддзеркалює назву модуля (Button.tsxButton.test.tsx).
  • describe() — містить ім’я компонента або функції.
  • it() / test() — описує поведінку, а не реалізацію
    (✅ “renders loading state”, ❌ “sets isLoading to true”).
  • Табличні тести оформлені через it.each, а не дублікатами блоків.
  • Тест перевіряє публічну поведінку (UI, ефекти, вихід), а не внутрішній state.
  • Враховано основні стани/гілки логіки (loading, success, error, disabled, edge-cases).
  • Не перевіряються тривіальні речі (“рендерить children”, “виводить title”), якщо це не умовна логіка.
  • Є хоча б один тест на негативний сценарій (помилка, невалідні дані).
  • Тести детерміновані - без setTimeout, random, “магічних” waitFor.
  • Для асинхронщини використовуються await findBy... або waitFor.
  • Немає реальних мережевих запитів - усі через моки або MSW.
  • Покриття реальне, не “snapshot-спам”.
  • Імпорти впорядковані (спочатку бібліотеки, потім локальні).
  • Є логічні групи describe(), тестові кейси короткі.
  • Є Arrange-Act-Assert або Given-When-Then структура.
  • Немає зайвих консольних логів, дебагів, коментів.
  • Якщо є снепшоти - вони малі й стабільні.
  • beforeEach / afterEach не дублюють setup з setupTests.ts.
  • Не використовується нестандартне середовище - все під jsdom або node.
  • Тестові файли розпізнаються vitest projects правильно.
  • Немає хардкоджених шляхів до dist або продакшн-файлів.
  • Використовуються стандартні хелпери (renderWithProviders, фабрики, фікстури).
  • Файл не виключено з покриття без причини (/* istanbul ignore file */).
  • Нові тести реально підвищують або утримують рівень покриття.
  • Генерує артефакти у стандартну папку reports/coverage / reports/junit-*.xml.
  • Тести читаються без додаткових пояснень (самодокументовані).
  • Імена кейсів і даних описові.
  • Тест не залежить від порядку виконання інших тестів.
  • При падінні тесту повідомлення зрозуміле (очікування vs результат).
  • Тест не дублює вже існуючий сценарій.