Weiter durch die rote Liste. Drei der vier Befunde zeigten auf
gesunden Code; die Pruefungen selbst waren seit einem Umbau nicht
nachgezogen worden.
pruef-schritt (2 rot -> 71 gruen statt 47)
Meldete "1 von 6 Kategorien". Die Karte geht seit dem 01.10.2026
gefiltert auf ("zugetragen"), Bloecke ohne solche Punkte werden gar
nicht gezeichnet. Die Pruefung zaehlte danach alle. Schlimmer: Weil
dann kein Block mehr zugeklappt war, lief der Klick auf einen
zugeklappten 30 Sekunden in die Frist und riss den Lauf mit -- 24 von
71 Pruefungen liefen nie. Jetzt wird erst die Vorgabe geprueft (sie
ist eine Zusage), dann auf "Alle" gestellt.
pruef-glocke (1 rot -> 34 gruen)
Meldete "auf der Anmeldeseite steht der Knopf". Gemessen landete sie
auf start.html: Dieselbe Seite war eine Zeile zuvor angemeldet durch
zwanzig Arbeitsseiten gelaufen, und angemeldet fuehrt /workspace/
nicht zur Wand. Jetzt eigener Kontext ohne Keks -- und davor die
Zeile, dass die Wand wirklich erreicht wurde.
pruef-zeichen (1 rot -> 8 gruen)
Meldete content: "·" als Kodierungstruemmer. Die Bytes sind C2 B7,
also korrektes UTF-8; der Mittelpunkt ist ein begruendeter Trennpunkt
(seit 03.10.). Die Regel stammt aus einer Zeit, in der sie selbst
festhielt: "KEINE einzige benutzt ein Zeichen aus diesem Block."
Jetzt eine benannte Ausnahme MIT Veraltungsschutz: Jedes Zeichen
darin muss wirklich vorkommen, sonst wird die Ausnahme rot.
pruef-tempo-workspace (1 rot -> 9 gruen) -- DER ECHTE BEFUND
uebersicht.html 959 KB, bereich.html?b=live 1094 KB bei einer Grenze
von 900. Die Pruefung sagt jetzt auch, WORAN es liegt, und die
Antwort war eindeutig: ZWEI Buehnenbilder auf einer Seite, die eines
zeigt (281 KB studio + 262 KB portal).
Ursache: start.css traegt an body.start::before einen Rueckfall
(studio), und kopf.js setzt `data-buehne` erst, wenn die Seite steht.
Bis dahin ist der Rueckfall geholt -- auf 43 von 45 Seiten.
Jetzt steht die Szene fest im <body>, erzeugt aus bereiche.js
(tools/buehne-festschreiben.mjs, 20 Seiten). bereich.html bedient
fuenf Bretter und kann das nicht; sie bekommt ein kleines Skript
gleich hinter <body>, das die Szene aus `?b=` setzt, bevor gezeichnet
wird. Gemessen: 1094 -> 879 KB, und die Grenze haelt wieder.
DIE ZUORDNUNG STEHT DAMIT AN ZWEI STELLEN. Das ist nur vertretbar,
weil sie nicht auseinanderlaufen kann: pruef-buehnen-fest.mjs (neu,
13 Pruefungen) haelt HTML gegen bereiche.js, prueft die Lage des
Skripts und dass jede genannte Szene eine Regel hat.
Dabei gefunden und berichtigt -- zweimal an mir selbst: Der erste
Entwurf verglich Szenen mit Dateinamen und meldete teamlage.html
("eingang") als Fehler; die Szene gibt es, ihre Regel zeigt nur auf
ein crew-Bild. Und der Lage-Anker suchte `data-buehne`, das Skript
schreibt `dataset.buehne` -- indexOf gab -1, die Rechnung wurde
negativ und meldete "-2276 Zeichen dahinter".
Gegenproben gefahren: Szene verschoben -> rot mit Abstand; Ausnahme
verwaist -> rot; erfundene Szene -> erkannt.
Dazu gruen: css-klassen, workspace-seiten, neue-seiten, haus-trennung,
kopfleiste-farbe.
Co-Authored-By: Claude Opus 5 <[email protected]>
707 lines
35 KiB
JavaScript
707 lines
35 KiB
JavaScript
/* =====================================================================
|
|
Aus einer Beobachtung wird ein Schritt (15.09.2026)
|
|
|
|
Filipe: „ich will dass du die 2 kategorien perfektionnierst […] es
|
|
soll so einfach wie möglich sein für jeden."
|
|
|
|
---------------------------------------------------------------------
|
|
WAS GEFEHLT HAT
|
|
|
|
Die Entwicklungskarte konnte genau eines: festhalten, dass etwas
|
|
hakt — mit Anlass, das war schon richtig. Danach passierte nichts.
|
|
Beim nächsten Öffnen stand dieselbe Beobachtung da, nur älter.
|
|
|
|
Ein Entwicklungsplan wirkt dann, wenn er an einer ECHTEN Aufgabe
|
|
hängt. Also wird aus „da hakt es" eine Aufgabe auf dem Brett — und
|
|
wenn sie erledigt ist, fragt die Karte dieselbe Frage noch einmal.
|
|
|
|
---------------------------------------------------------------------
|
|
UND GENAU DA SIND DIE RIEGEL
|
|
|
|
Aus „läuft" einen Schritt machen? (darf nicht)
|
|
Aus der Beobachtung eines anderen? (darf nicht)
|
|
Zweimal zum selben Punkt? (darf nicht)
|
|
Ein Modi für sich selbst? (darf nicht)
|
|
Steht der Anlass hinterher im Protokoll? (darf nicht)
|
|
|
|
Aufrufen mit: node server/pruef-schritt.mjs
|
|
===================================================================== */
|
|
|
|
import { mkdtempSync, rmSync, readFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { request as httpAnfrage } from "node:http";
|
|
import { eigenerPort } from "./helfer-port.mjs";
|
|
|
|
const PORT = await eigenerPort(import.meta, "pruef-schritt");
|
|
|
|
const ordner = mkdtempSync(join(tmpdir(), "ws-schritt-"));
|
|
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(240_000, "pruef-schritt");
|
|
await new Promise((r) => setTimeout(r, 700));
|
|
|
|
process.on("uncaughtException", (f) => { console.error("ABSTURZ:", f); process.exit(7); });
|
|
process.on("unhandledRejection", (f) => { console.error("ABSTURZ (Versprechen):", f); process.exit(7); });
|
|
|
|
let fehler = 0, geprueft = 0;
|
|
const melde = (t) => console.log(t);
|
|
const ok = (b, t) => { geprueft++; console.log((b ? " ok " : " FEHL ") + t); if (!b) fehler++; };
|
|
|
|
const CREW = "crew.dogfather-universe.com";
|
|
/* ==== DIESE PRUEFUNG WOHNT BEI TEAM DOGI (25.09.2026) ==============
|
|
|
|
Gemessen werden Modis, ihre Aufgaben und ihre Entwicklung -- alles
|
|
davon gehoert ins Teamhaus. Gefragt wurde trotzdem ueber die
|
|
AGENTURadresse, und seit der Trennung vom 24.09.2026 antwortet der
|
|
Server dort richtigerweise mit 400 oder 404: Einen Modi gibt es dort
|
|
nicht. Die Folge waren Meldungen, die alle an einem einzigen Aufruf
|
|
hingen -- Folge, keine Ursache.
|
|
|
|
Die Agenturadresse bleibt unter ihrem Namen stehen; gebraucht wird
|
|
sie nur noch dort, wo ausdruecklich das andere Haus gemeint ist. */
|
|
const AGENTUR = "workspace.dogfather-universe.com";
|
|
|
|
const { DatabaseSync } = await import("node:sqlite");
|
|
const { scryptSync, randomBytes, createHmac } = await import("node:crypto");
|
|
const kat = await import("./workspace-entwicklungs-punkte.js");
|
|
const ent = await import("./workspace-entwicklung.js");
|
|
|
|
const oeffne = () => new DatabaseSync(process.env.WORKSPACE_DB);
|
|
const jetzt = new Date().toISOString();
|
|
|
|
let idDogi, idHand, idFrida;
|
|
{
|
|
const d = oeffne();
|
|
const s = randomBytes(32).toString("hex");
|
|
d.prepare("INSERT INTO einstellungen (schluessel, wert, geaendert, von)"
|
|
+ " VALUES (?,?,?,NULL) ON CONFLICT(schluessel) DO NOTHING")
|
|
.run("code_kennung_schluessel", s, jetzt);
|
|
const anlegen = (name, rolle, code) => {
|
|
const salt = randomBytes(16).toString("hex");
|
|
const hash = scryptSync(code, 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, code_kennung, aktiv, erstellt)"
|
|
+ " VALUES (?,?,?,?,?,?,1,?)")
|
|
.run(name, rolle, hash, salt, 32768, createHmac("sha256", s).update(code).digest("hex"), jetzt);
|
|
return d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
|
};
|
|
idDogi = anlegen("Filipe", "admin", "CODE-DOGI-0001");
|
|
idHand = anlegen("Rieke", "hand", "CODE-HAND-0001");
|
|
idFrida = anlegen("Frida", "modi", "CODE-MODI-0001");
|
|
d.close();
|
|
}
|
|
|
|
function ruf(pfad, host, methode, kopf = {}, koerper = null) {
|
|
return new Promise((fertig, schief) => {
|
|
const a = httpAnfrage({ host: "127.0.0.1", port: PORT, path: pfad, method: methode,
|
|
headers: { Host: host, ...(koerper ? { "Content-Type": "application/json" } : {}), ...kopf } },
|
|
(antwort) => {
|
|
let text = "";
|
|
antwort.on("data", (s) => { text += s; });
|
|
antwort.on("end", () => fertig({ code: antwort.statusCode, text, kopf: antwort.headers }));
|
|
});
|
|
a.on("error", schief);
|
|
if (koerper) a.write(JSON.stringify(koerper));
|
|
a.end();
|
|
});
|
|
}
|
|
const json = (a) => { try { return JSON.parse(a.text); } catch { return {}; } };
|
|
async function anmelden(rolle, code, host) {
|
|
const r = await ruf("/workspace/api/anmelden", host, "POST", {}, { rolle, code });
|
|
return [].concat(r.kopf?.["set-cookie"] || []).map((c) => c.split(";")[0]).join("; ");
|
|
}
|
|
const kDogi = await anmelden("admin", "CODE-DOGI-0001", CREW);
|
|
const kHand = await anmelden("hand", "CODE-HAND-0001", CREW);
|
|
const kFrida = await anmelden("modi", "CODE-MODI-0001", CREW);
|
|
ok(!!kDogi && !!kHand && !!kFrida, "DogFather, die rechte Hand und ein Modi sind angemeldet");
|
|
|
|
/* Zwei Punkte, die andere setzen dürfen. */
|
|
const P1 = kat.ENTWICKLUNG_FREMD[0].schluessel;
|
|
const P2 = kat.ENTWICKLUNG_FREMD[1].schluessel;
|
|
const SELBST = kat.ENTWICKLUNG_SELBST[0].schluessel;
|
|
|
|
/* DIE ADRESSE GEHÖRT ZUM KEKS.
|
|
|
|
Ein Zugang ist an das Haus gebunden, über das er angemeldet wurde --
|
|
die rechte Hand arbeitet auf crew., DogFather auf workspace. Mein
|
|
erster Entwurf schickte beide über dieselbe Adresse; die rechte Hand
|
|
bekam daraufhin 401, und WEIL sie nichts setzen konnte, ging ein
|
|
zweiter Test ("aus der Beobachtung eines anderen wird kein Schritt")
|
|
aus dem falschen Grund durch. Ein grüner Haken über einer Leere. */
|
|
const wo = (keks) => (keks === kDogi ? CREW : CREW);
|
|
|
|
/* ==== ZUERST ZUTRAGEN, DANN MESSEN (25.09.2026) ====================
|
|
|
|
Filipe: „es sollen nur die menge angezeigt werden die wir zutragen
|
|
und erledigte dan auch nur die die erledigt wurden von den
|
|
zugetragenen."
|
|
|
|
Seither ist das GANZE der Kachel das, was einem Menschen zugetragen
|
|
ist -- nicht mehr der ganze Katalog. Diese Pruefung setzte
|
|
Einschaetzungen auf Punkte, die Frida nie bekommen hatte; die
|
|
Uebersicht zaehlte sie zu Recht nicht mit, und die Meldung lautete
|
|
„die Kachel zaehlt sofort mit (0 -> 0)".
|
|
|
|
DIE PRUEFUNG MISST JETZT DIESELBE LAGE WIE VORHER -- nur mit dem
|
|
Schritt davor, den es seit gestern gibt. Die drei Punkte, um die es
|
|
unten geht, werden Frida zugetragen; alles andere bleibt, wie es
|
|
war. Ueber die ECHTE Route und nicht ueber die Datenbank: So ist
|
|
der Weg, den auch DogFather nimmt, gleich mitgeprueft. */
|
|
{
|
|
const a = await ruf(`/workspace/api/entwicklung/person/${idFrida}/punkte`,
|
|
CREW, "PUT", { cookie: kDogi }, { punkte: [P1, P2] });
|
|
ok(a.code === 200, `die zwei Punkte sind Frida zugetragen (${a.code})`);
|
|
}
|
|
const setzen = (keks, punkt, stufe, anlass) =>
|
|
ruf(`/workspace/api/entwicklung/person/${idFrida}/${punkt}`, wo(keks),
|
|
"PUT", { cookie: keks }, { stufe, anlass });
|
|
const schritt = (keks, punkt, person = idFrida) =>
|
|
ruf(`/workspace/api/entwicklung/person/${person}/${punkt}/schritt`, wo(keks),
|
|
"POST", { cookie: keks }, {});
|
|
const karte = async (keks = kDogi) => json(await ruf(
|
|
`/workspace/api/entwicklung/person/${idFrida}`, wo(keks), "GET", { cookie: keks }));
|
|
const punktVon = (k, s) => k.bloecke?.flatMap((b) => b.punkte).find((p) => p.schluessel === s);
|
|
|
|
/* =======================================================================
|
|
1. EIN SCHRITT ENTSTEHT NUR AUS EINEM „DA HAKT ES"
|
|
======================================================================= */
|
|
melde("");
|
|
melde("=== 1. Nur aus „Da hakt es“ ===");
|
|
{
|
|
const l = await setzen(kDogi, P1, "laeuft");
|
|
ok(l.code === 200, `„Läuft“ ist gesetzt (${l.code})`);
|
|
const ohne = await schritt(kDogi, P1);
|
|
ok(ohne.code === 400 && json(ohne).fehler === "kein_hakt",
|
|
`daraus wird kein Schritt (${ohne.code}, ${json(ohne).fehler})`);
|
|
|
|
/* Gar nichts gesetzt: auch nicht. */
|
|
const nichts = await schritt(kDogi, P2);
|
|
ok(nichts.code === 400 && json(nichts).fehler === "kein_hakt",
|
|
"und aus gar nichts erst recht nicht");
|
|
|
|
const h = await setzen(kDogi, P1, "hakt", "Am Dienstag zweimal hintereinander gesehen.");
|
|
ok(h.code === 200, `mit „Da hakt es“ und Anlass geht es (${h.code})`);
|
|
const ja = await schritt(kDogi, P1);
|
|
ok(ja.code === 201, `und daraus wird ein Schritt (${ja.code})`);
|
|
ok(json(ja).titel === kat.ENTWICKLUNG_FREMD[0].titel,
|
|
`er heißt wie der Punkt: „${json(ja).titel}“`);
|
|
ok(/^\d{4}-\d{2}-\d{2}$/.test(json(ja).frist || ""),
|
|
`mit einer Frist in ${ent.SCHRITT_TAGE} Tagen (${json(ja).frist})`);
|
|
}
|
|
|
|
/* =======================================================================
|
|
2. ES IST EINE ECHTE AUFGABE — keine Notiz
|
|
======================================================================= */
|
|
melde("");
|
|
melde("=== 2. Eine echte Aufgabe ===");
|
|
{
|
|
const d = oeffne();
|
|
const a = d.prepare("SELECT * FROM aufgaben WHERE aus_punkt = ?").get(P1);
|
|
d.close();
|
|
ok(!!a, "sie steht in der Aufgabentabelle, nicht in einer eigenen Liste");
|
|
ok(a.verantwortlich_id === idFrida, "Frida ist verantwortlich, nicht DogFather");
|
|
ok(a.erstellt_von === idDogi, "und DogFather hat sie angelegt");
|
|
ok(a.status === "offen", `sie ist offen (${a.status})`);
|
|
/* DER ANLASS WANDERT MIT -- ohne ihn stuende auf dem Brett ein Satz
|
|
ohne Grund, und die Aufgabe waere ein Vorwurf. */
|
|
ok(/Am Dienstag zweimal/.test(a.beschreibung || ""),
|
|
"der Anlass steht in der Beschreibung");
|
|
|
|
/* UND SIE STEHT WIRKLICH AUF DEM BRETT, nicht nur in der Tabelle. */
|
|
const brett = json(await ruf("/workspace/api/aufgaben", CREW, "GET", { cookie: kDogi }));
|
|
const drauf = (brett.aufgaben || []).find((x) => x.id === a.id);
|
|
ok(!!drauf, "und sie taucht auf dem Aufgabenbrett auf");
|
|
|
|
/* AUCH FRIDA SIEHT SIE -- eine Aufgabe, die nur die Leitung sieht,
|
|
waere wieder eine Notiz. */
|
|
const ihres = json(await ruf("/workspace/api/aufgaben", CREW, "GET", { cookie: kFrida }));
|
|
ok((ihres.aufgaben || []).some((x) => x.id === a.id),
|
|
"Frida sieht sie ebenfalls — sonst wäre sie keine Aufgabe");
|
|
}
|
|
|
|
/* =======================================================================
|
|
3. DIE KARTE ZEIGT IHN
|
|
======================================================================= */
|
|
melde("");
|
|
melde("=== 3. Die Karte zeigt ihn ===");
|
|
{
|
|
const k = await karte();
|
|
const p = punktVon(k, P1);
|
|
ok(!!p?.schritt, "an dem Punkt hängt der Schritt");
|
|
ok(p.schritt.status === "offen", `er läuft (${p.schritt.status})`);
|
|
ok(punktVon(k, P2)?.schritt === null, "an einem Punkt ohne Schritt hängt nichts");
|
|
|
|
/* ZWEIMAL ZUM SELBEN PUNKT WAERE ZWEIMAL DIESELBE ERINNERUNG -- und
|
|
die zweite macht die erste wertlos. */
|
|
const nochmal = await schritt(kDogi, P1);
|
|
ok(nochmal.code === 400 && json(nochmal).fehler === "schon_da",
|
|
`ein zweiter Schritt zum selben Punkt: abgelehnt (${json(nochmal).fehler})`);
|
|
ok(json(nochmal).aufgabe_id === p.schritt.id,
|
|
"und die Absage nennt den, der schon läuft");
|
|
}
|
|
|
|
/* =======================================================================
|
|
4. WER DARF — UND WER NICHT
|
|
======================================================================= */
|
|
melde("");
|
|
melde("=== 4. Wer darf ===");
|
|
{
|
|
/* DIE RECHTE HAND FÜHRT DAS TEAM MIT -- sie darf. */
|
|
await setzen(kHand, P2, "hakt", "Ist mir im Stream am Freitag aufgefallen.");
|
|
const hand = await schritt(kHand, P2);
|
|
ok(hand.code === 201, `die rechte Hand darf auch (${hand.code})`);
|
|
|
|
/* EIN MODI NICHT -- nicht für sich und nicht für andere. */
|
|
const modi = await ruf(`/workspace/api/entwicklung/person/${idFrida}/${P1}/schritt`,
|
|
CREW, "POST", { cookie: kFrida }, {});
|
|
ok(json(modi).fehler === "nicht_gefunden", "mit der Auskunft „gibt es nicht“");
|
|
ok(modi.code === 404, `ein Modi bekommt 404 — nicht „verboten“ (${modi.code})`);
|
|
|
|
/* AUS DER BEOBACHTUNG EINES ANDEREN wird kein Schritt: DogFather hat
|
|
bei P2 nichts gesetzt, die rechte Hand schon. */
|
|
const fremd = await schritt(kDogi, P2);
|
|
ok(fremd.code === 400 && json(fremd).fehler === "kein_hakt",
|
|
"und aus der Beobachtung eines anderen auch nicht");
|
|
|
|
/* EIN PUNKT AUS BLOCK 5 SIEHT VON AUSSEN AUS WIE EIN ERFUNDENER. */
|
|
const geheim = await schritt(kDogi, SELBST);
|
|
ok(geheim.code === 404, `ein Punkt aus „Wie geht's dir?“ gibt 404 (${geheim.code})`);
|
|
const quatsch = await schritt(kDogi, "e-gibt-es-nicht");
|
|
ok(quatsch.code === 404, "ein erfundener Punkt ebenfalls");
|
|
}
|
|
|
|
/* =======================================================================
|
|
5. IM PROTOKOLL STEHT, DASS — NICHT WORAN
|
|
======================================================================= */
|
|
melde("");
|
|
melde("=== 5. Das Protokoll ===");
|
|
{
|
|
const d = oeffne();
|
|
const zeilen = d.prepare(
|
|
"SELECT detail FROM protokoll WHERE aktion = 'entwicklung_schritt'").all();
|
|
d.close();
|
|
ok(zeilen.length === 2, `${zeilen.length} Schritte stehen im Protokoll`);
|
|
ok(zeilen.every((z) => /Frida/.test(z.detail || "")),
|
|
"mit Punkt und Name — das ist der Vorgang");
|
|
/* WORAN JEMAND ETWAS GEMERKT HAT, GEHÖRT NICHT INS PROTOKOLL. Es
|
|
liest sich anders, wenn es zwischen Anmeldungen steht. */
|
|
ok(!zeilen.some((z) => /Dienstag|Freitag/.test(z.detail || "")),
|
|
"aber ohne den Anlass");
|
|
}
|
|
|
|
/* =======================================================================
|
|
6. UND DANN SCHLIESST SICH DER KREIS
|
|
======================================================================= */
|
|
melde("");
|
|
melde("=== 6. Der Kreis ===");
|
|
{
|
|
const d = oeffne();
|
|
const a = d.prepare("SELECT id FROM aufgaben WHERE aus_punkt = ?").get(P1);
|
|
d.close();
|
|
const fertig = await ruf(`/workspace/api/aufgaben/${a.id}`, CREW, "PATCH",
|
|
{ cookie: kDogi }, { status: "erledigt" });
|
|
ok(fertig.code === 200, `die Aufgabe wird erledigt (${fertig.code})`);
|
|
|
|
const k = await karte();
|
|
const p = punktVon(k, P1);
|
|
ok(p.schritt?.status === "erledigt", `die Karte sieht das (${p.schritt?.status})`);
|
|
ok(!!p.schritt?.erledigt_am, "mit Datum");
|
|
|
|
/* UND DANACH GEHT ES WIEDER -- der Kreis ist ein Kreis, keine
|
|
Einbahnstrasse. Waere das gesperrt, koennte man denselben Punkt
|
|
nie wieder angehen. */
|
|
const zweite = await schritt(kDogi, P1);
|
|
ok(zweite.code === 201, `zum selben Punkt geht danach ein neuer Schritt (${zweite.code})`);
|
|
const k2 = await karte();
|
|
ok(punktVon(k2, P1).schritt?.id === json(zweite).id,
|
|
"und die Karte zeigt den NEUEN, nicht den alten");
|
|
}
|
|
|
|
/* =======================================================================
|
|
7. DER VERWEIS AUFS BRETT FÜHRT WIRKLICH HIN
|
|
======================================================================= */
|
|
melde("");
|
|
melde("=== 7. Der Verweis ===");
|
|
{
|
|
/* `aufgaben.html#a12` stand an drei Stellen im Haus und wurde von
|
|
keiner gelesen -- das Brett kannte nur `?zeigen=`. Wer draufdrueckte,
|
|
landete auf dem Brett und suchte von Hand. */
|
|
const brett = readFileSync(new URL("../workspace/assets/js/aufgaben.js", import.meta.url), "utf8");
|
|
ok(/data-id=/.test(brett), "die Karten auf dem Brett tragen ihre Nummer");
|
|
ok(/\^#a/.test(brett), "und das Brett liest `#a<nummer>` aus der Adresse");
|
|
|
|
const e = readFileSync(new URL("../workspace/assets/js/entwicklung.js", import.meta.url), "utf8");
|
|
ok(/aufgaben\.html#a/.test(e), "die Entwicklungskarte verweist in dieser Schreibweise");
|
|
const b = readFileSync(new URL("../workspace/assets/js/bereich.js", import.meta.url), "utf8");
|
|
const r = readFileSync(new URL("../workspace/assets/js/report.js", import.meta.url), "utf8");
|
|
ok(/aufgaben\.html#a/.test(b) && /aufgaben\.html#a/.test(r),
|
|
"die beiden anderen Stellen auch — sie funktionieren jetzt mit");
|
|
}
|
|
|
|
/* =======================================================================
|
|
8. IM BROWSER
|
|
======================================================================= */
|
|
melde("");
|
|
melde("=== 8. Im Browser ===");
|
|
{
|
|
const { chromium } = await import(
|
|
"file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs");
|
|
const browser = await chromium.launch();
|
|
const kontext = await browser.newContext({ viewport: { width: 1280, height: 1100 } });
|
|
await kontext.addCookies(kDogi.split("; ").filter(Boolean).map((teil) => {
|
|
const i = teil.indexOf("=");
|
|
return { name: teil.slice(0, i), value: teil.slice(i + 1), domain: "127.0.0.1", path: "/" };
|
|
}));
|
|
const seite = await kontext.newPage();
|
|
const konsole = [];
|
|
seite.on("console", (m) => { if (m.type() === "error" && !/favicon|ERR_/i.test(m.text())) konsole.push(m.text()); });
|
|
seite.on("pageerror", (e) => konsole.push("Absturz: " + e.message));
|
|
|
|
await seite.goto(`http://127.0.0.1:${PORT}/workspace/entwicklung.html`, { waitUntil: "networkidle" });
|
|
await seite.waitForTimeout(800);
|
|
/* Erst die Person öffnen -- ohne Karte gibt es keine Punkte. */
|
|
/* FRIDAS KARTE, nicht die erste in der Liste. Die steht dort nach
|
|
der Hierarchie des Hauses -- also die rechte Hand -- und die hat
|
|
keinen Schritt. Mein erster Entwurf klickte blind auf die erste
|
|
und maß danach eine leere Karte. */
|
|
await seite.click('.e-person:has-text("Frida")');
|
|
await seite.waitForTimeout(900);
|
|
|
|
/* ===== DIE KATEGORIEN KLAPPEN AUF UND ZU (15.09.2026) ==============
|
|
|
|
Filipe: „ich will auch dass man die kategorien von den fragen, also
|
|
die liste auf und zu drücken kann mit einem button."
|
|
|
|
Geprüft wird nicht, dass es einen Knopf GIBT -- sondern dass er
|
|
etwas tut, und dass zugeklappt trotzdem dasteht, was drin ist.
|
|
================================================================ */
|
|
/* ==== DIE KARTE GEHT SEIT DEM 01.10.2026 GEFILTERT AUF ============
|
|
(nachgezogen am 07.10.2026)
|
|
|
|
entwicklung.js setzt beim Oeffnen `stufenFilter = 'zugetragen'`,
|
|
sobald dieser Mensch ueberhaupt etwas zugetragen bekommen hat --
|
|
„womit die Karte aufgeht". Bloecke ohne zugetragene Punkte werden
|
|
dann gar nicht gezeichnet (`if (!punkte.length) continue`).
|
|
|
|
DIESE PRUEFUNG WUSSTE DAVON NICHTS und zaehlte danach ALLE
|
|
Kategorien. Ergebnis: „1 von 6" -- ein Befund, der auf die Karte
|
|
zeigte, obwohl die Karte tat, was sie soll. Und weil danach kein
|
|
einziger Block mehr zugeklappt war, lief der Klick auf einen
|
|
zugeklappten 30 Sekunden in die Frist und riss den ganzen Lauf mit.
|
|
Ein Fehlalarm, der einen zweiten echten Fehler erzeugt.
|
|
|
|
ZUERST DIE VORGABE PRUEFEN -- sie ist eine Zusage, keine Nebensache
|
|
--, dann auf „Alle" stellen. Was die Zeile darunter behauptet („die
|
|
Karte zeigt ALLE Bloecke"), gilt genau dort. */
|
|
const vorgabe = await seite.evaluate(() => {
|
|
const k = document.querySelector('.e-stufen__knopf[aria-pressed="true"]');
|
|
return {
|
|
gewaehlt: k?.dataset.erwartung ?? null,
|
|
wort: k?.querySelector(".e-stufen__name")?.textContent.trim() ?? null,
|
|
zugetragen: Number(document.querySelector('.e-stufen__knopf[data-erwartung="zugetragen"] .e-stufen__zahl')?.textContent || 0),
|
|
};
|
|
});
|
|
ok(vorgabe.zugetragen > 0 && vorgabe.gewaehlt === "zugetragen",
|
|
`die Karte geht auf „${vorgabe.wort}" auf, weil ${vorgabe.zugetragen} Punkte zugetragen sind`);
|
|
|
|
await seite.click('.e-stufen__knopf[data-erwartung=""]');
|
|
await seite.waitForTimeout(600);
|
|
const nachAlle = await seite.evaluate(() =>
|
|
document.querySelector('.e-stufen__knopf[aria-pressed="true"]')?.dataset.erwartung);
|
|
ok(nachAlle === "", `„Alle" ist danach gewaehlt (${JSON.stringify(nachAlle)})`);
|
|
|
|
const bloecke = await seite.evaluate(() => {
|
|
const b = [...document.querySelectorAll(".e-block")];
|
|
return {
|
|
anzahl: b.length,
|
|
offen: b.filter((x) => x.dataset.offen === "ja").length,
|
|
schalter: document.querySelectorAll(".e-block__schalter").length,
|
|
staende: [...document.querySelectorAll(".e-block__stand")].map((x) => x.textContent.trim()),
|
|
hakt: [...document.querySelectorAll(".e-block__hakt")]
|
|
.filter((x) => !x.hidden).map((x) => x.textContent.trim()),
|
|
versteckt: b.filter((x) => x.querySelector(".e-block__koerper")?.hidden).length,
|
|
alleKnopf: document.querySelector(".e-bloecke__alle")?.textContent.trim() || "",
|
|
};
|
|
});
|
|
/* DIE ZAHL KOMMT AUS DEM KATALOG, nicht aus dieser Datei.
|
|
|
|
Hier stand `=== 4`. Am 17.09.2026 kamen zwei Bloecke dazu ("Clips,
|
|
Schnitt und Kommentare" und "Waehrend der Stream laeuft"), und die
|
|
Zeile war ab da rot, ohne dass irgendetwas kaputt war -- eine feste
|
|
Zahl ist eine Rechnung von gestern. Was die Zeile eigentlich
|
|
behauptet, ist: Die Karte zeigt ALLE Bloecke. */
|
|
const bloeckeErwartet = (await import("./workspace-entwicklungs-punkte.js"))
|
|
.ENTWICKLUNG_BLOECKE.filter((b) => !b.nurSelbst).length;
|
|
ok(bloecke.anzahl === bloeckeErwartet,
|
|
`${bloecke.anzahl} von ${bloeckeErwartet} Kategorien stehen auf der Karte`);
|
|
ok(bloecke.schalter === bloecke.anzahl, "jede hat einen Knopf zum Auf- und Zuklappen");
|
|
/* GENAU EINE STEHT OFFEN -- die erste, in der noch etwas fehlt. Alle
|
|
zu hieße jedes Mal suchen, alle auf wäre der Zustand von vorher. */
|
|
ok(bloecke.offen === 1, `genau eine steht offen (${bloecke.offen})`);
|
|
ok(bloecke.versteckt === bloecke.anzahl - 1,
|
|
`die anderen ${bloecke.versteckt} sind wirklich zugeklappt`);
|
|
/* ZUGEKLAPPT MUSS SIE TROTZDEM ETWAS SAGEN. */
|
|
ok(bloecke.staende.length === bloecke.anzahl
|
|
&& bloecke.staende.every((x) => x.includes(' / ')),
|
|
`jeder Kopf sagt, wie weit er ist (${bloecke.staende.join(", ")})`);
|
|
/* SICHTBAR, nicht bloß vorhanden. Seit dem 15.09. steht der Hinweis
|
|
immer im Baum (damit er nachgezogen werden kann, ohne den Kopf neu
|
|
zu bauen) -- „es gibt ihn“ wäre damit über vier versteckten grün. */
|
|
ok(bloecke.hakt.length === 1 && /hakt/.test(bloecke.hakt[0]),
|
|
`und NUR wo etwas hakt, steht es im Kopf (${bloecke.hakt.join(", ") || "nirgends"})`);
|
|
ok(/Alle aufklappen/.test(bloecke.alleKnopf),
|
|
`daneben einer für alle auf einmal („${bloecke.alleKnopf}“)`);
|
|
|
|
/* UND JETZT WIRKLICH DRÜCKEN. Ein Knopf, den niemand betätigt hat,
|
|
ist kein geprüfter Knopf. */
|
|
await seite.click(".e-block:not([data-offen='ja']) .e-block__schalter");
|
|
await seite.waitForTimeout(250);
|
|
const nachKlick = await seite.evaluate(() => ({
|
|
offen: document.querySelectorAll('.e-block[data-offen="ja"]').length,
|
|
ausgeklappt: [...document.querySelectorAll(".e-block__schalter")]
|
|
.filter((x) => x.getAttribute("aria-expanded") === "true").length,
|
|
}));
|
|
ok(nachKlick.offen === 2, `nach einem Klick stehen zwei offen (${nachKlick.offen})`);
|
|
ok(nachKlick.ausgeklappt === 2,
|
|
"und ein Vorleseprogramm erfährt dasselbe (aria-expanded)");
|
|
|
|
await seite.click(".e-bloecke__alle");
|
|
await seite.waitForTimeout(400);
|
|
const alle = await seite.evaluate(() => ({
|
|
offen: document.querySelectorAll('.e-block[data-offen="ja"]').length,
|
|
knopf: document.querySelector(".e-bloecke__alle")?.textContent.trim() || "",
|
|
}));
|
|
ok(alle.offen === bloeckeErwartet,
|
|
`„Alle aufklappen“ öffnet wirklich alle (${alle.offen} von ${bloeckeErwartet})`);
|
|
ok(/Alle zuklappen/.test(alle.knopf),
|
|
`und der Knopf heißt danach anders („${alle.knopf}“)`);
|
|
|
|
const stand = await seite.evaluate(() => ({
|
|
punkte: document.querySelectorAll(".e-punkt").length,
|
|
laeuft: document.querySelectorAll('.e-schritt[data-lage="laeuft"]').length,
|
|
knoepfe: document.querySelectorAll(".e-schritt__knopf").length,
|
|
leere: document.querySelectorAll(".e-schritt:not([data-lage])").length,
|
|
verweis: document.querySelector(".e-schritt__hin")?.getAttribute("href") || "",
|
|
}));
|
|
ok(stand.punkte > 20, `${stand.punkte} Punkte stehen auf der Karte`);
|
|
ok(stand.laeuft >= 1, `${stand.laeuft} Schritt läuft sichtbar`);
|
|
ok(/aufgaben\.html#a\d+/.test(stand.verweis),
|
|
`und verweist auf die Aufgabe (${stand.verweis})`);
|
|
/* KEIN KNOPF, WO ER NICHTS TUN KANN. Bei über zwanzig Punkten wären
|
|
zwanzig Knöpfe, die fast alle „geht nicht" antworten, schlimmer
|
|
als keiner. */
|
|
ok(stand.knoepfe === 0,
|
|
"an den übrigen Punkten steht kein Knopf — dort hakt nichts");
|
|
ok(stand.leere > 20, `und dort steht auch kein leerer Kasten (${stand.leere})`);
|
|
|
|
/* DER SPRUNG: die Adresse mit der Nummer, und das Brett zeigt genau
|
|
die eine Aufgabe. */
|
|
const d = oeffne();
|
|
const a = d.prepare("SELECT id FROM aufgaben WHERE aus_punkt IS NOT NULL ORDER BY id DESC").get();
|
|
d.close();
|
|
await seite.goto(`http://127.0.0.1:${PORT}/workspace/aufgaben.html#a${a.id}`,
|
|
{ waitUntil: "networkidle" });
|
|
await seite.waitForTimeout(1100);
|
|
const sprung = await seite.evaluate(() => ({
|
|
leiste: document.querySelector(".ziel-leiste__text")?.textContent || "",
|
|
marke: document.querySelector(".ziel-leiste__marke")?.textContent || "",
|
|
}));
|
|
ok(/Diese eine Aufgabe/.test(sprung.leiste),
|
|
`das Brett sagt, was es zeigt: „${sprung.leiste}“`);
|
|
ok(sprung.marke === "1", `und es ist genau eine (${sprung.marke})`);
|
|
|
|
/* =====================================================================
|
|
ZWEI FEHLER, DIE FILIPE GEMELDET HAT (15.09.2026)
|
|
|
|
Ein Fehler, der nur behoben ist, ist beim naechsten Umbau wieder da.
|
|
Beide werden deshalb nachgestellt, nicht beschrieben.
|
|
===================================================================== */
|
|
|
|
/* ZURÜCK AUF DIE ENTWICKLUNGSSEITE. Der Abschnitt davor ist zum
|
|
Aufgabenbrett gesprungen -- mein erster Entwurf maß danach auf dem
|
|
Brett weiter und fand dort weder Punkte noch eine Karte. Gemeldet
|
|
hat das die Prüfung selbst: „Kachel und Karte nennen dieselbe Zahl
|
|
(„“ / „“)" -- zwei leere Texte sind gleich und beweisen nichts.
|
|
Genau dafür steht die Zahl in der Bedingung daneben. */
|
|
await seite.goto(`http://127.0.0.1:${PORT}/workspace/entwicklung.html`,
|
|
{ waitUntil: "networkidle" });
|
|
await seite.waitForTimeout(800);
|
|
await seite.click('.e-person:has-text("Frida")');
|
|
await seite.waitForTimeout(1000);
|
|
await seite.click(".e-bloecke__alle");
|
|
await seite.waitForTimeout(400);
|
|
|
|
/* (1) und (2) IN EINEM DURCHGANG -- sie gehören zusammen.
|
|
|
|
Filipe hat beides am selben Klick gemerkt: Die Seite sprang hoch,
|
|
UND die Zahl auf der Kachel blieb stehen. Also wird auch beides am
|
|
selben Klick gemessen: Vorher die Zahl und die Höhe merken, EINMAL
|
|
drücken, beides nachsehen. */
|
|
await seite.evaluate(() => window.scrollTo({ top: 600, behavior: "instant" }));
|
|
await seite.waitForTimeout(250);
|
|
const vorDemKlick = await seite.evaluate(() => {
|
|
const name = document.querySelector("#karte .e-karte__name")?.textContent.trim() || "";
|
|
const kachel = [...document.querySelectorAll(".e-person")]
|
|
.find((x) => x.querySelector(".e-person__name")?.textContent.trim() === name);
|
|
return {
|
|
name,
|
|
y: Math.round(window.scrollY),
|
|
/* WO DIE ZAHL AUF DER KACHEL STEHT -- zum dritten Mal woanders.
|
|
|
|
Bis 17.09.2026 ein Satz ("2 von 68 angesehen"), danach ein
|
|
Bilanz-Kasten, seit dem 24.09.2026 die Ziffer vor "von 68
|
|
angesehen" plus der Ring darueber.
|
|
|
|
Das ist kein Zufall und kein Pech: Wer eine Kachel umbaut,
|
|
verschiebt die Zahl. Die Pruefung muss es merken -- und sie
|
|
merkt es nur, weil sie die Zahl VERGLEICHT statt sie bloss zu
|
|
lesen. Beim Umbau am 17.09. las genau dieser Selektor
|
|
monatelang einen leeren String, ohne dass etwas kaputt war.
|
|
|
|
DER RING WIRD MITGELESEN. Er ist seit dem 24.09. die groessere
|
|
der beiden Darstellungen; bewegte sich nur die Ziffer, stuende
|
|
ein Ring bei 3 % ueber einer 46 -- und das faellt niemandem
|
|
auf, weil man das eine sieht und das andere liest. */
|
|
kachel: kachel?.querySelector(".e-person__stand-zahl")?.textContent.trim() || "",
|
|
bogen: kachel?.querySelector(".e-ring__bogen")
|
|
?.getAttribute("stroke-dasharray") || "",
|
|
kopfZahl: (document.querySelector("#karte .e-karte__stand")?.textContent
|
|
.match(/(\d+) von/) || [])[1] || "",
|
|
kopf: document.querySelector("#karte .e-karte__stand")?.textContent.trim() || "",
|
|
};
|
|
});
|
|
ok(vorDemKlick.name === "Frida", `Fridas Karte ist offen (${vorDemKlick.name})`);
|
|
/* Die Kachel nennt jetzt eine nackte Ziffer, keinen Satz. */
|
|
const zahlAus = (x) => { const n = Number(x); return Number.isFinite(n) && x !== "" ? n : -1; };
|
|
ok(zahlAus(vorDemKlick.kachel) >= 0,
|
|
`vorher steht auf ihrer Kachel „${vorDemKlick.kachel}“`);
|
|
|
|
/* Ein Punkt, der noch NICHT gesetzt ist -- genau der löst den
|
|
Neuaufbau aus, und genau da sprang die Seite. */
|
|
const gedrueckt = await seite.evaluate(() => {
|
|
const p = [...document.querySelectorAll(".e-punkt")]
|
|
.find((x) => !x.dataset.stufe && x.offsetParent);
|
|
if (!p) return false;
|
|
p.querySelector('.e-wahl__knopf[data-stufe="laeuft"]')?.click();
|
|
return true;
|
|
});
|
|
ok(gedrueckt, "ein noch nicht gesetzter Punkt wird angeklickt");
|
|
await seite.waitForTimeout(1400);
|
|
|
|
const nachDemKlick = await seite.evaluate(() => {
|
|
const name = document.querySelector("#karte .e-karte__name")?.textContent.trim() || "";
|
|
const kachel = [...document.querySelectorAll(".e-person")]
|
|
.find((x) => x.querySelector(".e-person__name")?.textContent.trim() === name);
|
|
return {
|
|
y: Math.round(window.scrollY),
|
|
/* WO DIE ZAHL AUF DER KACHEL STEHT -- zum dritten Mal woanders.
|
|
|
|
Bis 17.09.2026 ein Satz ("2 von 68 angesehen"), danach ein
|
|
Bilanz-Kasten, seit dem 24.09.2026 die Ziffer vor "von 68
|
|
angesehen" plus der Ring darueber.
|
|
|
|
Das ist kein Zufall und kein Pech: Wer eine Kachel umbaut,
|
|
verschiebt die Zahl. Die Pruefung muss es merken -- und sie
|
|
merkt es nur, weil sie die Zahl VERGLEICHT statt sie bloss zu
|
|
lesen. Beim Umbau am 17.09. las genau dieser Selektor
|
|
monatelang einen leeren String, ohne dass etwas kaputt war.
|
|
|
|
DER RING WIRD MITGELESEN. Er ist seit dem 24.09. die groessere
|
|
der beiden Darstellungen; bewegte sich nur die Ziffer, stuende
|
|
ein Ring bei 3 % ueber einer 46 -- und das faellt niemandem
|
|
auf, weil man das eine sieht und das andere liest. */
|
|
kachel: kachel?.querySelector(".e-person__stand-zahl")?.textContent.trim() || "",
|
|
bogen: kachel?.querySelector(".e-ring__bogen")
|
|
?.getAttribute("stroke-dasharray") || "",
|
|
kopfZahl: (document.querySelector("#karte .e-karte__stand")?.textContent
|
|
.match(/(\d+) von/) || [])[1] || "",
|
|
kopf: document.querySelector("#karte .e-karte__stand")?.textContent.trim() || "",
|
|
};
|
|
});
|
|
|
|
/* (1) „immer wenn ich auf was drücke dan geht das fenster wieder hoch." */
|
|
ok(Math.abs(nachDemKlick.y - vorDemKlick.y) <= 4,
|
|
`die Seite bleibt stehen, wo sie stand (${vorDemKlick.y} -> ${nachDemKlick.y})`);
|
|
|
|
/* (2) „wieso steht bei vanvan 0 von 28 obwohl ich alle durch habe." */
|
|
ok(zahlAus(nachDemKlick.kachel) === zahlAus(vorDemKlick.kachel) + 1,
|
|
`die Kachel zählt sofort mit (${vorDemKlick.kachel} -> ${nachDemKlick.kachel})`);
|
|
ok(nachDemKlick.kachel === nachDemKlick.kopfZahl,
|
|
`und nennt dieselbe Zahl wie die Karte (${nachDemKlick.kachel} / ${nachDemKlick.kopfZahl})`);
|
|
/* UND DER RING WANDERT MIT. Seine Laenge ist der Anteil in Prozent
|
|
(Umfang 100) -- er muss also groesser werden, wenn die Ziffer es
|
|
wird. Ein Ring, der stehenbleibt, waere dieselbe zweite Wahrheit
|
|
wie die Zahl von vorhin, nur als Bild statt als Text. */
|
|
const bogenAus = (x) => Number(String(x).split(" ")[0]);
|
|
ok(bogenAus(nachDemKlick.bogen) > bogenAus(vorDemKlick.bogen),
|
|
`und der Ring wird voller (${vorDemKlick.bogen} -> ${nachDemKlick.bogen})`);
|
|
ok(zahlAus(nachDemKlick.kachel) > 0,
|
|
"es ist eine echte Zahl, keine Null — sonst wäre die Gleichheit wertlos");
|
|
|
|
/* =====================================================================
|
|
GEGENPROBE ZUM SPRUNG -- neu gefasst am 24.09.2026
|
|
=====================================================================
|
|
|
|
Sie muss es geben: Ohne sie hiesse "die Seite bleibt stehen"
|
|
vielleicht nur, dass ueberhaupt nichts mehr scrollt, und die
|
|
Pruefung darueber waere wertlos.
|
|
|
|
HIER STAND BIS HEUTE DER FALSCHE FALL. Sie klickte eine Kachel an
|
|
und verlangte einen Sprung zur Karte -- richtig bis zum
|
|
23.09.2026. An dem Tag wurde die Seite nach dem Arbeitsablauf
|
|
umgeraeumt: Zwischen Kachel und Karte liegen seither das
|
|
Verteil-Formular, der Katalog und die Aufgabenliste. Ein Sprung
|
|
zur Karte wuerde also ueber genau die drei Dinge hinwegspringen,
|
|
die man nach der Wahl zuerst braucht. Der Sprung wurde deshalb
|
|
ABSICHTLICH entfernt (siehe entwicklung.js, "KEIN SPRUNG MEHR").
|
|
|
|
Die Gegenprobe blieb stehen und war ab da rot -- nicht, weil
|
|
etwas kaputt war, sondern weil sie eine Zusage einforderte, die
|
|
zurueckgenommen worden ist. Gefunden beim Kachelumbau am
|
|
24.09.2026, also einen Tag spaeter; waere sie gruen gewesen,
|
|
haette es niemand bemerkt.
|
|
|
|
DER SPRUNG, DEN ES NOCH GIBT, ist der von aussen: Wer der
|
|
Talentseite folgt, kommt mit "?zeigen=person-<nr>" und will genau
|
|
diese eine Karte sehen. Daran laesst sich beweisen, dass die Seite
|
|
sehr wohl springen KANN -- und zwar an der einzigen Stelle, an der
|
|
sie es noch soll. */
|
|
const werDenn = await seite.evaluate(() =>
|
|
document.querySelector("#personen .e-person")?.dataset.person || "");
|
|
ok(werDenn !== "", `eine Kachel zum Anspringen gefunden (Nr. ${werDenn})`);
|
|
await seite.goto(`http://127.0.0.1:${PORT}/workspace/entwicklung.html?zeigen=person-${werDenn}`,
|
|
{ waitUntil: "networkidle" });
|
|
await seite.waitForSelector("#personen .e-person", { timeout: 15_000 });
|
|
await seite.waitForTimeout(1600);
|
|
const vonAussen = await seite.evaluate(() => ({
|
|
y: Math.round(window.scrollY),
|
|
karteOffen: !document.getElementById("karte")?.hidden,
|
|
wer: document.querySelector('#personen .e-person[aria-pressed="true"]')
|
|
?.dataset.person || "",
|
|
}));
|
|
ok(vonAussen.y > 0,
|
|
`von aussen verlinkt springt sie sehr wohl (scrollY ${vonAussen.y})`);
|
|
ok(vonAussen.karteOffen && vonAussen.wer === werDenn,
|
|
`und zwar zu genau dieser Karte (offen: ${vonAussen.karteOffen}, `
|
|
+ `gewaehlt: ${vonAussen.wer})`);
|
|
|
|
ok(konsole.length === 0,
|
|
konsole.length ? "Fehler im Browser: " + konsole[0].slice(0, 90) : "keine Fehler im Browser");
|
|
await browser.close();
|
|
}
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
melde("");
|
|
melde(`${geprueft} Pruefungen, ${fehler} Fehler`);
|
|
melde(fehler ? "NICHT IN ORDNUNG" : "ALLES IN ORDNUNG");
|
|
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* Aufraeumrest */ }
|
|
process.exit(fehler ? 1 : 0);
|