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.
187 lines
6.1 KiB
JavaScript
187 lines
6.1 KiB
JavaScript
import puppeteer from "puppeteer";
|
|
|
|
const URL = process.env.PROBE_URL || "http://localhost:5187/";
|
|
const b = await puppeteer.launch({
|
|
headless: "new",
|
|
args: ["--no-sandbox", "--use-gl=swiftshader", "--enable-unsafe-swiftshader"],
|
|
});
|
|
const p = await b.newPage();
|
|
await p.setViewport({ width: 1400, height: 900, deviceScaleFactor: 1 });
|
|
const errs = [];
|
|
p.on("pageerror", (e) => errs.push(e.message));
|
|
p.on("console", (m) => { if (m.type() === "error") errs.push("[console] " + m.text()); });
|
|
await p.goto(URL, { waitUntil: "networkidle0", timeout: 20000 }).catch(() => {});
|
|
await new Promise((r) => setTimeout(r, 800));
|
|
|
|
const clickTab = (label) =>
|
|
p.evaluate((x) => {
|
|
const el = [...document.querySelectorAll("button, .tab, [role=tab]")].find(
|
|
(b) => b.textContent.trim() === x,
|
|
);
|
|
el?.click();
|
|
return !!el;
|
|
}, label);
|
|
|
|
// Object-Info-Tab aktivieren (falls vorhanden).
|
|
const tabOk = await clickTab("Objekt-Info");
|
|
await new Promise((r) => setTimeout(r, 200));
|
|
|
|
// Eine Wand im Grundriss anklicken (obere Bandkante eines Wandpolygons).
|
|
async function selectWall() {
|
|
const bb = await p.evaluate(() => {
|
|
const polys = [...document.querySelectorAll(".plan-svg polygon")];
|
|
if (!polys.length) return null;
|
|
let minX = 1e9, minY = 1e9, maxX = -1e9, maxY = -1e9;
|
|
for (const pl of polys) {
|
|
const r = pl.getBoundingClientRect();
|
|
minX = Math.min(minX, r.left); minY = Math.min(minY, r.top);
|
|
maxX = Math.max(maxX, r.right); maxY = Math.max(maxY, r.bottom);
|
|
}
|
|
return { minX, minY, maxX, maxY };
|
|
});
|
|
if (!bb) return false;
|
|
const cx = (bb.minX + bb.maxX) / 2;
|
|
for (const dy of [4, 8, 12, 16, 20]) {
|
|
await p.mouse.click(cx, bb.minY + dy);
|
|
await new Promise((r) => setTimeout(r, 120));
|
|
const k = await p.evaluate(
|
|
() => document.querySelector(".objinfo-kind")?.textContent || "",
|
|
);
|
|
if (/Wand/.test(k)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const selected = await selectWall();
|
|
|
|
// (1) Wand-Abschnitt sichtbar?
|
|
const hasWallSection = await p.evaluate(() =>
|
|
[...document.querySelectorAll(".objinfo-section-label")].some(
|
|
(e) => e.textContent.trim() === "Wand",
|
|
),
|
|
);
|
|
const hasRefDropdown = await p.evaluate(
|
|
() => !!document.querySelector(".objinfo-head-ref"),
|
|
);
|
|
await p.screenshot({ path: "scripts/probe-wallattr-1-panel.png" });
|
|
|
|
// Plan-Footprint VORHER (bbox aller Wandpolygone).
|
|
const planBBox = () =>
|
|
p.evaluate(() => {
|
|
const polys = [...document.querySelectorAll(".plan-svg polygon")];
|
|
let minY = 1e9, maxY = -1e9;
|
|
for (const pl of polys) {
|
|
const r = pl.getBoundingClientRect();
|
|
minY = Math.min(minY, r.top); maxY = Math.max(maxY, r.bottom);
|
|
}
|
|
return { minY: Math.round(minY), maxY: Math.round(maxY) };
|
|
});
|
|
const beforeRef = await planBBox();
|
|
|
|
// (2) Referenzlinie auf „Außen (links)" stellen über das Kopf-Dropdown.
|
|
async function pickDropdown(triggerSel, optionText) {
|
|
const ok = await p.evaluate((sel) => {
|
|
const t = document.querySelector(sel);
|
|
if (!t) return false;
|
|
t.click();
|
|
return true;
|
|
}, triggerSel);
|
|
if (!ok) return false;
|
|
await new Promise((r) => setTimeout(r, 150));
|
|
const picked = await p.evaluate((txt) => {
|
|
const item = [...document.querySelectorAll(".tb-dd-menu .tb-dd-item")].find(
|
|
(i) => i.textContent.trim().includes(txt),
|
|
);
|
|
item?.click();
|
|
return !!item;
|
|
}, optionText);
|
|
await new Promise((r) => setTimeout(r, 200));
|
|
return picked;
|
|
}
|
|
|
|
const refPicked = await pickDropdown(
|
|
".objinfo-head-ref .tb-dd-trigger",
|
|
"Außen",
|
|
);
|
|
await new Promise((r) => setTimeout(r, 250));
|
|
const afterRef = await planBBox();
|
|
await p.screenshot({ path: "scripts/probe-wallattr-2-refline-aussen.png" });
|
|
|
|
// (3) OK auf „eigene Höhe" → Z-Wert ändern, dann 3D.
|
|
// Den OK-Block (zweite objinfo-wall-anchor) auf „Eigene Höhe" schalten.
|
|
const okCustom = await p.evaluate(() => {
|
|
const blocks = [...document.querySelectorAll(".objinfo-wall-anchor")];
|
|
const okBlock = blocks[1];
|
|
if (!okBlock) return false;
|
|
const btn = [...okBlock.querySelectorAll(".objinfo-seg-btn")].find(
|
|
(b) => b.textContent.trim() === "Eigene Höhe",
|
|
);
|
|
btn?.click();
|
|
return !!btn;
|
|
});
|
|
await new Promise((r) => setTimeout(r, 200));
|
|
// Z-Feld setzen (5.0 m) im OK-Block.
|
|
const heightBefore = await p.evaluate(
|
|
() =>
|
|
[...document.querySelectorAll(".objinfo-field")]
|
|
.find((f) => f.querySelector(".objinfo-flabel")?.textContent === "Höhe")
|
|
?.querySelector(".objinfo-fval")?.textContent || "",
|
|
);
|
|
const setZ = await p.evaluate(() => {
|
|
const blocks = [...document.querySelectorAll(".objinfo-wall-anchor")];
|
|
const okBlock = blocks[1];
|
|
const input = okBlock?.querySelector("input.objinfo-input");
|
|
if (!input) return false;
|
|
const setter = Object.getOwnPropertyDescriptor(
|
|
window.HTMLInputElement.prototype,
|
|
"value",
|
|
).set;
|
|
setter.call(input, "5");
|
|
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
input.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true }));
|
|
input.blur();
|
|
return true;
|
|
});
|
|
await new Promise((r) => setTimeout(r, 250));
|
|
const heightAfter = await p.evaluate(
|
|
() =>
|
|
[...document.querySelectorAll(".objinfo-field")]
|
|
.find((f) => f.querySelector(".objinfo-flabel")?.textContent === "Höhe")
|
|
?.querySelector(".objinfo-fval")?.textContent || "",
|
|
);
|
|
await p.screenshot({ path: "scripts/probe-wallattr-3-ok-custom.png" });
|
|
|
|
// 3D (Isometrie) umschalten und Screenshot — der Umschalter ist ein Icon-Button
|
|
// mit title „Isometrie …" in der Oberleiste (kein Tab).
|
|
await p.evaluate(() => {
|
|
const el = [...document.querySelectorAll("button[title]")].find((b) =>
|
|
(b.getAttribute("title") || "").startsWith("Isometrie"),
|
|
);
|
|
el?.click();
|
|
});
|
|
await new Promise((r) => setTimeout(r, 1000));
|
|
await p.screenshot({ path: "scripts/probe-wallattr-4-3d.png" });
|
|
|
|
console.log(
|
|
JSON.stringify(
|
|
{
|
|
tabOk,
|
|
selected,
|
|
hasWallSection,
|
|
hasRefDropdown,
|
|
refPicked,
|
|
beforeRef,
|
|
afterRef,
|
|
footprintShifted: beforeRef.minY !== afterRef.minY || beforeRef.maxY !== afterRef.maxY,
|
|
okCustom,
|
|
setZ,
|
|
heightBefore,
|
|
heightAfter,
|
|
errs,
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
);
|
|
await b.close();
|