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
3.6 KiB
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
- Installed
@playwright/test1.59.1 + Chromium headless shell binary - Created
playwright.config.ts— Pixel 5 viewport,reuseExistingServerfor local dev,githubreporter in CI, 30s timeout, 1 worker (serial) - Created
tests/e2e/helpers/mailpit.ts—deleteAllMail()andgetMagicLink(email)against Mailpit athttp://127.0.0.1:54324 - Created
tests/e2e/auth.spec.ts— 2 tests: full magic link flow + protected route redirect - Fixed
supabase/config.toml—site_urlchanged fromhttp://127.0.0.1:3000tohttp://localhost:3000;additional_redirect_urlsupdated to includehttp://localhost:3000/auth/callbackandhttp://127.0.0.1:3000/auth/callback - Added scripts to
package.json:test:e2e,test:e2e:ui,test:e2e:headed - 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)
IonButtonwithrouter-link→ usegetByRole('link', { name: '...' })IonButtonwithoutrouter-link→ usegetByRole('button', { name: '...' })IonInput→ usegetByPlaceholder(...)(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:
- Create
.gitea/workflows/build.yaml— unit tests + build + E2E (read bab-app pipeline as reference) - 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:
- Implement authenticated home content in
app/pages/index.vue(currently "Welcome to OYS Borrow a Boat" placeholder) - 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