В проекте есть два Vitest projects, Playwright E2E и Storybook. Главное правило: имя файла
определяет, какой runner увидит тест. Используйте явные суффиксы .unit.test и
.component.test, чтобы тест не потерялся.
Источники истины:
vitest.config.ts,playwright.config.ts,.storybook/и npm scripts.
| Что проверяем | Среда | Какие файлы запускаются |
|---|---|---|
| Unit | Node | **/*.unit.test.ts(x), packages/**/*.test.ts |
| Component | Headless Chromium, real DOM | **/*.component.test.ts(x), app/**/*.test.tsx, src/**/*.test.tsx |
| E2E | Chromium | src/tests/e2e/**/*.@(spec|test).?(c|m)[jt]s?(x) |
| Storybook | Browser preview | app/**/*.stories.tsx, packages/core/**/*.stories.tsx, src/**/*.stories.*, src/**/*.mdx |
Обратите внимание на исключения:
src/example.test.tsне входит ни в один Vitest project. Назовите файлexample.unit.test.ts.src/example.test.tsxпопадает в Component project даже без.component..packages/example.test.tsпопадает в Unit project.packages/example.test.tsxбез.component.не попадает под общий package pattern.
Chromium устанавливается один раз после npm ci:
# macOS
npx playwright install chromium
# Linux и CI: Chromium вместе с системными библиотеками
npx playwright install --with-deps chromiumИспользуйте Unit project для чистых функций, schemas, plugins, serialization, mock routing и логики, которая не зависит от браузера.
# Весь Unit project
npm run test:unit
# Один файл
npx vitest run src/mock-mode/runtime.unit.test.ts --project unit
# Тесты API workspace
npm --workspace @repo/api run testUnit project работает в Node. Не добавляйте самодельный jsdom setup. Если тест зависит от layout, focus, pointer/keyboard events, Base UI или hydration, используйте Component project.
src/tests/setup-env.ts подменяет fetch: любой незамоканный network request падает с ошибкой.
Явно mock transport или fetch, либо используйте generated mock client. Unit test не должен
случайно зависеть от запущенного backend.
Для @repo/api отдельно проверяйте transport, client config, mock scenarios и независимые
post-generators. После изменения pipeline или OpenAPI запускайте полный gen: он завершается
root TypeScript check, который включает generated output.
npx vitest run packages/api/client-config.unit.test.ts packages/api/mock-client.test.ts packages/api/mock-scenarios.test.ts --project unit
npx vitest run packages/api/generators --project unit
npm --workspace @repo/api run genComponent project запускается через @vitest/browser-playwright в реальном headless Chromium.
Компоненты рендерятся через vitest-browser-react, а взаимодействия проверяются browser
locators.
# Весь Component project
npm run test:component
# Один файл
npx vitest run src/components/utilities/error-boundary/error-boundary.test.tsx --project componentМинимальный пример:
import { expect, test } from 'vitest'
import { render } from 'vitest-browser-react'
test('отправляет форму с валидными значениями', async () => {
const screen = await render(<ExampleForm />)
await screen.getByRole('button', { name: 'Save' }).click()
await expect.element(screen.getByText('Saved')).toBeVisible()
})Config подменяет next/navigation, next/image и next/script aliases из
src/tests/mocks. Navigation mock сбрасывается после каждого browser test.
Не добавляйте глобальный mock Base UI только ради удобства: проверяйте реальное browser behavior. Для визуальных состояний reusable-компонента добавьте Storybook story. Story не заменяет interaction test, а Component test не заменяет visual review всех состояний.
E2E проверяет приложение через Chromium. Tests открывают относительные URL, а
playwright.config.ts формирует baseURL из FRONT_PORT, по умолчанию 3000.
# Вся E2E suite; Playwright сам поднимет npm run dev
npm run test:e2e
# Один файл
npx playwright test src/tests/e2e/example.spec.tsВ development mode Playwright переиспользует уже запущенный server.
GitLab pipeline сейчас не запускает E2E и не создаёт production build. Зелёный CI не означает, что production E2E прошёл.
Storybook нужен для просмотра состояний reusable UI и ручной проверки accessibility.
# Локальный preview
npm run storybook
# Проверка production Storybook build
npm run build-storybookStory располагайте рядом с reusable component. Интерактивное поведение всё равно покрывайте Component test.
Человекочитаемые названия новых и изменяемых test/it пишите по-русски. Начинайте с глагола
в настоящем времени и описывайте наблюдаемое поведение: возвращает, показывает,
блокирует, сохраняет.
| Хорошо | Плохо | Почему |
|---|---|---|
возвращает пустое тело для ответа 204 |
обработка ответа 204 |
Нет действия и результата |
показывает ошибку после потери фокуса |
должен работать корректно |
Неясно, что ожидается |
отправляет форму с валидными значениями |
проверяет submitForm |
Описана реализация, а не поведение |
игнорирует cookie mock-mode в production |
calls setState |
Английский текст и implementation detail |
describe тоже пишите по-русски: это название subject или context. Технические identifiers,
например mock-mode, NEXT_PUBLIC_BFF_PATH и API methods, не переводите.
Имена файлов остаются английскими и следуют patterns из первой таблицы:
registration-form.component.test.tsx. Существующее английское название теста переводите, когда
меняете этот тест. Массовое переименование всей suite выполняйте отдельной задачей.
Runners уже используют параллелизм. Каждый тест должен сам создавать данные и очищать mutable state. Не делите между параллельными тестами один database record, account, queue, temporary path, cookie/storage или module singleton.
Vitest запускает файлы параллельно в workers, а tests внутри файла — последовательно.
test.concurrent и describe.concurrent используйте только для независимых async-тестов,
которые в основном ждут I/O или timers. Они выполняются через Promise.all в том же worker и не
ускоряют синхронный CPU-bound код.
Не используйте concurrent mode вместе с общими vi.stubEnv, vi.stubGlobal, fake timers,
module mocks или browser DOM. В concurrent test берите expect и onTestFinished из локального
Test Context.
# Ограничить workers на одной машине
npx vitest run --project unit --maxWorkers=4
# Диагностика race condition
npx vitest run --project unit --maxWorkers=1В config включён fullyParallel: true, поэтому параллельно могут выполняться и files, и отдельные
tests. Используйте встроенные fixtures page и context: они изолированы для каждого теста.
Не сохраняйте их в module variable и не создавайте один раз в beforeAll.
Внешние данные делайте уникальными для test/worker. Дорогой ресурс можно оформить как worker-scoped
fixture с отдельным namespace, например по workerInfo.workerIndex. serial допустим только для
неизолируемой stateful sequence; обычно её лучше объединить в один E2E test или разделить данные.
# Workers на одной машине
npx playwright test --workers=4
# Диагностика race condition
npx playwright test --workers=1Workers делят suite на одной машине, shards — между CI jobs:
npx vitest run --project unit --shard=1/2
npx playwright test --shard=1/2Для shards нужны отдельные artifact paths. Playwright reports объединяйте через blob reporter и
playwright merge-reports. Текущий pipeline не настраивает sharding или merge reports.
Подробнее: Vitest parallelism, Playwright parallelism и Playwright sharding.
Vitest берёт разрешённые env values сначала из process.env, затем из корневого .env, и
передаёт их через src/tests/setup-env.ts. Не вызывайте dotenv в каждом test file и не коммитьте
test credentials.
Playwright не использует этот механизм: env передаётся через process или container. Различие между
FRONT_PORT и PORT описано в справочнике env.
Reporters создают test-results/, allure-results/ и Playwright report artifacts. Эти
директории игнорируются Git и не должны попадать в implementation commit.
| Изменение | Минимальная проверка |
|---|---|
| Pure utility или schema | Узкий Unit test + npm run tsc |
| React или Base UI component | Component test; story для reusable visual states |
| Route или navigation | Component test и/или узкий Playwright E2E |
| OpenAPI contract/codegen | lint:openapi, два gen, API tests, generated/root tsc |
| Cache handler или cache env | Unit + cache integration + нужная dev/prod matrix |
| Env, config или proxy | Unit tests, где возможно, + npm run build |
| Deployment или headers | Production build + smoke через реальный proxy/ingress |
| Документация | Semantic review по коду и config |
| Bug fix | Сначала минимальный regression test |
Для всех Vitest projects, coverage и watch mode:
npm run test
npm run test:coverage
npm run test:watchПосле узких тестов запустите npm run verify:fast: он проверяет formatting, lint и TypeScript.
npm run verify дополнительно запускает Knip, JSCPD, оба Vitest projects, fresh build и standalone
Playwright E2E.
- Проверяйте наблюдаемое поведение, а не внутренний state.
- Используйте accessible roles и names вместо хрупких CSS selectors.
- Не ставьте arbitrary timeout; ждите locator, state или event.
- Явно контролируйте время, randomness и network.
- Runtime mock client создаёт изолированный seeded Faker на каждый response. При прямом вызове factory передавайте контролируемый Faker или overrides для значимых полей.
- Для bug fix убедитесь, что тест падает на старом поведении и проходит после исправления.
- Не обновляйте snapshots вслепую: сначала прочитайте semantic diff.