feat(e2e): E2E-Integrationstests mit Playwright einfuehren #205

Closed
opened 2026-07-03 18:42:37 +02:00 by niboer · 1 comment
Owner

Ziel

E2E-Integrationstests mit Playwright im Docker-Container, die den vollen Stack (Postgres, Mailhog, Keycloak, Backend, Frontend) testen.

Phasen

Phase 1 — Kernpfade (5 Spec-Dateien, ~19 Tests)

  • e2e/-Verzeichnis anlegen: Dockerfile, package.json, playwright.config.ts
  • docker-compose.yml um e2e-runner-Service erweitern
  • scripts/docker-test.mjs um E2E-Schritt + Healthcheck + Log-Sammlung erweitern
  • --fast-Flag zum Ueberspringen von Lint
  • SIGINT-Handler fuer sauberes Ctrl+C (CurrentChild-Tracking, Log-Sammlung, Cleanup)
  • DEBUG_URL/DEBUG_COOKIE per -e an Container durchgereicht
  • Trace auf retain-on-failure, outputDir in ./output/
  • auth.ts-Fixture: Keycloak-Login via UI + Session-Cookie
  • login.spec.ts: Login/Logout, protected routes ohne Session
  • dashboard.spec.ts: Dashboard laedt, Statistik-Kacheln sichtbar
  • persons-table.spec.ts: Personen-Tabelle laden, sortieren, filtern
  • events-form.spec.ts: Event anlegen (positiv + negativ: leeres Datum, vergangenes Datum)
  • sidebar.spec.ts: Sidebar-Navigation, aktive Tabs
  • zz-logout.spec.ts: Logout-Test als letzte Datei (zerstoert Session nicht mehr)
  • Logout-Assertion auf generischen Login-Button statt hartkodiertem App-Namen
  • CI-Workflow .gitea/workflows/e2e.yml

Phase 1.5 — Coverage-Enforcement & Testbarkeit

Route-Test-Coverage:

  • scripts/check-e2e-coverage.mjs: Scannt frontend/src/routes/app/ und vergleicht gegen e2e/.test-coverage.json. Unbekannte Routen → Exit 1. --warn-Flag fuer CI-Warning-Modus.
  • e2e/.test-coverage.json: Mapping aller Routen mit Status covered / known_uncovered. Fehlender Eintrag = unbekannte Route → Fail.
  • CI-Step: node scripts/check-e2e-coverage.mjs --warn mit continue-on-error: true
  • Prozess in AGENTS.md: Neue Route braucht Eintrag in .test-coverage.json + korrespondierenden E2E-Test.

testid-Action & Enforcement:

  • frontend/src/lib/actions/testid.ts: Svelte-Action use:testid fuer zuverlaessiges Auffinden via getByTestId(). Namensschema: {komponente}-{aktion} (z. B. btn-logout, link-events, form-event-create).
  • testid in Templates: use:testid an allen <button>, <a href>, <form>-Elementen im Frontend anbringen. (Phase 2)
  • scripts/check-testid.mjs: Scannt .svelte-Dateien nach interaktiven Elementen ohne use:testid. --fail fuer Pre-Commit, --warn fuer CI.
  • Pre-Commit-Hook: scripts/check-testid.mjs --warn in lint-staged (aktuell Warn-Modus, nach Phase 2 auf --fail umstellen).
  • CI-Step (Warning): node scripts/check-testid.mjs --warn mit continue-on-error: true.

Organisatorisch:

  • PR-Vorlage .gitea/PULL_REQUEST_TEMPLATE/pull_request.md: Altes/Neues Verhalten, Begruendung, Checkliste (testid + E2E).
  • Issue-Vorlage aktualisieren (.gitea/ISSUE_TEMPLATE/): Checklisten-Punkt: "use:testid an allen <button>, <a href>, <form> gesetzt?"
  • AGENTS.md-Regel erweitern: testid-Pflicht + Schema + Verweis auf scripts/check-testid.mjs
  • CI-Pipeline vollenden (Issue #212): Branch-Protection, Pipeline laeuft bei PR

Phase 2 — Vollausbau (~9 Spec-Dateien, ~80-100 Tests)

  • events-full.spec.ts: Event update, publish, soft-delete, Tabs
  • guests.spec.ts: Gast einladen, Status aendern, Zahlungsstatus, Gast entfernen
  • groups.spec.ts: Haushalt CRUD, Mitglieder verwalten
  • templates.spec.ts: Vorlage anlegen, Formularfelder konfigurieren
  • account.spec.ts: Account, Consent, DSGVO
  • permissions.spec.ts: RBAC-Tests (403-Szenarien)
  • navigation.spec.ts: Tab-Navigation, ActionMenu, Breadcrumbs
  • mailhog.spec.ts: E-Mail-Pruefung via Mailhog-API nach Einladungsversand
  • error-pages.spec.ts: 404, Netzwerkfehler-Handling
  • testid in Templates: use:testid an allen <button>, <a>, <form>-Elementen im Frontend
  • Pre-Commit auf --fail: lint-staged auf --fail umstellen wenn alle Templates testid haben

Technische Details

Ports (Docker-intern):

  • Frontend: http://frontend:3000
  • Mailhog-API: http://mailhog:8025/api/v2/messages
  • Keycloak: http://keycloak:8080

Wichtige Konfiguration:

  • playwright.config.ts: baseURL = http://frontend.integration.local:3000, Chromium only, list + html Reporter, outputDir = ../output/e2e-results
  • e2e/Dockerfile: basiert auf mcr.microsoft.com/playwright, WORKDIR /app
  • helpers/mailhog.ts: API-Client zum Abfragen/Loeschen von E-Mails
  • fixtures/auth.ts: Keycloak-Login via UI (username/password aus Dev-Seed)
  • scripts/docker-test.mjs: Orchestriert Build, Start, Healthcheck, E2E-Tests, Log-Sammlung, Cleanup
  • e2e/docker-compose.e2e.yml: Override fuer Keycloak-Hostname und Frontend-Origin
  • Artifacts landen in ./output/ (Traces, HTML-Report, Container-Logs)

Dateien (neu/geaendert)

e2e/Dockerfile                           # NEU
e2e/package.json                         # NEU
e2e/playwright.config.ts                 # NEU/GEAENDERT
e2e/docker-compose.e2e.yml              # NEU
e2e/global-setup.ts                      # NEU
e2e/fixtures/auth.ts                     # NEU
e2e/fixtures/test-data.ts                # NEU
e2e/specs/phase-1/login.spec.ts          # NEU/GEAENDERT
e2e/specs/phase-1/dashboard.spec.ts      # NEU/GEAENDERT
e2e/specs/phase-1/persons-table.spec.ts  # NEU/GEAENDERT
e2e/specs/phase-1/events-form.spec.ts    # NEU/GEAENDERT
e2e/specs/phase-1/sidebar.spec.ts        # NEU/GEAENDERT
e2e/specs/phase-1/zz-logout.spec.ts      # NEU
e2e/helpers/mailhog.ts                   # Planung
e2e/.test-coverage.json                  # Phase 1.5 NEU
docker-compose.yml                       # GEAENDERT
scripts/docker-test.mjs                  # GEAENDERT
scripts/check-e2e-coverage.mjs           # Phase 1.5 NEU
scripts/check-testid.mjs                 # Phase 1.5 NEU
frontend/src/lib/actions/testid.ts       # Phase 1.5 NEU
.gitea/workflows/e2e.yml                 # NEU/GEAENDERT
.gitea/PULL_REQUEST_TEMPLATE/            # Phase 1.5 NEU
.gitea/ISSUE_TEMPLATE/                   # Phase 1.5 GEAENDERT
.gitignore                               # GEAENDERT
AGENTS.md                                # GEAENDERT
package.json                             # GEAENDERT (lint-script mit check-testid)
## Ziel E2E-Integrationstests mit Playwright im Docker-Container, die den vollen Stack (Postgres, Mailhog, Keycloak, Backend, Frontend) testen. ## Phasen ### Phase 1 — Kernpfade (5 Spec-Dateien, ~19 Tests) ✅ - [x] `e2e/`-Verzeichnis anlegen: `Dockerfile`, `package.json`, `playwright.config.ts` - [x] `docker-compose.yml` um `e2e-runner`-Service erweitern - [x] `scripts/docker-test.mjs` um E2E-Schritt + Healthcheck + Log-Sammlung erweitern - [x] `--fast`-Flag zum Ueberspringen von Lint - [x] SIGINT-Handler fuer sauberes Ctrl+C (CurrentChild-Tracking, Log-Sammlung, Cleanup) - [x] `DEBUG_URL`/`DEBUG_COOKIE` per `-e` an Container durchgereicht - [x] Trace auf `retain-on-failure`, `outputDir` in `./output/` - [x] `auth.ts`-Fixture: Keycloak-Login via UI + Session-Cookie - [x] **login.spec.ts**: Login/Logout, protected routes ohne Session - [x] **dashboard.spec.ts**: Dashboard laedt, Statistik-Kacheln sichtbar - [x] **persons-table.spec.ts**: Personen-Tabelle laden, sortieren, filtern - [x] **events-form.spec.ts**: Event anlegen (positiv + negativ: leeres Datum, vergangenes Datum) - [x] **sidebar.spec.ts**: Sidebar-Navigation, aktive Tabs - [x] **zz-logout.spec.ts**: Logout-Test als letzte Datei (zerstoert Session nicht mehr) - [x] Logout-Assertion auf generischen Login-Button statt hartkodiertem App-Namen - [x] CI-Workflow `.gitea/workflows/e2e.yml` ### Phase 1.5 — Coverage-Enforcement & Testbarkeit ✅ **Route-Test-Coverage:** - [x] **`scripts/check-e2e-coverage.mjs`**: Scannt `frontend/src/routes/app/` und vergleicht gegen `e2e/.test-coverage.json`. Unbekannte Routen → Exit 1. `--warn`-Flag fuer CI-Warning-Modus. - [x] **`e2e/.test-coverage.json`**: Mapping aller Routen mit Status `covered` / `known_uncovered`. Fehlender Eintrag = unbekannte Route → Fail. - [x] **CI-Step**: `node scripts/check-e2e-coverage.mjs --warn` mit `continue-on-error: true` - [x] **Prozess in `AGENTS.md`**: Neue Route braucht Eintrag in `.test-coverage.json` + korrespondierenden E2E-Test. **testid-Action & Enforcement:** - [x] **`frontend/src/lib/actions/testid.ts`**: Svelte-Action `use:testid` fuer zuverlaessiges Auffinden via `getByTestId()`. Namensschema: `{komponente}-{aktion}` (z. B. `btn-logout`, `link-events`, `form-event-create`). - [x] **testid in Templates**: `use:testid` an allen `<button>`, `<a href>`, `<form>`-Elementen im Frontend anbringen. (Phase 2) - [x] **`scripts/check-testid.mjs`**: Scannt `.svelte`-Dateien nach interaktiven Elementen ohne `use:testid`. `--fail` fuer Pre-Commit, `--warn` fuer CI. - [x] **Pre-Commit-Hook**: `scripts/check-testid.mjs --warn` in lint-staged (aktuell Warn-Modus, nach Phase 2 auf `--fail` umstellen). - [x] **CI-Step (Warning)**: `node scripts/check-testid.mjs --warn` mit `continue-on-error: true`. **Organisatorisch:** - [x] **PR-Vorlage** `.gitea/PULL_REQUEST_TEMPLATE/pull_request.md`: Altes/Neues Verhalten, Begruendung, Checkliste (testid + E2E). - [x] **Issue-Vorlage aktualisieren** (`.gitea/ISSUE_TEMPLATE/`): Checklisten-Punkt: "`use:testid` an allen `<button>`, `<a href>`, `<form>` gesetzt?" - [x] **`AGENTS.md`-Regel erweitern**: testid-Pflicht + Schema + Verweis auf `scripts/check-testid.mjs` - [ ] **CI-Pipeline vollenden (Issue #212)**: Branch-Protection, Pipeline laeuft bei PR ### Phase 2 — Vollausbau (~9 Spec-Dateien, ~80-100 Tests) - [x] **events-full.spec.ts**: Event update, publish, soft-delete, Tabs - [x] **guests.spec.ts**: Gast einladen, Status aendern, Zahlungsstatus, Gast entfernen - [x] **groups.spec.ts**: Haushalt CRUD, Mitglieder verwalten - [x] **templates.spec.ts**: Vorlage anlegen, Formularfelder konfigurieren - [x] **account.spec.ts**: Account, Consent, DSGVO - [x] **permissions.spec.ts**: RBAC-Tests (403-Szenarien) - [x] **navigation.spec.ts**: Tab-Navigation, ActionMenu, Breadcrumbs - [x] **mailhog.spec.ts**: E-Mail-Pruefung via Mailhog-API nach Einladungsversand - [x] **error-pages.spec.ts**: 404, Netzwerkfehler-Handling - [x] **testid in Templates**: `use:testid` an allen `<button>`, `<a>`, `<form>`-Elementen im Frontend - [x] **Pre-Commit auf --fail**: lint-staged auf `--fail` umstellen wenn alle Templates testid haben ## Technische Details **Ports (Docker-intern):** - Frontend: `http://frontend:3000` - Mailhog-API: `http://mailhog:8025/api/v2/messages` - Keycloak: `http://keycloak:8080` **Wichtige Konfiguration:** - `playwright.config.ts`: baseURL = `http://frontend.integration.local:3000`, Chromium only, list + html Reporter, outputDir = `../output/e2e-results` - `e2e/Dockerfile`: basiert auf `mcr.microsoft.com/playwright`, WORKDIR /app - `helpers/mailhog.ts`: API-Client zum Abfragen/Loeschen von E-Mails - `fixtures/auth.ts`: Keycloak-Login via UI (username/password aus Dev-Seed) - `scripts/docker-test.mjs`: Orchestriert Build, Start, Healthcheck, E2E-Tests, Log-Sammlung, Cleanup - `e2e/docker-compose.e2e.yml`: Override fuer Keycloak-Hostname und Frontend-Origin - Artifacts landen in `./output/` (Traces, HTML-Report, Container-Logs) ## Dateien (neu/geaendert) ``` e2e/Dockerfile # NEU e2e/package.json # NEU e2e/playwright.config.ts # NEU/GEAENDERT e2e/docker-compose.e2e.yml # NEU e2e/global-setup.ts # NEU e2e/fixtures/auth.ts # NEU e2e/fixtures/test-data.ts # NEU e2e/specs/phase-1/login.spec.ts # NEU/GEAENDERT e2e/specs/phase-1/dashboard.spec.ts # NEU/GEAENDERT e2e/specs/phase-1/persons-table.spec.ts # NEU/GEAENDERT e2e/specs/phase-1/events-form.spec.ts # NEU/GEAENDERT e2e/specs/phase-1/sidebar.spec.ts # NEU/GEAENDERT e2e/specs/phase-1/zz-logout.spec.ts # NEU e2e/helpers/mailhog.ts # Planung e2e/.test-coverage.json # Phase 1.5 NEU docker-compose.yml # GEAENDERT scripts/docker-test.mjs # GEAENDERT scripts/check-e2e-coverage.mjs # Phase 1.5 NEU scripts/check-testid.mjs # Phase 1.5 NEU frontend/src/lib/actions/testid.ts # Phase 1.5 NEU .gitea/workflows/e2e.yml # NEU/GEAENDERT .gitea/PULL_REQUEST_TEMPLATE/ # Phase 1.5 NEU .gitea/ISSUE_TEMPLATE/ # Phase 1.5 GEAENDERT .gitignore # GEAENDERT AGENTS.md # GEAENDERT package.json # GEAENDERT (lint-script mit check-testid) ```
niboer added this to the MS-INTEGRATION milestone 2026-07-03 18:42:37 +02:00
niboer self-assigned this 2026-07-03 18:42:37 +02:00
Author
Owner

Erweiterung Phase 2 — Credential-Tests

WebAuthn (Passkeys) und TOTP sind in Keycloak/Backend/Frontend bereits vollstaendig konfiguriert
(siehe docs/design/05-authentifizierung.md und keycloak-provision.ts).
E2E-Tests fuer beide koennen direkt umgesetzt werden.

TOTP

  • e2e/helpers/totp.ts: otplib-Bibliothek, QR-Code-URL aus Keycloak-Account-Console parsen,
    Secret extrahieren, TOTP-Code generieren
  • Test: TOTP via AIA (CONFIGURE_TOTP) registrieren, Login mit TOTP-Code verifizieren
  • Benoetigt: e2e/package.json + otplib

Passkey (WebAuthn Passwordless)

  • Playwright Chrome DevTools Protocol: page.context().newCDPSession(page)WebAuthn.enable
  • Virtuellen Authenticator (type: 'internal') erstellen via CDP
  • Test: Passkey via AIA (webauthn-register-passwordless) registrieren,
    Login per Passkey (Conditional UI, kein PW/OTP)
  • Nutzt die bestehende Keycloak-Konfiguration (webAuthnPolicyPasswordlessEnablePasskeys: true)
## Erweiterung Phase 2 — Credential-Tests WebAuthn (Passkeys) und TOTP sind in Keycloak/Backend/Frontend bereits vollstaendig konfiguriert (siehe `docs/design/05-authentifizierung.md` und `keycloak-provision.ts`). E2E-Tests fuer beide koennen direkt umgesetzt werden. ### TOTP - `e2e/helpers/totp.ts`: `otplib`-Bibliothek, QR-Code-URL aus Keycloak-Account-Console parsen, Secret extrahieren, TOTP-Code generieren - Test: TOTP via AIA (`CONFIGURE_TOTP`) registrieren, Login mit TOTP-Code verifizieren - Benoetigt: `e2e/package.json` + `otplib` ### Passkey (WebAuthn Passwordless) - Playwright Chrome DevTools Protocol: `page.context().newCDPSession(page)` → `WebAuthn.enable` - Virtuellen Authenticator (`type: 'internal'`) erstellen via CDP - Test: Passkey via AIA (`webauthn-register-passwordless`) registrieren, Login per Passkey (Conditional UI, kein PW/OTP) - Nutzt die bestehende Keycloak-Konfiguration (`webAuthnPolicyPasswordlessEnablePasskeys: true`)
Sign in to join this conversation.
No description provided.