# Sprint 16 — E2E regression suite + visual regression + nightly verify Цель: построить «постоянный» regression-контур, чтобы регресс ловился сам — не «вспомнили посмотреть». 35 user-flow specs + 60 visual snapshot'ов + автоматический nightly + CI на каждый push в main. Старт: 2026-06-07 (после Sprint 15). Исполнитель: Claude Opus 4.7. ## Принципы - Каждый flow — независимый, использует фабрику для подготовки данных через API (не через UI-клики). - Visual baseline — fresh stage post-deploy. Diff threshold 0.2% + маски на динамический контент (timestamps в артикулах, KPI). - Полный прогон < 15 минут (Playwright workers + retry=1 на CI). - НЕ трогать: `global.json`, prod admin.food-market.kz, POS WPF. ## Чек-лист - [x] **1. Regression suite** — `tests/regression/flows/` — **35 ключевых flow-тестов** в 8 spec-файлах (auth, catalog, documents post/unpost, reports, multi-tenant isolation, i18n+permissions+2FA+audit, realtime+misc). Прогон параллелен (workers=2 локально, 4 на CI). Отчёт `reports/playwright-html/` + JSON `reports/results.json`. - [x] **2. Visual regression** — `tests/regression/visual/` — **60 snapshot'ов** (15 страниц × 2 темы × 2 viewport'a: desktop 1280×800 + mobile Pixel 5 375×667). Threshold 0.002 (0.2%) + маски на артикулы/KPI/delta'ы для устойчивости к timestamp-дрейфу. - [x] **3. Test data factories** — `tests/regression/factories/` — `OrgFactory.for(slug).withProducts(N).withCounterparties(M).withSupplies(K).build()` собирает org через API за O(N) HTTP-вызовов (signup → token → refs → products → counterparties → posted supplies). Используется в каждом flow-тесте вместо signup-form. - [x] **4. Forgejo workflow `.forgejo/workflows/regression.yml`** — on `workflow_run` после Docker API/Web, wait-for-ready → install pnpm + chromium → flows + visual → артефакты + Telegram на падение. Cache на pnpm-store + Playwright-browsers — повторный прогон ~3 мин. - [x] **5. Nightly cron** — `~/nightly-verify.sh` + cron `0 4 * * *`: health-check → если падает, redeploy-stage → smoke flows (`@smoke` tag) → в воскресенье ещё полный flows + visual. Лог `~/.fm-watchdog/nightly-YYYYMMDD.log`, ротация >14 дней. Telegram-уведомление если упало (читает токен из `~/.fm-watchdog/telegram-token`). - [x] **6. README badges** — добавлены 4 CI-status badge (CI, Docker API, Stage verify, Regression — берутся с Forgejo `actions/workflows/*.svg`) + coverage badge (`badges/coverage.svg`, генерируется `scripts/generate-badges.sh` из cobertura.xml, авто-коммит из CI step «Update coverage badge»). ## Замеры ### Regression suite stats | Файл | Tests | Время (workers=2) | |---|---|---| | `flows/01-factory-smoke.spec.ts` | 1 | 5s | | `flows/02-auth.spec.ts` | 4 (login/signup/refresh/wrong-pw) | 4s | | `flows/03-catalog.spec.ts` | 5 (CRUD product/counterparty/store/price-type) | 6s | | `flows/04-documents.spec.ts` | 8 (supply/enter/retail-sale/loss/transfer/demand/supplier-return post+unpost) | 12s | | `flows/05-reports.spec.ts` | 4 (sales/stock/profit/abc с проверкой чисел) | 6s | | `flows/06-multi-tenant.spec.ts` | 3 (list-isolation, get-by-id-isolation, sales-isolation) | 4s | | `flows/07-i18n-permissions.spec.ts` | 5 (locale switch, 2FA enroll, audit log, anon→401) | 5s | | `flows/08-realtime-misc.spec.ts` | 5 (dashboard render, search, /health/ready) | 6s | | **Total** | **35** | **~30 секунд** ✓ | | Visual project | Snapshot count | Время | |---|---|---| | `desktop-chromium` 1280×800 | 30 (15 страниц × 2 темы) | 2m 10s | | `mobile-chromium` 375×667 (Pixel 5) | 30 | 2m 5s | | **Total** | **60** | **~4 минуты** | **Общий прогон**: ~30 сек (flows) + ~4 мин (visual) = **< 5 минут** end-to-end — существенно ниже 15-минутного целевого порога. ### Coverage badge - `scripts/generate-badges.sh` берёт cobertura.xml, считает покрытие по Application + Domain (combined), генерирует SVG через shields.io (offline fallback inline). - Текущее значение: **80%** (от Sprint 15 baseline). - Цвет шкалы: <50% red, 50-69% yellow, 70-84% green, ≥85% brightgreen. - CI step «Update coverage badge» (`.forgejo/workflows/ci.yml`) на каждый push в main: 1. `dotnet test --collect:"XPlat Code Coverage"`, 2. `bash scripts/generate-badges.sh`, 3. diff → commit `chore(badges): update coverage [skip ci]` → push. ### Nightly cron - Скрипт `~/nightly-verify.sh` (217 строк bash). - Crontab: `0 4 * * * /home/nns/nightly-verify.sh`. - Последовательность: 1. `curl /health/ready` — если не Healthy → `~/deploy-stage.sh` → повторная проверка → если опять упала → Telegram + exit. 2. `pnpm install` (если node_modules нет) + `playwright test flows/ --grep @smoke`. 3. Если воскресенье — полный прогон `flows/ visual/`. 4. Telegram-уведомление при провале (`~/.fm-watchdog/telegram-{token,chat}`). - Логи: `~/.fm-watchdog/nightly-YYYYMMDD.log`, `find -mtime +14 -delete` чистит каждый запуск. ## Журнал ### 2026-06-07 старт Sprint 15 закрыт (7/7 ✓). Поехали по regression-чек-листу. ### 2026-06-07 п.3 (factory) — фундамент `tests/regression/factories/OrgFactory.ts` + `api-client.ts` + `types.ts`. Builder-pattern: `OrgFactory.for(slug).withProducts(N)…build()`. Реквест-клиент на `fetch` (Node 20+), retry на 429 со сдвинутым backoff (под Sprint 13 IP-лимит signup'a). ### 2026-06-07 п.1 (35 flows) 8 spec-файлов с тегами `@smoke` на ключевых flows для быстрого прогона. API-driven где возможно (быстрее UI-кликов), Playwright UI только там где нужно (form-login, dashboard render, локаль switch). Несколько мелких фиксов по ходу: - Profit/ABC report возвращают непосредственно List, не PagedResult — `rowsOf` helper. - Multi-tenant isolation проверять по `id`, не `name` (одинаковые product-names в разных org'ах — норма). - Login редиректит на «/» (OnboardingPage) на свежей org, не /dashboard. - Loss-endpoint enum'у reason требует int, не строку. ### 2026-06-07 п.2 (visual 60) 2 spec'a (auth-pages + authenticated-pages). Baseline на свежий deploy. Маски на динамический контент: - `table td:nth-child(2)` (артикул с Date.now()), - `[data-kpi]` (зависит от текущей даты), - `[data-delta]` (стрелка от prev period). snapshotPathTemplate включает `{projectName}` чтобы desktop+mobile snapshot'ы не затирали друг друга. ### 2026-06-07 п.4 (forgejo workflow) `.forgejo/workflows/regression.yml` — `on workflow_run` после Docker API/Web. Cache на pnpm-store + Playwright-browsers. Артефакты upload при failure, Telegram-уведомление в обоих случаях. ### 2026-06-07 п.5 (nightly cron) `~/nightly-verify.sh` + crontab entry. Health → redeploy → smoke → weekly full + Telegram. Логи с ротацией. ### 2026-06-07 п.6 (badges) `scripts/generate-badges.sh` — coverage из cobertura.xml → SVG через shields.io с offline-fallback. 4 CI-status badge + coverage badge добавлены в README. CI-step авто-обновляет coverage badge на push в main. ## Итог Все 6 пунктов ✓. Локальные числа: - **35 flow-тестов**: 35/35 ✓ при workers=2 (~30 сек). - **60 visual snapshot'ов**: 60/60 ✓ при CI=1 (retries=1) (~4 мин). - **Полный прогон**: ~5 минут — **3× ниже** 15-минутного целевого порога. Контур регрессии работает: - На каждый push в main: Forgejo `Docker API`/`Docker Web` → `regression.yml` → 35 flows + 60 visual + Telegram. - Каждую ночь: nightly cron → health → smoke (или полный в воскресенье) + Telegram при провале. - Coverage и CI-status badges в README обновляются автоматически. Следующее расширение (не в этом sprint'е): - Перенести visual baseline'ы в LFS если они станут большими (сейчас 60 PNG ~10 МБ, в репе ок). - Добавить performance regression (k6 в CI nightly), сейчас k6 запускается только вручную. - Заглушить flake в `product-new light` через определённый wait или более широкую маску.