Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Hourly smoke watchdog + auto-fix loop + dashboard + multi-tenant guard + perf regression + cleanup job + README badge. 1. ~/quality-watchdog.sh (cron 5 * * * *) — 8 checks (~60s): /health/ready, signup→login→/api/me, GET products, Playwright UI smoke (3.1 product CRUD), /metrics format, /hubs/notifications negotiate with token, multi-tenant isolation, perf p95. 2. Auto-fix loop: 2× consecutive red → ~/.fm-watchdog/incident-*.txt + queue/0000-incident-* to bump it ahead of Server-Claude's sprint queue. fm-watchdog.sh sees prefix 0000- as next. 3. scripts/quality-dashboard.py — renders docs/quality-status.md (current emoji, 8-step table, perf baseline, 7-day history, 24-run sparkline) + injects README badge 🟢/🟡/🔴. 4. Multi-tenant smoke: signup 2 orgs `quality-{epoch}-A/B`, create product in A, verify B sees 404/403 + total=0. 5. Perf regression: p95 over 10 reqs for /api/me, products, sales/retail/stats. Baseline = median of last 10 samples (robust to noise). >50% from baseline → alert. First 5 runs always green (warm-up). 6. HousekeepingJobs.PruneQualityTestOrgsAsync (cron 30 2 * * * UTC): finds orgs `quality-%` older than 24h, dynamically scans information_schema for tables with OrganizationId, iteratively DELETEs with FK-violation retry (up to 10 passes), then cleans AspNetUser*/OpenIddict* by email pattern `quality-%@test-fm.local`, finally users + organizations. 7. README badge: <!-- quality-badge --> marker updated each run. Validated: stage deploy ✓, Hangfire job registered ✓, dry-run SQL on 24 stage candidates → 0 remaining ✓, 3 cron-triggered runs all 8/8 green (12:42/12:45/12:48 +05) ✓. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
45 lines
1.9 KiB
TypeScript
45 lines
1.9 KiB
TypeScript
/**
|
|
* Sprint 7 item 6 — визуальная проверка breadcrumbs на edit-странице.
|
|
* Логинимся, seed-demo, открываем первый товар, скриншот шапки.
|
|
*/
|
|
import { chromium } from 'playwright'
|
|
import { makeClient, login } from '../lib/api.js'
|
|
|
|
const BASE = process.env.E2E_ADMIN_URL ?? 'https://test.admin.food-market.kz'
|
|
const TS = Date.now()
|
|
const EMAIL = `crumb-shot-${TS}@food-market.local`
|
|
const PASS = 'CrumbShot12345!'
|
|
|
|
async function ensureSession() {
|
|
const api = makeClient()
|
|
const r = await api.post('/api/auth/signup', {
|
|
email: EMAIL, password: PASS,
|
|
organizationName: `CrumbShot ${TS}`, phone: '+77011190001', plan: 'start',
|
|
})
|
|
if (r.status !== 200) throw new Error(`signup ${r.status}: ${JSON.stringify(r.data)}`)
|
|
const sess = await login(EMAIL, PASS)
|
|
await makeClient(sess.accessToken).post('/api/admin/seed-demo', {})
|
|
return sess
|
|
}
|
|
|
|
async function main() {
|
|
const sess = await ensureSession()
|
|
const browser = await chromium.launch({ headless: true })
|
|
const ctx = await browser.newContext({ ignoreHTTPSErrors: true, viewport: { width: 1280, height: 800 } })
|
|
const page = await ctx.newPage()
|
|
await page.goto(`${BASE}/`)
|
|
await page.evaluate(({ token }) => localStorage.setItem('fm.access_token', token), { token: sess.accessToken })
|
|
|
|
await page.goto(`${BASE}/catalog/products`, { waitUntil: 'domcontentloaded' })
|
|
await page.waitForLoadState('networkidle')
|
|
await page.locator('tbody tr').first().waitFor({ timeout: 12000 })
|
|
await page.locator('tbody tr').first().click()
|
|
await page.waitForLoadState('networkidle')
|
|
await page.waitForSelector('nav[aria-label="Хлебные крошки"]', { timeout: 8000 })
|
|
await page.screenshot({ path: `reports/breadcrumbs-product-${TS}.png`, fullPage: false })
|
|
console.log(`[shot] saved → reports/breadcrumbs-product-${TS}.png`)
|
|
await browser.close()
|
|
}
|
|
|
|
main().catch(err => { console.error(err); process.exit(1) })
|