# UI Test Suites (Playwright)

This document tracks the UI/E2E automation efforts. The suites now live under `tests/ui` and are organized by product surface (Purchase, Auth, Admin, Guest PWA).

## Prerequisites
- Node 18+
- `npm install`
- Laravel app running at `http://localhost:8000`
- Seeded tenant admin account (see below)
- Lemon Squeezy sandbox credentials/config applied to the local `.env`

## Deterministic Data

### Tenant Admin
Use the existing seeder to provision a reusable tenant account for Admin suite flows:

```bash
php artisan db:seed --class=E2ETenantSeeder
```

Override defaults when necessary:

```bash
E2E_TENANT_EMAIL="tenant@example.com" \
E2E_TENANT_PASSWORD="super-secret" \
php artisan db:seed --class=E2ETenantSeeder
```

Expose the same credentials to Playwright:

```bash
export E2E_TENANT_EMAIL="tenant@example.com"
export E2E_TENANT_PASSWORD="super-secret"
```

### Coupon Presets & Mailbox API
The backend exposes `/api/_testing/...` endpoints (local/testing env only):

| Endpoint | Description |
| --- | --- |
| `POST /api/_testing/coupons/seed` | Seeds default coupons (`PERCENT10`, `FLAT50`, `EXPIRED25`) or accepts a custom payload. |
| `GET /api/_testing/mailbox` | Returns every captured email (see `App\Testing\Mailbox`). |
| `DELETE /api/_testing/mailbox` | Flushes the captured emails. |
| `GET /api/_testing/checkout/sessions/latest` | Fetches the newest checkout session for a given email/tenant filter. |
| `POST /api/_testing/checkout/sessions/{session}/simulate-lemonsqueezy` | Triggers the Lemon Squeezy webhook handler for the given session with a mock payload. |
| `GET /api/_testing/events/join-token` | Resolves (and optionally regenerates) a join token + QR for a given event ID or slug. |
| `POST /api/_testing/guest-events` | Provisions a deterministic guest/tenant event with sample tasks and returns its slug + join token. |

### Guest Demo Event
- Call `POST /api/_testing/guest-events` (optionally pass a custom `slug` or `name`) to ensure there is an event with ready-to-use tasks and join token.
- Export the slug so the guest suite knows which event to target:
  ```bash
  export E2E_GUEST_EVENT_SLUG="pwa-demo-event"
  export E2E_GUEST_BASE_URL="http://localhost:8000"
  ```
- The response includes `join_token` if you need to debug locally, but the UI tests grab a fresh token through `fetchJoinToken`.

Playwright fixtures (`tests/ui/helpers/test-fixtures.ts`) provide helpers that wrap these endpoints.

## Security Review (Dynamic Tests)

This section provides a staged, repeatable checklist for dynamic security reviews across product surfaces. It complements the UI suites above and is intended for staging/test environments.

### Environment Assumptions (Required)
- **Run in staging/test only** — never against production data.
- **Dedicated test tenants/users** — use seeded accounts (see above) and avoid real customer data.
- **Sandbox billing** — Lemon Squeezy sandbox and mock webhook endpoints only.
- **Testing token enabled** — set `E2E_TESTING_TOKEN` and ensure the backend accepts it for `/api/_testing/*`.
- **Stable base URL** — set `E2E_BASE_URL` to the target environment (`http://localhost:8000` or staging).
- **Email sink** — use `/api/_testing/mailbox` instead of real email delivery.
- **Rate limits** — keep request volume low; avoid concurrent fuzzing unless explicitly safe.

### Checklist: Marketing + Public API (Dynamic)
1) **Public routes**: `/de`, `/en`, `/de/packages`, `/de/blog`, `/de/kontakt` render with expected locale and canonical/hreflang tags.
2) **Redirect hygiene**: non‑prefixed routes redirect to locale (`/contact` → `/de/kontakt` or `/en/contact`).
3) **Contact form**: validation errors for missing fields; honeypot rejects bot payload; throttle returns 429 on excessive posts.
4) **Public API**: `GET /api/v1/events/{token}` and `/photos` reject invalid/expired tokens with 404/410 (no sensitive info).
5) **Abuse controls**: upload endpoints return 429 when rate‑limited; no 500s on malformed payloads.
6) **CORS**: public API does not allow wildcard origins for authenticated endpoints.

### Checklist: Guest PWA (Dynamic)
1) **Join token**: valid token joins, invalid/expired token shows safe error (no leakage).
2) **Permissions**: guest cannot access tenant/admin endpoints; 401/403 as expected.
3) **Uploads**: file type + size limits enforced; invalid uploads fail gracefully.
4) **Offline mode**: queued uploads don’t leak data; resync uses same join token.
5) **Likes/tasks**: actions scoped to event; cross‑event access denied.

### Checklist: Event Admin (Dynamic)
1) **Login flow**: correct error on invalid creds; throttling kicks in after repeated attempts.
2) **Tenant isolation**: admin cannot access other tenants’ events/photos (403/404).
3) **Join token lifecycle**: regenerate/disable token invalidates old links immediately.
4) **Moderation controls**: only admin can approve/hide; guest cannot mutate.
5) **Exports**: admin‑only endpoints require auth; signed URLs expire as expected.

### Checklist: Webhooks/Billing (Dynamic)
1) **Signature validation**: invalid signature is rejected (401/403) and logged.
2) **Freshness**: stale timestamps are rejected; replayed webhook payloads are idempotent.
3) **Lemon Squeezy sandbox flow**: use `/api/_testing/checkout/sessions/{session}/simulate-lemonsqueezy` to simulate success/failure; verify ledger updates.
4) **Webhook retries**: transient failures produce retry‑safe behavior (no duplicate ledger entries).
5) **Error handling**: malformed payload returns 4xx (not 500), with minimal error detail.

## Suite Layout & Goals

| Suite | Location | Primary Coverage |
| --- | --- | --- |
| Purchase | `tests/ui/purchase` | Marketing site package selection, checkout flow, coupon handling, Lemon Squeezy sandbox hand-off, post-purchase dashboard verification. |
| Auth | `tests/ui/auth` | Registration/login fuzzing, password reset, Social/OAuth hooks, email delivery assertions, throttling/error UX. |
| Admin | `tests/ui/admin` | Tenant onboarding wizard, dashboard widgets, event creation (incl. wedding preset), task assignment, join-token + QR verification, Lemon Squeezy billing history. |
| Guest | `tests/ui/guest` | Guest PWA onboarding, join-token entry, offline sync, uploads/likes/tasks for ≥15 guests, achievement + notification UX. |

Each suite should be executable independently to keep CI fast and to allow targeted debugging.

## Commands
- `npm run test:ui` — run all suites serially.
- `npm run test:ui:purchase` — Purchase-only regressions.
- `npm run test:ui:auth` — Authentication fuzzing.
- `npm run test:ui:admin` — Admin panel journeys.
- `npm run test:ui:guest` — Guest PWA scenarios.

Traces are recorded on first retry (`playwright.config.ts`); open via `npx playwright show-trace path/to/trace.zip`.

## Implementation Roadmap

1. **Purchase suite**
   - Seed coupons via helper.
   - Cover `/de/packages` Standard selection, coupon states (valid/invalid/expired), Lemon Squeezy inline + hosted checkout using sandbox card `4000 0566 5566 5557 / CVV 100`.
   - Simulate webhook success (helper endpoint TBD) so dashboard reflects the purchase.
   - Assert confirmation emails captured via mailbox API.

2. **Auth suite**
   - Expand current scaffold to fully automate registration, login, password reset, MFA prompts, and throttling.
   - Fuzz invalid inputs; assert inline validation + error banners.
   - Use mailbox helper to fetch verification/reset emails and follow links.

3. **Admin suite**
   - After purchase, log into `/event-admin`, confirm latest package appears, create a wedding event, assign predefined tasks, fetch join token + QR (helper should expose raw token/URL).
   - Cover task management UX (assign, reorder, complete).
   - Verify billing history shows the recent Lemon Squeezy transaction.

4. **Guest suite**
   - Use join token from Admin suite (or seed via helper) to onboard 15 simulated guests in parallel contexts.
   - Exercise uploads (with quota edge cases), likes, task completion, achievements, push subscription, offline queue + resync.
   - Validate guest-facing error states (expired token, upload failure, network loss).

5. **Shared helpers (backend + Playwright)**
   - Webhook trigger endpoint for Lemon Squeezy sandbox.
   - Join token + QR extraction endpoint for tests.
   - Task template seeding helper.
   - Optional guest factory endpoint to mint attendees quickly.

Track implementation progress in this document to keep future contributors aligned.

### Guest Suite

`tests/ui/guest/guest-pwa-journey.test.ts` simulates 15 independent guests joining the event, naming themselves, visiting the task list, opening the upload screen (via gallery picker), toggling offline mode for the final wave, and visiting the gallery to like a photo when one exists.

#### Requirements

1. **Existing event** – create a tenant admin event with active join token and set `E2E_GUEST_EVENT_SLUG` (e.g., `export E2E_GUEST_EVENT_SLUG=wedding-showcase`).
2. **Guest base URL** – defaults to `http://localhost:8000`. Override with `E2E_GUEST_BASE_URL` if the PWA runs elsewhere (Capacitor/TWA build).
3. **Media fixture** – the test auto-generates `tests/ui/guest/fixtures/sample-upload.png` for the gallery upload flow.

Run with `npm run test:ui:guest`. The test creates Playwright contexts sequentially to keep memory usage predictable.
