diff --git a/server/mess-anleitung-crew.mjs b/server/mess-anleitung-crew.mjs index d1fc0552..b7cec7da 100644 --- a/server/mess-anleitung-crew.mjs +++ b/server/mess-anleitung-crew.mjs @@ -239,6 +239,47 @@ for (const [rolle, wie] of ROLLEN) { console.log(` Browsermeldungen : ${klagen.length ? klagen.join(" | ") : "keine"}`); console.log(` Fehlgeschlagen : ${schlecht.length ? schlecht.slice(0, 6).join(" | ") : "nichts"}`); + /* ==== DER RUNDGANG BEIM ERSTEN ANMELDEN (Bauplan Kapitel 10) ==== + + Er ist selbstanpassend gebaut ("Wird ein Ziel nicht gefunden, + faellt der Schritt weg") -- daraus sollen sich die drei Schritte + der Community und die fuenf der Teamrollen von selbst ergeben. + Geglaubt wird das nicht, es wird gezaehlt. */ + const start = await kontext.newPage(); + await start.goto(`https://${CREW}:${HP}/workspace/start.html`, + { waitUntil: "networkidle" }); + await start.waitForTimeout(1800); + const gruss = await start.evaluate(() => { + const g = document.querySelector(".rg-gruss"); + return { da: !!g, text: (g?.textContent || "").replace(/\s+/g, " ").trim().slice(0, 70) }; + }); + let stationen = 0; + if (gruss.da) { + await start.evaluate(() => { + const k = [...document.querySelectorAll(".rg-gruss button")] + .find((b) => /Los/i.test(b.textContent || "")); + k?.click(); + }); + await start.waitForTimeout(700); + /* Durchklicken und zaehlen, wie viele Stationen es wirklich gibt. */ + for (let i = 0; i < 9; i++) { + const da = await start.evaluate(() => !!document.querySelector(".rg__kasten")); + if (!da) break; + stationen++; + const weiter = await start.evaluate(() => { + const b = [...document.querySelectorAll(".rg__knoepfe button")] + .find((x) => /Weiter|Fertig|Los/i.test(x.textContent || "")); + if (!b) return false; + b.click(); return true; + }); + if (!weiter) break; + await start.waitForTimeout(400); + } + } + console.log(` Begruessung : ${gruss.da} "${gruss.text}"`); + console.log(` Stationen gezaehlt : ${stationen}`); + await start.close(); + await seite.screenshot({ path: new URL("./" + datei, import.meta.url).pathname .replace(/^\/([A-Za-z]:)/, "$1"), fullPage: true }); await kontext.close(); diff --git a/server/pruef-anleitung.mjs b/server/pruef-anleitung.mjs index 465149db..521348b7 100644 --- a/server/pruef-anleitung.mjs +++ b/server/pruef-anleitung.mjs @@ -890,6 +890,85 @@ ok(eDogi.code === 200 && eDogi.j?.zeigen === false, d5.close(); } +/* ===================================================================== + DREI SCHRITTE FUER DIE COMMUNITY, FUENF FUERS TEAM + --------------------------------------------------------------------- + Bauplan Kapitel 10: "Community drei Schritte ... Team-Rollen fuenf + Schritte (zusaetzlich 'Deine Aufgaben' und die Gruppen ...)". + + Gemessen wird das in ZWEI Haelften, weil die Entscheidung an zwei + Stellen liegt: + + 1. Der Server sagt Ja/Nein ("team"). Das ist die Stelle, an der + die Rolle vorkommt -- `rundgang.js` kennt absichtlich keinen + einzigen Rollennamen, sonst muesste jede neue Rolle dort + nachgetragen werden und waere sonst stillschweigend Team. + 2. Der Browser siebt damit die Stationen. + + Die zweite Haelfte wird hier NICHT nachgebildet, sondern + AUSGEFUEHRT: Stationsliste und Siebausdruck werden aus der echten + Datei geholt und laufen zweimal -- einmal mit team=true, einmal mit + team=false. Ein Muster ("steht da istTeam?") waere gruen, sobald das + Wort irgendwo in einem Kommentar steht; der Ausdruck selbst kann + nicht luegen. Und der zweite Lauf ist gleich die Gegenprobe: Faellt + das Sieb weg, kommen beide Male fuenf heraus, und beide Zeilen + schlagen an. */ +melde("\n=== Rundgang: drei Schritte / fuenf Schritte ==="); +{ + const erwartet = { gast: false, modi: true, linke: true, hand: true }; + for (const [rolle, soll] of Object.entries(erwartet)) { + const e = await einweisung(rolle, CREW_HOST); + ok(e.j?.team === soll, + `${rolle}: Server meldet team=${soll} (bekommen ${e.j?.team})`); + } + /* Das Agenturhaus arbeitet -- dort ist jede Rolle eine Teamrolle. + Diese Zeile ist die Gegenrichtung zum Gast: Sie beweist, dass das + Feld nicht einfach immer dasselbe antwortet. */ + const eCre = await einweisung("creator"); + ok(eCre.j?.team === true, `creator: Server meldet team=true (${eCre.j?.team})`); + + const quelle = readFileSync( + new URL("../workspace/assets/js/rundgang.js", import.meta.url), "utf8"); + + /* Die Stationsliste aus der echten Datei, als Ausdruck ausgefuehrt. */ + const anfang = quelle.indexOf("const STATIONEN = ["); + const ende = quelle.indexOf("\n ];", anfang); + const liste = anfang >= 0 && ende > anfang + ? vm.runInNewContext(quelle.slice(anfang + "const STATIONEN = ".length, ende + 4)) + : null; + ok(Array.isArray(liste) && liste.length === 5, + `fuenf Stationen in rundgang.js (${liste?.length})`); + ok(Array.isArray(liste) && liste.filter((s) => s.nurTeam).length === 2, + `davon zwei nur fuers Team (${liste?.filter((s) => s.nurTeam).length})`); + + /* Der Siebausdruck, ebenfalls aus der echten Datei. Faellt er weg, + ist das KEIN Ueberspringen, sondern ein Fehlschlag: Die Aussage + "die Community bekommt drei" waere dann unbewiesen, und genau das + ist der Zustand, den diese Pruefung verhindern soll. */ + const m = quelle.match(/\.filter\(\(s\) => \((s\.nurTeam[^\n]*?)\)\)/); + ok(!!m, `der Siebausdruck steht in rundgang.js${m ? "" : " — NICHT gefunden"}`); + if (m && Array.isArray(liste)) { + const sieb = (istTeam) => + liste.filter(vm.runInNewContext(`(s) => (${m[1]})`, { istTeam })).length; + ok(sieb(false) === 3, `Community: drei Stationen (${sieb(false)})`); + ok(sieb(true) === 5, `Teamrolle: fuenf Stationen (${sieb(true)})`); + } else { + ok(false, "Community/Team-Zaehlung nicht durchfuehrbar — Siebausdruck fehlt"); + ok(false, "Community/Team-Zaehlung nicht durchfuehrbar — Siebausdruck fehlt"); + } + + /* KEIN ROLLENNAME IN rundgang.js. Der Grund steht im Kopf der + Datei; diese Zeile haelt ihn fest, damit die naechste Rolle nicht + per Hand nachgetragen werden muss. */ + const nurCode = quelle + .replace(/\/\*[\s\S]*?\*\//g, " ") + .replace(/(^|[^:])\/\/[^\n]*/g, "$1 "); + const gefunden = ["'gast'", '"gast"', "'hand'", "'modi'", "'linke'", "'creator'"] + .filter((w) => nurCode.includes(w)); + ok(gefunden.length === 0, + `kein Rollenname im Code von rundgang.js${gefunden.length ? " — " + gefunden.join(", ") : ""}`); +} + /* ---------- Abschluss ------------------------------------------------ */ try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ } console.log(`\n${fehler ? "FEHLER: " + fehler : "Alles in Ordnung"} — ${geprueft} Prüfungen`); diff --git a/server/workspace-anleitung.js b/server/workspace-anleitung.js index 544a78a4..5743e9d3 100644 --- a/server/workspace-anleitung.js +++ b/server/workspace-anleitung.js @@ -33,7 +33,7 @@ ===================================================================== */ import express from "express"; -import { db, sitzungLesen } from "./workspace.js"; +import { db, sitzungLesen, AUSSEN_ROLLEN } from "./workspace.js"; import { STUFEN, PFLEGE_ROLLEN, fassungenFuer, } from "./anleitung-tabellen.js"; @@ -611,6 +611,16 @@ anleitungRouter.get("/workspace/api/anleitung/einweisung", (req, res) => { rolle, name: person.name || "", muss, + /* IST DAS EINE TEAMROLLE? (06.10.2026, Bauplan Kapitel 10) + "Community drei Schritte, Team-Rollen fuenf." + + Als Ja/Nein und nicht als Rollenname: rundgang.js laeuft im + Browser, und in dieser Datei steht bewusst kein einziger + Rollenname -- sie waere sonst am Tag nach der naechsten + Aenderung falsch, und zwar bei jedem, der sie schon geladen + hat. Gefragt wird dieselbe Menge, die auch sonst entscheidet, + wer von aussen kommt. */ + team: !AUSSEN_ROLLEN.has(rolle), }); } catch (fehler) { console.error("[workspace] Einweisung:", fehler?.message); diff --git a/workspace/anleitung.html b/workspace/anleitung.html index c8ba9a0a..fbab67e2 100644 --- a/workspace/anleitung.html +++ b/workspace/anleitung.html @@ -7,17 +7,17 @@ - - - - - + + + + + - - + +
@@ -289,16 +289,16 @@ Und anleitung.js braucht es doppelt: Symbol, Farbe, Name und Adresse jeder Karte kommen von dort, nicht vom Server. --> - + - - - - - - + + + + + +