food-market/tests/regression/visual/03-wizard-screenshots.spec.ts
nns f56c6efab1 feat(s17): onboarding wizard + help kb + feedback + diagnostic + whats-new
Sprint 17 — onboarding-контур: 4-шаг wizard, контекстный help, in-app
feedback, admin self-diagnostic, /whats-new из CHANGELOG.md.

Ключевые цифры:
- Wizard: 4 шага + skip каждого, 7 e2e тестов ✓ за 20 секунд.
- Diagnostic: 7 параллельных проверок, ~80ms на stage.
- Bundle impact: initial +4 KB gzip (только FeedbackWidget +
  HelpTooltip + EmptyStateWithDemo в основном bundle; страницы lazy).
- Regression-suite: 35 → 42 flows + 60 → 66 visual snapshots.

Backend (новые endpoint'ы):
- /api/admin/diagnostic/run — 7 параллельных проверок (DB, SMTP,
  MinIO, Hangfire, диск, сертификаты, бэкап). Task.WhenAll, ~80ms.
- /api/feedback — POST {category, message}, email на FromEmail +
  Telegram (если SupportTelegram:* настроены). Rate-limit 5/час.
- /api/whats-new — парсер CHANGELOG.md, возвращает {buildVersion,
  items}. Dockerfile.api копирует CHANGELOG.md в content-root +
  пишет VERSION из GIT_SHA build-arg.

Frontend:
- /onboarding-wizard — 4-step builder, состояние в useState,
  localStorage.fm.wizardCompleted после завершения.
- <HelpTooltip topic="key"/> — popover на каждой странице, mapping
  src/lib/help-topics.ts (13 keys).
- /help — knowledge base, 7 markdown topics через import.meta.glob,
  mini-renderer без heavy deps, fuzzy search.
- /whats-new — список из /api/whats-new, иконки по типу (feat/fix).
- /admin/diagnostic — Admin/SuperAdmin only, 🟢/🟡/🔴 индикаторы.
- <FeedbackWidget> в sidebar footer + ссылки на /help и /whats-new.
- <EmptyStateWithDemo> placeholder для будущих видео-демо.

scripts/generate-changelog.sh — git log feat:/fix: за 90 дней
→ CHANGELOG.md (307 строк сгенерировано).

Wizard UX-screenshots в docs/sprint17-screenshots/ (6 PNG: 4 шага +
help + diagnostic).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 17:04:26 +05:00

67 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Sprint 17: визуальные screenshots каждого шага wizard'а для отчёта.
*
* Шаги 1-4 captured как `wizard-step-N.png`. Используется один build()
* на весь файл — caпture'ы быстрые.
*/
import { expect, test } from '@playwright/test'
import { OrgFactory, type BuiltOrg } from '../factories/OrgFactory.js'
import { attachSession } from '../lib/ui.js'
let built: BuiltOrg
test.beforeAll(async () => {
built = await OrgFactory.for('wiz-shots').build()
})
test('wizard step 1 (магазин)', async ({ page }) => {
await attachSession(page, built.session, '/onboarding-wizard')
await page.waitForLoadState('networkidle')
await expect(page).toHaveScreenshot('wizard-step-1.png')
})
test('wizard step 2 (товар)', async ({ page }) => {
await attachSession(page, built.session, '/onboarding-wizard')
await page.waitForLoadState('networkidle')
await page.getByRole('button', { name: 'Пропустить', exact: true }).first().click()
await page.waitForLoadState('networkidle')
await expect(page).toHaveScreenshot('wizard-step-2.png')
})
test('wizard step 3 (сотрудник)', async ({ page }) => {
await attachSession(page, built.session, '/onboarding-wizard')
await page.waitForLoadState('networkidle')
await page.getByRole('button', { name: 'Пропустить', exact: true }).first().click()
await page.waitForLoadState('networkidle')
await page.getByRole('button', { name: 'Пропустить', exact: true }).first().click()
await page.waitForLoadState('networkidle')
await expect(page).toHaveScreenshot('wizard-step-3.png')
})
test('wizard step 4 (demo-данные)', async ({ page }) => {
await attachSession(page, built.session, '/onboarding-wizard')
await page.waitForLoadState('networkidle')
await page.getByRole('button', { name: 'Пропустить', exact: true }).first().click()
await page.waitForLoadState('networkidle')
await page.getByRole('button', { name: 'Пропустить', exact: true }).first().click()
await page.waitForLoadState('networkidle')
await page.getByRole('button', { name: /Сделать позже/i }).click()
await page.waitForLoadState('networkidle')
await expect(page).toHaveScreenshot('wizard-step-4.png')
})
test('help page', async ({ page }) => {
await attachSession(page, built.session, '/help')
await page.waitForLoadState('networkidle')
await expect(page).toHaveScreenshot('help-page.png')
})
test('admin diagnostic page', async ({ page }) => {
await attachSession(page, built.session, '/admin/diagnostic')
await page.waitForLoadState('networkidle')
// Запускаем check'и для screenshot'a с реальным результатом.
await page.getByRole('button', { name: /Запустить/i }).click()
await page.waitForTimeout(2000)
await expect(page).toHaveScreenshot('admin-diagnostic.png', { fullPage: true })
})