import { chromium } from "@playwright/test"; import "dotenv/config"; import { prisma } from "@/lib/db"; import { anmelden, SEED_GERAET, SEED_TAG, SEED_VORLAGE } from "./helfer"; /** * Was vor dem ersten Ablauf stimmen muss (#018). * * Bisher standen die Voraussetzungen als Satz im Kopfkommentar jeder Datei * („Voraussetzung: ein gebauter Stand laeuft und `pnpm beispiel:vorlage` hat * …“). Ein Kommentar prueft nichts. Stimmte etwas davon nicht, fiel das erst * mitten im Lauf auf, und die Meldung sprach von einem Zeitablauf oder von null * Treffern — nie von der Ursache. * * Hier wird es geprueft, einmal, bevor irgendein Ablauf startet. Jede Meldung * sagt, **was** fehlt und **was zu tun ist**. */ const APP_URL = process.env["E2E_APP_URL"] ?? "http://127.0.0.1:3000"; function fehlen(was: string, abhilfe: string): never { throw new Error(`Ende-zu-Ende-Tests: ${was}\n → ${abhilfe}`); } export default async function vorbereiten(): Promise { if (!process.env["SEED_ADMIN_EMAIL"] || !process.env["SEED_ADMIN_PASSWORD"]) { fehlen( "SEED_ADMIN_EMAIL oder SEED_ADMIN_PASSWORD fehlt.", "Beide stehen in der .env und müssen zu dem Administrator passen, den der Seed angelegt hat.", ); } // 1. Laeuft ueberhaupt etwas an dieser Adresse? const antwort = await fetch(`${APP_URL}/api/gesundheit`, { signal: AbortSignal.timeout(5000) }).catch( () => undefined, ); if (!antwort?.ok) { fehlen( `Unter ${APP_URL} antwortet keine Anwendung.`, "Erst bauen und starten: pnpm build && PORT=3300 APP_URL=http://127.0.0.1:3300 pnpm start — " + "und die Adresse über E2E_APP_URL mitgeben. Gegen `pnpm dev` laufen die Abläufe nicht " + "(siehe CLAUDE.md, „Oberfläche prüfen“).", ); } // 2. Steht der Seed-Bestand, mit dem die Ablaeufe arbeiten? const vorlage = await prisma.vorlage.findFirst({ where: { name: SEED_VORLAGE }, select: { id: true, versionen: { where: { status: "VEROEFFENTLICHT" }, select: { id: true } } }, }); if (!vorlage || vorlage.versionen.length === 0) { fehlen( `Die Vorlage „${SEED_VORLAGE}“ fehlt oder ist nicht veröffentlicht.`, "pnpm db:seed laufen lassen.", ); } const geraet = await prisma.geraet.findUnique({ where: { tagCode: SEED_TAG }, select: { id: true } }); if (!geraet) { fehlen(`Das Beispielgerät ${SEED_GERAET} (${SEED_TAG}) fehlt.`, "pnpm db:seed laufen lassen."); } /* * 2b. In welchem Betriebsmodus laeuft die Installation? * * Ein Ablauf soll das nicht selbst aus der Datenbank holen muessen — und zwei * Quellen fuer dieselbe Auskunft liefen frueher oder spaeter auseinander. Der * Modus steht danach in `E2E_BETRIEBSMODUS`, und ein Ablauf, der nur in einem * der beiden Sinn ergibt, ueberspringt sich selbst mit einem Grund. */ const einstellung = await prisma.einstellung.findUnique({ where: { id: "global" }, select: { modus: true }, }); process.env["E2E_BETRIEBSMODUS"] = einstellung?.modus ?? "INTERN"; /* * 3. Liest der Server **dieselbe** Datenbank? * * Der Testprozess schreibt über DATABASE_URL aus der .env, der Server bekommt * seine eigene mit. Zeigen beide woandershin, legt ein Ablauf seine Daten in * die eine und sucht sie in der anderen. Geprüft wird an einer Vorlage, die * hier entsteht und gleich wieder verschwindet. */ const probe = `ZZ Datenbankprüfung ${Date.now()}`; const angelegt = await prisma.vorlage.create({ data: { name: probe, kategorie: "ZZ Test" } }); const browser = await chromium.launch(); try { const tab = await browser.newPage({ baseURL: APP_URL }); await anmelden(tab); await tab.goto(`/vorlagen?suche=${encodeURIComponent(probe)}`); if ((await tab.getByRole("link", { name: probe }).count()) === 0) { fehlen( "Der Server unter Test liest eine andere Datenbank als dieser Lauf.", "DATABASE_URL des Testprozesses (aus der .env) und die des Servers müssen auf dieselbe " + "Datenbank zeigen — sonst schreibt der Ablauf in die eine und sucht in der anderen.", ); } } finally { await browser.close(); await prisma.vorlage.delete({ where: { id: angelegt.id } }); await prisma.$disconnect(); } }