From 2093f12d0acbb970a8ad01150025edb5e6cdfb36 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 30 May 2026 14:55:06 +0100 Subject: [PATCH] multiple verifications --- .env.example | 9 +- README.md | 70 ++++++++++-- docs/plans/e2e-login-and-report.md | 168 +++++++++++++++++++++++++++++ e2e/package.json | 1 + e2e/playwright.auth.config.ts | 65 +++++++++++ e2e/tests-auth/login.spec.ts | 86 +++++++++++++++ e2e/tests/report.spec.ts | 67 ++++++++++++ package.json | 1 + 8 files changed, 460 insertions(+), 7 deletions(-) create mode 100644 docs/plans/e2e-login-and-report.md create mode 100644 e2e/playwright.auth.config.ts create mode 100644 e2e/tests-auth/login.spec.ts create mode 100644 e2e/tests/report.spec.ts diff --git a/.env.example b/.env.example index 55ed796..5a28083 100644 --- a/.env.example +++ b/.env.example @@ -22,7 +22,14 @@ AUTH_SECRET="dev-secret-do-not-use-in-production-please-change-me" # must consciously opt in by editing their .env. See README "Auth" section. AUTH_DEV_AUTOLOGIN="false" -# Base URL of the operator-pwa app — used by Auth.js for callback URLs. +# Base URL Auth.js uses to build callback/redirect URLs. It MUST match the host +# of the app being served. This shared .env can hold only ONE value, set here to +# the operator-pwa (:3000). The admin-web (:3001) therefore needs its OWN +# AUTH_URL whenever autologin is OFF (real-login dev, or production) — otherwise +# Auth.js redirects admin users to :3000 and the admin login breaks. +# - Local with autologin ON: this value is harmless (middleware never redirects). +# - E2E real-login: e2e/playwright.auth.config.ts passes AUTH_URL=:3001 to admin. +# - Production: give EACH app its own AUTH_URL (per-app env), not this shared file. NEXT_PUBLIC_APP_URL="http://localhost:3000" AUTH_URL="http://localhost:3000" diff --git a/README.md b/README.md index a334c50..08d768b 100644 --- a/README.md +++ b/README.md @@ -147,14 +147,65 @@ mc mirror local/fieldops ./backup-photos ```sh # One-time browser install (downloads ~170 MB of Chromium) pnpm --filter @repo/e2e install-browsers - -# Run the happy-path test (starts both dev servers automatically) -pnpm test:e2e ``` -The Playwright config force-sets `AUTH_DEV_AUTOLOGIN=true` for the child -servers, so the test does not depend on the developer's `.env`. -Expected: **1 passed** in ~30 s. +### `pnpm test:e2e` — happy-path + shift report (autologin ON) + +Starts both dev servers with `AUTH_DEV_AUTOLOGIN=true`. Safe to run at any +time — reuses servers already running on 3000/3001 if available. + +Expected: **3 passed** (~45 s): +- MAI CALL happy path: create → claim → resolve +- Shift report: renders with seed data and reacts to window selection +- Shift report: accessible from the maintenance queue link + +### `pnpm test:e2e:auth` — real login (autologin OFF) + +Tests that the login UI actually works — operator PIN keypad and admin +email/password — without the dev back door. + +**Precondition: no servers running on ports 3000 or 3001.** This command +starts its own servers with `AUTH_DEV_AUTOLOGIN=false`. If ports are busy: + +```sh +# Windows +Get-Process node | Stop-Process -Force +``` + +Also requires `pnpm db:seed` to have been run. + +Expected: **4 passed** (~60 s): +- Operator: wrong PIN shows error, correct PIN enters the app +- Operator: unauthenticated root redirects to picker +- Admin: protected route redirects to /login without session +- Admin: wrong password shows error, correct password enters the queue + +--- + +### Manual smoke checklist (5 min — covers print + offline) + +Automated tests don't cover the print PDF or offline sync. Run this when +you want end-to-end confidence before a demo: + +``` +1. docker compose up -d && pnpm db:seed + +2. Operator (real login): + pnpm --filter @repo/operator-pwa dev → http://localhost:3000/select-operator + Try PIN 9999 → see error. Then op1 → PIN 1111 → enters app. + +3. Admin (real login): + pnpm --filter @repo/admin-web dev → http://localhost:3001/login + admin@demo.local / admin1234 → maintenance queue. + +4. Shift report: + Click "Relatório de turno" in header → click Manhã/Tarde/Noite/Hoje + → numbers update each time. + Click "Imprimir" → confirm PDF is clean (no buttons/selector/nav). + +5. Offline (requires production build of operator-pwa — see Troubleshooting): + DevTools → Network → Offline → create 2 requests → Online → they sync. +``` --- @@ -248,6 +299,13 @@ by changing the endpoint env var. **`Tenant not found`** — the seed was wiped. Run `pnpm db:seed`. +**Admin login redirects to `:3000` / the operator picker** — the shared `.env` +sets `AUTH_URL=http://localhost:3000`, which is correct for the operator-pwa but +wrong for the admin-web (:3001). With `AUTH_DEV_AUTOLOGIN=true` it never bites +(the middleware doesn't redirect). With autologin OFF, give the admin-web its own +`AUTH_URL=http://localhost:3001` (the E2E auth config does this). In production, +each app must have its own `AUTH_URL`. + **`DATABASE_URL not found`** — `.env` is missing or Docker Postgres is not running. Run `docker compose up -d` then retry. diff --git a/docs/plans/e2e-login-and-report.md b/docs/plans/e2e-login-and-report.md new file mode 100644 index 0000000..8f764c3 --- /dev/null +++ b/docs/plans/e2e-login-and-report.md @@ -0,0 +1,168 @@ +# Plano — E2E de verificação: login real + relatório de turno + +> Autor: Opus 4.8 (sessão de design, 2026-05-30). Destinado a implementação pelo Sonnet. +> Pré-requisitos: MAI CALL v0.1 + Auth v0.2 + v0.3 (relatório), todos implementados e verificados ao nível de lógica/build. Estado do código verificado contra o repo. +> **Motivo:** Pedro escolheu "travar features e verificar". Três camadas de interação nunca foram exercitadas por um browser: (a) a UI do relatório, (b) o **login real** (o E2E atual usa `AUTH_DEV_AUTOLOGIN=true` e **contorna** o login), (c) offline. Este plano fecha (a) e (b) com Playwright. (c) fica para um smoke manual. + +## Objetivo numa frase + +Acrescentar testes E2E que provem que **o relatório de turno renderiza e reage** e que o **login real funciona no browser** (operador PIN + admin password), sem depender do back door de autologin. + +## Decisões fixadas (não revisitar sem motivo forte) + +1. **Dois configs Playwright.** O atual ([`e2e/playwright.config.ts`](../../e2e/playwright.config.ts)) arranca ambos os servidores com `AUTH_DEV_AUTOLOGIN: 'true'` — mantém-se para os testes que não precisam de login (happy-path + **relatório**). Um **segundo config** arranca os servidores com o autologin **desligado** para os testes de **login real**. +2. **Porquê dois servidores e não um:** o autologin é decidido server-side (`resolveUser()` + `middleware.ts`). Com o flag ligado no servidor, apagar cookies no browser não chega — o middleware volta a deixar entrar. A única forma de testar o login real é um servidor com o flag desligado. +3. **Como desligar o flag no servidor de teste:** passar `AUTH_DEV_AUTOLOGIN: 'false'` em `webServer[].env`. Funciona porque o script de dev usa `dotenv -e ../../.env`, e **`dotenv` não sobrepõe variáveis já presentes** no processo — o valor do Playwright ganha. (É o mesmo mecanismo pelo qual o config atual força `'true'`.) +4. **Mesmas portas (3000/3001), `reuseExistingServer: false` no config de auth.** Consequência: **`test:e2e:auth` não pode correr com servidores já a correr nessas portas** (dá "port in use"). Documentar. Em CI corre isolado, sem problema. +5. **Não testar o lockout no E2E.** Já está coberto pelo `auth-smoke` (11/11). Testar lockout no browser exigiria 5 tentativas e deixaria `failedAttempts`/`lockedUntil` sujos por 5 min, podendo partir outros testes. O E2E de login cobre **sucesso** + **credencial errada mostra erro** (1 tentativa), e o **sucesso reseta** `failedAttempts`. +6. **Asserções tolerantes a dados acumulados.** O DB é partilhado e sequencial (`workers: 1`); o happy-path cria pedidos extra. O teste do relatório usa asserções **estruturais** (elementos existem, valores não-vazios) e **≥**, nunca números exatos — mesma postura do `report-smoke`. + +## Estrutura de ficheiros (nova) + +``` +e2e/ + playwright.config.ts (existe — autologin ON, testDir ./tests) + playwright.auth.config.ts (NOVO — autologin OFF, testDir ./tests-auth, reuseExistingServer:false) + tests/ + mai-call.spec.ts (existe) + report.spec.ts (NOVO — Passo 1) + tests-auth/ + login.spec.ts (NOVO — Passo 2) +``` + +> O config atual tem `testDir: './tests'`, por isso os specs em `./tests-auth` **não** são apanhados por ele. Sem colisão. + +## Selectores confirmados (lidos do código — usar exatamente) + +**Operador (operator-pwa, `/select-operator`):** +- Lista: `