/* ===================================================================== test-webdesign-verwaltung.mjs — Verwaltungsbereich im echten Browser Prüft vor allem das, was hier wirklich zählt: - ohne Anmeldung sieht man NICHTS - ein erfundenes Token wird abgewiesen - das Sitzungstoken überlebt das Schließen NICHT - mit Anmeldung: Liste, Detail, Status ändern, Notiz, Archivieren Der Verwaltungscode kommt aus der Umgebung, nie aus dieser Datei: WD_ADMIN_CODE=... node test-webdesign-verwaltung.mjs Ohne Code laufen nur die Sicherheitsprüfungen — die sind die wichtigeren. ===================================================================== */ import { chromium } from "playwright"; const BASIS = process.env.WD_BASIS || "http://127.0.0.1:4199"; const ZUGANG = process.env.WD_CODE || "DOGI-TEST-1"; const ADMIN_CODE = process.env.WD_ADMIN_CODE || null; let ok = 0, schlecht = 0; const pruefe = (name, b, zusatz = "") => { if (b) { ok++; console.log(" ok " + name); } else { schlecht++; console.log(" FEHLT " + name + " " + zusatz); } }; const browser = await chromium.launch(); const kontext = await browser.newContext(); const seite = await kontext.newPage(); const konsole = []; seite.on("console", (m) => { if (m.type() !== "error") return; /* Ein abgewiesener Anmeldeversuch erzeugt zwangslaeufig eine Browser-Meldung ueber die 401-Antwort. Das ist das GEWUENSCHTE Verhalten -- wuerde man es als Fehler zaehlen, koennte der Test "falscher Code wird abgewiesen" nie bestehen. */ if (/status of 40[13]/.test(m.text())) return; konsole.push(m.text()); }); seite.on("pageerror", (e) => konsole.push("pageerror: " + e.message)); console.log("\n=== Verwaltungsbereich ===\n"); /* ---------- 1. Die Seite selbst ist hinter der Zugangswand ---------- */ console.log("1. Doppelter Schutz"); { const frisch = await browser.newContext(); const p = await frisch.newPage(); await p.goto(BASIS + "/webdesign/verwaltung.html", { waitUntil: "networkidle" }); pruefe("ohne Zugangscode gar nicht erreichbar", p.url().includes("zugang.html"), "-> die Verwaltung steckt hinter ZWEI Türen"); await frisch.close(); } // Ab hier: durch die Zugangswand, aber noch nicht in der Verwaltung angemeldet. await seite.goto(BASIS + "/webdesign/zugang.html", { waitUntil: "networkidle" }); await seite.fill("#zg-code-dogfather", ZUGANG); await Promise.all([ seite.waitForURL((u) => !u.pathname.endsWith("zugang.html"), { timeout: 15000 }), seite.click("#zg-form-dogfather button[type=submit]"), ]); console.log("\n2. Anmeldung der Verwaltung"); await seite.goto(BASIS + "/webdesign/verwaltung.html", { waitUntil: "networkidle" }); await seite.waitForTimeout(500); pruefe("Anmeldemaske erscheint", await seite.locator("#vw-anmeldung").isVisible()); pruefe("Arbeitsbereich bleibt verborgen", !(await seite.locator("#vw-bereich").isVisible())); pruefe("keine Anfragedaten im Quelltext", !(await seite.content()).includes("A-2608"), "-> ohne Anmeldung darf nichts durchsickern"); await seite.click("#vw-login-form button[type=submit]"); await seite.waitForTimeout(400); pruefe("leerer Code wird bemaengelt", (await seite.locator("#vw-feld-code.wd-feld--fehler").count()) > 0); await seite.fill("#vw-code", "garantiert-falscher-code"); await seite.click("#vw-login-form button[type=submit]"); /* Auf die Fehlermarkierung WARTEN statt fest zu schlafen: der Aufruf geht an den echten Server, und eine feste Wartezeit ist entweder zu kurz (Fehlalarm) oder unnoetig lang. */ const abgewiesen = await seite.locator("#vw-feld-code.wd-feld--fehler") .waitFor({ state: "attached", timeout: 15000 }).then(() => true).catch(() => false); pruefe("falscher Code wird abgewiesen", abgewiesen, abgewiesen ? "" : "Meldung: " + (await seite.locator("#vw-feld-code .wd-feld-fehler").textContent().catch(() => ""))); pruefe("bleibt auf der Anmeldemaske", await seite.locator("#vw-anmeldung").isVisible()); /* ---------- 3. Erfundenes Token ---------- */ console.log("\n3. Erfundenes Sitzungstoken"); await seite.evaluate(() => sessionStorage.setItem("wd-vw-token", "voellig-erfunden-1234")); await seite.reload({ waitUntil: "networkidle" }); await seite.waitForTimeout(2500); pruefe("erfundenes Token fuehrt zurueck zur Anmeldung", await seite.locator("#vw-anmeldung").isVisible(), "-> und nicht zu einer leeren Liste, die wie 'keine Anfragen' aussieht"); /* ---------- 4. Token verschwindet beim Schliessen ---------- */ console.log("\n4. Sitzung endet beim Schliessen"); { const speicherArt = await seite.evaluate(() => { sessionStorage.setItem("wd-vw-token", "test"); const inSession = sessionStorage.getItem("wd-vw-token") !== null; const inLocal = localStorage.getItem("wd-vw-token") !== null; sessionStorage.removeItem("wd-vw-token"); return { inSession, inLocal }; }); pruefe("Token liegt im Sitzungsspeicher, nicht dauerhaft", speicherArt.inSession && !speicherArt.inLocal, "-> sonst bliebe die Verwaltung nach dem Schliessen offen"); } /* ---------- 5. Mit echtem Zugang ---------- */ if (!ADMIN_CODE) { console.log("\n5. Angemeldeter Durchlauf"); console.log(" (uebersprungen -- WD_ADMIN_CODE nicht gesetzt)"); } else { console.log("\n5. Angemeldeter Durchlauf"); await seite.evaluate(() => sessionStorage.removeItem("wd-vw-token")); await seite.reload({ waitUntil: "networkidle" }); await seite.fill("#vw-code", ADMIN_CODE); await seite.click("#vw-login-form button[type=submit]"); await seite.waitForTimeout(3500); const drin = await seite.locator("#vw-bereich").isVisible(); pruefe("Anmeldung erfolgreich", drin, drin ? "" : (await seite.locator("#vw-feld-code .wd-feld-fehler").textContent().catch(() => ""))); if (drin) { pruefe("Kennzahlen werden angezeigt", (await seite.locator("#vw-zahlen .vw-zahl").count()) === 5); pruefe("Filterleiste ist da", (await seite.locator("#vw-filter .vw-filter-knopf").count()) >= 8); const anzahl = await seite.locator(".vw-karte").count(); console.log(" -> " + anzahl + " Anfragen in der Liste"); pruefe("Anfragen werden gelistet", anzahl > 0); if (anzahl > 0) { await seite.locator(".vw-karte").first().click(); await seite.waitForTimeout(2000); pruefe("Detailansicht oeffnet", await seite.locator("#vw-detail.vw-auf").isVisible()); const text = await seite.locator("#vw-detail-blatt").textContent(); pruefe("zeigt die Anfragenummer", /A-\d{4}-\d{4}/.test(text)); pruefe("zeigt Kontakt und Vorhaben", text.includes("Kontakt") && text.includes("Vorhaben")); pruefe("bietet Statuswechsel an", (await seite.locator("[data-neuer-status]").count()) === 7); pruefe("hat ein Notizfeld", await seite.locator("#vw-neue-notiz").isVisible()); pruefe("Archivieren erklaert, dass nichts geloescht wird", text.includes("löscht nichts") || text.includes("loescht nichts")); await seite.keyboard.press("Escape"); await seite.waitForTimeout(400); pruefe("Escape schliesst die Detailansicht", !(await seite.locator("#vw-detail.vw-auf").isVisible())); } // Suche await seite.fill("#vw-suche", "zzz-gibt-es-nicht"); await seite.waitForTimeout(400); pruefe("Suche ohne Treffer meldet das verstaendlich", (await seite.locator("#vw-liste").textContent()).includes("Filter")); await seite.fill("#vw-suche", ""); await seite.waitForTimeout(300); // Abmelden await seite.click("#vw-abmelden"); await seite.waitForTimeout(2500); pruefe("Abmelden fuehrt zurueck zur Anmeldung", await seite.locator("#vw-anmeldung").isVisible()); pruefe("Token ist nach dem Abmelden weg", (await seite.evaluate(() => sessionStorage.getItem("wd-vw-token"))) === null); } } await browser.close(); console.log(konsole.length ? "\nKONSOLENFEHLER:\n" + [...new Set(konsole)].join("\n") : "\nKeine Konsolenfehler."); console.log(`\n=== ${ok} bestanden, ${schlecht} gescheitert ===\n`); process.exit(schlecht === 0 && konsole.length === 0 ? 0 : 1);