Appearance
Testing Strategy — Partizap Frontend
Дата: 2026-03-12 Контекст: MVP / pre-launch, solo dev + Claude, backend через dev-стенд (dev.partizap.ru)
Подход: Прагматичный гибрид
Три слоя тестирования с разным приоритетом. Компонентные тесты (@vue/test-utils) откладываем до стабилизации UI после MVP.
Фаза 0 — Экстракция логики из компонентов
Фаза 1 — Unit тесты (Vitest)
Фаза 2 — E2E smoke (Playwright)
Фаза 3 — Ручной regression (USER_FLOWS.md)Порядок строгий: 0 → 1 → 2 → 3. Каждая фаза самодостаточна.
Фаза 0: Экстракция логики из компонентов
Цель: Вынести бизнес-логику из Vue-компонентов в тестируемые единицы.
0.1 — Форматтеры в shared/lib/ ✅
| Файл | Функция | Дублируется в | Статус |
|---|---|---|---|
shared/lib/format-price.ts | formatPrice(value: number): string | 8+ компонентов | ✅ done |
shared/lib/format-date.ts | formatTime(), formatDateShort(), formatDateTime(), formatMonthYear(), formatSmartDate() | 10+ компонентов | ✅ done |
shared/lib/product-image.ts | getProductImageUrl(images, size): string | null | 4 компонента | ✅ done |
shared/lib/highlight-text.ts | highlightText(text, query): string, escapeHtml() | 2 компонента | ✅ done (XSS fix) |
35 новых тестов, 9 компонентов рефакторено. План: docs/plans/2026-03-12-extract-formatters.md
0.2 — DRY fix: SearchBar ✅
Вынесено в features/search/composables/useSearchAutocomplete.ts (12 тестов). SearchBar и HeroSearchBar стали тонкими обёртками (-102 строки).
0.3 — Декомпозиция толстых компонентов ✅
| Компонент | Строк | Что вынести | Куда | Статус |
|---|---|---|---|---|
| ProductFormPage | 590 | price input masking, OEM array CRUD, unsaved changes guard | composables в features/product-form/ | ✅ |
| Catalog page | 373 | URL ↔ filters sync, filter state | features/catalog-filters/composables/ | ✅ |
| PhoneManager | 276 | phone masking, modal state | composables в features/cabinet-settings/ | ✅ |
| CitySelector | 229 | Set-based multi-select + search | composable в features/geo-select/ | ✅ |
Правило: экстрагируем → пишем тест → заменяем в компоненте → проверяем ручным прокликиванием.
Фаза 1: Unit тесты (Vitest)
Текущее покрытие (433 теста, 48 файлов) ✅
Stores: auth, favorites, geo, geoLookup. Composables: admin-*, cabinet-settings, search (+ searchAutocomplete), geo-select, ymm-select, image-upload, product-form (+ pricing, OEM, guards), catalog-filters, category-select, phone-manager (+ phoneForm), citySelector. Schemas: product, user, car, category, geo. Middleware: admin. Shared: api client, cursor pagination, phone utils, format-price, format-date, product-image, highlight-text. Auth: apiError.
1.1 — Stores (critical path) ✅
useAuthStore — 19 тестов: login, logout, fetchUser, setUser, getters.
1.2 — Непокрытые composables ✅
| Composable | Слой | Тестов |
|---|---|---|
useCursorPagination | shared | 10 |
useApiError | features/auth | 13 |
useGeoCascade | features/geo-select | 9 |
useYmmCascade | features/ymm-select | 12 |
useProductForm | features/product-form | 23 |
useImageUpload | features/image-upload | 11 |
1.3 — Schemas ✅
user (15), car (30), category (10), geo (10) = 65 тестов
expect(schema.parse(valid)).toEqual(...) + expect(() => schema.parse(invalid)).toThrow()
Что НЕ тестируем юнитами
- Vue-компоненты (рендеринг, DOM) — зона E2E
- Middleware
guest.ts— тривиальный redirect - Layouts — чистые шаблоны
- Плагин
auth.ts— покрывается через store тест
Фаза 2: E2E smoke (Playwright) ✅
Принцип
13 smoke тестов + 50 функциональных E2E тестов против dev-стенда. Smoke — "приложение не сломалось", функциональные — проверка user flows.
Smoke тесты
| # | Flow | Что проверяем |
|---|---|---|
| 1 | Каталог → карточка (гость) | SSR, SEO, навигация |
| 2 | Регистрация | Ворота в продукт |
| 3 | Логин → кабинет | Critical auth path |
| 4 | Создание объявления (черновик) | Основной бизнес-флоу |
| 5 | Публикация → модерация (админ) | Pipeline продукта |
| 6 | Поиск по YMMM каскаду | Уникальная фича |
Функциональные E2E тесты
| Группа | Файлы | Тестов | Тикет |
|---|---|---|---|
| Auth (login, register, password-reset) | 3 | 13 | DEV-204 |
| Catalog (list, product-detail, ymm-cascade, search) | 4 | 24 | DEV-205 |
| Seller (create-product) | 1 | 7 | DEV-206 |
| Chat (start-conversation, messaging) | 2 | 5 | DEV-207 |
| Admin (moderation) | 1 | 3 | DEV-207 |
| Итого | 11 | 52 |
Что НЕ автоматизируем
- Verify email (нужен доступ к почте)
- Профиль, избранное, сессии (покрыты юнитами composables)
- Admin CRUD справочников (покрыт юнитами composables)
Работа с dev-стендом
- Setup через API, не UI. POST
/auth/login→ cookie → тестируем UI. - Не assert'им конкретные данные.
expect(card).toBeVisible(), неtoBe('Колодки'). - Retry + soft assertions для flaky элементов.
- Отдельный тестовый юзер на стенде.
Структура
tests/e2e/
├── gate.setup.ts # Проход формы авторизации dev-сервера
├── auth.setup.ts # Логин ролей через API
├── smoke/ # 5 smoke-тестов
├── auth/ # 13 функциональных тестов (DEV-204)
├── catalog/ # 24 функциональных теста (DEV-205)
├── seller/ # 7 функциональных тестов (DEV-206)
├── chat/ # 5 функциональных тестов (DEV-207)
├── admin/ # 3 функциональных теста (DEV-207)
├── helpers/
│ ├── auth.helper.ts # loginViaApi(), RateLimitError
│ ├── auth.state.ts # storageState пути
│ └── api.helper.ts # Прямые API-вызовы
└── .auth/ # Автогенерируемые storageState (gitignored)Подробная структура — см.
docs/dev/frontend/e2e-user-flows.md
CI-интеграция
yaml
test:e2e:
stage: test-e2e
needs: [deploy:dev]
allow_failure: true # не блокирует merge пока стабилизируем
script:
- npx playwright test --reporter=listЗапускает все проекты (gate → setup → smoke + functional). allow_failure: true на первое время → blocking после стабилизации.
Фаза 3: Ручной regression
USER_FLOWS.md как structured checklist перед каждым merge в main:
- Фазы 1-3 из USER_FLOWS.md (базовые + авторизация + продавец) — ~20 мин
- Фаза 4 (чат) — ~5 мин
- Фаза 5 (админка) — ~10 мин
Сознательно откладываем
| Что | Почему | Когда |
|---|---|---|
| Component тесты (@vue/test-utils) | UI меняется на MVP, тесты будут ломаться | После стабилизации UI |
| E2E verify email (UF-03) | Нужен доступ к почтовому ящику | — (не автоматизируется) |
| Полное покрытие оставшихся flows (UF-13–16, 18–20, 22–25) | ROI не оправдан на MVP | После запуска, при стабилизации |
| Visual regression (Percy, Chromatic) | Overkill для solo dev | Когда появится команда |
Инструменты
| Категория | Инструмент |
|---|---|
| Unit | Vitest + @nuxt/test-utils |
| Mocks | vi.mock / msw (для API) |
| E2E | Playwright |
| E2E recording | Gasoline MCP / Playwright Codegen |
| CI | GitLab CI (существующий pipeline) |
| Regression | USER_FLOWS.md (ручной чеклист) |