/* ===================================================================== test-webdesign-formular.mjs — Anfrageformular im echten Browser Spielt das Formular so durch, wie ein Mensch es tut, und prüft die Dinge, die man beim Klicken NICHT sieht: - Pflichtfelder blockieren das Weitergehen - Folgefragen erscheinen nur passend zur Auswahl - Eingaben überleben das Schließen des Tabs - die Zusammenfassung zeigt wirklich das Eingegebene - Absenden erzeugt eine echte Anfragenummer Standardmäßig wird NICHT abgeschickt (sonst entsteht bei jedem Lauf ein Datensatz in der echten Datenbank). Mit --senden wird einmal wirklich abgeschickt: node test-webdesign-formular.mjs --senden ===================================================================== */ import { chromium } from "playwright"; const BASIS = "http://127.0.0.1:4199"; const CODE = "DOGI-TEST-1"; const WIRKLICH_SENDEN = process.argv.includes("--senden"); 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") konsole.push(m.text()); }); seite.on("pageerror", (e) => konsole.push("pageerror: " + e.message)); async function anmelden(p) { await p.goto(BASIS + "/webdesign/zugang.html", { waitUntil: "networkidle" }); await p.fill("#zg-code-dogfather", CODE); await Promise.all([ p.waitForURL((u) => !u.pathname.endsWith("zugang.html"), { timeout: 15000 }), p.click("#zg-form-dogfather button[type=submit]"), ]); } console.log("\n=== Anfrageformular im Browser ===\n"); await anmelden(seite); /* ---------- 1. Aufbau ---------- */ console.log("1. Aufbau"); await seite.goto(BASIS + "/webdesign/anfrage.html", { waitUntil: "networkidle" }); await seite.waitForTimeout(400); pruefe("Schritt 1 ist sichtbar", await seite.locator('[data-seite="1"]').isVisible()); pruefe("Schritt 2 ist verborgen", !(await seite.locator('[data-seite="2"]').isVisible())); pruefe("Zaehler zeigt Schritt 1 von 4", (await seite.locator("#af-zaehler").textContent()).includes("1")); pruefe("Zurueck ist auf Schritt 1 ausgeblendet", !(await seite.locator("#af-zurueck").isVisible())); pruefe("Tabelle 'Was hast du schon' wurde gebaut", (await seite.locator("#af-vorhanden tr").count()) === 4); /* ---------- 2. Pflichtfelder ---------- */ console.log("\n2. Pflichtfelder blockieren"); await seite.click("#af-weiter"); await seite.waitForTimeout(400); pruefe("bleibt auf Schritt 1", await seite.locator('[data-seite="1"]').isVisible()); pruefe("Paket wird bemaengelt", await seite.locator("#feld-paket.wd-feld--fehler").count() > 0); pruefe("Ziel wird bemaengelt", await seite.locator("#feld-ziel.wd-feld--fehler").count() > 0); pruefe("Sammelmeldung erscheint", await seite.locator("#af-meldung").isVisible()); /* ---------- 3. Vorauswahl per Adresszeile ---------- */ console.log("\n3. Vorauswahl ueber ?paket="); await seite.goto(BASIS + "/webdesign/anfrage.html?paket=shop", { waitUntil: "networkidle" }); await seite.waitForTimeout(400); pruefe("Paket 'shop' ist vorausgewaehlt", await seite.locator('[name="paket"][value="shop"]').isChecked()); /* ---------- 4. Durchlauf ---------- */ console.log("\n4. Durchlauf"); await seite.fill("#af-ziel", "Wir wollen unsere Haekelwerke endlich online verkaufen."); await seite.fill("#af-zielgruppe", "Bastelfans, 25-55 Jahre"); await seite.click("#af-weiter"); await seite.waitForTimeout(500); pruefe("Schritt 2 erreicht", await seite.locator('[data-seite="2"]').isVisible()); pruefe("Shop-Folgefragen erscheinen bei Paket 'shop'", await seite.locator("#af-folge-shop").isVisible(), "-> Masterplan S.10 'Intelligente Felder'"); pruefe("Verwaltungs-Folgefragen bleiben verborgen", !(await seite.locator("#af-folge-verwaltung").isVisible())); await seite.fill("#af-shop-anzahl", "40"); await seite.check('[name="funktionen"][value="galerie"]'); await seite.check('[name="funktionen"][value="login"]'); await seite.waitForTimeout(300); pruefe("Verwaltungs-Folgefragen erscheinen nach 'Kundenbereich'", await seite.locator("#af-folge-verwaltung").isVisible()); await seite.click("#af-weiter"); await seite.waitForTimeout(500); pruefe("Schritt 3 erreicht", await seite.locator('[data-seite="3"]').isVisible()); await seite.check('[name="v_texte"][value="teilweise"]'); await seite.check('[name="v_bilder"][value="ja"]'); await seite.check('[name="v_logo"][value="nein"]'); await seite.check('[name="v_domain"][value="ja"]'); await seite.selectOption("#af-budget", "1000-2500"); await seite.fill("#af-termin", "moeglichst im Oktober"); await seite.click("#af-weiter"); await seite.waitForTimeout(500); pruefe("Schritt 4 erreicht", await seite.locator('[data-seite="4"]').isVisible()); pruefe("Knopf heisst jetzt 'Angaben pruefen'", /pr[üu]fen/i.test(await seite.locator("#af-weiter").textContent())); /* ---------- 5. Telefonpflicht ---------- */ console.log("\n5. Telefon wird Pflicht bei 'Per Telefon'"); await seite.fill("#af-name", "Testfirma Meier"); await seite.fill("#af-email", "meier@example.com"); await seite.check('[name="kontaktweg"][value="telefon"]'); await seite.check("#af-datenschutz"); await seite.click("#af-weiter"); await seite.waitForTimeout(400); pruefe("ohne Nummer wird blockiert", await seite.locator("#feld-telefon.wd-feld--fehler").count() > 0, "-> sonst ein Wunsch, der gar nicht erfuellbar ist"); await seite.check('[name="kontaktweg"][value="email"]'); /* ---------- 6. Datenschutz ---------- */ await seite.uncheck("#af-datenschutz"); await seite.click("#af-weiter"); await seite.waitForTimeout(400); pruefe("ohne Datenschutz-Zustimmung wird blockiert", await seite.locator("#feld-datenschutz.wd-feld--fehler").count() > 0); await seite.check("#af-datenschutz"); await seite.fill("#af-bemerkung", "Bitte moeglichst bald melden."); /* ---------- 7. Zusammenfassung ---------- */ console.log("\n6. Zusammenfassung"); await seite.click("#af-weiter"); await seite.waitForTimeout(600); pruefe("Zusammenfassung erreicht", await seite.locator('[data-seite="5"]').isVisible()); const zusText = await seite.locator("#af-zusammenfassung").textContent(); pruefe("zeigt das eingegebene Ziel", zusText.includes("Haekelwerke")); pruefe("zeigt Name und E-Mail", zusText.includes("Testfirma Meier") && zusText.includes("meier@example.com")); pruefe("zeigt angekreuzte Funktionen", /Galerie|galerie/i.test(zusText)); pruefe("zeigt die Shop-Folgefrage", zusText.includes("40")); pruefe("leere Felder als 'keine Angabe'", /keine Angabe/i.test(zusText)); pruefe("Knopf heisst jetzt 'Anfrage absenden'", /absenden/i.test(await seite.locator("#af-weiter").textContent())); pruefe("jeder Block hat einen Aendern-Knopf", (await seite.locator("#af-zusammenfassung [data-zu]").count()) === 4); await seite.locator('[data-zu="1"]').click(); await seite.waitForTimeout(400); pruefe("'Aendern' springt zum richtigen Schritt", await seite.locator('[data-seite="1"]').isVisible()); pruefe("Eingaben sind dabei erhalten", (await seite.inputValue("#af-ziel")).includes("Haekelwerke")); /* ---------- 8. Zwischenspeicherung ---------- */ console.log("\n7. Zwischenspeicherung"); const neuerTab = await kontext.newPage(); await anmelden(neuerTab); await neuerTab.goto(BASIS + "/webdesign/anfrage.html", { waitUntil: "networkidle" }); await neuerTab.waitForTimeout(600); pruefe("Hinweis auf wiederhergestellte Eingaben erscheint", await neuerTab.locator("#af-wieder").isVisible()); pruefe("Ziel wurde wiederhergestellt", (await neuerTab.inputValue("#af-ziel")).includes("Haekelwerke")); pruefe("Name wurde wiederhergestellt", (await neuerTab.inputValue("#af-name")) === "Testfirma Meier"); pruefe("Paketwahl wurde wiederhergestellt", await neuerTab.locator('[name="paket"][value="shop"]').isChecked()); await neuerTab.click("#af-verwerfen"); await neuerTab.waitForTimeout(600); pruefe("'Neu anfangen' leert das Formular", (await neuerTab.inputValue("#af-ziel")) === ""); await neuerTab.close(); /* ---------- 9. Absenden ---------- */ console.log("\n8. Absenden"); if (!WIRKLICH_SENDEN) { console.log(" (uebersprungen -- mit --senden wird wirklich abgeschickt)"); } else { await seite.goto(BASIS + "/webdesign/anfrage.html", { waitUntil: "networkidle" }); /* Der Server weist Absendungen unter 3 Sekunden als vermutlich automatisch ab (Spamschutz, siehe routes/webdesign-anfragen.js). Ein Testlauf ist naturgemaess schneller als ein Mensch -- ohne diese Wartezeit prueft der Test versehentlich den Spamschutz statt des Formulars. Genau so beim ersten Lauf passiert. */ await seite.waitForTimeout(3500); await seite.check('[name="paket"][value="onepager"]'); await seite.fill("#af-ziel", "TESTANFRAGE aus dem Selbsttest - bitte archivieren."); await seite.click("#af-weiter"); await seite.waitForTimeout(400); await seite.click("#af-weiter"); await seite.waitForTimeout(400); await seite.click("#af-weiter"); await seite.waitForTimeout(400); await seite.fill("#af-name", "Selbsttest"); await seite.fill("#af-email", "selbsttest@example.com"); await seite.check("#af-datenschutz"); await seite.click("#af-weiter"); await seite.waitForTimeout(600); await seite.click("#af-weiter"); await seite.waitForTimeout(6000); const aufDanke = await seite.locator('[data-seite="6"]').isVisible(); pruefe("Dankeseite erscheint", aufDanke, aufDanke ? "" : "Meldung: " + (await seite.locator("#af-meldung").textContent().catch(() => ""))); if (aufDanke) { const nummer = (await seite.locator("#af-nummer").textContent()).trim(); pruefe("echte Anfragenummer im Format A-JJMM-0001", /^A-\d{4}-\d{4}$/.test(nummer), nummer); console.log(" -> Nummer: " + nummer); pruefe("Entwurf wurde nach Erfolg geloescht", (await seite.evaluate(() => localStorage.getItem("wd-anfrage-entwurf"))) === null); pruefe("Schrittanzeige ist auf der Dankeseite weg", !(await seite.locator("#af-fortschritt").isVisible())); } } 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);