mirror of
https://github.com/azaion/ui.git
synced 2026-06-21 21:11:10 +00:00
[AZ-463] [AZ-469] [AZ-476] [AZ-477] Batch 6 - flight/responsive/upload/settings tests
- AZ-463 flight selection persistence (FT-P-16) + rehydration
on boot (FT-P-17) PASS at the wire; 100-cycle leak guard
(NFT-RES-LIM-07) and 1h SSE soak (NFT-RES-LIM-06)
scaffolded as RUN_LONG_RUNNING-gated e2e companions.
- AZ-469 browser-support smoke (FT-P-34) runs in both
Chromium and Firefox via the existing playwright config;
responsive variants (FT-P-35 480px / FT-P-36 1024px) PASS
in fast (Tailwind class shape) and e2e (visibility).
- AZ-476 upload 501 MB -> 413: AC-1 user-visible error is
drift today (uploadFiles silently falls through to local
mode); it.fails() + control + e2e test.fail. AC-2 no-alert
PASS via dialog spy.
- AZ-477 settings save 500 / network drop: AC-1+AC-2+AC-3
all drift today (no try/finally, no error region, deadline
unmeasurable); 4 it.fails() + control pinning the stuck-
disabled drift; e2e companions test.fail mirror it.
- LESSONS.md seeded: vi.stubGlobal('URL', {...URL,...})
destroys the URL constructor and breaks new URL(...) in
MSW; patch the methods directly instead.
Code review: PASS (0 findings). Fast: 22/22 files, 120
passed / 13 skipped. Static: 24/24 PASS.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
// AZ-477 — e2e companion for Settings save resilience + 2 s deadline.
|
||||
//
|
||||
// AC-1 (FT-N-13 / NFT-RES-05): real backend returns 500 on settings PUT;
|
||||
// SPA renders an error region AND clears the
|
||||
// `saving` flag (button enabled again) within
|
||||
// 2 s. Today both contracts are drift —
|
||||
// `test.fail()` until try/finally + alert lands.
|
||||
// AC-2 (FT-N-14 / NFT-RES-06): same on a network drop. The fast-profile
|
||||
// test pins both contracts against MSW; this
|
||||
// companion exercises the real wire boundary
|
||||
// against the suite stack.
|
||||
// AC-3 (NFT-PERF-09): ≤ 2 s deadline for error visibility — pinned
|
||||
// in the fast suite via `performance.now()`;
|
||||
// the e2e companion just asserts visibility
|
||||
// within Playwright's 2 s timeout.
|
||||
//
|
||||
// Requires the suite docker-compose stack (`e2e/docker-compose.suite-e2e.yml`).
|
||||
// Uses `page.route` to inject the failure mode without depending on a real
|
||||
// crashed backend in CI.
|
||||
|
||||
test.describe('AZ-477 — Settings save resilience (e2e companion)', () => {
|
||||
test.fail(
|
||||
'AC-1 (500) — Save button re-enables AND error region visible within 2 s',
|
||||
async ({ page }) => {
|
||||
// Force the system-settings PUT to fail with a 500. Other endpoints
|
||||
// pass through so the page mounts normally.
|
||||
await page.route('**/api/annotations/settings/system', async (route) => {
|
||||
if (route.request().method() === 'PUT') {
|
||||
await route.fulfill({ status: 500, body: 'upstream failure' })
|
||||
return
|
||||
}
|
||||
await route.continue()
|
||||
})
|
||||
|
||||
await page.goto('/settings')
|
||||
|
||||
// Tenant Configuration heading + scoped Save button — same anchor as
|
||||
// the fast suite. If the suite seed has no tenant config, the test
|
||||
// reports the gap rather than masking the UI.
|
||||
const tenantHeading = page.getByRole('heading', { name: /Tenant Configuration/i })
|
||||
if (!(await tenantHeading.isVisible({ timeout: 5000 }).catch(() => false))) {
|
||||
test.skip(true, 'Suite UI did not render Settings → Tenant Configuration')
|
||||
}
|
||||
const tenantPanel = tenantHeading.locator('xpath=..')
|
||||
const saveBtn = tenantPanel.getByRole('button', { name: /^Save$/i })
|
||||
|
||||
await saveBtn.click()
|
||||
|
||||
// Both assertions race the 2 s deadline.
|
||||
await expect(saveBtn).toBeEnabled({ timeout: 2000 })
|
||||
const alertEl = page.getByRole('alert').first()
|
||||
await expect(alertEl).toBeVisible({ timeout: 2000 })
|
||||
await expect(alertEl).toContainText(/error|failed|try again|500/i)
|
||||
},
|
||||
)
|
||||
|
||||
test.fail(
|
||||
'AC-2 (network drop) — Save button re-enables AND error region visible within 2 s',
|
||||
async ({ page }) => {
|
||||
await page.route('**/api/annotations/settings/system', async (route) => {
|
||||
if (route.request().method() === 'PUT') {
|
||||
await route.abort('connectionfailed')
|
||||
return
|
||||
}
|
||||
await route.continue()
|
||||
})
|
||||
|
||||
await page.goto('/settings')
|
||||
|
||||
const tenantHeading = page.getByRole('heading', { name: /Tenant Configuration/i })
|
||||
if (!(await tenantHeading.isVisible({ timeout: 5000 }).catch(() => false))) {
|
||||
test.skip(true, 'Suite UI did not render Settings → Tenant Configuration')
|
||||
}
|
||||
const tenantPanel = tenantHeading.locator('xpath=..')
|
||||
const saveBtn = tenantPanel.getByRole('button', { name: /^Save$/i })
|
||||
|
||||
await saveBtn.click()
|
||||
|
||||
await expect(saveBtn).toBeEnabled({ timeout: 2000 })
|
||||
const alertEl = page.getByRole('alert').first()
|
||||
await expect(alertEl).toBeVisible({ timeout: 2000 })
|
||||
},
|
||||
)
|
||||
})
|
||||
Reference in New Issue
Block a user