import { expect, test, type Page } from "@playwright/test"; import "dotenv/config"; import { prisma } from "@/lib/db"; /** * Admin → Verzeichnis durch die Oberflaeche (#016). * * Ohne LDAP-Container: geprueft wird, was auch ohne Verzeichnis gilt — dass die * Attributzuordnung bedienbar ist, dass eine krumme Eingabe abgewiesen wird und * dass eine gute wirklich in der Datenbank landet. Was der Abgleich **tut**, * steht in `tests/abgleich.test.ts` gegen einen echten Server. * * Voraussetzung: ein **gebauter** Stand laeuft (`pnpm build && pnpm start`). * Im Entwicklungsmodus haengt React sich hier nicht an, und dann tut kein Knopf * etwas (siehe CLAUDE.md, „Oberflaeche pruefen“). */ async function anmelden(seite: Page) { const email = process.env["SEED_ADMIN_EMAIL"]; const passwort = process.env["SEED_ADMIN_PASSWORD"]; if (!email || !passwort) throw new Error("SEED_ADMIN_EMAIL und SEED_ADMIN_PASSWORD fehlen."); await seite.goto("/anmelden"); await seite.fill('input[name="email"]', email); await seite.fill('input[name="passwort"]', passwort); await Promise.all([seite.waitForURL("**/"), seite.click('button[type="submit"]')]); } test.describe("Verzeichnis", () => { test("macht die Attributzuordnung bedienbar und prüft sie", async ({ page }) => { test.slow(); const quelle = await prisma.verzeichnisquelle.findFirst({ orderBy: { name: "asc" } }); test.skip(quelle === null, "Keine Verzeichnisquelle im Bestand."); if (!quelle) return; const vorher = quelle.attributZuordnung; await anmelden(page); await page.goto("/admin/verzeichnis"); await page.locator("summary", { hasText: "Einstellungen bearbeiten" }).first().click(); await page.locator("summary", { hasText: "Attributzuordnung anpassen" }).first().click(); const kennung = page.locator('input[name="attr.externeId"]').first(); await expect(kennung).toBeVisible(); await expect(kennung).toHaveValue("objectGUID"); // Eine Klammer darf nicht in eine LDAP-Anfrage wandern. const titel = page.locator('input[name="attr.titel"]').first(); await titel.fill("(objectClass=*)"); await page.getByRole("button", { name: "Speichern" }).first().click(); await expect(page.locator('[role="alert"]').first()).toContainText("kein Attributname"); // Und eine gute Eingabe steht danach wirklich in der Datenbank. await titel.fill("personalTitle"); await page.getByRole("button", { name: "Speichern" }).first().click(); await expect(page.locator('[role="status"]').last()).toContainText("gespeichert"); const nachher = await prisma.verzeichnisquelle.findUniqueOrThrow({ where: { id: quelle.id } }); expect((nachher.attributZuordnung as Record)["titel"]).toBe("personalTitle"); // Neu geladen steht sie auch im Formular – sonst waere sie nur gespeichert, // aber nicht bearbeitbar. await page.reload(); await page.locator("summary", { hasText: "Einstellungen bearbeiten" }).first().click(); await page.locator("summary", { hasText: "Attributzuordnung anpassen" }).first().click(); await expect(page.locator('input[name="attr.titel"]').first()).toHaveValue("personalTitle"); await prisma.verzeichnisquelle.update({ where: { id: quelle.id }, data: { attributZuordnung: vorher === null ? {} : vorher }, }); }); test("zeigt das Abgleich-Log und trägt am Handy ohne horizontales Scrollen", async ({ page }) => { await anmelden(page); await page.goto("/admin/verzeichnis"); const log = page.locator("summary", { hasText: "Abgleich-Log" }).first(); if ((await log.count()) > 0) { await log.click(); await expect(page.locator("details", { has: log })).toBeVisible(); } const masse = await page.evaluate(() => ({ scroll: document.documentElement.scrollWidth, sichtbar: document.documentElement.clientWidth, })); expect(masse.scroll).toBeLessThanOrEqual(masse.sichtbar); }); });