RFQ Compare scenario evidence
Overview / Cross-role + Infrastructure

Cross-role + Infrastructure 12 scenarios

Cross-role flows exercise the full order lifecycle across personas plus auth/session, input-validation, notifications and locale; infra checks validate the staging environment itself (health, RBAC isolation, API error-paths, Stripe/Service-Worker CSP, seed data).

Cross-role lifecycle

X1

Full procurement lifecycle across every role

e2e/tests/staging-validation/cross-x1-full-lifecycle.spec.js
Cross-role
  1. Admin seeds a project (requesters can't always create projects).
  2. Requester opens the order-creation form in that project and submits an order.
  3. Office opens the order, approves it and sends it downstream to logistic.
  4. Logistic opens their queue and views the order.
  5. Role is swapped between steps via per-role storageState in a serial block.
admin creates project for the lifecycle · L33 requester opens order-creation form and submits · L57 office user approves and sends downstream · L80 logistic user views the order in their queue · L118
X2

Session expiry & invalid-token graceful handling

e2e/tests/staging-validation/cross-x2-auth-session.spec.js
Cross-role
  1. Load /projects with a valid admin session and confirm no redirect to /login.
  2. Wipe all cookies and local/session storage mid-session to simulate token expiry.
  3. Navigate to a protected route and confirm a redirect to /login or a visible login form.
  4. Open a fresh context with a deliberately bogus auth cookie.
  5. Confirm the SPA resolves (redirect or login form) in under 25 seconds — no infinite spinner.
X2.1 — authenticated session loads /projects · L18 X2.2 — wiping auth mid-session forces redirect to /login (no infinite spinner) · L24 X2.3 — invalid token cookie does not hang the SPA · L56
X3

Edge-case input validation on create forms

e2e/tests/staging-validation/cross-x3-edge-input-validation.spec.js
Cross-role
  1. Submit the create-project form empty and confirm it stays on the form or shows an inline error.
  2. Submit a 5000-character project name and confirm no JS page error and a non-blank page.
  3. Open an existing project's create-order page and enter a negative quantity.
  4. Confirm the negative quantity is rejected (error, stays on form, or field reset).
X3.1 — submitting empty create-project form does not crash · L22 X3.2 — extremely long project name handled gracefully · L45 X3.3 — negative / non-numeric quantity rejected on order item input · L72
X4

Cross-role notification delivery

e2e/tests/staging-validation/cross-x4-notifications.spec.js
Cross-role
  1. Admin seeds a project for the notification flow.
  2. Requester creates an order in that project and submits it for approval.
  3. Office opens the order and approves it to trigger the requester notification.
  4. Requester opens /notifications and confirms the feed page renders with content.
admin creates project · L26 requester creates and submits the order · L44 office approves to trigger requester notification · L82 notification appears in requester feed · L112
X5

Staging API contract (headless request tests)

e2e/tests/staging-validation/cross-x5-api-contract.spec.js
Cross-role
  1. Run unauthenticated request-fixture calls against the staging baseURL.
  2. GET /api/v1/users/me and /api/v1/projects without auth — expect 401/403 in under 2s.
  3. GET an unknown endpoint — expect 404.
  4. POST /api/v1/users/login with bad credentials — expect 400/401/403.
  5. GET /health — expect 200 with a non-empty body.
X5.1 — GET /api/v1/users/me without auth returns 401 in <2s (Spec 010 regression) · L22 X5.2 — GET /api/v1/nonexistent returns 404 · L35 X5.3 — POST /api/v1/users/login with bad credentials returns 401 · L40 X5.4 — GET /health returns 200 · L52 X5.5 — /health body is non-empty (liveness signal) · L57 X5.6 — GET /api/v1/projects without auth returns 401 fast (<2s) · L64
X6

Locale switching & persistence

e2e/tests/staging-validation/cross-x6-locale-switch.spec.js
Cross-role
  1. Confirm the /locales page is reachable for admin.
  2. Open /my-account, capture the baseline body text and find a language selector.
  3. Switch to a non-English language, save, navigate to /projects and confirm the body text changed.
  4. Reload /my-account and confirm the page still renders (no auth bounce, no reset to default).
X6.1 — locales page is reachable for admin · L18 X6.2 — switch language from my-account/settings and observe UI change · L26 X6.3 — locale choice persists across reload · L93

Staging infrastructure checks

X7

Data isolation by role (RBAC)

e2e/tests/staging-validation/staging-x7-data-isolation-by-role.spec.js
Infra
  1. Log in as a non-admin requester via stored storageState.
  2. Attempt each admin-only route: /roles, /members, /settings, /company-info.
  3. For each route, confirm at least one guard trips: 401/403, a redirect away, or an access-denied message.
  4. A full admin UI rendering for a non-admin would be flagged as privilege escalation.
requester is denied / redirected on ${route} (/roles, /members, /settings, /company-info) · L21
X8

/health marker fields & latency

e2e/tests/staging-validation/staging-x8-health-marker.spec.js
Infra
  1. GET /health and confirm a 200 response.
  2. Confirm the JSON marker fields: status=ok, dbEngine=postgres, publicClientFolder=publicAppUsers.
  3. Confirm /health responds in under 2 seconds.
returns 200 + JSON marker fields · L7 responds in <2s · L17
X9

Spec 010 regression — /api/* error path does not hang

e2e/tests/staging-validation/staging-x9-spec010-regression.spec.js
Infra
  1. GET /api/v1/users/me with no auth — expect 401 in under 2s with status=fail and a log-in message.
  2. GET /api/v1/nonexistent — expect 404 in under 2s with a can't-find/not-found message.
  3. POST /api/v1/users/login with bad credentials — expect 400/401 in under 2s.
GET /api/v1/users/me (no auth) -> 401 in <2s · L9 GET /api/v1/nonexistent -> 404 in <2s · L20 POST /api/v1/users/login (bad creds) -> 401 in <2s · L31
X10

Staging seed data present

e2e/tests/staging-validation/staging-x10-seed-data-present.spec.js
Infra
  1. Confirm admin storageState still logs in and lands off /login.
  2. GET /api/v1/projects and confirm the seeded staging projects (name matching "Staging") are present.
  3. POST /api/v1/users/login as the logistic@staging.example.test user (added 2026-05-26) and expect a 200 with a token.
admin login succeeds + lands on dashboard · L15 projects list contains 2 seeded staging projects · L23 logistic user (added 2026-05-26) can log in via API · L39
X11

Spec F2 — Stripe CSP regression

e2e/tests/staging-validation/staging-x11-stripe-csp.spec.js
Infra
  1. GET /company-info and read the Content-Security-Policy header.
  2. Confirm frame-src, connect-src and script-src name the required Stripe origins (js/hooks/m.stripe, api.stripe).
  3. Load /company-info and confirm no Stripe Framing CSP violation in the console.
  4. Confirm at least one js.stripe.com script tag loads.
CSP header includes all required Stripe origins · L19 /company-info loads without Framing CSP violation in console · L40 Stripe.js script loads (script-src allows it) · L72
X12

Spec F1 — Service Worker CSP regression

e2e/tests/staging-validation/staging-x12-sw-csp.spec.js
Infra
  1. GET / and confirm connect-src includes storage.googleapis.com (for workbox sub-module imports).
  2. Confirm an explicit worker-src directive allowing 'self' is present.
  3. GET /custom-service-worker.js and confirm a 200 with a JavaScript MIME type.
  4. Force a fresh SW registration in the page and confirm no "script evaluation failed" error.
CSP connect-src includes storage.googleapis.com (workbox sub-module imports) · L20 CSP includes an explicit worker-src directive · L30 /custom-service-worker.js is served with correct MIME type · L37 forced SW registration completes without 'script evaluation failed' · L44

Screenshot evidence

Captured against staging 2026-05-26. Click any shot to enlarge. Filenames preserved as captions.

No dedicated screenshots — cross-role flows reuse the per-persona captures; see the persona pages.