ca859c4aa4
Standalone-Browser-Port von DOSSIER. Enthaelt das semantische Modell mit Plan-/3D-Ableitung, Zeichen- und Editierwerkzeuge, Rhino-artiges Befehlssystem, dockbares Panel-System, Resource-Manager, DXF/.lin/.pat-Import, i18n (de/en) sowie Projektdokumentation und Probe-Harness.
135 lines
5.3 KiB
JavaScript
135 lines
5.3 KiB
JavaScript
// Probe für das DOSSIER-Dokumentmodell (Augen-Navigator + Mehrgeschoss-3D).
|
|
// Erfasst fünf Zustände in separate PNGs (deviceScaleFactor 2):
|
|
// (a) Standard: EG Grundriss mit Augen-Navigator (EG aktiv, andere gedimmt).
|
|
// (b) Perspektive mit EG + OG sichtbar → zwei Räume vertikal gestapelt.
|
|
// (c) OG-Auge ausgeschaltet → nur EG bleibt im 3D.
|
|
// (d) EG Geschosshöhe auf 3.5 → größerer Abstand zu OG; "+ Ebene" anklicken
|
|
// → neue Kategorie erscheint im Navigator.
|
|
// (e) Zeichnungsebene "Detail 1" → leerer Zeichnungs-Platzhalter.
|
|
//
|
|
// Aufruf: node scripts/probe-dossier.mjs
|
|
import puppeteer from "puppeteer";
|
|
|
|
const URL = process.env.PROBE_URL || "http://localhost:5173/";
|
|
const OUT = "scripts";
|
|
|
|
const browser = await puppeteer.launch({
|
|
headless: "new",
|
|
args: ["--no-sandbox", "--use-gl=swiftshader", "--enable-unsafe-swiftshader"],
|
|
});
|
|
const page = await browser.newPage();
|
|
await page.setViewport({ width: 1280, height: 820, deviceScaleFactor: 2 });
|
|
|
|
const logs = [];
|
|
page.on("console", (m) => logs.push(`[${m.type()}] ${m.text()}`));
|
|
page.on("pageerror", (e) => logs.push(`[PAGEERROR] ${e.message}`));
|
|
|
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
|
|
// Klick auf das Element, dessen Textinhalt `text` enthält (innerhalb selector).
|
|
async function clickByText(selector, text) {
|
|
const handle = await page.evaluateHandle(
|
|
(sel, t) =>
|
|
[...document.querySelectorAll(sel)].find((el) =>
|
|
el.textContent.includes(t),
|
|
),
|
|
selector,
|
|
text,
|
|
);
|
|
const el = handle.asElement();
|
|
if (!el) throw new Error(`Element nicht gefunden: ${selector} ~ "${text}"`);
|
|
await el.click();
|
|
}
|
|
|
|
// Klick auf das Augen-Symbol einer Zeichnungsebene mit gegebenem Namen.
|
|
async function toggleLevelEyeByName(name) {
|
|
const ok = await page.evaluate((n) => {
|
|
const row = [...document.querySelectorAll(".nav-row")].find((r) =>
|
|
r.querySelector(".nav-label")?.textContent.trim().includes(n),
|
|
);
|
|
const eye = row?.querySelector(".eye");
|
|
if (!eye) return false;
|
|
eye.click();
|
|
return true;
|
|
}, name);
|
|
if (!ok) throw new Error(`Augen-Schalter nicht gefunden für Ebene: ${name}`);
|
|
}
|
|
|
|
// Diagnose: aktueller Navigator-Zustand (für Querprüfung der Screenshots).
|
|
const navState = () =>
|
|
page.evaluate(() => {
|
|
const levels = [...document.querySelectorAll(".nav-row")].map((r) => ({
|
|
name: r.querySelector(".nav-label")?.textContent.trim(),
|
|
active: r.classList.contains("active"),
|
|
dimmed: r.classList.contains("hidden"),
|
|
elev: r.querySelector(".nav-elev")?.textContent.trim() ?? null,
|
|
}));
|
|
const cats = [...document.querySelectorAll(".cat-row")].map((r) =>
|
|
r.querySelector(".cat-name")?.textContent.trim(),
|
|
);
|
|
const canvas = document.querySelector(".viewport canvas");
|
|
return {
|
|
levels,
|
|
catCount: cats.length,
|
|
catNames: cats,
|
|
hasCanvas: !!canvas,
|
|
egHeight: document.querySelector(".props-strip input")?.value ?? null,
|
|
};
|
|
});
|
|
|
|
try {
|
|
await page.goto(URL, { waitUntil: "networkidle0", timeout: 20000 });
|
|
} catch (e) {
|
|
logs.push(`[GOTO-ERROR] ${e.message}`);
|
|
}
|
|
await sleep(700);
|
|
|
|
// ── (a) Standard: EG Grundriss mit Augen-Navigator ──────────────────────────
|
|
await page.screenshot({ path: `${OUT}/probe-a-eg-grundriss.png` });
|
|
logs.push("(a) STATE " + JSON.stringify(await navState()));
|
|
|
|
// ── (b) Perspektive mit EG + OG sichtbar ───────────────────────────────────
|
|
await clickByText(".view-btn", "Perspektive");
|
|
await sleep(1400);
|
|
await page.screenshot({ path: `${OUT}/probe-b-eg-og-perspektive.png` });
|
|
logs.push("(b) STATE " + JSON.stringify(await navState()));
|
|
|
|
// ── (c) OG-Auge ausschalten → nur EG bleibt im 3D ──────────────────────────
|
|
await toggleLevelEyeByName("Obergeschoss");
|
|
await sleep(1400);
|
|
await page.screenshot({ path: `${OUT}/probe-c-only-eg-3d.png` });
|
|
logs.push("(c) STATE " + JSON.stringify(await navState()));
|
|
|
|
// OG wieder einblenden, damit (d) den Stapel-Abstand zeigt.
|
|
await toggleLevelEyeByName("Obergeschoss");
|
|
await sleep(400);
|
|
|
|
// ── (d) EG Geschosshöhe auf 3.5 → größerer Abstand zu OG ───────────────────
|
|
// EG ist die Standardauswahl; die props-strip zeigt das aktive Geschoss.
|
|
await page.evaluate(() => {
|
|
const input = document.querySelector(".props-strip input");
|
|
if (!input) throw new Error("Geschosshöhe-Feld nicht gefunden");
|
|
const setter = Object.getOwnPropertyDescriptor(
|
|
window.HTMLInputElement.prototype,
|
|
"value",
|
|
).set;
|
|
setter.call(input, "3.5");
|
|
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
input.dispatchEvent(new Event("change", { bubbles: true }));
|
|
});
|
|
await sleep(1400);
|
|
// "+ Ebene" anklicken → neue Kategorie erscheint im Navigator.
|
|
await clickByText(".nav-add", "+ Ebene");
|
|
await sleep(500);
|
|
await page.screenshot({ path: `${OUT}/probe-d-height-and-addlayer.png` });
|
|
logs.push("(d) STATE " + JSON.stringify(await navState()));
|
|
|
|
// ── (e) Zeichnungsebene "Detail 1" → leerer Zeichnungs-Platzhalter ─────────
|
|
await clickByText(".nav-label", "Detail 1");
|
|
await sleep(500);
|
|
await page.screenshot({ path: `${OUT}/probe-e-detail-drawing.png` });
|
|
logs.push("(e) STATE " + JSON.stringify(await navState()));
|
|
|
|
console.log(logs.join("\n"));
|
|
await browser.close();
|