同步五轴仿真文档和验证证据
This commit is contained in:
@@ -44,6 +44,43 @@
|
||||
}
|
||||
return win.webRtcp5AxisSimulation.getState();
|
||||
}
|
||||
function assertActiveGcodeRowVisible(doc, expectedLine) {
|
||||
const activeRow = doc.querySelector(".gcode-row.active");
|
||||
const list = doc.querySelector(".gcode-list");
|
||||
if (!activeRow || !list) {
|
||||
throw new Error("missing active G-code row or list");
|
||||
}
|
||||
if (expectedLine && activeRow.dataset.programLine !== String(expectedLine)) {
|
||||
throw new Error(`active G-code row should be line ${expectedLine}, got ${activeRow.dataset.programLine}`);
|
||||
}
|
||||
if (activeRow.dataset.lineStatus !== "running") {
|
||||
throw new Error(`active G-code row should be running, got ${activeRow.dataset.lineStatus}`);
|
||||
}
|
||||
const activeBackground = getComputedStyle(activeRow).backgroundColor.replace(/\s/g, "");
|
||||
if (activeBackground !== "rgb(33,165,83)") {
|
||||
throw new Error(`active G-code row should be green, got ${activeBackground}`);
|
||||
}
|
||||
const previousLine = Number(activeRow.dataset.programLine || 0) - 1;
|
||||
const previousRow = doc.querySelector(`.gcode-row[data-program-line="${previousLine}"]`);
|
||||
if (previousRow) {
|
||||
const previousBackground = getComputedStyle(previousRow).backgroundColor.replace(/\s/g, "");
|
||||
if (previousRow.dataset.lineStatus !== "done") {
|
||||
throw new Error(`executed G-code row should be done, got ${previousRow.dataset.lineStatus}`);
|
||||
}
|
||||
if (previousBackground !== "rgb(238,238,238)") {
|
||||
throw new Error(`executed G-code row should be light gray, got ${previousBackground}`);
|
||||
}
|
||||
}
|
||||
const listText = list.textContent;
|
||||
if (/\bpending\b|\bstopped\s+\|\s+F\b|\brunning\s+\|\s+F\b/.test(listText)) {
|
||||
throw new Error("G-code list should not render execution status text");
|
||||
}
|
||||
const rowBounds = activeRow.getBoundingClientRect();
|
||||
const listBounds = list.getBoundingClientRect();
|
||||
if (rowBounds.bottom < listBounds.top || rowBounds.top > listBounds.bottom) {
|
||||
throw new Error(`active G-code row ${activeRow.dataset.programLine} is not visible after auto-scroll`);
|
||||
}
|
||||
}
|
||||
|
||||
async function runSmoke() {
|
||||
await new Promise((resolve, reject) => {
|
||||
@@ -236,10 +273,18 @@
|
||||
throw new Error("initial machine state should show power off");
|
||||
}
|
||||
|
||||
win.webRtcp5AxisSimulation.dispatch({ type: "RUN" });
|
||||
const initiallyBlockedRunButton = doc.querySelector('[data-action="RUN"]');
|
||||
if (
|
||||
initiallyBlockedRunButton.disabled ||
|
||||
initiallyBlockedRunButton.dataset.commandReady !== "false" ||
|
||||
initiallyBlockedRunButton.getAttribute("aria-disabled") !== "true"
|
||||
) {
|
||||
throw new Error("RUN button should remain clickable and marked blocked before power on");
|
||||
}
|
||||
initiallyBlockedRunButton.click();
|
||||
await wait(50);
|
||||
if (!win.webRtcp5AxisSimulation.getState().operatorMessage.includes("blocked")) {
|
||||
throw new Error("RUN should be blocked before power on");
|
||||
throw new Error("RUN button should report why execution is blocked before power on");
|
||||
}
|
||||
doc.querySelector('[data-action="power"]').click();
|
||||
await wait(50);
|
||||
@@ -489,12 +534,10 @@
|
||||
if (!doc.querySelector('[data-session-persistence="status"]')?.textContent.includes("opfs unavailable")) {
|
||||
throw new Error("session save status did not render OPFS unavailable fallback");
|
||||
}
|
||||
if (doc.querySelector('[data-active-program-line]')?.textContent !== "Current line 2") {
|
||||
if (doc.querySelector('[data-active-program-line]')?.textContent !== "Executing line 2") {
|
||||
throw new Error("loaded program did not render first LinuxCNC motion line");
|
||||
}
|
||||
if (doc.querySelector(".gcode-row.active")?.dataset.programLine !== "2") {
|
||||
throw new Error("loaded program active row should be first LinuxCNC motion line");
|
||||
}
|
||||
assertActiveGcodeRowVisible(doc, 2);
|
||||
|
||||
win.webRtcp5AxisSimulation.dispatch({ type: "RUN" });
|
||||
await wait(250);
|
||||
@@ -510,6 +553,25 @@
|
||||
if (Number(doc.querySelector(".gcode-row.active")?.dataset.programLine || 0) < 2) {
|
||||
throw new Error("RUN did not highlight a LinuxCNC task/HAL motion line");
|
||||
}
|
||||
assertActiveGcodeRowVisible(doc);
|
||||
const stopLineBefore = win.webRtcp5AxisSimulation.getState().activeLine;
|
||||
doc.querySelector('[data-action="STOP"]').click();
|
||||
await wait(150);
|
||||
const stoppedState = win.webRtcp5AxisSimulation.getState();
|
||||
if (stoppedState.runState !== "stopped" || stoppedState.machine.interpState !== "idle") {
|
||||
throw new Error(`STOP did not stop the running G-code program: ${stoppedState.runState}/${stoppedState.machine.interpState}`);
|
||||
}
|
||||
if (stoppedState.feed.currentVelocity !== 0) {
|
||||
throw new Error(`STOP did not zero current velocity: ${stoppedState.feed.currentVelocity}`);
|
||||
}
|
||||
if (stoppedState.activeLine !== stopLineBefore) {
|
||||
throw new Error(`STOP allowed G-code execution to continue: ${stopLineBefore} -> ${stoppedState.activeLine}`);
|
||||
}
|
||||
doc.querySelector('[data-action="RUN"]').click();
|
||||
await wait(250);
|
||||
if (win.webRtcp5AxisSimulation.getState().runState !== "running") {
|
||||
throw new Error("RUN did not restart after STOP");
|
||||
}
|
||||
canvas = doc.querySelector("[data-five-axis-canvas]");
|
||||
if (
|
||||
Number(canvas.dataset.threeExecutedPathPoints ?? 0) < 1 ||
|
||||
|
||||
@@ -119,6 +119,20 @@ store.dispatch({ type: "RESUME" });
|
||||
await waitForTaskHal(store);
|
||||
assert.equal(store.getState().machine.interpState, "reading");
|
||||
|
||||
store.dispatch({ type: "STEP" });
|
||||
await waitForTaskHal(store);
|
||||
state = store.getState();
|
||||
assert.equal(state.machine.interpState, "paused");
|
||||
assert.equal(state.machine.taskPaused, true);
|
||||
assert.equal(state.taskHalStatus.task.singleStepping, true);
|
||||
|
||||
store.dispatch({ type: "STOP" });
|
||||
await waitForTaskHal(store);
|
||||
state = store.getState();
|
||||
assert.equal(state.runState, "stopped");
|
||||
assert.equal(state.machine.interpState, "idle");
|
||||
assert.equal(state.taskHalStatus.motionStatus.motion.aborted, true);
|
||||
|
||||
console.log("linuxcnc_task_hal_runtime_smoke=ok");
|
||||
console.log("task_hal_machine_file_smoke=ok");
|
||||
console.log("switchkins_remap_hal_sync_smoke=ok");
|
||||
|
||||
@@ -199,8 +199,16 @@ async function verifyRunReadySequence({ profileId, sourceRel }) {
|
||||
assert.notEqual(state.operatorMessage, "run blocked: home machine first");
|
||||
assert.equal(state.machine.allHomed, true);
|
||||
|
||||
const activeLineBeforeStop = state.activeLine;
|
||||
store.dispatch({ type: "STOP" });
|
||||
await waitForTaskHalCommand(store);
|
||||
await new Promise((resolve) => setTimeout(resolve, 120));
|
||||
state = store.getState();
|
||||
assert.equal(state.taskHalStatusLoop.active, false);
|
||||
assert.equal(state.runState, "stopped");
|
||||
assert.equal(state.machine.interpState, "idle");
|
||||
assert.equal(state.feed.currentVelocity, 0);
|
||||
assert.equal(state.activeLine, activeLineBeforeStop);
|
||||
}
|
||||
|
||||
async function waitForTaskHalCommand(store) {
|
||||
|
||||
Reference in New Issue
Block a user