strava-frontend/.roo/memory-bank/activeContext.md

8.7 KiB
Raw Blame History

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/signup in beforeAll
  • 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() inside page.evaluate()
  • Base URLs: FRONTEND (5173), BACKEND (8000)
  • freshPage() helper: goto → clear localStorage → goto again

Тесты в spec:

  1. Signup: POST /api/v0/signup → returns token, user, profile; navigate to /auth/signup → fill form → submit → redirect to /explore
  2. Login success: pre-seed user via API → UI login → token in localStorage → redirect to /explore
  3. Login failure: wrong password → error toast appears, stays on /auth/login
  4. Logout: logged in → open profile dropdown → «Выход» → redirect to login, token cleared

Acceptance Criteria:

  1. Spec file created at ../integration/tests/auth-flows.spec.ts
  2. All tests self-contained (self-seed data)
  3. Follows existing sidebar-auth-switch.spec.ts patterns
  4. npx playwright test tests/auth-flows.spec.ts passes against integration stack

TASK-MCP-SETUP: Playwright MCP configuration

Что сделано:

  • MCP-конфиг Zoo Code (mcp_settings.json): server web-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):

  1. yarn dev — запустить dev server (порт 5173)
  2. browser_navigate → http://localhost:5173/explore — проверить публичную страницу
  3. browser_evaluate → () => { localStorage.setItem('token', 'test'); localStorage.setItem('user', JSON.stringify({id:1,name:'Test'})); location.reload(); } — сымитировать auth
  4. browser_navigate → проверить auth-страницы (/workouts, /workouts/:id)
  5. browser_snapshot — проверить DOM-структуру
  6. browser_take_screenshot — визуальная проверка
  7. 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).
  • Убедиться, что items computed (зависит от route.matched и findRouteName) остаётся реактивным — т.к. findRouteName читает globalStore.isAuthenticated внутри items computed, реactivity сохранится.

Acceptance Criteria (TASK-AUTH-NAV-2)

  1. yarn lint → 0 ошибок.
  2. yarn build → 0 ошибок (vue-tsc --noEmit).
  3. NavigationRoutes.ts: authRoutes и publicRoutes экспортируются; статического routes с localStorage-тернарником больше нет.
  4. AppSidebar.vue: routes = computed от globalStore.isAuthenticated; setActiveExpand использует routes.value.
  5. AppLayoutNavigation.vue: traverse использует выбор по globalStore.isAuthenticated.
  6. Ручной сценарий (ключевой): без 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 (вызывается в items computed → реactivity сохранена).
  • Verified: yarn lint exit 0, yarn build exit 0 (vue-tsc --noEmit 0 ошибок, vite ✓ 7.07s).

История (закрытые задачи)

  • TASK-AUTH-NAV-1: success — isAuthenticated + setAuthenticated в useGlobalStore; Login setAuthenticated(true), Logout setAuthenticated(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 + фиксы карты тренировки.