Fix web homing motion and synchronize preview state
This commit is contained in:
79
scripts/test_xyzac_home_reset_browser.mjs
Normal file
79
scripts/test_xyzac_home_reset_browser.mjs
Normal file
@@ -0,0 +1,79 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { pathToFileURL } from "node:url";
|
||||
|
||||
const modulePath = process.env.PLAYWRIGHT_MODULE;
|
||||
assert.ok(modulePath, "PLAYWRIGHT_MODULE is required");
|
||||
const imported = await import(pathToFileURL(modulePath).href);
|
||||
const playwright = imported.default ?? imported;
|
||||
const browser = await playwright.chromium.launch({
|
||||
headless: false,
|
||||
executablePath: process.env.BROWSER_EXECUTABLE_PATH ?? "/usr/bin/google-chrome",
|
||||
args: ["--disable-gpu", "--ignore-certificate-errors", "--window-size=1440,1000"],
|
||||
});
|
||||
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
|
||||
const main = page.locator("main.axis-app");
|
||||
page.on("dialog", async (dialog) => { if (dialog.type() === "confirm") await dialog.accept(); else await dialog.dismiss(); });
|
||||
const state = () => main.evaluate((element) => {
|
||||
const preview = element.querySelector("[data-xyzac-preview]");
|
||||
return {
|
||||
loading: element.dataset.axisProgramLoading,
|
||||
homed: element.dataset.axisHomed,
|
||||
pose: preview?.dataset.xyzacLivePose,
|
||||
hud: element.querySelector(".axis-preview-hud")?.textContent ?? "",
|
||||
queue: element.dataset.axisTpQueueDepth,
|
||||
command: element.querySelector(".command-status")?.textContent ?? "",
|
||||
error: element.querySelector(".diagnostic-error")?.textContent ?? null,
|
||||
};
|
||||
});
|
||||
const wait = async (predicate, label) => {
|
||||
const started = Date.now(); let latest;
|
||||
while (Date.now() - started < 45000) { latest = await state(); if (predicate(latest)) return latest; await page.waitForTimeout(100); }
|
||||
throw new Error(`${label}:${JSON.stringify(latest)}`);
|
||||
};
|
||||
const control = (id) => main.locator(`[data-axis-control="${id}"]`);
|
||||
const click = async (id) => { const button = control(id); await wait(async () => await button.count() > 0 && !await button.isDisabled(), `${id}_enabled`); await button.click(); };
|
||||
const pose = async () => JSON.parse((await state()).pose ?? "{}");
|
||||
const screenshot = async (name) => { await page.screenshot({ path: `/tmp/axis-home-reset-${name}.png` }); console.log(name, JSON.stringify(await state())); };
|
||||
|
||||
try {
|
||||
await page.goto(process.env.XYZAC_PANEL_URL ?? "http://127.0.0.1:5175/", { waitUntil: "domcontentloaded" });
|
||||
await wait((value) => value.loading === "false", "startup");
|
||||
await click("toolbar-power"); await wait((value) => value.command.includes("POWER acknowledged"), "power");
|
||||
await click("manual-home-all"); await wait((value) => value.command.includes("HOME acknowledged") && value.homed === "[true,true,true,true,true]", "home_all");
|
||||
await screenshot("01-home-all-zero");
|
||||
await control("manual-axis-x").check();
|
||||
const jog = control("manual-jog-positive");
|
||||
await jog.dispatchEvent("pointerdown", { pointerId: 41, button: 0 });
|
||||
await wait((value) => value.command.includes("JOG_START acknowledged"), "jog_start");
|
||||
await page.waitForTimeout(450);
|
||||
await jog.dispatchEvent("pointerup", { pointerId: 41, button: 0 });
|
||||
await wait((value) => value.command.includes("JOG_STOP acknowledged") && value.queue === "0", "jog_stop");
|
||||
const jogged = await pose(); assert.ok(Math.abs(Number(jogged.x)) > 1e-6, JSON.stringify(jogged));
|
||||
await screenshot("02-jogged-x");
|
||||
await click("manual-home-axis");
|
||||
const movingAxis = await wait((value) => value.command.includes("HOME acknowledged") && value.queue !== "0", "home_axis_motion");
|
||||
const movingAxisPose = JSON.parse(movingAxis.pose); assert.ok(Math.abs(Number(movingAxisPose.x)) > 1e-6, JSON.stringify(movingAxisPose));
|
||||
await screenshot("03-home-axis-moving");
|
||||
const homedAxis = await wait((value) => value.command.includes("HOME acknowledged") && value.queue === "0", "home_axis");
|
||||
const homeAxisPose = JSON.parse(homedAxis.pose); assert.ok(Math.abs(Number(homeAxisPose.x)) < 1e-8, JSON.stringify(homeAxisPose));
|
||||
await screenshot("04-home-axis-zero");
|
||||
for (const [axis, pointerId] of [["y", 42], ["z", 43], ["a", 44], ["c", 45]]) {
|
||||
await control(`manual-axis-${axis}`).check();
|
||||
const button = control("manual-jog-negative");
|
||||
await button.dispatchEvent("pointerdown", { pointerId, button: 0 });
|
||||
await wait((value) => value.command.includes("JOG_START acknowledged"), `${axis}_jog_start`);
|
||||
await page.waitForTimeout(300);
|
||||
await button.dispatchEvent("pointerup", { pointerId, button: 0 });
|
||||
await wait((value) => value.command.includes("JOG_STOP acknowledged") && value.queue === "0", `${axis}_jog_stop`);
|
||||
}
|
||||
await screenshot("05-multi-axis-jogged");
|
||||
await click("manual-home-all");
|
||||
const movingAll = await wait((value) => value.command.includes("HOME acknowledged") && value.queue !== "0", "home_all_motion");
|
||||
const movingAllPose = JSON.parse(movingAll.pose); assert.ok(Object.entries(movingAllPose).some(([axis, value]) => ["x", "y", "z", "a", "c"].includes(axis) && Math.abs(Number(value)) > 1e-6), JSON.stringify(movingAllPose));
|
||||
await screenshot("06-home-all-moving");
|
||||
const final = await wait((value) => value.command.includes("HOME acknowledged") && value.queue === "0", "home_all_again");
|
||||
const finalPose = JSON.parse(final.pose);
|
||||
for (const axis of ["x", "y", "z", "a", "c"]) assert.ok(Math.abs(Number(finalPose[axis])) < 1e-8, `${axis}:${JSON.stringify(finalPose)}`);
|
||||
await screenshot("07-home-all-zero");
|
||||
console.log(JSON.stringify({ schema: "xyzac-home-reset-browser.v1", status: "verified", url: process.env.XYZAC_PANEL_URL ?? "http://127.0.0.1:5175/", jogged, home_axis: homeAxisPose, home_all: finalPose, screenshots: ["/tmp/axis-home-reset-01-home-all-zero.png", "/tmp/axis-home-reset-02-jogged-x.png", "/tmp/axis-home-reset-03-home-axis-moving.png", "/tmp/axis-home-reset-04-home-axis-zero.png", "/tmp/axis-home-reset-05-multi-axis-jogged.png", "/tmp/axis-home-reset-06-home-all-moving.png", "/tmp/axis-home-reset-07-home-all-zero.png"] }));
|
||||
} finally { await browser.close(); }
|
||||
@@ -20,6 +20,7 @@ page.on("dialog", async (dialog) => {
|
||||
dialogs.push({ type: dialog.type(), message: dialog.message() });
|
||||
if (dialog.type() === "prompt" && dialog.message().startsWith("Touch Off:")) await dialog.accept("0");
|
||||
else if (dialog.type() === "prompt" && dialog.message().startsWith("Coordinate system")) await dialog.accept("P1 G54");
|
||||
else if (dialog.type() === "confirm" && dialog.message().includes("already homed")) await dialog.accept();
|
||||
else await dialog.dismiss();
|
||||
});
|
||||
const main = page.locator("main.axis-app");
|
||||
@@ -114,7 +115,7 @@ try {
|
||||
results.push(await record("MANUAL MODE", async () => { await main.getByRole("tab", { name: "Manual Control [F3]" }).click(); await wait((s) => s.mode === "MANUAL" || s.command?.includes("SET_MODE acknowledged"), "manual_mode_ack"); }));
|
||||
results.push(await record("HOME/TOUCH OFF boundaries", async () => {
|
||||
await click(main.locator('button[data-axis-control="manual-home-axis"]'), "home_axis_repeat");
|
||||
await wait((s) => s.command?.includes("home_joint_requires_joint_mode"), "world_axis_home_source_rejection");
|
||||
await wait((s) => s.error === null && s.command?.includes("HOME acknowledged"), "home_axis_ack");
|
||||
await click(main.locator('button[data-axis-control="manual-touch-off"]'), "touch_off");
|
||||
await wait((s) => s.error === null && s.command?.includes("TOUCH_OFF acknowledged"), "touch_off_ack");
|
||||
if (!await main.locator('[data-axis-control="manual-tool-touch-off"]').isDisabled()) throw new Error("tool_touch_off_must_be_disabled");
|
||||
|
||||
Reference in New Issue
Block a user