test(auth): Playwright E2E coverage for the Spring Session login flow #613

Open
opened 2026-05-17 22:55:39 +02:00 by marcel · 0 comments
Owner

Context

Follow-up to #523 / PR #612. Sara's review flagged that the new login/logout/idle-timeout flow has Vitest unit coverage on the SvelteKit server actions and the userGroup hook, plus Java unit/slice/integration tests on the backend, but no end-to-end Playwright coverage of the full user journey. The manual checklist in PR #612 is not regression coverage — it will not run on the next deploy.

This issue lands a small Playwright spec that exercises the real browser ↔ SvelteKit ↔ Spring Boot stack.

Scope

Add a single E2E spec covering the four happy-path beats:

  1. Login + cookie shape. Navigate to /login, fill the form with admin creds, submit. After redirect to /:

    • fa_session cookie is present, HttpOnly, SameSite=Strict
    • auth_token cookie is absent
    • Calling any /api/* route through the dev proxy returns 200 (i.e. the session authenticates subsequent requests)
  2. Session-expired banner. After login, programmatically set the fa_session cookie's Max-Age to 0 via context.addCookies, then navigate to a private route. Expect:

    • Redirect to /login?reason=expired
    • Banner is visible with the warning icon and the localised expired-session message
    • axe-playwright check passes on the expired-banner state (Sara's concern #3)
  3. Logout clears server + client state. From a logged-in state, submit the logout form. Expect:

    • Backend /api/auth/logout returns 204 (verify via response interception)
    • fa_session cookie is gone
    • Subsequent request to any /api/* route returns 401
  4. Login banner at 320px width. Visual-regression check that the new banner with icon does not break layout at the smallest mobile width (Leonie's suggestion in PR #612).

Acceptance criteria

Given the dev stack is running (backend + frontend)
When I run `npm run test:e2e -- auth-session`
Then four tests pass:
  - login_sets_fa_session_cookie_and_authenticates_api_calls
  - expired_session_shows_banner_with_warning_icon
  - logout_clears_cookies_and_subsequent_api_calls_return_401
  - banner_does_not_break_layout_at_320px

Implementation hints

  • Use the existing e2e profile admin seed (admin@familienarchiv.local / admin123) — already configured.
  • The dev profile clears fa_session between specs via the existing fixture (or add a beforeEach that calls /api/auth/logout to wipe state).
  • For the cookie-shape assertions: await context.cookies() returns the full attribute set including httpOnly, sameSite, secure, expires.
  • For axe-playwright: await checkA11y(page) after navigation; existing tests in frontend/e2e/ already use this pattern.
  • For the 320px visual regression: await page.setViewportSize({ width: 320, height: 800 }) then await expect(page).toHaveScreenshot('login-expired-banner-320.png').

Out of scope

  • Multi-context concurrent-session test (deferred to #524 — needs the session-revocation API to be meaningful)
  • Rate-limit E2E (also #524)
  • 2FA / SSO

Priority & sizing

  • MoSCoW: Should for v1.1.0
  • Priority: P2-medium (Vitest + Java tests catch most regressions; Playwright closes the proxy / browser / cookie-attribute gap)
  • Linked NFRs: NFR-OBSV-coverage (E2E layer of the test pyramid)
  • Depends on: #523 (merged when this is picked up)

References

  • PR #612 — Sara's review (S2) flagged the gap
  • PR #612 — Leonie's suggestion on the 320px visual check
  • docs/ARCHITECTURE.md — test-pyramid expectations
  • ADR-020 — Spring Session JDBC model that this exercises end-to-end

— Filed as follow-up while implementing PR #612 feedback.

## Context Follow-up to #523 / PR #612. Sara's review flagged that the new login/logout/idle-timeout flow has Vitest unit coverage on the SvelteKit server actions and the userGroup hook, plus Java unit/slice/integration tests on the backend, but **no end-to-end Playwright coverage** of the full user journey. The manual checklist in PR #612 is not regression coverage — it will not run on the next deploy. This issue lands a small Playwright spec that exercises the real browser ↔ SvelteKit ↔ Spring Boot stack. ## Scope Add a single E2E spec covering the four happy-path beats: 1. **Login + cookie shape.** Navigate to `/login`, fill the form with admin creds, submit. After redirect to `/`: - `fa_session` cookie is present, HttpOnly, SameSite=Strict - `auth_token` cookie is absent - Calling any `/api/*` route through the dev proxy returns 200 (i.e. the session authenticates subsequent requests) 2. **Session-expired banner.** After login, programmatically set the `fa_session` cookie's Max-Age to 0 via `context.addCookies`, then navigate to a private route. Expect: - Redirect to `/login?reason=expired` - Banner is visible with the warning icon and the localised expired-session message - `axe-playwright` check passes on the expired-banner state (Sara's concern #3) 3. **Logout clears server + client state.** From a logged-in state, submit the logout form. Expect: - Backend `/api/auth/logout` returns 204 (verify via response interception) - `fa_session` cookie is gone - Subsequent request to any `/api/*` route returns 401 4. **Login banner at 320px width.** Visual-regression check that the new banner with icon does not break layout at the smallest mobile width (Leonie's suggestion in PR #612). ## Acceptance criteria ``` Given the dev stack is running (backend + frontend) When I run `npm run test:e2e -- auth-session` Then four tests pass: - login_sets_fa_session_cookie_and_authenticates_api_calls - expired_session_shows_banner_with_warning_icon - logout_clears_cookies_and_subsequent_api_calls_return_401 - banner_does_not_break_layout_at_320px ``` ## Implementation hints - Use the existing `e2e` profile admin seed (admin@familienarchiv.local / admin123) — already configured. - The dev profile clears `fa_session` between specs via the existing fixture (or add a `beforeEach` that calls `/api/auth/logout` to wipe state). - For the cookie-shape assertions: `await context.cookies()` returns the full attribute set including `httpOnly`, `sameSite`, `secure`, `expires`. - For axe-playwright: `await checkA11y(page)` after navigation; existing tests in `frontend/e2e/` already use this pattern. - For the 320px visual regression: `await page.setViewportSize({ width: 320, height: 800 })` then `await expect(page).toHaveScreenshot('login-expired-banner-320.png')`. ## Out of scope - Multi-context concurrent-session test (deferred to #524 — needs the session-revocation API to be meaningful) - Rate-limit E2E (also #524) - 2FA / SSO ## Priority & sizing - MoSCoW: **Should** for v1.1.0 - Priority: **P2-medium** (Vitest + Java tests catch most regressions; Playwright closes the proxy / browser / cookie-attribute gap) - Linked NFRs: NFR-OBSV-coverage (E2E layer of the test pyramid) - Depends on: #523 (merged when this is picked up) ## References - PR #612 — Sara's review (S2) flagged the gap - PR #612 — Leonie's suggestion on the 320px visual check - `docs/ARCHITECTURE.md` — test-pyramid expectations - ADR-020 — Spring Session JDBC model that this exercises end-to-end — Filed as follow-up while implementing PR #612 feedback.
marcel added the P2-mediumtest labels 2026-05-17 22:55:58 +02:00
Sign in to join this conversation.
No Label P2-medium test
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#613