mirror of
https://github.com/azaion/ui.git
synced 2026-06-21 16:31:11 +00:00
2051088706
Implements 4 blackbox-test tasks for AZ-455 Phase A baseline:
- AZ-458 SSE lifecycle + bearer rotation: 9 fast tests (8 pass, 1
QUARANTINE for annotation-status); 4 e2e scenarios (gated by suite
stack). Uses tests/helpers/sse-mock.ts with globalThis.EventSource
monkey-patch per AC-3 (no stub of src/api/sse.ts). AC-2 bearer
rotation captured as documented drift via it.fails() — FlightsPage
useEffect deps do not include the token today.
- AZ-467 ProtectedRoute spinner + timeout + RBAC: 9 new fast tests
extending the AZ-457 file (6 pass, 3 QUARANTINE), plus 3 e2e
scenarios. FT-P-32 spinner a11y is it.fails() drift; FT-P-33 timeout
and FT-N-03/05 RBAC redirects are it.skip QUARANTINE (no production
behavior today). Positive control: admin_carol reaches /admin.
- AZ-468 Header flight-dropdown a11y: 6 fast tests (5 pass, 1
QUARANTINE). FT-P-30/31 are it.fails() drift (aria-expanded /
role=listbox / aria-activedescendant currently missing); FT-N-09
is it.skip QUARANTINE (no document keydown handler exists).
- AZ-482 Secrets + banned-libs + AC-N1 anti-criterion: 3 new static
checks (STC-SEC13 legacy integrations, STC-SEC14 concurrent-edit,
STC-SEC1B dist/ OWM key) plus refactor of 4 existing checks
(STC-N2/N4/S13/S6) to read from tests/security/banned-deps.json
via scripts/check-banned-deps.mjs per AZ-482 constraint
("deny-list lives in tests/security/banned-deps.json so additions
are visible in code review"). All 22 static checks PASS.
Totals: 57 fast tests pass + 9 skipped; 22/22 static checks pass.
Self-review verdict PASS_WITH_WARNINGS — all five findings are
documented drifts captured by it.fails() / it.skip QUARANTINE +
control tests. See _docs/03_implementation/batch_03_report.md
for the per-task / per-AC matrix and recommended Phase B follow-up
production tasks (Header a11y; ProtectedRoute spinner/timeout/RBAC;
SSE bearer-rotation reconnect; AnnotationsPage SSE).
Co-authored-by: Cursor <cursoragent@cursor.com>
63 lines
2.5 KiB
TypeScript
63 lines
2.5 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
|
|
// AZ-467 — e2e variants of the RBAC scenarios that require the real
|
|
// admin/ service to issue role-specific bearers and the suite's nginx to
|
|
// route /admin and /settings.
|
|
//
|
|
// FT-N-03 — Operator → /admin redirects to /flights (or to /login if
|
|
// permission middleware is unauthenticated-equivalent)
|
|
// FT-N-05 — integrator-dave → /settings redirects (no SETTINGS perm)
|
|
//
|
|
// Profile: e2e (gated by docker compose). Skipped in fast/host runs.
|
|
//
|
|
// Production status: src/auth/ProtectedRoute.tsx does NOT check
|
|
// permissions today (only `user != null`). These tests are wrapped in
|
|
// `test.fail()` to capture the drift — they will start passing once
|
|
// ProtectedRoute gains a `requirePermission` prop (or wrapping) and the
|
|
// /admin and /settings routes opt in.
|
|
|
|
const OPERATOR_EMAIL = 'op_bob@test.local' // Operator without ADMIN_WRITE / SETTINGS
|
|
const INTEGRATOR_EMAIL = 'integrator_dave@test.local' // SystemIntegrator without SETTINGS
|
|
const ADMIN_EMAIL = 'admin_carol@test.local' // Admin with full perms
|
|
const TEST_PASSWORD = 'TestPassword!23'
|
|
|
|
async function login(page: import('@playwright/test').Page, email: string) {
|
|
await page.goto('/login')
|
|
await page.getByLabel(/email/i).fill(email)
|
|
await page.getByLabel(/password/i).fill(TEST_PASSWORD)
|
|
await Promise.all([
|
|
page.waitForResponse(
|
|
(r) => r.url().includes('/api/admin/auth/login') && r.request().method() === 'POST',
|
|
),
|
|
page.getByRole('button', { name: /sign in/i }).click(),
|
|
])
|
|
}
|
|
|
|
test.describe('AZ-467 e2e — RBAC route gating', () => {
|
|
test('FT-N-03 — Operator hitting /admin is redirected to /flights (AC-3 drift)', async ({ page }) => {
|
|
test.fail(
|
|
true,
|
|
'AC-3 drift: src/auth/ProtectedRoute.tsx today checks only `user != null`. Test passes once route-level RBAC lands.',
|
|
)
|
|
await login(page, OPERATOR_EMAIL)
|
|
await page.goto('/admin')
|
|
await expect(page).toHaveURL(/\/flights$/)
|
|
})
|
|
|
|
test('FT-N-05 — integrator-dave hitting /settings is redirected away (AC-3 drift)', async ({ page }) => {
|
|
test.fail(
|
|
true,
|
|
'AC-3 drift: same as FT-N-03 — ProtectedRoute does not gate on permissions today.',
|
|
)
|
|
await login(page, INTEGRATOR_EMAIL)
|
|
await page.goto('/settings')
|
|
await expect(page).not.toHaveURL(/\/settings$/)
|
|
})
|
|
|
|
test('Admin reaches /admin normally (positive control)', async ({ page }) => {
|
|
await login(page, ADMIN_EMAIL)
|
|
await page.goto('/admin')
|
|
await expect(page).toHaveURL(/\/admin$/)
|
|
})
|
|
})
|