Gestern Mittag gemessen: 39 `newContext`-Aufrufe nehmen ihre Breite
aus einer Variablen und setzen kein `hasTouch`. Ohne das meldet der
Browser `pointer: fine`, und KEINE Regel aus `@media (pointer:
coarse)` greift — dort stehen im ganzen Haus die 44-Pixel-
Beruehrziele, die ausgeblendeten Tastenkuerzel und die
eingeklappte Reiterleiste.
Was das anrichtet, war an pruef-breiten zu sehen: drei Befunde auf
320, 390 und 430 Pixeln, die mit dem Finger allesamt verschwanden —
Messfehler, keine Fehler.
37 DAVON HABEN IHN JETZT. Nur `hasTouch`, nicht `isMobile`: Gefragt
ist genau die eine Sache, um die es geht. `isMobile` waere eine
zweite Aenderung in derselben Zeile, und wenn danach etwas anders
aussieht, wuesste niemand, welche von beiden es war.
ZWEI BLEIBEN STEHEN, beide in pruef-grosscheck.mjs. Die Aenderung
dort waere ein Zweizeiler; sie zu pruefen hiesse, 206 Seiten ueber
vier Rollen laufen zu lassen, und das braucht Filipes Zusage. Eine
Aenderung, die ich nicht pruefen darf, liefere ich nicht aus.
Grundlinie in pruef-fingermass steht deshalb auf 2.
JEDE EINZELN NACHGELAUFEN — 37 Laeufe:
34 gruen, darunter pruef-handy 186, pruef-material 159,
pruef-start-ansicht 160, pruef-kalender 141, pruef-erwaehnung 129,
pruef-bewerbung-aufgaben 163, pruef-neue-seiten 109
3 mit Befunden, ALLE DREI VORBESTEHEND (Gegenprobe: alter Stand
derselben Datei, gleicher Lauf, gleiche Zahl):
pruef-browser 3 (WebKit startet auf diesem Rechner nicht)
pruef-chat-anhaenge 2
pruef-crew-wand-bild 3
EINE ZEITBOMBE GEFUNDEN UND ENTSCHAERFT
pruef-dabei-optik meldete „Haekchen: 0 -> 0" — aber nur, wenn vier
andere Pruefungen gleichzeitig liefen. Allein: „0 -> 1", gruen.
Dort stand `waitForTimeout(250)` mit der Begruendung „250 ms sind
reichlich ueber den 160" (der Dauer der Blende). Auf einem Rechner,
auf dem nebenher vier Browser messen, sind sie es nicht. Die
Pruefung war damit gruen, solange nichts anderes lief, und rot im
Gesamtlauf — also genau dann, wenn niemand sie einzeln nachstellen
kann.
Eine Wartezeit ist eine Annahme ueber den Rechner. Gewartet wird
jetzt auf das, worauf es ankommt: dass das Haekchen da ist. Laeuft
die Frist ab, faellt die Pruefung mit dem ECHTEN Wert um und nicht
mit einem Messfehler. Gegenprobe: unter derselben vierfachen Last,
die sie vorher rot gemacht hat, jetzt gruen.
UND DIE GRUNDLINIE WIEDER STRENG. Ich hatte sie kurz auf
„hoechstens" gestellt — damit haette ein Rueckgang stillschweigend
Platz fuer die naechste Suende gedeckt. Genau davor warnt der Kopf
derselben Datei bei der anderen Grundlinie, und ich habe es eine
Stunde spaeter selbst falsch gemacht.
Co-Authored-By: Claude Opus 5 <[email protected]>
493 lines
23 KiB
JavaScript
493 lines
23 KiB
JavaScript
/* =====================================================================
|
||
VANVANS MELDUNG AUS DEM SUPPORT (30.09.2026)
|
||
|
||
„Wenn ich im Bereich eure Aufgaben runterscrolle und dort bei den 68
|
||
Aufgaben … Aufgaben an einen Modi zutrage und auch bewerte, dann
|
||
sieht der Modi zwar die Auswertung im Bereich Entwicklung, aber bei
|
||
ihm taucht nichts im Bereich eure Aufgaben unten in der Karte auf.
|
||
Bei mir zum Beispiel steht in der Karte im Bereich eure Aufgaben
|
||
bei jedem Punkt läuft obwohl auch wenn die Aufgaben darüber gar
|
||
nicht zugetragen wurde."
|
||
|
||
---------------------------------------------------------------------
|
||
ZWEI FRAGEN, UND BEIDE LASSEN SICH NUR AM BILDSCHIRM BEANTWORTEN
|
||
|
||
1. Was sieht der MODI unten in seiner eigenen Karte, nachdem ihm
|
||
etwas zugetragen und bewertet wurde?
|
||
2. Was steht bei der LEITUNG an einem Punkt, der gar nicht
|
||
zugetragen ist?
|
||
|
||
Der Quelltext allein sagt das nicht. Er sagt, was gerendert wird --
|
||
nicht, was ein Mensch daraus liest. Und genau darum geht es in ihrer
|
||
Meldung.
|
||
|
||
---------------------------------------------------------------------
|
||
DER AUFBAU IST IHR FALL, NICHT EIN AEHNLICHER
|
||
|
||
Filipe (admin) und VanVan (hand) sind die beiden Beurteiler --
|
||
genauso wie im Haus. Diene ist ein Modi. VanVan traegt ihm ZWEI von
|
||
68 Punkten zu und bewertet sie; einen DRITTEN bewertet sie, ohne ihn
|
||
zuzutragen. Filipe bewertet ABSICHTLICH NICHTS -- denn genau so war
|
||
es bei ihr, und wenn das der Grund ist, muss er hier sichtbar
|
||
werden.
|
||
|
||
Sie prueft nichts und meldet keinen Fehlschlag. Sie sagt, was auf
|
||
dem Bildschirm steht.
|
||
|
||
Aufrufen mit: node server/mess-vanvan-karte.mjs
|
||
===================================================================== */
|
||
|
||
import { mkdtempSync, rmSync } from "node:fs";
|
||
import { tmpdir } from "node:os";
|
||
import { join } from "node:path";
|
||
import { eigenerPort } from "./helfer-port.mjs";
|
||
|
||
const PORT = await eigenerPort(import.meta);
|
||
const ordner = mkdtempSync(join(tmpdir(), "ws-vanvan-"));
|
||
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
|
||
process.env.PORT = String(PORT);
|
||
process.env.SITE_ACCESS_SECRET = "lokaler-test";
|
||
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
|
||
|
||
const express = (await import("express")).default;
|
||
const ec = express.response.cookie;
|
||
express.response.cookie = function (n, w, o) {
|
||
return ec.call(this, n, w, { ...(o || {}), secure: false });
|
||
};
|
||
import { notbremse } from "./helfer-notbremse.mjs";
|
||
await import("./index.js");
|
||
notbremse(180_000, "mess-vanvan-karte");
|
||
await new Promise((r) => setTimeout(r, 800));
|
||
const BASIS = `http://127.0.0.1:${PORT}`;
|
||
|
||
process.on("uncaughtException", (f) => { console.error("ABSTURZ:", f?.stack || f); process.exit(7); });
|
||
process.on("unhandledRejection", (f) => { console.error("ABSTURZ:", f?.stack || f); process.exit(7); });
|
||
|
||
const { DatabaseSync } = await import("node:sqlite");
|
||
const { scryptSync, randomBytes, createHmac } = await import("node:crypto");
|
||
const { ENTWICKLUNG_FREMD } = await import("./workspace-entwicklungs-punkte.js");
|
||
|
||
const d = new DatabaseSync(process.env.WORKSPACE_DB);
|
||
const jetzt = new Date().toISOString();
|
||
const geheim = randomBytes(32).toString("hex");
|
||
d.prepare("INSERT INTO einstellungen (schluessel, wert, geaendert, von)"
|
||
+ " VALUES (?,?,?,NULL) ON CONFLICT(schluessel) DO NOTHING")
|
||
.run("code_kennung_schluessel", geheim, jetzt);
|
||
function anlegen(name, rolle, code) {
|
||
const salz = randomBytes(16).toString("hex");
|
||
const hash = scryptSync(code, salz, 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, code_kennung, aktiv, erstellt)"
|
||
+ " VALUES (?,?,?,?,?,?,1,?)")
|
||
.run(name, rolle, hash, salz, 32768,
|
||
createHmac("sha256", geheim).update(code).digest("hex"), jetzt);
|
||
return d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
||
}
|
||
const idDogi = anlegen("Filipe", "admin", "CODE-DOGI-0001");
|
||
const idVan = anlegen("VanVan", "hand", "CODE-VANVAN-01");
|
||
const idModi = anlegen("Diene", "modi", "CODE-DIENE-001");
|
||
d.close();
|
||
|
||
/* ---- Anmelden ---------------------------------------------------- */
|
||
async function anmelden(rolle, code) {
|
||
const a = await fetch(BASIS + "/workspace/api/anmelden", {
|
||
method: "POST", headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({ rolle, code, alter_ok: true }),
|
||
});
|
||
return (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; ");
|
||
}
|
||
const kVan = await anmelden("hand", "CODE-VANVAN-01");
|
||
const kModi = await anmelden("modi", "CODE-DIENE-001");
|
||
const kDogi = await anmelden("admin", "CODE-DOGI-0001");
|
||
if (!kVan || !kModi || !kDogi) {
|
||
console.error("KONNTE NICHT NACHSEHEN: die Anmeldung hat nicht geklappt.");
|
||
process.exit(1);
|
||
}
|
||
const ruf = (keks, weg, rumpf, art = "GET") => fetch(BASIS + weg, {
|
||
method: art,
|
||
headers: { "Content-Type": "application/json", Cookie: keks },
|
||
body: rumpf === undefined ? undefined : JSON.stringify(rumpf),
|
||
});
|
||
|
||
/* ---- VanVans Handgriffe ------------------------------------------ */
|
||
const P1 = ENTWICKLUNG_FREMD[0].schluessel;
|
||
const P2 = ENTWICKLUNG_FREMD[1].schluessel;
|
||
const P3 = ENTWICKLUNG_FREMD[2].schluessel; // bewertet, NICHT zugetragen
|
||
|
||
console.log("");
|
||
console.log("=== Was VanVan getan hat ===");
|
||
for (const [p, wort] of [[P1, "zugetragen"], [P2, "zugetragen"]]) {
|
||
const a = await ruf(kVan, `/workspace/api/entwicklung/person/${idModi}/punkt/${p}`,
|
||
{ an: true }, "PUT");
|
||
console.log(` ${wort}: ${p} (HTTP ${a.status})`);
|
||
}
|
||
for (const p of [P1, P2, P3]) {
|
||
const a = await ruf(kVan, `/workspace/api/entwicklung/person/${idModi}/${p}`,
|
||
{ stufe: "laeuft", anlass: "Im Stream gesehen, passt." }, "PUT");
|
||
console.log(` bewertet „Läuft": ${p} (HTTP ${a.status})`);
|
||
}
|
||
console.log(` Filipe bewertet NICHTS -- genau wie in ihrem Fall.`);
|
||
console.log(` Von ${ENTWICKLUNG_FREMD.length} Punkten sind 2 zugetragen und 3 bewertet.`);
|
||
|
||
/* =====================================================================
|
||
FRAGE 1: WAS SIEHT DER MODI UNTEN IN SEINER KARTE?
|
||
===================================================================== */
|
||
console.log("");
|
||
console.log("=== 1. Die eigene Karte des Modi (API) ===");
|
||
{
|
||
const k = await (await ruf(kModi, "/workspace/api/entwicklung/meine-karte")).json();
|
||
console.log(` hat_karte=${k.hat_karte} Beurteiler=${k.beurteiler} `
|
||
+ `fertig=${k.fertig} von ${k.gesamt}`);
|
||
const alle = (k.bloecke || []).flatMap((b) => b.punkte);
|
||
const offen = alle.filter((p) => p.offen).length;
|
||
console.log(` ${offen} von ${alle.length} Punkten stehen auf „offen"`);
|
||
for (const s of [P1, P2, P3]) {
|
||
const p = alle.find((x) => x.schluessel === s);
|
||
console.log(` ${s.padEnd(26)} offen=${p?.offen} `
|
||
+ `zugetragen=${"zugetragen" in (p || {}) ? p.zugetragen : "(gibt es nicht)"} `
|
||
+ `antworten=${JSON.stringify(p?.antworten ?? null)}`);
|
||
}
|
||
/* DIE KERNFRAGE: Steht in seiner Karte ueberhaupt irgendwo, WELCHE
|
||
Punkte ihm als Aufgabe zugetragen wurden? */
|
||
const kennt = alle.some((p) => "zugetragen" in p);
|
||
console.log(` Kennt seine Karte das Wort „zugetragen"? ${kennt ? "JA" : "NEIN"}`);
|
||
}
|
||
|
||
/* =====================================================================
|
||
FRAGE 2: WAS STEHT BEI VANVAN AN EINEM PUNKT?
|
||
===================================================================== */
|
||
console.log("");
|
||
console.log("=== 2. VanVans Karte ueber Diene (API) ===");
|
||
{
|
||
const k = await (await ruf(kVan, `/workspace/api/entwicklung/person/${idModi}`)).json();
|
||
const alle = (k.bloecke || []).flatMap((b) => b.punkte);
|
||
console.log(` ${alle.length} Punkte insgesamt, `
|
||
+ `${alle.filter((p) => p.zugetragen).length} davon zugetragen, `
|
||
+ `${alle.filter((p) => p.meins).length} bewertet, `
|
||
+ `${alle.filter((p) => p.schritt).length} mit einem Schritt`);
|
||
for (const s of [P1, P3]) {
|
||
const p = alle.find((x) => x.schluessel === s);
|
||
console.log(` ${s.padEnd(26)} zugetragen=${p?.zugetragen} `
|
||
+ `meins=${p?.meins?.stufe ?? "-"} schritt=${p?.schritt ? p.schritt.status : "-"}`);
|
||
}
|
||
}
|
||
|
||
/* =====================================================================
|
||
UND JETZT DER BILDSCHIRM
|
||
===================================================================== */
|
||
const { chromium } = await import(
|
||
"file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs");
|
||
const browser = await chromium.launch();
|
||
|
||
async function alsWer(keks, breite = 1280, hoehe = 1000) {
|
||
const kontext = await browser.newContext({ viewport: { width: breite, height: hoehe }, hasTouch: breite <= 860 });
|
||
await kontext.addCookies(keks.split("; ").filter(Boolean).map((z) => {
|
||
const [n, ...r] = z.split("=");
|
||
return { name: n, value: r.join("="), domain: "127.0.0.1", path: "/" };
|
||
}));
|
||
const seite = await kontext.newPage();
|
||
const konsole = [];
|
||
seite.on("console", (e) => { if (e.type() === "error") konsole.push(e.text()); });
|
||
seite.on("pageerror", (f) => konsole.push(String(f?.message || f)));
|
||
return { kontext, seite, konsole };
|
||
}
|
||
|
||
console.log("");
|
||
console.log("=== 3. Was der Modi auf der Seite Eure Aufgaben WIRKLICH sieht ===");
|
||
{
|
||
const { kontext, seite, konsole } = await alsWer(kModi);
|
||
await seite.goto(`${BASIS}/workspace/entwicklung.html`, { waitUntil: "networkidle" });
|
||
await seite.waitForTimeout(1500);
|
||
const w = await seite.evaluate(() => {
|
||
/* GEMESSEN WIRD IN SEINER KARTE, nicht auf der ganzen Seite. Das
|
||
Wort „Aufgabe" steht oben in der Kopfleiste und in der
|
||
Vorlagen-Kachel -- eine Suche ueber die ganze Seite haette
|
||
„ja" gesagt, ohne dass in der Karte irgendetwas steht. Genau
|
||
die Sorte gruener Haken, die nichts geprueft hat. */
|
||
const karte = document.getElementById("karte-block");
|
||
const auf = karte?.querySelector(".e-block--auftrag") || null;
|
||
return {
|
||
ueberschriften: [...document.querySelectorAll("h1, h2")]
|
||
.map((x) => x.textContent.trim()).filter(Boolean).slice(0, 12),
|
||
karteDa: !!karte && !karte.hidden,
|
||
/* SEIT DEM 30.09.2026 IST DER KOPF EIN SCHALTER. Der Name steht
|
||
in `.e-block__name`, die Zahl daneben in `.e-block__stand` --
|
||
`.e-block__titel` gibt es hier nicht mehr. Die Zeile meldete
|
||
`undefined` und haette das stillschweigend weiter getan. */
|
||
auftragsblock: auf
|
||
? [auf.querySelector(".e-block__name")?.textContent.trim(),
|
||
auf.querySelector(".e-block__stand")?.textContent.trim()].join(" ")
|
||
: null,
|
||
auftragKlappbar: !!auf?.querySelector(".e-block__schalter"),
|
||
aufgabenTitel: auf
|
||
? [...auf.querySelectorAll(".e-punkt__titel")].map((x) => x.textContent.trim())
|
||
: [],
|
||
aufgabenLage: auf
|
||
? [...auf.querySelectorAll(".e-punkt__wann")].map((x) => x.textContent.trim())
|
||
: [],
|
||
satz: (document.getElementById("karte-satz")?.textContent || "").trim().slice(0, 160),
|
||
punkte: karte ? karte.querySelectorAll(".e-punkt").length : 0,
|
||
};
|
||
});
|
||
console.log(` Ueberschriften: ${w.ueberschriften.join(" | ")}`);
|
||
console.log(` Karte sichtbar: ${w.karteDa}, Punktzeilen darin: ${w.punkte}`);
|
||
console.log(` Abschnitt: ${JSON.stringify(w.auftragsblock)} `
|
||
+ `(einklappbar=${w.auftragKlappbar})`);
|
||
console.log(` Seine Aufgaben: ${JSON.stringify(w.aufgabenTitel)}`);
|
||
console.log(` Lage dazu: ${JSON.stringify(w.aufgabenLage)}`);
|
||
console.log(` Satz: ${w.satz}`);
|
||
if (!w.aufgabenTitel.length) {
|
||
console.log(" ACHTUNG: In seiner Karte steht nicht, welche Punkte seine "
|
||
+ "Aufgaben sind -- genau VanVans Meldung.");
|
||
}
|
||
await seite.screenshot({ path: "server/mess-vanvan-karte-modi.png", fullPage: true });
|
||
console.log(" Bild: server/mess-vanvan-karte-modi.png");
|
||
if (konsole.length) console.log(" KONSOLE:", konsole.slice(0, 3).join(" | "));
|
||
await kontext.close();
|
||
}
|
||
|
||
console.log("");
|
||
console.log("=== 4. Was VanVan an einem Punkt sieht ===");
|
||
{
|
||
const { kontext, seite, konsole } = await alsWer(kVan);
|
||
await seite.goto(`${BASIS}/workspace/entwicklung.html`, { waitUntil: "networkidle" });
|
||
await seite.waitForTimeout(1200);
|
||
/* Dienes Kachel aufmachen. */
|
||
const auf = await seite.evaluate((name) => {
|
||
const k = [...document.querySelectorAll("#personen .e-person")]
|
||
.find((x) => (x.querySelector(".e-person__name")?.textContent || "").includes(name));
|
||
if (!k) return false;
|
||
(k.querySelector("button, a") || k).click();
|
||
return true;
|
||
}, "Diene");
|
||
console.log(` Dienes Kachel geoeffnet: ${auf}`);
|
||
await seite.waitForTimeout(2000);
|
||
|
||
const z = await seite.evaluate(() => {
|
||
const zeilen = [...document.querySelectorAll(".e-punkt")].slice(0, 6).map((p) => ({
|
||
titel: (p.querySelector(".e-punkt__titel")?.textContent || "").trim().slice(0, 34),
|
||
zugetragen: p.dataset.zugetragen,
|
||
auftrag: (p.querySelector(".e-punkt__auftrag")?.textContent || "").trim(),
|
||
/* WAS WIRKLICH AN DER ZEILE STEHT -- ohne die Knopfbeschriftungen
|
||
vorher zu kennen. Genau das ist die Frage: Was liest ein
|
||
Mensch dort? */
|
||
woerter: (p.innerText || "").replace(/\s+/g, " ").trim().slice(0, 150),
|
||
gedrueckt: [...p.querySelectorAll("[aria-pressed='true']")]
|
||
.map((b) => b.textContent.trim()),
|
||
}));
|
||
return {
|
||
anzahl: document.querySelectorAll(".e-punkt").length,
|
||
zeilen,
|
||
/* Sieht SIE, dass es bei ihm noch nicht ankommt? */
|
||
wartet: [...document.querySelectorAll(".e-punkt__wartet")]
|
||
.map((x) => x.textContent.trim()),
|
||
/* Und gibt es den Knopf, mit dem sie auf das Zugetragene
|
||
eingrenzen kann? */
|
||
knoepfe: [...document.querySelectorAll(".e-stufen__knopf")]
|
||
.map((k) => `${k.querySelector(".e-stufen__name")?.textContent.trim()}`
|
||
+ `=${k.querySelector(".e-stufen__zahl")?.textContent.trim()}`),
|
||
};
|
||
});
|
||
console.log(` ${z.anzahl} Punktzeilen sichtbar. Die ersten sechs:`);
|
||
for (const r of z.zeilen) {
|
||
console.log(` · ${r.titel.padEnd(36)} zugetragen=${r.zugetragen} `
|
||
+ `Knopf=„${r.auftrag}" gedrueckt=${JSON.stringify(r.gedrueckt)}`);
|
||
console.log(` „${r.woerter}"`);
|
||
}
|
||
console.log(` „Er sieht das noch nicht" steht an ${z.wartet.length} Punkten`);
|
||
if (z.wartet[0]) console.log(` „${z.wartet[0]}"`);
|
||
console.log(` Filterknoepfe: ${z.knoepfe.join(" ")}`);
|
||
if (!z.wartet.length) {
|
||
console.log(" ACHTUNG: Sie hat bewertet, es kommt beim Modi nicht an, und "
|
||
+ "nichts auf ihrem Bildschirm sagt ihr das.");
|
||
}
|
||
await seite.screenshot({ path: "server/mess-vanvan-karte-leitung.png", fullPage: true });
|
||
console.log(" Bild: server/mess-vanvan-karte-leitung.png");
|
||
|
||
/* ---- WOMIT GEHT DIE KARTE AUF? (01.10.2026) -----------------
|
||
|
||
Filipe: „mach alles los" -- damit auch: „Zugetragen" ist die
|
||
Vorgabe, wenn es etwas zu zeigen gibt.
|
||
|
||
VORHER KLICKTE DIESE MESSUNG AUF DEN FILTER und zaehlte nach.
|
||
Seit er beim Aufmachen schon steht, haette derselbe Klick ihn
|
||
AUSgeschaltet -- die Messung haette das Gegenteil gemessen und
|
||
trotzdem eine Zahl gemeldet. Genau die Sorte gruener Haken, die
|
||
nichts prueft.
|
||
|
||
Gefragt wird deshalb, was DASTEHT, bevor jemand etwas anfasst. */
|
||
const beimAufmachen = await seite.evaluate(() => {
|
||
const gedrueckt = [...document.querySelectorAll(".e-stufen__knopf")]
|
||
.find((k) => k.getAttribute("aria-pressed") === "true");
|
||
return {
|
||
filter: gedrueckt?.querySelector(".e-stufen__name")?.textContent.trim() || null,
|
||
punkte: document.querySelectorAll(".e-punkt").length,
|
||
alleZugetragen: [...document.querySelectorAll(".e-punkt")]
|
||
.every((p) => p.dataset.zugetragen === "ja"),
|
||
};
|
||
});
|
||
console.log(` Beim Aufmachen steht der Filter auf „${beimAufmachen.filter}": `
|
||
+ `${beimAufmachen.punkte} Punkte, alle zugetragen=${beimAufmachen.alleZugetragen}`);
|
||
if (beimAufmachen.filter !== "Zugetragen" || beimAufmachen.punkte !== 2
|
||
|| !beimAufmachen.alleZugetragen) {
|
||
console.log(" ACHTUNG: Die Karte geht nicht auf dem Zugetragenen auf.");
|
||
}
|
||
|
||
/* GEGENPROBE: „Alle" ist einen Klick entfernt und zeigt wieder alle
|
||
68. Ohne sie hiesse „2 Punkte" womoeglich nur, dass es nicht
|
||
mehr gibt. */
|
||
const zurueck = await seite.evaluate(() => {
|
||
const k = [...document.querySelectorAll(".e-stufen__knopf")]
|
||
.find((x) => x.querySelector(".e-stufen__name")?.textContent.trim() === "Alle");
|
||
if (!k) return null;
|
||
k.click();
|
||
return true;
|
||
});
|
||
if (zurueck) {
|
||
await seite.waitForTimeout(1200);
|
||
const alle = await seite.evaluate(() => document.querySelectorAll(".e-punkt").length);
|
||
console.log(` Nach „Alle": ${alle} Punkte`);
|
||
if (alle !== 68) {
|
||
console.log(` ACHTUNG: „Alle“ zeigt nicht mehr alle 68.`);
|
||
}
|
||
} else {
|
||
console.log(` ACHTUNG: Den Knopf „Alle“ gibt es nicht.`);
|
||
}
|
||
|
||
await seite.screenshot({ path: "server/mess-vanvan-karte-filter.png", fullPage: true });
|
||
console.log(" Bild: server/mess-vanvan-karte-filter.png");
|
||
|
||
/* ==== UND WER NICHTS ZUGETRAGEN HAT? (01.10.2026) ==============
|
||
|
||
Das ist die Gegenprobe, die der alte Kommentar verlangt: „Ein
|
||
Filter, der beim Öffnen schon etwas versteckt, lässt einen
|
||
Punkte suchen, die gestern noch da waren." Bei einem Menschen
|
||
ohne zugetragene Punkte zeigte „Zugetragen" eine LEERE Karte --
|
||
und eine leere Karte sieht aus wie ein Fehler.
|
||
|
||
VanVan hat in diesem Aufbau nichts zugetragen bekommen; ihre
|
||
Karte muss deshalb auf „Alle" aufgehen. */
|
||
const beiVanVan = await seite.evaluate(async () => {
|
||
const k = [...document.querySelectorAll("#personen .e-person")]
|
||
.find((x) => (x.querySelector(".e-person__name")?.textContent || "").includes("VanVan"));
|
||
if (!k) return null;
|
||
(k.querySelector("button, a") || k).click();
|
||
await new Promise((r) => setTimeout(r, 2200));
|
||
const gedrueckt = [...document.querySelectorAll(".e-stufen__knopf")]
|
||
.find((x) => x.getAttribute("aria-pressed") === "true");
|
||
return {
|
||
filter: gedrueckt?.querySelector(".e-stufen__name")?.textContent.trim() || null,
|
||
punkte: document.querySelectorAll(".e-punkt").length,
|
||
};
|
||
});
|
||
if (!beiVanVan) {
|
||
console.log(" KONNTE NICHT NACHSEHEN: VanVans Kachel war nicht zu finden.");
|
||
} else {
|
||
console.log(` Bei jemandem OHNE Zugetragenes: Filter „${beiVanVan.filter}", `
|
||
+ `${beiVanVan.punkte} Punkte`);
|
||
if (beiVanVan.filter !== "Alle" || beiVanVan.punkte !== 68) {
|
||
console.log(" ACHTUNG: Wer nichts zugetragen hat, bekommt eine leere Karte.");
|
||
}
|
||
}
|
||
if (konsole.length) console.log(" KONSOLE:", konsole.slice(0, 3).join(" | "));
|
||
await kontext.close();
|
||
}
|
||
|
||
/* =====================================================================
|
||
5. VANVANS ZWEITE MELDUNG: „Deine Karte kann man nicht einklappen"
|
||
|
||
„was die Seite unnötig lang zieht und unübersichtlich macht."
|
||
|
||
IHRE EIGENE KARTE, nicht die eines Modi. Im Bildschirmfoto steht an
|
||
jedem Punkt „1 × Läuft" -- eine einzige Antwort. Ueber die rechte
|
||
Hand urteilt nur DogFather, also ist bei ihr alles „fertig" und die
|
||
Karte entsprechend lang. Ein Modi braucht zwei Stimmen und sieht
|
||
deshalb meist gar nichts.
|
||
|
||
GEMESSEN WIRD DIE HOEHE. „Unnötig lang" ist eine Zahl, keine
|
||
Meinung -- und ohne sie laesst sich nachher nicht sagen, ob es
|
||
besser geworden ist.
|
||
===================================================================== */
|
||
console.log("");
|
||
console.log("=== 5. VanVans eigene Karte: wie lang wird die Seite? ===");
|
||
{
|
||
/* Filipe bewertet VanVan durch -- alle Punkte, wie im echten Haus
|
||
ueber Monate gewachsen. */
|
||
let gesetzt = 0;
|
||
for (const pt of ENTWICKLUNG_FREMD) {
|
||
const a = await ruf(kDogi, `/workspace/api/entwicklung/person/${idVan}/${pt.schluessel}`,
|
||
{ stufe: "laeuft", anlass: "" }, "PUT");
|
||
if (a.status === 200) gesetzt++;
|
||
}
|
||
console.log(` Filipe hat ${gesetzt} von ${ENTWICKLUNG_FREMD.length} Punkten gesetzt.`);
|
||
|
||
const { kontext, seite, konsole } = await alsWer(kVan, 1280, 1000);
|
||
await seite.goto(`${BASIS}/workspace/entwicklung.html`, { waitUntil: "networkidle" });
|
||
await seite.waitForTimeout(1800);
|
||
|
||
const m = await seite.evaluate(() => {
|
||
const karte = document.getElementById("karte-block");
|
||
const r = karte?.getBoundingClientRect();
|
||
return {
|
||
seitenhoehe: document.documentElement.scrollHeight,
|
||
kartenhoehe: r ? Math.round(r.height) : 0,
|
||
bloecke: karte ? karte.querySelectorAll(".e-block").length : 0,
|
||
zeilen: karte ? karte.querySelectorAll(".e-punkt").length : 0,
|
||
/* Gibt es ueberhaupt einen Schalter zum Zuklappen? */
|
||
schalter: karte ? karte.querySelectorAll(".e-block__schalter").length : 0,
|
||
alleKnopf: karte ? karte.querySelectorAll(".e-bloecke__alle").length : 0,
|
||
};
|
||
});
|
||
console.log(` Seite gesamt: ${m.seitenhoehe} px`);
|
||
console.log(` Davon „Deine Karte": ${m.kartenhoehe} px `
|
||
+ `(${m.bloecke} Abschnitte, ${m.zeilen} Zeilen)`);
|
||
console.log(` Schalter zum Zuklappen: ${m.schalter}, „Alle"-Knopf: ${m.alleKnopf}`);
|
||
if (!m.schalter) {
|
||
console.log(" ACHTUNG: Kein einziger Abschnitt laesst sich zuklappen -- "
|
||
+ "genau VanVans Meldung.");
|
||
} else {
|
||
/* ZUKLAPPEN UND NACHMESSEN. Ohne diesen Griff hiesse „es gibt
|
||
Schalter" nur, dass es Schalter gibt. */
|
||
const nach = await seite.evaluate(() => {
|
||
const k = document.querySelector("#karte-block .e-bloecke__alle");
|
||
if (k && k.textContent.includes("zuklappen")) k.click();
|
||
else document.querySelectorAll("#karte-block .e-block__schalter")
|
||
.forEach((s) => { if (s.getAttribute("aria-expanded") === "true") s.click(); });
|
||
const r = document.getElementById("karte-block")?.getBoundingClientRect();
|
||
return {
|
||
kartenhoehe: r ? Math.round(r.height) : 0,
|
||
sichtbar: [...document.querySelectorAll("#karte-block .e-punkt")]
|
||
.filter((z) => z.getBoundingClientRect().height > 0).length,
|
||
};
|
||
});
|
||
console.log(` Zugeklappt: ${nach.kartenhoehe} px `
|
||
+ `(${nach.sichtbar} Zeilen noch sichtbar)`);
|
||
const gespart = m.kartenhoehe - nach.kartenhoehe;
|
||
const anteil = Math.round(gespart / Math.max(1, m.kartenhoehe) * 100);
|
||
console.log(` Gespart: ${gespart} px (${anteil} %)`);
|
||
/* EIN ANTEIL UND KEINE FESTE PIXELZAHL. Wie hoch die Karte ist,
|
||
haengt am Bestand -- 68 Punkte heute, vielleicht 90 im
|
||
naechsten Jahr. Eine feste Grenze waere die Rechnung von
|
||
gestern; „mehr als die Haelfte weg" gilt auch dann noch. */
|
||
if (anteil < 50 || nach.sichtbar > 0) {
|
||
console.log(" ACHTUNG: Zuklappen bringt kaum etwas "
|
||
+ `(${anteil} %, ${nach.sichtbar} Zeilen bleiben stehen).`);
|
||
}
|
||
}
|
||
if (m.schalter && !m.alleKnopf) {
|
||
console.log(" ACHTUNG: Es gibt Schalter, aber keinen Knopf, der alle "
|
||
+ "auf einmal zuklappt -- bei sechs Abschnitten ist das sechsmal tippen.");
|
||
}
|
||
await seite.screenshot({ path: "server/mess-vanvan-karte-eigene.png", fullPage: true });
|
||
console.log(" Bild: server/mess-vanvan-karte-eigene.png");
|
||
if (konsole.length) console.log(" KONSOLE:", konsole.slice(0, 3).join(" | "));
|
||
await kontext.close();
|
||
}
|
||
|
||
await browser.close();
|
||
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* Rest im Temp */ }
|
||
console.log("");
|
||
console.log("Fertig.");
|
||
process.exit(0);
|