8.7 KiB
Active Context — Strava Frontend
Task State
- task_id: TASK-TEST-PUBLIC
- status: in_progress
- parent_task: —
- summary: Написать Playwright integration тесты для фронтенда в
../integration/tests/. 3 spec файла: auth-flows ✅, public-pages, auth-protected. - next task: TASK-TEST-PROTECTED → Verify
✅ CODER SUCCESS REPORT — TASK-TEST-AUTH
../integration/tests/auth-flows.spec.tsсоздан: 4 теста (login success, login failure, signup+auto-login, logout)- Self-seed via
POST /api/v0/signup, Vuestic selectors (input[type=email],input[type=password]) - Verified:
npx playwright test tests/auth-flows.spec.ts→ 4 passed (19.2s)
TASK-TEST-PUBLIC: public-pages.spec.ts
Цель: Playwright spec для auth-сценариев (signup, login success/error, logout, validation).
Файл для создания: ../integration/tests/auth-flows.spec.ts
Конвенции (см. SKILL.md):
- Self-seed user via
POST /api/v0/signupinbeforeAll - Selectors:
input[type=email],input[type=password],getByRole('button', { name: 'Вход' }) - Vuestic floating labels → select by input type, NOT placeholder
- Auth mock via
page.evaluate(() => localStorage.setItem(...)) - Do NOT call
expect()insidepage.evaluate() - Base URLs:
FRONTEND(5173),BACKEND(8000) freshPage()helper: goto → clear localStorage → goto again
Тесты в spec:
- Signup:
POST /api/v0/signup→ returns token, user, profile; navigate to/auth/signup→ fill form → submit → redirect to/explore - Login success: pre-seed user via API → UI login → token in localStorage → redirect to
/explore - Login failure: wrong password → error toast appears, stays on
/auth/login - Logout: logged in → open profile dropdown → «Выход» → redirect to login, token cleared
Acceptance Criteria:
- Spec file created at
../integration/tests/auth-flows.spec.ts - All tests self-contained (self-seed data)
- Follows existing
sidebar-auth-switch.spec.tspatterns npx playwright test tests/auth-flows.spec.tspasses against integration stack
TASK-MCP-SETUP: Playwright MCP configuration
Что сделано:
- MCP-конфиг Zoo Code (
mcp_settings.json): serverweb-browser→@playwright/mcp@latest, Node 22 via nvm absolute path,--headless - Chromium
1234уже установлен в~/.cache/ms-playwright/ .mcp.jsonсоздан в проекте (project-level, для совместимости)techContext.mdобновлён: секция "UI Verification (MCP Browser)"
Как использовать (workflow):
yarn dev— запустить dev server (порт 5173)browser_navigate→http://localhost:5173/explore— проверить публичную страницуbrowser_evaluate→() => { localStorage.setItem('token', 'test'); localStorage.setItem('user', JSON.stringify({id:1,name:'Test'})); location.reload(); }— сымитировать authbrowser_navigate→ проверить auth-страницы (/workouts,/workouts/:id)browser_snapshot— проверить DOM-структуруbrowser_take_screenshot— визуальная проверкаbrowser_network_requests— проверить API-запросы
Баг (контекст)
Сайдбар показывает publicRoutes (Лента + Маршрут) после логина до F5. Корень: NavigationRoutes.ts:70 — routes вычисляется один раз при module evaluation и кэшируется. TASK-AUTH-NAV-1 уже добавил реактивный isAuthenticated в useGlobalStore (инициализация из localStorage + setAuthenticated в Login/Logout). Эта задача переключает UI на computed.
TASK-AUTH-NAV-2: реактивные маршруты (3 файла)
1. src/components/sidebar/NavigationRoutes.ts
- Сделать named exports:
export const authRoutes: INavigationRoute[]иexport const publicRoutes: INavigationRoute[](сейчас это локальныеconst, не экспортированные). - Убрать статическое поле
routesиз default export (или оставить default безroutes, т.к. оба потребителя перейдут на computed).INavigationRouteинтерфейс — не трогать. - Важно: массивы
authRoutes/publicRoutesостаются теми же по структуре/содержимому — только экспортируются.
2. src/components/sidebar/AppSidebar.vue (Options API, setup())
import { useGlobalStore } from "../../stores/global-store";+import { authRoutes, publicRoutes } from "./NavigationRoutes";(импортnavigationRoutesпо default можно оставить/убрать — но все обращенияnavigationRoutes.routesзаменить).- В
setup():const globalStore = useGlobalStore(); - computed:
const routes = computed(() => globalStore.isAuthenticated ? authRoutes : publicRoutes); - В
returnзаменитьnavigationRoutesнаroutes(тепловой шаблон уже используетnavigationRoutes.routes→ поправить наroutes.value? НЕТ — в Options API computed из setup доступно в шаблоне какroutesбез.value, т.е. в шаблонеnavigationRoutes.routes→routes). setActiveExpand:navigationRoutes.routes.map(...)→routes.value.map(...)(в setup.valueнужен).- Шаблоны:
v-for="(route, index) in navigationRoutes.routes"→in routes.
3. src/components/app-layout-navigation/AppLayoutNavigation.vue (script setup)
import { authRoutes, publicRoutes } from "../sidebar/NavigationRoutes";+import { useGlobalStore } from "../../stores/global-store";const globalStore = useGlobalStore();findRouteName(строка ~64):traverse(NavigationRoutes.routes)→traverse(globalStore.isAuthenticated ? authRoutes : publicRoutes).- Убедиться, что
itemscomputed (зависит отroute.matchedиfindRouteName) остаётся реактивным — т.к.findRouteNameчитаетglobalStore.isAuthenticatedвнутриitemscomputed, реactivity сохранится.
Acceptance Criteria (TASK-AUTH-NAV-2)
yarn lint→ 0 ошибок.yarn build→ 0 ошибок (vue-tsc --noEmit).NavigationRoutes.ts:authRoutesиpublicRoutesэкспортируются; статическогоroutesс localStorage-тернарником больше нет.AppSidebar.vue: routes = computed отglobalStore.isAuthenticated;setActiveExpandиспользуетroutes.value.AppLayoutNavigation.vue:traverseиспользует выбор поglobalStore.isAuthenticated.- Ручной сценарий (ключевой): без F5 — выход из профиля →
/explore→ логин → сайдбар сразу показывает «Мои тренировки» (authRoutes). Аут → сайдбар сразуpublicRoutes.
✅ CODER SUCCESS REPORT — TASK-AUTH-NAV-2
src/components/sidebar/NavigationRoutes.ts:export const authRoutes/export const publicRoutes; удалён статическийroutes: localStorage.getItem("token") ? ...из default export (оставлен толькоroot).src/components/sidebar/AppSidebar.vue: импортauthRoutes, publicRoutes+useGlobalStore;computed(() => globalStore.isAuthenticated ? authRoutes : publicRoutes);setActiveExpandиспользуетroutes.value.map; шаблонv-for="(route, index) in routes".src/components/app-layout-navigation/AppLayoutNavigation.vue:const globalStore = useGlobalStore();traverse(globalStore.isAuthenticated ? authRoutes : publicRoutes)внутриfindRouteName(вызывается вitemscomputed → реactivity сохранена).- Verified:
yarn lintexit 0,yarn buildexit 0 (vue-tsc --noEmit 0 ошибок, vite ✓ 7.07s).
История (закрытые задачи)
- TASK-AUTH-NAV-1: success —
isAuthenticated+setAuthenticatedвuseGlobalStore; LoginsetAuthenticated(true), LogoutsetAuthenticated(false). Verified lint/build 0. - TASK-SSR-DETAIL: success — SSR /public/workouts/:id под DOM WorkoutItem.vue.
- TASK-404: success — HTTP 404 для неизвестных страниц.
- TASK-PUBLIC-ROUTE-FIX: success — workout_public_item в top-level router.
- TASK-F11/F12/F13/F14: success — SEO + фиксы карты тренировки.