Files
linuxcncWebWASM/scripts/test_trt_parametric_browser.mjs

104 lines
7.0 KiB
JavaScript

import assert from "node:assert/strict";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { pathToFileURL } from "node:url";
const { chromium } = await import(pathToFileURL(process.env.PLAYWRIGHT_MODULE).href);
const output = process.env.TRT_EVIDENCE_DIR ? pathToFileURL(`${process.env.TRT_EVIDENCE_DIR.replace(/\/$/, "")}/`) : new URL("../coverage/trt-parametric/", import.meta.url);
await mkdir(output, { recursive: true });
const browser = await chromium.launch({ executablePath: "/usr/bin/google-chrome", headless: true, args: ["--no-sandbox", "--use-angle=swiftshader", "--enable-unsafe-swiftshader"] });
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
await page.addInitScript(() => { window.showSaveFilePicker = undefined; });
const errors = [];
page.on("pageerror", (error) => errors.push(error.message));
const control = (id) => page.locator(`[data-axis-control="${id}"]`);
const machine = page.locator(".xyzac-machine-view");
const panel = page.locator(".trt-geometry");
const openGeometry = async () => {
if (!(await page.locator(".geometry-dialog[open]").count())) await control("geometry-settings").click();
};
const closeGeometry = async () => {
if (await page.locator(".geometry-dialog[open]").count()) await page.locator(".geometry-dialog [aria-label=\"关闭机床几何参数\"]").click();
};
const settled = async () => {
await page.waitForFunction(() => document.querySelector("main")?.dataset.axisProgramLoading === "false" && document.querySelector(".trt-geometry")?.getAttribute("aria-busy") === "false");
await page.waitForTimeout(350);
};
const pixels = () => machine.locator("canvas[data-engine]").evaluate((canvas) => {
const gl = canvas.getContext("webgl2"); const bytes = new Uint8Array(canvas.width * canvas.height * 4);
gl.readPixels(0, 0, canvas.width, canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, bytes);
let hash = 2166136261; const colors = new Set();
for (let i = 0; i < bytes.length; i += 16) { hash = Math.imul(hash ^ bytes[i], 16777619); colors.add(`${bytes[i]},${bytes[i + 1]},${bytes[i + 2]}`); }
return { hash: hash >>> 0, colors: colors.size, width: canvas.width, height: canvas.height };
});
const report = { report_id: "trt-parametric-browser-v1", status: "running", machines: [], viewports: [] };
try {
await page.goto(process.env.XYZAC_PANEL_URL ?? "http://127.0.0.1:5174/"); await settled();
for (const [id, unsupported] of [["xyzac-trt", "x-offset"], ["xyzbc-trt", "y-offset"]]) {
if (id === "xyzbc-trt") { await control("machine-type-select").selectOption({ label: "XYZBC TRT" }); await settled(); }
assert.equal(await machine.getAttribute("data-xyzac-model-id"), id);
await openGeometry();
assert.equal(await panel.getByLabel(unsupported, { exact: true }).isDisabled(), true);
const beforePath = await page.locator("main").getAttribute("data-axis-program-path");
const original = JSON.parse(await machine.getAttribute("data-xyzac-offsets"));
const before = await pixels(); assert.ok(before.colors > 100);
await panel.getByLabel("x-rot-point", { exact: true }).fill("24");
await panel.getByLabel("y-rot-point", { exact: true }).fill("-12");
await panel.getByLabel("z-rot-point", { exact: true }).fill("8");
await control("geometry-apply").click(); await settled();
await closeGeometry();
const offsets = JSON.parse(await machine.getAttribute("data-xyzac-offsets"));
assert.equal(offsets.x_rot_point, 24); assert.equal(offsets.y_rot_point, -12); assert.equal(offsets.z_rot_point, 8);
assert.equal(await page.locator("main").getAttribute("data-axis-program-path"), beforePath);
assert.notEqual((await pixels()).hash, before.hash);
await machine.screenshot({ path: new URL(`${id}-model.png`, output).pathname });
await openGeometry();
const downloading = page.waitForEvent("download"); await control("geometry-save").click();
const download = await downloading;
assert.equal(download.suggestedFilename(), `${id}.ini`);
const exported = await readFile(await download.path(), "utf8");
assert.match(exported, /x-rot-point\s+24/); assert.match(exported, /LIB:basic_sim.tcl/);
assert.doesNotMatch(exported, /HALFILE = .*_cmds.hal/);
await control("geometry-reload").click(); await settled();
await openGeometry();
assert.deepEqual(JSON.parse(await machine.getAttribute("data-xyzac-offsets")), original);
await panel.locator('input[type="file"]').setInputFiles({ name: `${id}.ini`, mimeType: "text/plain", buffer: Buffer.from(exported) });
await page.waitForFunction(() => document.querySelector('.trt-geometry input[aria-label="x-rot-point"]')?.value === "24");
await control("geometry-apply").click(); await settled();
assert.equal(JSON.parse(await machine.getAttribute("data-xyzac-offsets")).x_rot_point, 24);
await closeGeometry();
await control("toolbar-power").click();
await page.waitForFunction(() => document.querySelector('.trt-geometry input[aria-label="x-rot-point"]')?.disabled === true);
assert.equal(await panel.getByLabel("x-rot-point", { exact: true }).isDisabled(), true);
await control("toolbar-power").click();
await page.waitForFunction(() => document.querySelector('.trt-geometry input[aria-label="x-rot-point"]')?.disabled === false);
assert.equal(await panel.getByLabel("x-rot-point", { exact: true }).isDisabled(), false);
report.machines.push({ id, offsets, export_bytes: exported.length, preserved_program: beforePath, canvas: before });
}
for (const [width, height] of [[1440, 1000], [390, 844]]) {
await page.setViewportSize({ width, height }); await panel.scrollIntoViewIfNeeded(); await page.waitForTimeout(400);
const canvas = await pixels(); assert.ok(canvas.colors > 100 && canvas.width > 100 && canvas.height >= 220);
await openGeometry();
const boxes = await page.locator(".geometry-dialog").locator("label, input:not([hidden]), button").evaluateAll((elements) => elements.map((element) => {
const r = element.getBoundingClientRect(); return { x: r.x, right: r.right, width: r.width };
}));
assert.ok(boxes.every((r) => r.width > 0 && r.x >= 0 && r.right <= width), JSON.stringify(boxes));
assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth));
await closeGeometry();
const before = await pixels();
await control("machine-rotateLeft").click(); await page.waitForTimeout(400);
assert.notEqual((await pixels()).hash, before.hash);
await page.screenshot({ path: new URL(`layout-${width}.png`, output).pathname, fullPage: true });
report.viewports.push({ width, height, canvas, controls_fit: true, interactive: true });
}
assert.deepEqual(errors, []); report.status = "verified";
} catch (error) {
report.status = "failed"; report.error = String(error.stack ?? error);
await page.screenshot({ path: new URL("failure.png", output).pathname, fullPage: true });
throw error;
} finally {
report.browser_errors = errors;
await writeFile(new URL("browser.report.json", output), JSON.stringify(report, null, 2) + "\n");
await browser.close();
}
console.log(JSON.stringify(report));