codex/frontend-debt-audit #40
@ -39,17 +39,68 @@ npm run test:watch -w apps/backend
|
||||
|
||||
## Тесты frontend
|
||||
|
||||
Фреймворк: **Vitest 4** + **React Testing Library** + **MSW**.
|
||||
Фреймворк: **Vitest** + **React Testing Library** + **MSW**.
|
||||
|
||||
Запуск:
|
||||
### Запуск
|
||||
|
||||
```bash
|
||||
npm run test:frontend
|
||||
# или
|
||||
npm run test -w apps/frontend
|
||||
npm run test:frontend # все тесты
|
||||
npm run test -w apps/frontend # или напрямую
|
||||
npx vitest run apps/frontend/src/pages/profile/ProfilePage.test.tsx -w apps/frontend # один файл
|
||||
```
|
||||
|
||||
Тесты покрывают API-клиент, auth context, hooks, базовые pages и shared components.
|
||||
### Helpers (`src/shared/lib/test/`)
|
||||
|
||||
| Файл | Назначение |
|
||||
|---|---|
|
||||
| `test-utils.tsx` | `renderWithProviders` — обёртка в QueryClient + Session + Router |
|
||||
| `TestSessionProvider.tsx` | Провайдер сессии для тестов (вызывает `/auth/refresh` при монтировании) |
|
||||
| `factories.ts` | Фабрики mock-данных (`createMockShare`, `createMockBond` и др.) |
|
||||
| `setup.ts` | Глобальный setup: jest-dom, MSW lifecycle, jsdom polyfills |
|
||||
| `README.md` | Конвенции и правила тестирования |
|
||||
|
||||
### Шаблоны
|
||||
|
||||
**Компонент без auth/routing** — просто `render` + фабрика:
|
||||
|
||||
```tsx
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { createMockShare } from '@/shared/lib/test/factories'
|
||||
|
||||
const stock = createMockShare()
|
||||
render(<StockDetails stock={stock} />)
|
||||
expect(screen.getByText('Сбер (SBER)')).toBeInTheDocument()
|
||||
```
|
||||
|
||||
**Компонент с auth/Router** — `renderWithProviders`:
|
||||
|
||||
```tsx
|
||||
import { renderWithProviders } from '@/shared/lib/test/test-utils'
|
||||
|
||||
renderWithProviders(<ProfilePage />, { route: '/profile' })
|
||||
```
|
||||
|
||||
**Ошибка API** — переопределить MSW handler:
|
||||
|
||||
```ts
|
||||
server.use(
|
||||
http.post('/api/v1/auth/me', () => new HttpResponse(null, { status: 500 })),
|
||||
)
|
||||
```
|
||||
|
||||
### Конвенции
|
||||
|
||||
- AAA (Arrange → Act → Assert)
|
||||
- `findBy*` / `findAllBy*` вместо `waitFor` + `getBy*`
|
||||
- `userEvent` вместо `fireEvent`
|
||||
- MSW для API; `vi.fn()` только для callback-ов
|
||||
- Свежий `QueryClient` на каждый тест (`retry: false`)
|
||||
- Нет snapshot-тестов
|
||||
- Тест рядом с компонентом: `ComponentName.test.tsx` рядом с `ComponentName.tsx`
|
||||
|
||||
### Покрытие
|
||||
|
||||
Тесты покрывают API-клиент, auth context, hooks, страницы (Profile, Search), компоненты (StockDetails, BondDetails, DividendsTable).
|
||||
|
||||
## Тесты design system
|
||||
|
||||
|
||||
@ -1,9 +1,75 @@
|
||||
# Tests
|
||||
# Frontend Testing Conventions
|
||||
|
||||
## Common issues
|
||||
## Helpers
|
||||
|
||||
### Auth loading screen
|
||||
Components rendered through `renderWithProviders` are wrapped in AuthProvider which shows
|
||||
a loading screen until `POST /api/v1/auth/refresh` resolves.
|
||||
- Use `await screen.findByText()` to wait for auth to complete.
|
||||
- For components that don't need auth, render with just QueryClientProvider + MemoryRouter.
|
||||
### renderWithProviders (`test-utils.tsx`)
|
||||
|
||||
Wraps component in `QueryClientProvider` + `TestSessionProvider` + `RouterProvider`.
|
||||
|
||||
Use for components that depend on auth or routing.
|
||||
|
||||
```ts
|
||||
import { renderWithProviders } from '@/shared/lib/test/test-utils'
|
||||
|
||||
renderWithProviders(<ProfilePage />, { route: '/profile' })
|
||||
```
|
||||
|
||||
Options: `queryClient` (fresh by default with `retry: false`), `route` (default `/`).
|
||||
|
||||
### Plain render
|
||||
|
||||
For components that only need factory data (no auth, no query):
|
||||
|
||||
```ts
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
render(<StockDetails stock={createMockShare()} />)
|
||||
```
|
||||
|
||||
### TestSessionProvider (`TestSessionProvider.tsx`)
|
||||
|
||||
Calls `POST /api/v1/auth/refresh` on mount. Always resolves successfully via MSW by default.
|
||||
Override by adding a `server.use()` before rendering.
|
||||
|
||||
### Factories (`factories.ts`)
|
||||
|
||||
| Factory | Returns |
|
||||
|---|---|
|
||||
| `createMockShare(overrides?)` | `ShareResponse` |
|
||||
| `createMockBond(overrides?)` | `BondResponse` |
|
||||
| `createMockUser(overrides?)` | `UserResponse` |
|
||||
| `createMockAuth(overrides?)` | `AuthResponse` |
|
||||
| `createMockMarketData(overrides?)` | `StockMarketData` |
|
||||
| `createMockBondMarketData(overrides?)` | `BondMarketData` |
|
||||
| `createMockCandles(count?)` | `CandleItem[]` |
|
||||
| `createMockDividends()` | `DividendItem[]` |
|
||||
| `createMockSearchResults()` | `SearchResultItem[]` |
|
||||
|
||||
All factories accept `overrides` to customise specific fields per test.
|
||||
|
||||
## Rules
|
||||
|
||||
- **AAA pattern** — Arrange, Act, Assert
|
||||
- **`findBy*` / `findAllBy*` over `waitFor` + `getBy*`** (already await)
|
||||
- **`userEvent` over `fireEvent`** — simulates real interactions
|
||||
- **MSW for API** — mock network layer; `server.use()` per test for error cases
|
||||
- **`vi.fn()` for callbacks only**
|
||||
- **Fresh QueryClient per test** — `retry: false`, `gcTime: 0`
|
||||
- **No snapshot tests**
|
||||
- **Each `describe` tests one concern** — no 200-line tests
|
||||
|
||||
## MSW
|
||||
|
||||
Global handlers cover all API endpoints with 200 responses.
|
||||
Override per test:
|
||||
|
||||
```ts
|
||||
import { server } from '@mocks/server'
|
||||
import { http, HttpResponse } from 'msw'
|
||||
|
||||
server.use(
|
||||
http.post('/api/v1/auth/refresh', () => new HttpResponse(null, { status: 401 })),
|
||||
)
|
||||
```
|
||||
|
||||
Handlers reset automatically in `afterEach`.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Frontend Debt Backlog
|
||||
|
||||
Статус: запланировано
|
||||
Статус: завершено
|
||||
|
||||
Порядок реализации:
|
||||
|
||||
@ -12,6 +12,6 @@
|
||||
Features:
|
||||
- [ ] [frontend-debt-audit](../features/frontend-debt-audit/spec.md) — аудит frontend-техдолга и приоритизация backlog
|
||||
- [x] [frontend-docs-sync](../features/frontend-docs-sync/spec.md) — синхронизация inbox/roadmap и устаревшей frontend-документации
|
||||
- [ ] [frontend-infrastructure-hardening](../features/frontend-infrastructure-hardening/spec.md) — завершение infrastructure/tooling debt
|
||||
- [ ] [frontend-shared-boundary-cleanup](../features/frontend-shared-boundary-cleanup/spec.md) — сужение shared/public API и границ слоёв
|
||||
- [ ] [frontend-test-hygiene](../features/frontend-test-hygiene/spec.md) — упрощение и нормализация frontend-test infrastructure
|
||||
- [x] [frontend-infrastructure-hardening](../features/frontend-infrastructure-hardening/spec.md) — завершение infrastructure/tooling debt
|
||||
- [x] [frontend-shared-boundary-cleanup](../features/frontend-shared-boundary-cleanup/spec.md) — сужение shared/public API и границ слоёв
|
||||
- [x] [frontend-test-hygiene](../features/frontend-test-hygiene/spec.md) — упрощение и нормализация frontend-test infrastructure
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Frontend Infrastructure Hardening
|
||||
|
||||
Дата: 2026-06-23
|
||||
Статус: спецификация
|
||||
Статус: выполнено
|
||||
|
||||
## Контекст
|
||||
|
||||
|
||||
@ -1,34 +1,34 @@
|
||||
# Frontend Infrastructure Hardening — tasks
|
||||
|
||||
Статус: pending
|
||||
Статус: completed
|
||||
|
||||
## 1. Включить browser mock mode
|
||||
|
||||
- [ ] Добавить `apps/frontend/mocks/browser.ts` с `setupWorker`
|
||||
- [ ] Подключить worker в `apps/frontend/src/main.tsx` через `VITE_API_MOCK`
|
||||
- [ ] Обновить frontend docs, чтобы явно описать mock-free vs mock-enabled dev flow
|
||||
- [x] Добавить `apps/frontend/mocks/browser.ts` с `setupWorker`
|
||||
- [x] Подключить worker в `apps/frontend/src/main.tsx` через `VITE_API_MOCK`
|
||||
- [x] Обновить frontend docs, чтобы явно описать mock-free vs mock-enabled dev flow
|
||||
|
||||
## 2. Валидация env
|
||||
|
||||
- [ ] Описать обязательные `VITE_*` переменные в `apps/frontend/src/shared/config/env.ts`
|
||||
- [ ] Провалить старт приложения на невалидной конфигурации до рендера
|
||||
- [ ] Проверить, что сообщение об ошибке не раскрывает секреты
|
||||
- [x] Описать обязательные `VITE_*` переменные в `apps/frontend/src/shared/config/env.ts`
|
||||
- [x] Провалить старт приложения на невалидной конфигурации до рендера
|
||||
- [x] Проверить, что сообщение об ошибке не раскрывает секреты
|
||||
|
||||
## 3. Tooling consistency
|
||||
|
||||
- [ ] Проверить `apps/frontend/package.json` и синхронизировать скрипты с текущим состоянием проекта
|
||||
- [ ] Обновить docs, где перечислены команды разработки, lint и build
|
||||
- [ ] Удалить или переписать устаревшие упоминания старых миграционных шагов
|
||||
- [x] Проверить `apps/frontend/package.json` и синхронизировать скрипты с текущим состоянием проекта
|
||||
- [x] Обновить docs, где перечислены команды разработки, lint и build
|
||||
- [x] Удалить или переписать устаревшие упоминания старых миграционных шагов
|
||||
|
||||
## 4. Contract freshness
|
||||
|
||||
- [ ] Привести frontend API docs к текущему source of truth
|
||||
- [ ] Проверить, что generated types остаются generated, а не редактируются вручную
|
||||
- [ ] Убедиться, что frontend shared API entrypoints не ссылаются на устаревшие слойные соглашения
|
||||
- [x] Привести frontend API docs к текущему source of truth
|
||||
- [x] Проверить, что generated types остаются generated, а не редактируются вручную
|
||||
- [x] Убедиться, что frontend shared API entrypoints не ссылаются на устаревшие слойные соглашения
|
||||
|
||||
## 5. Финальная проверка
|
||||
|
||||
- [ ] Запустить `npm run lint -w apps/frontend`
|
||||
- [ ] Запустить `npm run test -w apps/frontend`
|
||||
- [ ] Запустить `npm run build -w apps/frontend`
|
||||
- [ ] Проверить `VITE_API_MOCK=true npm run dev -w apps/frontend` на локальном старте без backend
|
||||
- [x] Запустить `npm run lint -w apps/frontend`
|
||||
- [x] Запустить `npm run test -w apps/frontend`
|
||||
- [x] Запустить `npm run build -w apps/frontend`
|
||||
- [x] Проверить `VITE_API_MOCK=true npm run dev -w apps/frontend` на локальном старте без backend
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Frontend Shared Boundary Cleanup
|
||||
|
||||
Дата: 2026-06-23
|
||||
Статус: спецификация
|
||||
Статус: выполнено
|
||||
|
||||
## Контекст
|
||||
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
# Frontend Shared Boundary Cleanup — tasks
|
||||
|
||||
Статус: pending
|
||||
Статус: completed
|
||||
|
||||
## 1. Найти boundary ambiguity
|
||||
|
||||
- [ ] Проверить `apps/frontend/src/shared/api/index.ts` на слишком широкие exports
|
||||
- [ ] Проверить `apps/frontend/src/entities/*/index.ts` на недостающие public entrypoints
|
||||
- [ ] Проверить `apps/frontend/src/widgets/*/index.ts` на конфликтующие или неявные зависимости
|
||||
- [x] Проверить `apps/frontend/src/shared/api/index.ts` на слишком широкие exports
|
||||
- [x] Проверить `apps/frontend/src/entities/*/index.ts` на недостающие public entrypoints
|
||||
- [x] Проверить `apps/frontend/src/widgets/*/index.ts` на конфликтующие или неявные зависимости
|
||||
|
||||
## 2. Сузить shared/public surface
|
||||
|
||||
- [ ] Убрать из `shared/api` то, что является доменной convenience-обёрткой, а не shared infrastructure
|
||||
- [ ] Переключить доменные потребители на entity barrels
|
||||
- [ ] Убедиться, что новые imports не обходят public API слои
|
||||
- [x] Убрать из `shared/api` то, что является доменной convenience-обёрткой, а не shared infrastructure
|
||||
- [x] Переключить доменные потребители на entity barrels
|
||||
- [x] Убедиться, что новые imports не обходят public API слои
|
||||
|
||||
## 3. Обновить документацию слоёв
|
||||
|
||||
- [ ] Обновить `apps/docs/docs/frontend/overview.md`
|
||||
- [ ] Обновить `apps/docs/docs/frontend/api-client.md`
|
||||
- [ ] Зафиксировать правила публичных API слоёв для shared/entities/widgets
|
||||
- [x] Обновить `apps/docs/docs/frontend/overview.md`
|
||||
- [x] Обновить `apps/docs/docs/frontend/api-client.md`
|
||||
- [x] Зафиксировать правила публичных API слоёв для shared/entities/widgets
|
||||
|
||||
## 4. Финальная проверка
|
||||
|
||||
- [ ] Запустить `npm run lint -w apps/frontend`
|
||||
- [ ] Запустить `npm run test -w apps/frontend`
|
||||
- [ ] Запустить `npm run build -w apps/frontend`
|
||||
- [ ] Убедиться, что изменения не затронули runtime-поведение
|
||||
- [x] Запустить `npm run lint -w apps/frontend`
|
||||
- [x] Запустить `npm run test -w apps/frontend`
|
||||
- [x] Запустить `npm run build -w apps/frontend`
|
||||
- [x] Убедиться, что изменения не затронули runtime-поведение
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Frontend Test Hygiene
|
||||
|
||||
Дата: 2026-06-23
|
||||
Статус: спецификация
|
||||
Статус: выполнено
|
||||
|
||||
## Контекст
|
||||
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
# Frontend Test Hygiene — tasks
|
||||
|
||||
Статус: pending
|
||||
Статус: completed
|
||||
|
||||
## 1. Проверить тестовые helpers
|
||||
|
||||
- [ ] Проверить `apps/frontend/src/test/test-utils.tsx` на избыточные обёртки
|
||||
- [ ] Проверить `apps/frontend/src/test/factories.ts` на слишком широкие mock fixtures
|
||||
- [ ] Проверить `apps/frontend/src/test/handlers.ts` на лишние defaults
|
||||
- [x] Проверить `apps/frontend/src/shared/lib/test/test-utils.tsx` на избыточные обёртки
|
||||
- [x] Проверить `apps/frontend/src/shared/lib/test/factories.ts` на слишком широкие mock fixtures
|
||||
- [x] Проверить `apps/frontend/src/shared/lib/test/handlers.ts` на лишние defaults
|
||||
|
||||
## 2. Сузить test layer
|
||||
|
||||
- [ ] Убрать лишнюю глобальную магию из shared test setup
|
||||
- [ ] Перенести one-off setup в конкретные тесты, если он не нужен всем
|
||||
- [ ] Оставить только действительно shared helpers
|
||||
- [x] Убрать лишнюю глобальную магию из shared test setup
|
||||
- [x] Перенести one-off setup в конкретные тесты, если он не нужен всем
|
||||
- [x] Оставить только действительно shared helpers
|
||||
|
||||
## 3. Нормализовать conventions
|
||||
|
||||
- [ ] Обновить frontend docs, описывающие test strategy и conventions
|
||||
- [ ] Убедиться, что global setup не распухает и остаётся понятным
|
||||
- [ ] Сверить conventions с `frontend-test-coverage` как отдельной фичей
|
||||
- [x] Обновить frontend docs, описывающие test strategy и conventions
|
||||
- [x] Убедиться, что global setup не распухает и остаётся понятным
|
||||
- [x] Сверить conventions с `frontend-test-coverage` как отдельной фичей
|
||||
|
||||
## 4. Финальная проверка
|
||||
|
||||
- [ ] Запустить `npm run test -w apps/frontend`
|
||||
- [ ] Запустить `npm run lint -w apps/frontend`
|
||||
- [ ] Запустить `npm run build -w apps/frontend`
|
||||
- [ ] Убедиться, что изменения не меняют пользовательское поведение
|
||||
- [x] Запустить `npm run test -w apps/frontend`
|
||||
- [x] Запустить `npm run lint -w apps/frontend`
|
||||
- [x] Запустить `npm run build -w apps/frontend`
|
||||
- [x] Убедиться, что изменения не меняют пользовательское поведение
|
||||
|
||||
@ -83,9 +83,6 @@ Roadmap отражает порядок продуктовой работы, н
|
||||
|
||||
## Кандидаты следующих фич
|
||||
|
||||
- [ ] [Frontend infrastructure hardening](features/frontend-infrastructure-hardening/spec.md) — завершение infrastructure/tooling debt.
|
||||
- [ ] [Frontend shared boundary cleanup](features/frontend-shared-boundary-cleanup/spec.md) — сужение shared/public API и границ слоёв.
|
||||
- [ ] [Frontend test hygiene](features/frontend-test-hygiene/spec.md) — упрощение и нормализация frontend test infrastructure.
|
||||
- [ ] [Frontend debt audit and backlog](features/frontend-debt-audit/spec.md) — audit текущего
|
||||
frontend-техдолга, разделение open items на follow-up фичи, синхронизация inbox/roadmap.
|
||||
- [ ] [Миграция таблиц на дизайн-систему](features/table-migration/spec.md) — перевести legacy-таблицы
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user