diff --git a/apps/docs/docs/development/testing.md b/apps/docs/docs/development/testing.md
index 7c8906d..aebd225 100644
--- a/apps/docs/docs/development/testing.md
+++ b/apps/docs/docs/development/testing.md
@@ -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()
+expect(screen.getByText('Сбер (SBER)')).toBeInTheDocument()
+```
+
+**Компонент с auth/Router** — `renderWithProviders`:
+
+```tsx
+import { renderWithProviders } from '@/shared/lib/test/test-utils'
+
+renderWithProviders(, { 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
diff --git a/apps/frontend/src/shared/lib/test/README.md b/apps/frontend/src/shared/lib/test/README.md
index c7abefe..8816a95 100644
--- a/apps/frontend/src/shared/lib/test/README.md
+++ b/apps/frontend/src/shared/lib/test/README.md
@@ -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(, { 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()
+```
+
+### 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`.
diff --git a/docs/epics/FrontendDebtBacklog.md b/docs/epics/FrontendDebtBacklog.md
index 8c81299..c5cf1dd 100644
--- a/docs/epics/FrontendDebtBacklog.md
+++ b/docs/epics/FrontendDebtBacklog.md
@@ -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
diff --git a/docs/features/frontend-infrastructure-hardening/spec.md b/docs/features/frontend-infrastructure-hardening/spec.md
index 754d60c..67b56c7 100644
--- a/docs/features/frontend-infrastructure-hardening/spec.md
+++ b/docs/features/frontend-infrastructure-hardening/spec.md
@@ -1,7 +1,7 @@
# Frontend Infrastructure Hardening
Дата: 2026-06-23
-Статус: спецификация
+Статус: выполнено
## Контекст
diff --git a/docs/features/frontend-infrastructure-hardening/tasks.md b/docs/features/frontend-infrastructure-hardening/tasks.md
index 188c817..19cfd08 100644
--- a/docs/features/frontend-infrastructure-hardening/tasks.md
+++ b/docs/features/frontend-infrastructure-hardening/tasks.md
@@ -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
diff --git a/docs/features/frontend-shared-boundary-cleanup/spec.md b/docs/features/frontend-shared-boundary-cleanup/spec.md
index c946df5..29e3ff2 100644
--- a/docs/features/frontend-shared-boundary-cleanup/spec.md
+++ b/docs/features/frontend-shared-boundary-cleanup/spec.md
@@ -1,7 +1,7 @@
# Frontend Shared Boundary Cleanup
Дата: 2026-06-23
-Статус: спецификация
+Статус: выполнено
## Контекст
diff --git a/docs/features/frontend-shared-boundary-cleanup/tasks.md b/docs/features/frontend-shared-boundary-cleanup/tasks.md
index 700754a..2abaa5d 100644
--- a/docs/features/frontend-shared-boundary-cleanup/tasks.md
+++ b/docs/features/frontend-shared-boundary-cleanup/tasks.md
@@ -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-поведение
diff --git a/docs/features/frontend-test-hygiene/spec.md b/docs/features/frontend-test-hygiene/spec.md
index 33bb767..7b8e7a1 100644
--- a/docs/features/frontend-test-hygiene/spec.md
+++ b/docs/features/frontend-test-hygiene/spec.md
@@ -1,7 +1,7 @@
# Frontend Test Hygiene
Дата: 2026-06-23
-Статус: спецификация
+Статус: выполнено
## Контекст
diff --git a/docs/features/frontend-test-hygiene/tasks.md b/docs/features/frontend-test-hygiene/tasks.md
index 64e954d..d838b54 100644
--- a/docs/features/frontend-test-hygiene/tasks.md
+++ b/docs/features/frontend-test-hygiene/tasks.md
@@ -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] Убедиться, что изменения не меняют пользовательское поведение
diff --git a/docs/roadmap.md b/docs/roadmap.md
index 81b4408..c8278d3 100644
--- a/docs/roadmap.md
+++ b/docs/roadmap.md
@@ -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-таблицы