E2E test journeys & status.
The living map of what Playwright covers against
https://dev.cplk.org — every journey, every role, every backend gap
the suite has surfaced. References point at the spec files in
e2e/tests/ so a click on a row tells you exactly where to read or
edit the test.
How to read this page
The Playwright suite is partitioned by role project: each
project loads a Keycloak storage state (e2e/.auth/<role>.json)
and matches only the specs that role is responsible for. Multi-actor flows
capture a Bearer token from a second role's storage state via the
captureBearerForRole helper, so a single spec can drive cross-role
interactions without context-switching the whole browser.
| Status | Meaning |
|---|---|
| PASS | Active — tests pass against the current dev backend. |
| JOURNEY | Multi-step test.describe flow that walks an actor across a lifecycle. |
| PARTIAL | Has a documented gap — some tests are test.skip with a tagged reason. |
| BLOCKED | Backend missing, deferred, or relies on infrastructure (mail, captcha) not available against shared dev. |
How to run
All commands are run from e2e/ against the default base URL https://dev.cplk.org (override with CPLK_E2E_BASE_URL).
# first time / refresh role storage states
pnpm test:auth-setup
# everything
pnpm test
# only journeys (~22 files)
pnpm test:journeys
# only one role's projects
npx playwright test --project=agent
npx playwright test --project=property-owner
# only the new journeys added in this round
npx playwright test --project=agent --grep "notification-preferences|system-announcements|support-ticket-lifecycle"
# point at a different env
CPLK_E2E_BASE_URL=https://localhost:3000 npx playwright test
docs/E2E_TEST_COVERAGE.md is regenerated by
e2e/scripts/coverage-report.mjs. This page is the human-friendly
mirror, with the same data formatted for browsing.
Role projects
| Project | Storage state | Owns |
|---|---|---|
setup | writes .auth/<role>.json | Keycloak UI login for every role; runs first. |
anonymous | — | Public-site specs that need no auth (~660 atomic tests). |
anonymous-journeys | — | Public visitor journey. |
agent | .auth/agent.json | Property creation wizard, daily workflow, boost UI, favorites, the three new journeys. |
agency-admin | .auth/agency-admin.json | Agency lifecycle, subscription mgmt, property creation as admin. |
agency-super-admin | .auth/agency-super-admin.json | Agency-admin portal, user-invite journey. |
super-admin | .auth/super-admin.json | Platform-wide agency administration. |
blog-editor | .auth/blog-editor.json | Blog draft → review → publish workflow. |
financial-officer | .auth/financial-officer.json | Payment-slip verification, refund processing. |
property-owner | .auth/property-owner.json | PO full UI lifecycle, PO rejection, refund, approver UI variant. |
Journeys
A journey is a multi-step test.describe that walks
an actor (or a small cast) through a complete lifecycle. Most journeys are
self-contained: setup, action, assertion, cleanup. A few open side contexts to
act as a second role within the same spec.
Property lifecycle
| Spec | Project | Tests | Status | What it covers |
|---|---|---|---|---|
journeys/agent-daily-workflow.journey.spec.ts | agent | 5 (1 skip) | PARTIAL | Dashboard → list → drill-in → inquiries → favourites in one run. |
journeys/property-approval-lifecycle-agent.journey.spec.ts | agent | 3 | JOURNEY | Agent submits, approver approves, agent sees ACTIVE. |
journeys/property-approval-lifecycle-po.journey.spec.ts | property-owner | 2 | JOURNEY | PO variant of the approval lifecycle. |
journeys/property-approval-multirole-ui.journey.spec.ts | agent | 3 | JOURNEY | Multi-role UI flow — agent creates, opens approver context, asserts back in agent. |
journeys/property-approver-and-permanent-reject-ui.journey.spec.ts | agent · property-owner | 3 (3 skip) | PARTIAL | UI variants for approver-side controls; PA1/PA2 fixme on dev. |
journeys/property-edit-after-approval.journey.spec.ts | agent | 4 | JOURNEY | Edits triggering re-approval, history surfacing in the audit log. |
journeys/property-po-full-ui.journey.spec.ts | property-owner | 3 | JOURNEY | PO end-to-end: create → pay → publish → review → see in public. |
journeys/property-rejection-po.journey.spec.ts | property-owner | 1 | JOURNEY | PO sees structured rejection + revise path. |
journeys/property-rejection-scenarios.journey.spec.ts | agent | 6 | JOURNEY | Reason captured, redirect rules, draft return. |
journeys/property-refund-lifecycle.journey.spec.ts | property-owner | 4 | JOURNEY | PERMANENTLY_REJECTED → AWAITING_REFUND_DETAILS → REFUND_PENDING → REFUND_COMPLETED. |
Agency, content & engagement
| Spec | Project | Tests | Status | What it covers |
|---|---|---|---|---|
journeys/agency-admin-lifecycle.journey.spec.ts | agency-admin | 5 | JOURNEY | Agency dashboard → team → settings → property list flow. |
journeys/agency-user-invite-ui.journey.spec.ts | agency-super-admin | 3 | JOURNEY | Invite mints Keycloak user, role assignment, deactivation. |
journeys/blog-editor-workflow.journey.spec.ts | blog-editor | 6 | JOURNEY | Draft → submit → approve / reject → published edit (BE1–BE5). |
journeys/boost-purchase-ui.journey.spec.ts | agent | 3 (6 skip) | PARTIAL | BoostModal flow; some skips guard on stable seed boostable listing. |
journeys/favorites-flow.journey.spec.ts | agent | 7 (3 skip) | PARTIAL | Auth-gated favourite from anonymous → favourite from agent → list view. |
journeys/inquiry-handling-multirole-ui.journey.spec.ts | agent | 7 (4 skip) | PARTIAL | Inquiry submit → assign → respond → close, across roles. |
journeys/public-visitor.journey.spec.ts | anonymous-journeys | 6 (1 skip) | PARTIAL | Public search, filter, slug detail, inquiry submit. |
New journeys added in this round
Three additional journeys close real coverage gaps on dev. All three exercise public REST contracts that previously had unit-test coverage only.
| Spec | Project | Tests | Status | What it covers |
|---|---|---|---|---|
journeys/notification-preferences.journey.spec.ts |
agent | 3 (NP1–NP3) | PASS | GET defaults · single-type PUT round-trip · bulk PUT round-trip. Hits GET /api/notifications/preferences & PUT /api/notifications/preferences; restores defaults so the test is idempotent. |
journeys/system-announcements.journey.spec.ts |
agent (+ super-admin token) | 3 (SA1–SA3) | PASS | SUPER_ADMIN publishes ALL-targeted announcement → agent sees unread → agent PATCHes {id}/read → agent sees read. SA3 asserts role-isolation (AGENT cannot see FINANCIAL_OFFICER-targeted announcement). |
journeys/support-ticket-lifecycle.journey.spec.ts |
agent (+ super-admin token) | 4 (ST1–ST4) | PASS | Agent creates ticket → external reply → SUPER_ADMIN internal note isolation → NEW → IN_PROGRESS → RESOLVED → reporter REOPENED → CLOSED transitions. |
CPLK_E2E_BASE_URL=https://dev.cplk.org npx playwright test --project=agent --grep "notification-preferences|system-announcements|support-ticket-lifecycle"
→ 18 passed (auth setup 8 + journey tests 10) in 14.3 s.
Atomic spec areas
Outside the journeys, ~660 atomic specs cover the rest of the surface. The full inventory is in docs/E2E_TEST_COVERAGE.md; below is the summary by area.
| Area | Specs | Tests | Notes |
|---|---|---|---|
| Auth | 4 | 98 | Login, register, password reset, email verification. |
| Properties | 13 | ~130 | Wizard catalog by role, image upload, edit, detail, public detail, status transitions. |
| Inquiries | 3 | 45 | Public form, list, detail. |
| Favorites | 2 | 30 | Button + page. |
| Dashboard / Analytics | 3 | 68 | Dashboard widgets, property analytics, agency analytics. |
| Notifications | 3 | 36 | Bell, page, badge increments. |
| Portal (admin) | 7 | 64 | Agency admin / super-admin views, subscriptions, boost, financial officer. |
| Public site | 6 | 116 | Homepage, agencies, properties, search, link audit. |
| SEO | 2 | 19 | Sitemap, robots, OG tags, structured data, canonicals. |
| Onboarding | 6 | 41 | Company agency, individual agent, PO, skip, redirect. |
| Security / RBAC | 6 | 93 | API auth errors, validation errors, RBAC denial, cross-agency, blog/article RBAC. |
| Errors | 4 | 25 | API 5xx fallback, network, permission, validation. |
| Accessibility | 3 | ~18 (16 skip) | A11y, form validation, modal focus. |
| Mobile / responsive | 2 | 12 | Mobile + tablet viewport runs. |
| Smoke / core / network | 5 | 9 | Console-error scan, network audit, smoke. |
Known gaps & backend issues
The Playwright suite is also a forcing function for backend issues. Every gap below has a corresponding active or test.skip test, so the suite flips green automatically when the backend ships the fix.
Deferred — infrastructure / shared-env constraints
- Email-channel notification delivery (requires SMTP / mailbox interception not wired against dev).
- R2 upload failure retry behaviour (requires S3 5xx mocking).
- Slow-network / offline behaviour (requires fault-injection harness).
- Cross-browser (Firefox / WebKit / Edge) — deliberately Chrome-only since the journey redesign.
- Two users editing the same property / shared ad-slot races (not deterministic on shared dev).
Backend gaps surfaced by the suite
| Severity | Issue | Discovered by |
|---|---|---|
| CRITICAL | Cross-agency property approve bypass — an agency-admin can approve a property in another agency. | security/rbac-denial.spec.ts (S6) |
| CRITICAL | Cross-agency DELETE — DELETE of another agency's resource succeeds where it should 403. | security/api-auth-errors.spec.ts |
| HIGH | 500 instead of 400 on POST /api/properties bean validation. | security/api-validation-errors.spec.ts (V2–V6) |
| HIGH | 500 instead of 400 on PATCH /api/inquiries/{id}/status invalid enum. | security/api-validation-errors.spec.ts (V7) |
| HIGH | 500 instead of 400 on POST /api/boosts invalid enum. | security/api-validation-errors.spec.ts (V12) |
| HIGH | SOLD / LEASED property transition endpoints missing. | properties/property-status-transitions.spec.ts (T3–T6 skip) |
| MEDIUM | POST /properties/{id}/reject does not require a rejection reason. | security/api-validation-errors.spec.ts (V13) |
| MEDIUM | Validation runs before role check on POST /api/agencies — leaks field names to non-admins. | security/rbac-denial.spec.ts |
| MEDIUM | Auto-renew toggle endpoint missing. | portal/subscription.spec.ts (SUB6) |
| MEDIUM | Subscription payment-slip upload flow has no backend. | portal/subscription.spec.ts (SUB7) |
| LOW | Sitemap can lag behind property publish events. | seo/sitemap-and-meta.spec.ts |
| LOW | No hard DELETE for agencies (suspension only). | portal/agencies-admin.spec.ts (AG4) |
Conventions in this suite
- One file per journey. Each journey lives in
e2e/tests/journeys/*.journey.spec.tsand is named after the lifecycle it covers. - Independent tests. Where possible, journey tests are not serial — each creates its own resource and cleans up in
afterEachso a single flake doesn't cascade. - Cross-role via Bearer tokens. Multi-actor journeys use
captureBearerForRoleto pull a JWT from another role's storageState rather than spinning up a second browser session. - Unique title prefixes. Test artefacts use
[E2E-XX]prefixes (e.g.[E2E-BE]for blog editor,[E2E-ST]for support tickets) so manual cleanup is straightforward if a spec crashes. - The
coverage-report.mjsscript walkstests/**.spec.tsand rewrites the auto-generated section ofdocs/E2E_TEST_COVERAGE.mdbetween markers. This HTML page is the human-friendly mirror — keep both in sync.
References
- Playwright config —
e2e/playwright.config.ts - Auth setup —
e2e/setup/auth.setup.ts - Credentials fixture —
e2e/tests/fixtures/credentials.ts - Live coverage runbook —
docs/E2E_TEST_COVERAGE.md - Backend state machines —
backend/src/main/java/com/cplk/api/config/PropertyStateMachineConfig.java