/* =================================================================== pruef-wahl-scrollen.mjs — die Namensliste bleibt beim Scrollen offen. ANLASS (Filipe, 04.09.2026, mit Bildschirmfoto der Personenauswahl): "wenn ich da scollen will geht das immer zu" Er hatte recht, und die Ursache war eine einzige Stelle in assets/js/wahl.js: addEventListener('scroll', schliessen, true); Das dritte Argument bedeutet "in der Einfangphase lauschen" -- und damit auf JEDES Scroll-Ereignis im ganzen Dokument, auch auf das in der Liste selbst. Wer die Namensliste herunterrollen wollte, schloss sie im selben Moment. Bei acht Eintraegen faellt das kaum auf; beim ganzen Manager- und Scout-Team ist die Liste unbedienbar. Zumachen MUSS sie trotzdem, wenn die Seite scrollt: Sie haengt an position:fixed und schwaemme sonst neben ihrem Knopf davon. Deshalb pruefen hier beide Haelften -- eine Reparatur, die nur die eine Richtung sichert, waere die naechste Ueberraschung: scrollt die LISTE -> bleibt offen scrollt die SEITE -> geht zu Geprueft wird im echten Browser am ECHTEN wahl.js und gate.css, nicht an einer Nachbildung. Eine Nachbildung haette genau die Zeile nicht gehabt, um die es geht. Aufruf: node pruef-wahl-scrollen.mjs =================================================================== */ import { chromium } from "playwright"; import { readFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; const HIER = dirname(fileURLToPath(import.meta.url)); const JS = join(HIER, "workspace", "assets", "js", "wahl.js"); /* ALLE Stylesheets, die eine Arbeitsplatz-Seite laedt -- nicht nur gate.css. Beim ersten Lauf war nur gate.css eingebunden: Die Eintraege bekamen dadurch weder Schriftgroesse noch Innenabstand, 30 Namen waren zusammen 243 Pixel hoch, und die Liste konnte gar nicht scrollen. Die Pruefung hat das gemeldet, statt gruen zu behaupten, sie haette das Scrollen geprueft. */ const CSS_DATEIEN = ["gate.css", "start.css", "aufgaben.css"] .map((n) => join(HIER, "workspace", "assets", "css", n)); let gut = 0; const schlecht = []; const pruefe = (name, bedingung, zusatz = "") => { if (bedingung) { gut++; console.log(" ok " + name); } else { schlecht.push(name); console.log(" FEHLER " + name + (zusatz ? " — " + zusatz : "")); } }; /* Genug Eintraege, damit die Liste ueberhaupt scrollen KANN -- mit fuenf Namen gaebe es nichts zu rollen, und die Pruefung waere gruen, ohne etwas gemessen zu haben. Die Namen sind die aus Filipes Bild. */ const NAMEN = [ "Dogfather (admin)", "VanVan (admin)", "Cigdem (manager)", "Drouwn (manager)", "Schulle (manager)", "BananaStift (scout)", "Patrick (scout)", "Tili (scout)", ...Array.from({ length: 22 }, (_, i) => `Weitere Person ${i + 9} (scout)`), ]; const browser = await chromium.launch(); /* Ein NIEDRIGES Fenster, wie auf Filipes Bildschirmfoto. Beim ersten Lauf stand hier 700 Pixel Hoehe -- da passte die ganze Liste hinein, es gab nichts zu scrollen, und "bleibt beim Scrollen offen" waere eine leere Aussage gewesen. Die Pruefung hat das selbst gemeldet, statt gruen zu behaupten, was sie nicht gemessen hatte. */ const seite = await browser.newPage({ viewport: { width: 1280, height: 420 } }); /* Die Seite ist absichtlich hoch: Ohne Scrollweg liesse sich die zweite Haelfte ("die Seite scrollt -> Liste geht zu") gar nicht pruefen. */ await seite.setContent(`
`); for (const datei of CSS_DATEIEN) await seite.addStyleTag({ content: readFileSync(datei, "utf8") }); await seite.addScriptTag({ content: readFileSync(JS, "utf8") }); await seite.waitForTimeout(150); console.log("\n--- Die Liste laesst sich ueberhaupt oeffnen ---"); const knopf = seite.locator(".wahl2__knopf").first(); pruefe("Das Auswahlfeld wurde eingepackt", await knopf.count() > 0); await knopf.click(); await seite.waitForTimeout(120); const liste = seite.locator(".wahl2__liste").first(); pruefe("Die Liste ist offen", await liste.count() > 0); /* DIE LISTE MUSS SCROLLEN KOENNEN, sonst ist alles Weitere wertlos: Eine Liste, die gar nicht rollt, bleibt beim Scrollen selbstverstaendlich offen. Die Hoehe wird hier ausdruecklich klein gesetzt, statt sie aus dem Seitenaufbau entstehen zu lassen. Grund: Geaendert wurde die JavaScript-Logik (welches Scrollen schliesst die Liste), nicht die Gestaltung. Ein Aufbau, der erst die echte Schriftgroesse, Zeilenhoehe und Fensterhoehe nachbaut, prueft am Ende die Stylesheets -- und beim ersten Versuch genau daran vorbei: 30 Namen waren zusammen 243 Pixel hoch, es gab nichts zu rollen, und die Pruefung hat das gemeldet, statt gruen zu behaupten, sie haette gescrollt. Wie gross die Liste im Betrieb wird, entscheidet gate.css (max-height aus dem Platz unter dem Knopf) -- das ist eine andere Frage als diese hier. */ await liste.evaluate((el) => { el.style.maxHeight = "150px"; }); await seite.waitForTimeout(80); const scrollbar = await liste.evaluate((el) => el.scrollHeight > el.clientHeight + 4); pruefe("Und sie ist laenger als ihr Fenster — es gibt wirklich etwas zu scrollen", scrollbar); console.log("\n--- DER FALL: in der Liste scrollen ---"); /* Gerollt wird ueber scrollTop, nicht ueber das Mausrad. Grund: Beim ersten Versuch stand hier hover() + mouse.wheel() -- die Liste blieb offen, aber scrollTop war 0. Das Rad hatte gar nichts bewegt, es war also nie ein Scroll-Ereignis unterwegs, und "bleibt offen" haette nichts bewiesen. Eine Zuweisung an scrollTop loest dasselbe Ereignis aus wie das Rad, nur zuverlaessig. */ await liste.evaluate((el) => { el.scrollTop = 60; }); await seite.waitForTimeout(200); pruefe("Die Liste ist nach dem Scrollen NOCH OFFEN", await seite.locator(".wahl2__liste").count() > 0); const versatz = await seite.locator(".wahl2__liste").first() .evaluate((el) => el.scrollTop).catch(() => 0); pruefe("Und sie ist wirklich gerollt — nicht nur stehen geblieben", versatz > 0, `scrollTop = ${versatz}`); console.log("\n--- GEGENPROBE: die SEITE scrollen ---"); /* Die andere Haelfte der Zusage. Ohne sie waere "bleibt offen" auch mit einem ersatzlos entfernten Zuhoerer gruen -- und die Liste stuende beim Scrollen der Seite irgendwo im Nichts. */ await seite.mouse.move(20, 20); await seite.mouse.wheel(0, 400); await seite.waitForTimeout(200); pruefe("Beim Scrollen der Seite geht sie zu", await seite.locator(".wahl2__liste").count() === 0); console.log("\n--- Und danach laesst sie sich wieder oeffnen ---"); await seite.evaluate(() => window.scrollTo(0, 0)); await seite.waitForTimeout(100); await seite.locator(".wahl2__knopf").first().click(); await seite.waitForTimeout(120); pruefe("Erneutes Oeffnen geht", await seite.locator(".wahl2__liste").count() > 0); await browser.close(); console.log(""); console.log("=".repeat(60)); if (schlecht.length === 0) console.log(`Alle ${gut} Pruefungen bestanden.`); else { console.log(`${gut} bestanden, ${schlecht.length} fehlgeschlagen:`); schlecht.forEach((s) => console.log(" - " + s)); } process.exit(schlecht.length ? 1 : 0);