docs: simplify conventions layout
Frontend security / security (pull_request) Successful in 8s
Frontend verify / verify (pull_request) Successful in 3m53s
Conventional commits / commits (pull_request) Successful in 19s
Frontend security / security (push) Successful in 8s
Frontend verify / verify (push) Successful in 3m53s

This commit was merged in pull request #14.
This commit is contained in:
2026-09-15 05:58:31 +03:00
parent 718365cd5a
commit 9f7e342333
11 changed files with 93 additions and 114 deletions
+58
View File
@@ -0,0 +1,58 @@
# Frontend testing
Перед нетривиальными тестами сформулируй
[общий Test Intent](../../../.ai/conventions/testing.md); отдельный документ
не требуется. Trivial low-risk изменения обходятся без него.
## Выбор проверки
Читай при изменении тестов, доступа, денежных расчётов, восстановления
интерфейса или исправлении подтверждённой регрессии.
Выбирай boundary по наблюдаемому исходу, а не внутреннему helper/component state.
| Изменение | Дешёвая надёжная проверка |
| --- | --- |
| Чистое domain преобразование/денежный расчёт | Unit case с граничными значениями |
| Форма, route access, recovery, UI-state selection | RTL component/route test через видимое поведение |
| Headers, refresh/retry, query invalidation | MSW на transport boundary |
| Критический browser flow, который JSDOM не доказывает | Browser/e2e proof существующими доступными средствами; отдельный frontend e2e runner пока не принят |
| Только declarative props/Storybook fixture | Type/build + semantic/visual review; unit test без собственной логики не нужен |
Tests colocated с source (`*.test.tsx` для UI, существующий `*.test.ts` для pure code).
Arrange/Act/Assert, semantic queries (`getByRole`, label); test id — когда
пользовательский selector не выражает нужный элемент. Не тестируй Mantine/React
internals, private calls или passthrough wrapper ради coverage.
## Инструменты и isolation
Используй `fireEvent` из объявленного `@testing-library/react` и ожидай async
outcome через `findBy*`/`waitFor`. `user-event` доступен транзитивно через Storybook,
но не принят как direct dependency; не добавляй его ради старого Markdown.
MSW запускается только Vitest setup в `src/test/`, без browser worker/mock dev mode.
Проверяй сеть MSW handlers, а не mock внутренностей query client или реальный backend.
Независимый case получает свой `createTestQueryClient`; rerender сохраняет
экземпляр и seeded cache. Providers выбирай явно. Existing teardown выполняет
RTL cleanup, auth reset и MSW reset: [test client](../../src/test/query.tsx).
Тестовый клиент отключает retries запросов и мутаций для предсказуемого исхода;
это не меняет [политику обновления приложения](../../../docs/adr/007-react-query-fetch-policy.md).
## Важные случаи
Форма: field errors, отсутствие request при invalid input, submit blocking,
сохранение ввода при network error. Routes: доступ/redirect и neutral auth bootstrap.
Finance: loading/error/empty/loaded, cached snapshot при refetch failure, retry,
отсутствие старых данных после session/connection switch. ErrorBoundary: test-only
throwing route, безопасная ссылка и reset после navigation.
Примеры: [AuthForm test](../../src/features/auth/ui/AuthForm.test.tsx),
[client test](../../src/shared/api/client.test.ts),
[usePortfolio test](../../src/entities/portfolio/api/usePortfolio.test.tsx).
Не копируй fixtures/сценарии целиком, если задача затрагивает один исход.
## Команды
Итерация: `npm run test:run -- <path>` без coverage. Полный `npm run verify`
запускает Vitest один раз через `test:coverage`. Coverage floors — anti-regression
constraint, не повод тестировать декларации. После UI изменения отдельно
проверь доступность/визуальные состояния, которых JSDOM не доказывает.