Der komplette Pruefstand vor der Vorstellung (38 Laeufe im Workspace) lief bis auf zwei durch. Beide Fehlschlaege waren KEINE Fehler in der Anwendung, sondern Pruefungen mit veraltetem Weltbild -- Folgen von Entscheidungen, die Filipe selbst getroffen hat: 1. pruef-workspace-seiten (32 von 32 rot) pruefte, dass JEDE Seite ihre EIGENE Buehne hat (Aufgaben = Werkstatt, Kalender = Nachtstadt, ...). Am 03.09.2026 hat Filipe die neun Szenen durch EIN Bild ersetzt. Jetzt wird geprueft, was weiterhin wichtig ist: dass ueberhaupt ein Hintergrundbild ANKOMMT (ein data-buehne ohne CSS-Regel waere still wirkungslos) -- und dass es auf JEDER Seite dasselbe ist. Ohne die zweite Bedingung waere sie auch gruen, wenn irgendwo eine alte Szene zurueckkaeme. 2. pruef-zustand-ansicht erwartete, dass ein Manager den Systemzustand sieht. Seit dem 02.09.2026 gilt "die manager sollen diese kategorien garnicht sehen"; der Zustand gehoert zur Automationen-Seite. Beide UMGEDREHT statt geloescht. Eine geloeschte Pruefung hinterlaesst keine Spur davon, dass hier einmal etwas anderes galt -- und niemand merkt, wenn eine Sperre spaeter versehentlich wieder faellt. Co-Authored-By: Claude Opus 5 <[email protected]>
166 lines
8.9 KiB
JavaScript
166 lines
8.9 KiB
JavaScript
/* Kurzpruefung: Steht die Kopfleiste auf dem Handy ueber -- und zwar
|
|
auf ALLEN Seiten oder nur auf der neuen? Beantwortet die Frage, ob
|
|
ich einen eigenen Fehler gebaut oder einen alten gefunden habe. */
|
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
|
|
const ordner = mkdtempSync(join(tmpdir(), "ws-kopf-"));
|
|
process.env.WORKSPACE_DB = join(ordner, "pruef.sqlite");
|
|
process.env.PORT = "4178";
|
|
process.env.SITE_ACCESS_SECRET = "lokaler-test";
|
|
process.env.SITE_ACCESS_CODE_DOGI = "DOGI-TEST-1";
|
|
process.env.SITE_ACCESS_CODE_VANVAN = "VANVAN-TEST-1";
|
|
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
|
|
|
|
const express = (await import("express")).default;
|
|
const echteCookie = express.response.cookie;
|
|
express.response.cookie = function (n, w, o) {
|
|
return echteCookie.call(this, n, w, { ...(o || {}), secure: false });
|
|
};
|
|
await import("./index.js");
|
|
await new Promise((r) => setTimeout(r, 700));
|
|
const BASIS = "http://127.0.0.1:4178";
|
|
setTimeout(() => { console.log("ABBRUCH"); process.exit(1); }, 150_000).unref?.();
|
|
|
|
await fetch(BASIS + "/workspace/api/anmelden", {
|
|
method: "POST", headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ rolle: "admin", code: "x" }),
|
|
}).catch(() => {});
|
|
|
|
const { DatabaseSync } = await import("node:sqlite");
|
|
const { scryptSync, randomBytes } = await import("node:crypto");
|
|
const d = new DatabaseSync(process.env.WORKSPACE_DB);
|
|
const salt = randomBytes(16).toString("hex");
|
|
const hash = scryptSync("CODE-DOGI-0001", salt, 64, { N: 32768, r: 8, p: 1, maxmem: 96 * 1024 * 1024 }).toString("hex");
|
|
d.prepare("INSERT INTO personen (name, rolle, code_hash, code_salt, code_n, aktiv, erstellt) VALUES (?,?,?,?,?,1,?)")
|
|
.run("Test-DogFather", "admin", hash, salt, 32768, new Date().toISOString());
|
|
d.close();
|
|
|
|
const { chromium } = await import(
|
|
"file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs");
|
|
const browser = await chromium.launch();
|
|
|
|
/* Alle Seiten, die eine angemeldete Person zu sehen bekommt. Geprueft
|
|
wird auf beiden Groessen, weil die geteilten Klassen (.kopf-zeile,
|
|
.inhalt--breit, .leise) am 31.08.2026 von aufgaben.css nach start.css
|
|
gewandert sind -- faellt dabei etwas herunter, sieht man es hier. */
|
|
const SEITEN = ["start.html", "uebersicht.html", "aufgaben.html", "kalender.html",
|
|
"personen.html", "profil.html", "steckbrief.html", "wissen.html", "dateien.html",
|
|
"calls.html", "startcheck.html", "report.html", "scouting.html",
|
|
"automation.html", "content.html", "bereich.html?b=live"];
|
|
|
|
let fehler = 0;
|
|
for (const [breite, hoehe, wie] of [[1440, 1000, "Computer"], [390, 844, "Handy"]]) {
|
|
console.log(`\n=== ${wie} (${breite}px)`);
|
|
const kontext = await browser.newContext({ viewport: { width: breite, height: hoehe } });
|
|
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));
|
|
|
|
await seite.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" });
|
|
await seite.click('.rolle[data-rolle="admin"]');
|
|
await seite.fill("#code", "CODE-DOGI-0001");
|
|
await seite.click("button[type=submit]");
|
|
await seite.waitForURL("**/start.html", { timeout: 15000 });
|
|
|
|
for (const s of SEITEN) {
|
|
konsole.length = 0;
|
|
await seite.goto(BASIS + "/workspace/" + s, { waitUntil: "networkidle" });
|
|
await seite.waitForTimeout(300);
|
|
const r = await seite.evaluate(() => ({
|
|
ueber: document.documentElement.scrollWidth - document.documentElement.clientWidth,
|
|
schuld: [...document.querySelectorAll("body *")]
|
|
.filter((e) => e.getBoundingClientRect().right > window.innerWidth + 1)
|
|
.map((e) => (e.tagName + "." + e.className).slice(0, 40)).slice(0, 4),
|
|
/* Die verschobenen Klassen muessen weiterhin greifen. .inhalt--breit
|
|
setzt 1240px -- kommt nur 880px an, ist die Regel verloren. */
|
|
breit: document.querySelector(".inhalt--breit")
|
|
? getComputedStyle(document.querySelector(".inhalt--breit")).maxWidth : null,
|
|
kopfzeile: document.querySelector(".kopf-zeile")
|
|
? getComputedStyle(document.querySelector(".kopf-zeile")).display : null,
|
|
abmelden: (() => {
|
|
const a = document.querySelector(".abmelden")?.getBoundingClientRect();
|
|
return a ? a.right <= window.innerWidth && a.left >= 0 : null;
|
|
})(),
|
|
/* Der Schriftzug oben links wird von kopf.js in Rang aufgeteilt.
|
|
Auf den Unterseiten ist der vordere Teil ein VERWEIS zurück zur
|
|
Startseite -- der muss die Aufteilung überleben, sonst ist der
|
|
Rückweg weg. Genau das wäre beim Zerlegen von Textknoten leicht
|
|
zu übersehen. */
|
|
markeHaupt: document.querySelector(".kopfleiste .marke__haupt")?.textContent
|
|
.replace(/ /g, " ") || null,
|
|
markeLeise: document.querySelector(".kopfleiste .marke__leise")?.textContent
|
|
.replace(/ /g, " ") || null,
|
|
markeRaute: document.querySelectorAll(".kopfleiste .marke__raute").length,
|
|
/* Ist der vordere Teil auf einer Unterseite noch ein klickbarer
|
|
Verweis auf die Startseite? */
|
|
rueckweg: document.querySelector(".kopfleiste .marke__haupt")?.tagName === "A"
|
|
? document.querySelector(".kopfleiste .marke__haupt").getAttribute("href") : null,
|
|
/* Jede Unterseite trägt Zeichen und Farbton ihrer Kachel. Beides
|
|
kommt aus bereiche.js, derselben Liste wie die Kachel -- fehlt
|
|
eins davon, ist die Zuordnung gerissen und die Seite sieht
|
|
wieder aus wie jede andere. */
|
|
ton: document.body.dataset.ton || null,
|
|
/* Jede Seite hat ihre eigene Bühne aus Filipes Bildern. Geprüft
|
|
wird nicht das Merkmal, sondern das TATSÄCHLICH geladene Bild --
|
|
ein data-buehne ohne passende CSS-Regel wäre still wirkungslos
|
|
und niemand würde es merken. */
|
|
buehne: document.body.dataset.buehne || null,
|
|
buehneBild: (getComputedStyle(document.body, "::before").backgroundImage
|
|
.match(/buehne-([a-z]+)-(breit|schmal)/) || [])[1] || null,
|
|
kopfZeichen: document.querySelectorAll(".kopf-zeichen__svg path").length,
|
|
kopfZeichenFarbe: document.querySelector(".kopf-zeichen__svg")
|
|
? getComputedStyle(document.querySelector(".kopf-zeichen__svg")).stroke : null,
|
|
wasserzeichen: document.querySelectorAll(".kopf-wasserzeichen__svg path").length,
|
|
}));
|
|
const istStart = s === "start.html";
|
|
const markeGut = r.markeHaupt && r.markeLeise && r.markeRaute === 1
|
|
&& (istStart || r.rueckweg === "start.html");
|
|
/* Auf der Startseite gibt es keinen Seitenkopf -- dort sind die
|
|
Kacheln selbst der Kopf. Überall sonst ist er Pflicht. */
|
|
const kopfGut = istStart
|
|
|| (r.ton !== null && r.kopfZeichen > 0 && r.wasserzeichen > 0);
|
|
/* AM 03.09.2026 UMGESTELLT.
|
|
|
|
Hier stand: "jede Seite hat ihre EIGENE Bühne" -- geprüft wurde,
|
|
dass das geladene Bild zum data-buehne der Seite passt (Aufgaben
|
|
= Werkstatt, Kalender = Nachtstadt, und so weiter).
|
|
|
|
Filipe hat die neun Szenen an diesem Tag durch EIN Bild ersetzt:
|
|
"ersetze überall das hintergrund bild durch dieses bild". Damit
|
|
ist die alte Erwartung nicht mehr falsch bewiesen, sondern
|
|
überholt.
|
|
|
|
Was hier geprüft wird, bleibt aber dasselbe WICHTIGE: dass ein
|
|
Hintergrundbild überhaupt ankommt. Ein data-buehne ohne passende
|
|
CSS-Regel wäre still wirkungslos, und niemand würde es merken --
|
|
die Seite sähe nur "etwas dunkler" aus.
|
|
|
|
Zusätzlich: Es muss auf JEDER Seite DASSELBE sein. Ohne diese
|
|
zweite Bedingung wäre die Prüfung auch dann grün, wenn irgendwo
|
|
eine der alten Szenen zurückkäme. */
|
|
const buehneGut = r.buehneBild === "dogfather";
|
|
const gut = r.ueber <= 0 && konsole.length === 0 && r.abmelden !== false
|
|
&& markeGut && kopfGut && buehneGut
|
|
&& (r.breit === null || r.breit === "1240px")
|
|
&& (r.kopfzeile === null || r.kopfzeile === "flex");
|
|
if (!gut) fehler++;
|
|
console.log(` ${gut ? "ok " : "FEHL"} ${String(s).padEnd(20)}`
|
|
+ `über=${String(r.ueber).padStart(3)}px abmelden=${r.abmelden}`
|
|
+ ` marke=${r.markeHaupt ? `"${r.markeHaupt}"◆"${r.markeLeise}"` : "FEHLT"}`
|
|
+ `${istStart ? "" : ` zurück=${r.rueckweg || "FEHLT"}`}`
|
|
+ `${istStart ? "" : ` ton=${r.ton || "FEHLT"} zeichen=${r.kopfZeichen}/${r.wasserzeichen}`}`
|
|
+ ` bühne=${r.buehneBild || "FEHLT"}${r.buehne && r.buehneBild !== r.buehne ? ` (gewollt: ${r.buehne})` : ""}`
|
|
+ ` breit=${r.breit}`
|
|
+ (konsole.length ? " KONSOLE: " + konsole.join(" | ") : "")
|
|
+ (r.schuld.length ? " -> " + r.schuld.join(" | ") : ""));
|
|
}
|
|
await kontext.close();
|
|
}
|
|
await browser.close();
|
|
console.log(`\n${fehler === 0 ? "Alles in Ordnung." : fehler + " Seite(n) fehlerhaft."}`);
|
|
try { rmSync(ordner, { recursive: true, force: true }); } catch {}
|
|
process.exit(fehler === 0 ? 0 : 1);
|