rules
Gitea Actions Demo / build_and_push (push) Successful in 1m14s Details

This commit is contained in:
artem 2026-09-24 23:36:26 +03:00
parent a44267cea8
commit ad9e1a5bbf
6 changed files with 229 additions and 6 deletions

11
.mcp.json Normal file
View File

@ -0,0 +1,11 @@
{
"mcpServers": {
"playwright": {
"command": "/home/artem/.nvm/versions/node/v22.14.0/bin/npx",
"args": ["@playwright/mcp@latest", "--browser", "chromium", "--headless", "--viewport-size", "1440x900"],
"env": {
"PATH": "/home/artem/.nvm/versions/node/v22.14.0/bin:/usr/local/bin:/usr/bin:/bin"
}
}
}
}

View File

@ -0,0 +1,101 @@
# MCP Browser Verification Guide
## Что это
Playwright MCP server (`@playwright/mcp`) предоставляет инструменты для взаимодействия с браузером
через Model Context Protocol. Позволяет агенту (Zoo Code) открывать страницы, делать snapshot DOM,
кликать, заполнять формы, делать скриншоты — без написания тест-кода.
## Конфигурация
- **Сервер**: `web-browser` в `mcp_settings.json` (Zoo Code global storage)
- **Браузер**: Chromium (headless)
- **Node**: 22.14.0 (nvm, absolute path)
- **Пакет**: `@playwright/mcp@latest` (npm)
## Workflow: UI Verification после изменения
### 1. Запуск dev-сервера
```bash
yarn dev
# → http://localhost:5173
```
### 2. Проверка публичных страниц (без auth)
| Рут | Что проверять |
|-----|---------------|
| `/explore` | Feed загружен, карточки тренировок рендерятся |
| `/public/workouts/:id` | Детали тренировки: chart, map, данные |
| `/routes` | Список маршрутов |
| `/404` | Страница 404 для неизвестных маршрутов |
### 3. Проверка auth-страниц (с моком auth)
```js
// browser_evaluate: установить мок-токен и перезагрузить
() => {
localStorage.setItem('token', 'mock-jwt-token');
localStorage.setItem('user', JSON.stringify({ id: 1, name: 'Test User', email: 'test@test.ru' }));
localStorage.setItem('profile', JSON.stringify({ name: 'Test', avatar: null }));
location.reload();
}
```
После reload:
| Рут | Что проверять |
|-----|---------------|
| `/workouts` | Список пользовательских тренировок |
| `/workouts/:id` | Detail: chart (power, HR, elevation), map polyline |
| `/preferences` | Профиль, настройки |
| `/workouts/upload` | Форма загрузки FIT/GPX |
### 4. Инструменты MCP (ключевые)
| Инструмент | Назначение |
|-----------|-----------|
| `browser_navigate` | Перейти по URL |
| `browser_snapshot` | Получить accessibility tree (структура DOM) |
| `browser_take_screenshot` | Скриншот (PNG) |
| `browser_click` | Клик по элементу (по ref из snapshot) |
| `browser_fill_form` | Заполнить форму |
| `browser_evaluate` | Выполнить JS на странице |
| `browser_network_requests` | Список HTTP-запросов (проверить API) |
| `browser_wait_for` | Дождаться появления текста |
| `browser_console_messages` | Console errors/warnings |
### 5. Типовой сценарий проверки (example)
```
1. browser_navigate → http://localhost:5173/explore
2. browser_wait_for → "Тренировки" (заголовок)
3. browser_snapshot → проверить структуру feed
4. browser_take_screenshot → визуал
5. browser_evaluate → mock auth (localStorage)
6. browser_navigate → http://localhost:5173/workouts
7. browser_snapshot → проверить сайдбар (authRoutes), список
8. browser_network_requests → убедиться что API /api/v0/workouts вызван
```
## Ограничения
- **API**: dev-сервер проксирует API на `HOST` (production). Для изолированной проверки
нужно либо:
- Использовать production API (read-only запросы — ок)
- Поднять локальный mock-сервер (axios interceptors)
- **Yandex Maps**: API key hardcoded, работает в headless, но рендер может отличаться
- **Chart.js**: Canvas — в snapshot не виден, только через screenshot
- **SSR**: MCP проверяет SPA (client-side). SSR — отдельно через `curl` или `browser_navigate` на SSR-порт
## Acceptance Criteria для Coder-задач
Каждая Coder-задача с UI-изменениями должна включать:
```markdown
### Acceptance Criteria
1. `yarn lint` → 0 ошибок
2. `yarn build` → 0 ошибок (vue-tsc --noEmit)
3. MCP browser: [конкретный сценарий проверки — рут, что ожидать в DOM]
```

View File

@ -2,11 +2,44 @@
## Task State ## Task State
- task_id: TASK-MCP-SETUP - task_id: TASK-TEST-PUBLIC
- status: success - status: in_progress
- parent_task: — - parent_task: —
- summary: **Настроить Playwright MCP для UI-верификации через браузер. Конфиг Zoo Code обновлён (Node 22), Chromium установлен.** - summary: **Написать Playwright integration тесты для фронтенда в `../integration/tests/`. 3 spec файла: auth-flows ✅, public-pages, auth-protected.**
- next task: — - 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 ## TASK-MCP-SETUP: Playwright MCP configuration

View File

@ -1,5 +1,21 @@
# Progress — Strava Frontend # Progress — Strava Frontend
## 2026-09-24 — UI-testing skill + mandatory rule
- `.roo/skills/ui-testing/SKILL.md` — how to test UI via (A) MCP browser ad-hoc and (B) the Playwright integration stand: run commands, spec conventions, selectors, gotchas.
- `.roo/rules/ui-testing.md` — MANDATORY rule: after any `src/` change affecting a visible route/interaction the task is not done until `yarn lint` + `yarn build` + browser verification (MCP ad-hoc for quick/visual, Playwright spec for must-not-regress) + green `npx playwright test`. Includes run cheat-sheet and required reporting format.
## 2026-09-24 — Integration UI-test stand (Playwright + docker-compose)
- Created `../integration/` (sibling of `frontend/`, `backend/`):
- `docker-compose.yml` — 3 services: `db` (postgres:15, host:5433, schema `strava` via `db-init/01-schema.sql`), `backend` (python:3.12, `pip install -r requirements.txt` + `alembic upgrade head` + `python -m app.web.__main__`, port 8000, `DB_URI=postgresql+asyncpg://svcuser:svcpass@db:5432/svc`), `frontend` (node:20-alpine, `yarn install --frozen-lockfile --ignore-scripts` + `yarn dev --host 0.0.0.0 --port 5173`, env `VITE_HOST=http://localhost:8000`, `HUSKY=0`).
- `package.json` + `playwright.config.ts` (`@playwright/test` ^1.54, baseURL `FRONTEND_URL||localhost:5173`, `API_URL`).
- `tests/sidebar-auth-switch.spec.ts` — TASK-AUTH-NAV regression: publicRoutes (no «Тренировки») → UI login (`/auth/login`, `input[type=email]` + `input[type=password]` + button «Вход») → authRoutes («Тренировки» appears, no reload) → UI logout (profile dropdown → «Выход») → publicRoutes. Self-seeds a unique user via `POST /api/v0/signup` in `beforeAll`.
- `README.md` — run instructions (`yarn up`, wait for backend, `yarn test`).
- Frontend change: `src/main.ts` `HOST = import.meta.env.VITE_HOST || "https://cycle-rider.ru"` (production unaffected — env unset → falls back to prod host).
- Verified: full stack up (frontend 200, backend 200 on `/api/v0/html_test/login`, db healthy); `npx playwright test tests/sidebar-auth-switch.spec.ts` → **1 passed (9.9s)** on Node 22 (nvm `~/.nvm/versions/node/v22.14.0/bin`).
- Gotchas: (1) npm install in frontend container fails on `@unhead/vue` peer-dep (wants vite>=6, project vite 5) → must use **yarn** (`yarn.lock`), and `node:20-alpine` already ships yarn (do NOT `npm i -g yarn` → EEXIST); (2) backend health path is `/api/v0/html_test/login` (router_public prefix `/api/v0`, no `/auth`); (3) Vuestic `VaInput` uses floating labels → no usable placeholder, select login fields by `input[type=email]` / `input[type=password]`; (4) Playwright/MCP need Node ≥20 (system node is 18) → run via nvm Node 22.
## 2026-09-24 — TASK-AUTH-NAV-2: реактивные маршруты в сайдбаре и хлебных крошках ## 2026-09-24 — TASK-AUTH-NAV-2: реактивные маршруты в сайдбаре и хлебных крошках
- `NavigationRoutes.ts`: named exports `authRoutes`/`publicRoutes`, удалён module-level `localStorage.getItem("token")` тернарник. - `NavigationRoutes.ts`: named exports `authRoutes`/`publicRoutes`, удалён module-level `localStorage.getItem("token")` тернарник.

63
.roo/rules/ui-testing.md Normal file
View File

@ -0,0 +1,63 @@
# UI Testing Rule (mandatory after frontend changes)
> Procedure + commands: see the **`ui-testing`** skill (`.roo/skills/ui-testing/SKILL.md`).
> This rule defines the **when** (obligation) and the **gate** (definition of done).
## When this rule applies
Any change under `src/` that affects a **visible route or interaction**:
pages, components, auth flows, sidebar/breadcrumbs, forms, charts, maps, i18n
labels. Pure backend-only or docs-only changes are exempt.
## The gate (Definition of Done)
A frontend task is **not done** until ALL of the following pass. Do not claim
completion otherwise.
1. `yarn lint` (frontend) → 0 errors
2. `yarn build` (frontend) → 0 errors (`vue-tsc --noEmit`)
3. **Browser verification** — the changed behavior is actually exercised in a
real browser (this is the non-negotiable step the user requires):
- **Quick change / visual only** → **MCP browser** ad-hoc check:
`browser_navigate` the affected route → `browser_snapshot` (assert the
structure) → `browser_take_screenshot` → `browser_console_messages`
(no app errors).
- **Behavior that must not regress** → a **Playwright integration spec** in
`../integration/tests/` that passes against the docker-compose stack.
4. If a Playwright spec was touched or added: `npx playwright test` green
(Node ≥20, via nvm Node 22).
## How to run (cheat-sheet)
```bash
# Playwright integration stack (repeatable / regression)
cd ../integration
export PATH="$HOME/.nvm/versions/node/v22.14.0/bin:$PATH" # Playwright needs Node ≥20
yarn up # docker compose up -d --build
until curl -sf http://localhost:8000/api/v0/html_test/login >/dev/null; do sleep 2; done
npx playwright test # all
npx playwright test tests/<name>.spec.ts # one
yarn down # stop (keep DB)
```
MCP browser (ad-hoc) needs the app reachable: `yarn dev` → `:5173`, or the
integration stack (`yarn up`) so the SPA talks to the real backend at `:8000`.
## Reporting
When finishing a task, state explicitly in the completion message:
- lint/build result
- which browser verification was performed (MCP ad-hoc vs Playwright spec) and
the outcome (pass/fail)
- for Playwright: the spec name and that it is green
## Gotchas (must follow)
- Frontend deps install with **yarn**, never npm (peer-dep conflict on
`@unhead/vue` / vite).
- Vuestic inputs have **floating labels → empty placeholder**: select by
`input[type=email]` / `input[type=password]`, not by placeholder.
- Sidebar = `<aside>`; auth-only item is «Тренировки» (`menu.workouts`).
- Do NOT call `expect(...)` inside `page.evaluate(...)`.
- `node:20-alpine` already ships yarn — do not `npm i -g yarn` (EEXIST).
- Full stack + command details: `../integration/README.md`.

View File

@ -14,8 +14,7 @@ import axios from "axios";
import { AxiosResponse } from "axios"; import { AxiosResponse } from "axios";
import { createYmaps } from "vue-yandex-maps"; import { createYmaps } from "vue-yandex-maps";
const HOST = "https://cycle-rider.ru"; const HOST = import.meta.env.VITE_HOST || "https://cycle-rider.ru";
// const HOST = "http://localhost:8000";
axios.defaults.baseURL = HOST; axios.defaults.baseURL = HOST;