Files
oysqn.app/docs/archive/handoffs/handoff-2026-04-19-playwright-e2e-setup.md
Patrick Toal 108c042921 fix(edge-fn): replace getClaims with adminClient.auth.getUser(token)
fix(edge-fn): use user.id instead of claims.sub; fixes 500s and false cert_required
fix(migrations): drop broad reservations SELECT policy; add reservation_slots view with security_invoker=false
fix(tests): correct weekSlot() keys from start/end to start_time/end_time
fix(tests): spread overlap test slots across separate ISO weeks
fix(tests): update e2e assertion to match actual authenticated home text
fix(app): hide IonMenu before user is authenticated
feat(dx): add test:all script running unit, integration, and e2e in sequence
docs(claude-md): document SELinux fix, Edge Function auth pattern, security_invoker behaviour
2026-04-20 14:32:37 -04:00

3.6 KiB

Session Handoff: Playwright E2E Setup

Date: 2026-04-19 Session Focus: Set up Playwright E2E testing; write and pass auth flow tests

What Was Accomplished

  1. Installed @playwright/test 1.59.1 + Chromium headless shell binary
  2. Created playwright.config.ts — Pixel 5 viewport, reuseExistingServer for local dev, github reporter in CI, 30s timeout, 1 worker (serial)
  3. Created tests/e2e/helpers/mailpit.tsdeleteAllMail() and getMagicLink(email) against Mailpit at http://127.0.0.1:54324
  4. Created tests/e2e/auth.spec.ts — 2 tests: full magic link flow + protected route redirect
  5. Fixed supabase/config.tomlsite_url changed from http://127.0.0.1:3000 to http://localhost:3000; additional_redirect_urls updated to include http://localhost:3000/auth/callback and http://127.0.0.1:3000/auth/callback
  6. Added scripts to package.json: test:e2e, test:e2e:ui, test:e2e:headed
  7. Both tests pass: 2/2

Key Debugging Discoveries

Problem Root Cause Fix
getByRole('button', { name: 'Log In' }) not found IonButton with router-link renders as <a> (role=link) Changed to getByRole('link', { name: 'Log In' })
getByLabel('Email address') not found IonLabel is not associated via for/id with IonInput Changed to getByPlaceholder('you@example.com')
page.goto(magicLink)ERR_CONNECTION_REFUSED to 127.0.0.1:54321 Playwright's Chromium headless shell cannot reach Supabase local auth server directly Use Node.js fetch(magicLink, { redirect: 'manual' }) to follow redirect server-side; navigate browser to the resulting app callback URL
Callback URL was /?code= instead of /auth/callback?code= emailRedirectTo not whitelisted in supabase/config.toml; Supabase fell back to site_url Fixed config.toml redirect URLs; required supabase stop && supabase start

Ionic-Specific Playwright Patterns (confirmed working)

  • IonButton with router-link → use getByRole('link', { name: '...' })
  • IonButton without router-link → use getByRole('button', { name: '...' })
  • IonInput → use getByPlaceholder(...) (label association not standard HTML)
  • Never navigate browser directly to Supabase local auth URL — follow redirect server-side first

Files Created or Modified

File Action
playwright.config.ts Created
tests/e2e/helpers/mailpit.ts Created
tests/e2e/auth.spec.ts Created
supabase/config.toml Modified — site_url and redirect URLs
package.json Modified — added test:e2e scripts

What the NEXT Session Should Do

Option A — CI pipeline:

  1. Create .gitea/workflows/build.yaml — unit tests + build + E2E (read bab-app pipeline as reference)
  2. Note: E2E in CI requires local Supabase running in the pipeline — confirm if feasible or skip E2E in CI for now

Option B — Home page content:

  1. Implement authenticated home content in app/pages/index.vue (currently "Welcome to OYS Borrow a Boat" placeholder)
  2. Likely a boat list or dashboard — check docs/planning/ for persona requirements

Open Questions

  • Should E2E tests run in CI (requires Supabase in pipeline) or local-only? — OPEN
  • What is the authenticated home content? Boat list, dashboard, or something else? — check planning docs

Dev Environment Reference

# Required before running E2E:
DOCKER_HOST=unix:///run/user/1000/podman/podman.sock npx supabase start

# Run E2E:
yarn test:e2e          # headless
yarn test:e2e:headed   # visible browser
yarn test:e2e:ui       # Playwright UI mode