import "dotenv/config"; import { spawnSync } from "node:child_process"; import { PrismaClient } from "@prisma/client"; /** * Die Testwehr zurücksetzen. * * npm run db:test-reset * * Legt einen eigenen Mandanten für die E2E-Tests an — und setzt ihn bei jedem * Aufruf auf den Ausgangsstand zurück. * * **Warum es das gibt.** Bis Phase 8 schrieben die Playwright-Tests in die * Beispielwehr `ff-musterhausen`, also in genau den Bestand, den die Anleitung * zeigt. Nach fünf Phasen standen dort 94 Atemschutz-Überwachungen statt * einer, 49 Geräte statt 45 und Termine mit Namen wie „E2E-Absage-m1x8kq". * Zweimal fielen Tests aus, weil ein gesuchter Eintrag von Seite 1 gerutscht * war — und bei jedem Testlauf unterschieden sich alle 72 Bildschirmfotos. * * **Warum Löschen und nicht Aufräumen.** Ein Lauf, der abbricht, lässt beim * Aufräumen einen Bestand zurück, den niemand erwartet. Ein vollständiger * Neuaufbau ist der einzige Zustand, den man kennt — und er dauert * Sekunden, weil der Seed ohnehin schon alles kann. * * **Die Beispielwehr wird nicht angefasst.** Weder gelesen noch geschrieben: * gelöscht wird ausschließlich der Mandant mit der Testkennung. */ const SLUG = process.env.E2E_SLUG ?? "ff-teststelle"; const NAME = process.env.E2E_NAME ?? "Freiwillige Feuerwehr Teststelle"; const KURZNAME = process.env.E2E_KURZNAME ?? "FF Teststelle"; const EMAIL = process.env.E2E_ADMIN_EMAIL ?? "e2e@teststelle.de"; const PASSWORT = process.env.E2E_ADMIN_PASSWORT ?? "Feuerwehr2026"; /** Die Beispielwehr. Sie darf unter keinen Umständen getroffen werden. */ const GESCHUETZT = process.env.SEED_SLUG ?? "ff-musterhausen"; const prisma = new PrismaClient({ datasources: { db: { url: process.env.DIRECT_DATABASE_URL ?? process.env.DATABASE_URL ?? "" }, }, }); function log(nachricht: string): void { console.info(`[testdaten] ${nachricht}`); } async function main(): Promise { if (SLUG === GESCHUETZT) { throw new Error( `Die Testkennung "${SLUG}" ist dieselbe wie die der Beispielwehr. ` + "Das würde den Bestand löschen, den die Anleitung zeigt — abgebrochen.", ); } const vorhanden = await prisma.organisation.findUnique({ where: { slug: SLUG }, select: { id: true, name: true }, }); if (vorhanden) { log(`Entferne die bisherige Testwehr "${vorhanden.name}" ...`); // Das Audit-Log ist append-only; für das Abräumen einer ganzen Wehr wird // die Ausnahme gesetzt, die auch der Aufbewahrungslauf des Workers // benutzt. Alles Übrige hängt am Fremdschlüssel und geht mit. await prisma.$transaction(async (tx) => { await tx.$executeRaw`SELECT set_config('app.audit_bereinigung', 'an', true)`; // Die Trigger, die Protokollzeilen unveränderlich machen, stehen dem // Löschen im Weg. Im Betrieb passiert das nie — hier wird eine ganze // Wehr entfernt, und zwar eine, die es nur für Tests gibt. for (const tabelle of [ "druckmessung", "atemschutz_ereignis", "ki_vorgang", "kiosk_vorgang", ]) { await tx.$executeRawUnsafe(`ALTER TABLE "${tabelle}" DISABLE TRIGGER USER`); } await tx.organisation.delete({ where: { slug: SLUG } }); for (const tabelle of [ "druckmessung", "atemschutz_ereignis", "ki_vorgang", "kiosk_vorgang", ]) { await tx.$executeRawUnsafe(`ALTER TABLE "${tabelle}" ENABLE TRIGGER USER`); } }); } log(`Lege "${NAME}" neu an ...`); // Der Seed kann das alles schon — er bekommt nur eine andere Kennung. // // Über die Shell aufgerufen, weil `npx` auf Windows eine Batchdatei ist: // ohne `shell: true` findet spawnSync sie nicht und liefert stillschweigend // den Status null statt einer Fehlermeldung. const ergebnis = spawnSync("npx tsx prisma/seed.ts", { stdio: "inherit", shell: true, env: { ...process.env, SEED_SLUG: SLUG, SEED_NAME: NAME, SEED_KURZNAME: KURZNAME, SEED_ADMIN_EMAIL: EMAIL, SEED_ADMIN_PASSWORT: PASSWORT, }, }); if (ergebnis.status !== 0) { throw new Error( `Der Seed ist mit Code ${ergebnis.status ?? "unbekannt"} abgebrochen.` + (ergebnis.error ? ` (${ergebnis.error.message})` : ""), ); } log(""); log("Testwehr steht. Die E2E-Tests melden sich damit an:"); log(` E-Mail: ${EMAIL}`); log(` Passwort: ${PASSWORT}`); log(""); log(`Die Beispielwehr "${GESCHUETZT}" wurde nicht angefasst.`); } main() .catch((fehler) => { console.error("[testdaten] Abbruch:", fehler instanceof Error ? fehler.message : fehler); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });