Files
atomic-design-poc/e2e/error-state.spec.ts
T
ehoandClaude Opus 4.8 62cb34b60f feat(privacy): WP-40 — PII kernel (Bsn value object + masked-value atom)
Branded Bsn value object with the elfproef (11-test) checksum in shared/kernel/bsn.ts,
wired into the DigiD login boundary so login does real BSN validation (hint + e2e BSNs
updated to a valid 123456782). Consolidate the pure maskers into shared/kernel/pii.ts
(maskBsn/maskTail/REDACTED); debug-state keeps redactProfile (needs the registratie
BigProfile — boundary). New <app-masked-value> atom (+story) centralises the masked
`.includes('*')` detection + reveal affordance; behandel-scherm refactored onto it.
Session.bsn stays string (persistence boundary drops it for privacy). +specs for bsn/pii.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 15:24:59 +02:00

33 lines
1.9 KiB
TypeScript

import { expect, test } from '@playwright/test';
// The dev-only `?scenario=error` toggle forces the scenario.interceptor to fail
// the request WITHOUT ever reaching the real HTTP transport (it substitutes a
// `throwError` in the rxjs pipe before `next(req)` runs) — so this is not
// observable as a browser network request. It IS observable as a real resource
// reload: `retry()` calls `resource.reload()`, which flips <app-async> back to
// its Loading (`aria-busy="true"`) state before failing again 400ms later.
// `currentScenario()` re-reads `window.location.search` on every call, not a
// one-shot value, so as long as the query param is still there, the retry
// genuinely re-runs and genuinely fails the same way — that's what's asserted
// here: a real reload cycle, not a no-op button.
test('dashboard error state renders, retry re-fetches (and fails again)', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('BSN').fill('123456782');
await page.getByRole('button', { name: 'Inloggen met DigiD' }).click();
await expect(page).toHaveURL(/\/dashboard$/);
await page.goto('/dashboard?scenario=error');
// The dashboard has more than one independent <app-async> (profile,
// aantekeningen) — both fail under the blanket ?scenario=error, so this text
// legitimately appears more than once. Assert at least one, not exactly one.
const errorAlert = page.getByText('Er ging iets mis bij het laden van de gegevens.').first();
await expect(errorAlert).toBeVisible();
const retry = page.getByRole('button', { name: 'Opnieuw proberen' }).first();
await expect(retry).toBeVisible();
await retry.click();
// A real reload cycle: back to Loading (aria-busy) before failing again.
await expect(page.locator('[aria-busy="true"]').first()).toBeAttached({ timeout: 1_000 });
await expect(errorAlert).toBeVisible({ timeout: 5_000 });
});