codex/frontend-debt-audit #40

Merged
ksv741 merged 10 commits from codex/frontend-debt-audit into main 2026-06-24 09:10:42 +03:00
10 changed files with 182 additions and 68 deletions
Showing only changes of commit d529d51612 - Show all commits

View File

@ -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

View File

@ -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`.

View File

@ -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

View File

@ -1,7 +1,7 @@
# Frontend Infrastructure Hardening
Дата: 2026-06-23
Статус: спецификация
Статус: выполнено
## Контекст

View File

@ -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

View File

@ -1,7 +1,7 @@
# Frontend Shared Boundary Cleanup
Дата: 2026-06-23
Статус: спецификация
Статус: выполнено
## Контекст

View File

@ -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-поведение

View File

@ -1,7 +1,7 @@
# Frontend Test Hygiene
Дата: 2026-06-23
Статус: спецификация
Статус: выполнено
## Контекст

View File

@ -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] Убедиться, что изменения не меняют пользовательское поведение

View File

@ -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-таблицы