test: Integrations-, Migrations- und E2E-Tests ergänzen

Der Integrationstest prüft gegen eine echte Datenbank, was Vitest nicht
sieht: Eindeutigkeit, Fremdschlüssel, Kaskaden und dass das Protokoll den
gelöschten Benutzer überlebt. Er läuft bewusst ohne umschließende
Transaktion — er prüft absichtlich Fälle, die scheitern müssen, und ein
gescheiterter Befehl bricht in PostgreSQL die ganze Transaktion ab.
Stattdessen tragen alle Testdaten dieselbe Kennung und werden am Ende
wieder entfernt.

Der Migrationstest legt eine Wegwerf-Datenbank an, spielt alle
Migrationen ein und vergleicht das Ergebnis mit dem Schema. Dass er
Abweichungen wirklich bemerkt, wurde mit einem probeweise ergänzten Feld
nachgewiesen.

Der E2E-Rauchtest deckt den Weg ab, der in M1 trägt: Umleitung ohne
Anmeldung samt gemerktem Ziel, Abweisung falscher Zugangsdaten,
erfolgreiche Anmeldung und die Verwaltungsseite.

Dafür neu: eine Middleware, die nur den angefragten Pfad als Kopfzeile
durchreicht. Ein Layout kennt seinen Pfad nicht, braucht ihn aber für die
Rückkehr nach der Anmeldung. Anmeldelogik steht dort bewusst nicht — die
Middleware läuft im Edge-Umfeld ohne Prisma.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-09-10 13:10:54 +02:00
co-authored by Claude Opus 5
parent 24a799d6ba
commit 126ad93301
7 changed files with 495 additions and 2 deletions
+46
View File
@@ -0,0 +1,46 @@
import { defineConfig, devices } from '@playwright/test'
import 'dotenv/config'
const PORT = Number(process.env.E2E_PORT ?? 3100)
const BASIS = `http://127.0.0.1:${PORT}`
/**
* E2E-Tests gegen eine echte, gebaute Anwendung.
*
* Der Testserver läuft auf einem eigenen Port, damit er einer laufenden
* Entwicklungsinstanz nicht in die Quere kommt. Die Datenbank ist dieselbe wie
* im Entwicklungsbetrieb – die Tests legen nur Daten mit eigenem Präfix an und
* räumen hinter sich auf.
*/
export default defineConfig({
testDir: './e2e',
fullyParallel: false,
forbidOnly: Boolean(process.env.CI),
retries: process.env.CI ? 1 : 0,
workers: 1,
reporter: process.env.CI ? 'github' : 'list',
timeout: 30_000,
use: {
baseURL: BASIS,
locale: 'de-DE',
timezoneId: 'Europe/Berlin',
trace: 'retain-on-failure',
screenshot: 'only-on-failure',
},
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
webServer: {
command: 'npm run start',
url: `${BASIS}/api/health`,
reuseExistingServer: !process.env.CI,
timeout: 120_000,
env: {
PORT: String(PORT),
APP_URL: BASIS,
WEBAUTHN_ORIGIN: BASIS,
WEBAUTHN_RP_ID: '127.0.0.1',
},
},
})