fix: make Pause button pause running program
This commit is contained in:
@@ -1007,6 +1007,19 @@
|
||||
if (win.webRtcp5AxisSimulation.getState().runState !== "running") {
|
||||
throw new Error("RESUME action did not restore running state");
|
||||
}
|
||||
doc.querySelector('[data-action="PAUSE"]').click();
|
||||
await wait(50);
|
||||
if (
|
||||
win.webRtcp5AxisSimulation.getState().runState !== "paused" ||
|
||||
win.webRtcp5AxisSimulation.getState().machine.interpState !== "paused"
|
||||
) {
|
||||
throw new Error("PAUSE action did not pause running task on direct second use");
|
||||
}
|
||||
doc.querySelector('[data-action="RESUME"]').click();
|
||||
await wait(50);
|
||||
if (win.webRtcp5AxisSimulation.getState().runState !== "running") {
|
||||
throw new Error("RESUME action did not restore running state after direct second pause");
|
||||
}
|
||||
const tcpButton = doc.querySelector('[data-action="kins-tcp"]');
|
||||
tcpButton.click();
|
||||
await wait(50);
|
||||
|
||||
@@ -143,11 +143,24 @@
|
||||
if (!Array.isArray(buttonParity) || buttonParity.length < 50) {
|
||||
throw new Error(`AXIS button parity list too small: ${buttonParity?.length}`);
|
||||
}
|
||||
for (const action of ["estop", "power", "run-ready", "run", "pause", "resume", "step", "stop", "home-all", "jog-plus", "jog-minus", "kins-identity", "kins-tcp", "kins-userk", "clear-preview"]) {
|
||||
for (const action of ["estop", "power", "run-ready", "run", "pause", "resume", "pause-resume", "step", "stop", "home-all", "jog-plus", "jog-minus", "spindle-reverse", "spindle-stop", "spindle-forward", "kins-identity", "kins-tcp", "kins-userk", "clear-preview"]) {
|
||||
if (!buttonParity.some((item) => item.action === action && item.sourceSymbol && item.sourceLines && item.expected)) {
|
||||
throw new Error(`missing source-referenced button parity for ${action}`);
|
||||
}
|
||||
}
|
||||
const domControls = [...doc.querySelectorAll("[data-action], [data-menu-command]")];
|
||||
for (const action of [...new Set(buttonParity.map((item) => item.action))]) {
|
||||
const controls = domControls.filter((control) => (
|
||||
control.dataset.action === action ||
|
||||
control.dataset.menuCommand === action
|
||||
));
|
||||
if (controls.length === 0) {
|
||||
throw new Error(`button parity action has no DOM control: ${action}`);
|
||||
}
|
||||
if (!controls.some((control) => control.dataset.axisSourceRef && control.dataset.axisExpectedEffect)) {
|
||||
throw new Error(`button parity action has no source-tagged DOM control: ${action}`);
|
||||
}
|
||||
}
|
||||
for (const selector of [
|
||||
'[data-action="estop"]',
|
||||
'[data-action="power"]',
|
||||
@@ -156,6 +169,9 @@
|
||||
'[data-action="step"]',
|
||||
'[data-action="stop"]',
|
||||
'[data-action="jog-plus"]',
|
||||
'[data-action="spindle-reverse"]',
|
||||
'[data-action="spindle-stop"]',
|
||||
'[data-action="spindle-forward"]',
|
||||
'[data-action="toggle-flood"]',
|
||||
'[data-action="kins-tcp"]',
|
||||
'[data-action="clear-preview"]',
|
||||
@@ -273,17 +289,90 @@
|
||||
await click('[data-action="power"]', "AXIS power");
|
||||
await waitState((state) => state.machine.powerOn === true && state.machine.taskState === "on", "machine power on");
|
||||
await click('[data-action="home-all"]', "AXIS home all");
|
||||
await waitState((state) => state.machine.allHomed === true && state.machine.mode === "manual", "home all");
|
||||
await waitState((state) => (
|
||||
state.machine.allHomed === true
|
||||
&& state.machine.mode === "manual"
|
||||
&& Math.abs(Number(state.axisPose.x) - 0) < 1e-6
|
||||
&& Math.abs(Number(state.axisPose.y) - 0) < 1e-6
|
||||
&& Math.abs(Number(state.axisPose.z) - 10) < 1e-6
|
||||
&& Math.abs(Number(state.dro.x) - 0) < 1e-6
|
||||
&& Math.abs(Number(state.dro.y) - 0) < 1e-6
|
||||
&& Math.abs(Number(state.dro.z) - 10) < 1e-6
|
||||
), "home all");
|
||||
await click('[data-action="toggle-auto-manual"]', "AXIS AUTO mode toolbar toggle");
|
||||
await waitState((state) => state.machine.mode === "auto", "toolbar toggle to AUTO");
|
||||
await click('[data-action="toggle-auto-manual"]', "AXIS MANUAL mode toolbar toggle");
|
||||
await waitState((state) => state.machine.mode === "manual", "toolbar toggle to MANUAL");
|
||||
await click('[data-action="run"]', "AXIS immediate-pause run");
|
||||
assert(doc.querySelector('[data-tool-id="tbtn_pause"]')?.dataset.action === "pause-resume", "toolbar pause button is LinuxCNC task_pauseresume");
|
||||
await click('[data-tool-id="tbtn_pause"]', "AXIS immediate pause/resume button after run click");
|
||||
await waitState((state) => (
|
||||
state.runState === "paused"
|
||||
&& state.machine.interpState === "paused"
|
||||
&& state.machine.taskPaused === true
|
||||
), "immediate pause after run click");
|
||||
assert(doc.querySelector('[data-tool-id="tbtn_pause"]')?.dataset.paused === "true", "toolbar pause button visibly enters paused state");
|
||||
assert(doc.querySelector('[data-tool-id="tbtn_pause"]')?.title === "Resume program", "toolbar pause button title switches to resume");
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
assert(api.getState().runState === "paused", "immediate pause remains paused after async task/HAL settle");
|
||||
await click('[data-action="stop"]', "AXIS stop after immediate pause");
|
||||
await waitState((state) => state.runState === "stopped" && state.machine.mode === "auto", "stop after immediate pause");
|
||||
await click('[data-action="tab-manual"]', "AXIS manual tab after immediate pause");
|
||||
await waitState((state) => state.machine.mode === "manual", "manual mode after immediate pause");
|
||||
await click('[data-action="run"]', "AXIS direct run after home");
|
||||
await waitState((state) => (
|
||||
(state.runState === "running" || state.runState === "complete")
|
||||
&& state.machine.mode === "auto"
|
||||
&& state.programRuntimeFeedback
|
||||
), "direct run after power and home");
|
||||
await click('[data-menu-command="pause"]', "AXIS menu Pause after direct run");
|
||||
await waitState((state) => (
|
||||
state.runState === "paused"
|
||||
&& state.machine.interpState === "paused"
|
||||
&& state.machine.taskPaused === true
|
||||
), "menu Pause after direct run");
|
||||
await click('[data-menu-command="resume"]', "AXIS menu Resume after direct Pause");
|
||||
await waitState((state) => state.runState === "running" && state.machine.interpState === "reading", "menu Resume after direct Pause");
|
||||
await click('[data-tool-id="tbtn_pause"]', "AXIS toolbar pause after direct run");
|
||||
await waitState((state) => (
|
||||
state.runState === "paused"
|
||||
&& state.machine.interpState === "paused"
|
||||
&& state.machine.taskPaused === true
|
||||
), "pause after direct run");
|
||||
const pauseToolbarAfterPause = doc.querySelector('[data-tool-id="tbtn_pause"]');
|
||||
assert(pauseToolbarAfterPause?.dataset.action === "pause-resume", "toolbar pause button stays bound to LinuxCNC task_pauseresume while paused");
|
||||
assert(pauseToolbarAfterPause?.dataset.paused === "true", "toolbar pause button has paused dataset while paused");
|
||||
assert(pauseToolbarAfterPause?.getAttribute("aria-pressed") === "true", "toolbar pause button aria pressed while paused");
|
||||
await click('[data-tool-id="tbtn_pause"]', "AXIS toolbar pause/resume resumes while already paused");
|
||||
await waitState((state) => state.runState === "running" && state.machine.interpState === "reading", "toolbar pause/resume resumes while paused");
|
||||
assert(doc.querySelector('[data-tool-id="tbtn_pause"]')?.dataset.paused === "false", "toolbar pause button leaves paused state after resume");
|
||||
assert(doc.querySelector('[data-tool-id="tbtn_pause"]')?.title === "Pause program", "toolbar pause button title switches to pause after resume");
|
||||
await click('[data-tool-id="tbtn_pause"]', "AXIS toolbar pause/resume pauses again");
|
||||
await waitState((state) => (
|
||||
state.runState === "paused"
|
||||
&& state.machine.interpState === "paused"
|
||||
&& state.machine.taskPaused === true
|
||||
), "toolbar pause/resume pauses again");
|
||||
const beforeStepSample = api.getState().programExecutionSampleIndex;
|
||||
await click('[data-action="step"]', "AXIS step after pause");
|
||||
await waitState((state) => (
|
||||
(state.runState === "stepping" || state.runState === "paused")
|
||||
&& state.machine.interpState === "paused"
|
||||
&& state.machine.taskPaused === true
|
||||
&& Number(state.programExecutionSampleIndex) > Number(beforeStepSample)
|
||||
), "step after pause");
|
||||
assert(doc.querySelector('[data-tool-id="tbtn_pause"]')?.dataset.action === "pause-resume", "toolbar pause button stays task_pauseresume after step");
|
||||
await click('[data-tool-id="tbtn_pause"]', "AXIS toolbar pause/resume after pause");
|
||||
await waitState((state) => state.runState === "running" && state.machine.interpState === "reading", "resume after pause");
|
||||
assert(doc.querySelector('[data-tool-id="tbtn_pause"]')?.dataset.action === "pause-resume", "toolbar pause button stays task_pauseresume after resume");
|
||||
await click('[data-tool-id="tbtn_pause"]', "AXIS second toolbar pause after resume");
|
||||
await waitState((state) => (
|
||||
state.runState === "paused"
|
||||
&& state.machine.interpState === "paused"
|
||||
&& state.machine.taskPaused === true
|
||||
), "second pause after resume");
|
||||
await click('[data-tool-id="tbtn_pause"]', "AXIS second toolbar resume after pause");
|
||||
await waitState((state) => state.runState === "running" && state.machine.interpState === "reading", "second resume after pause");
|
||||
await click('[data-action="stop"]', "AXIS stop after direct run");
|
||||
await waitState((state) => state.runState === "stopped" && state.machine.mode === "auto", "stop after direct run");
|
||||
await click('[data-action="tab-manual"]', "AXIS manual tab after direct run");
|
||||
@@ -329,10 +418,38 @@
|
||||
const beforeFeed = api.getState().feed.feedOverride;
|
||||
await click('[data-action="feed-override-up"]', "feed override up");
|
||||
await waitState((state) => state.feed.feedOverride === Math.min(beforeFeed + 10, 200), "feed override");
|
||||
await click('[data-action="spindle-forward"]', "spindle forward");
|
||||
await waitState((state) => state.spindle.direction === "forward" && state.spindle.enabled === true, "spindle forward");
|
||||
await click('[data-action="spindle-reverse"]', "spindle reverse");
|
||||
await waitState((state) => (
|
||||
state.spindle.direction === "reverse"
|
||||
&& state.spindle.enabled === true
|
||||
&& state.linuxCncProcessMonitor.spindle.halPins.on === 1
|
||||
&& state.linuxCncProcessMonitor.spindle.halPins.forward === 0
|
||||
&& state.linuxCncProcessMonitor.spindle.halPins.reverse === 1
|
||||
&& state.linuxCncProcessMonitor.spindle.halPins.speedOut > 0
|
||||
), "spindle reverse");
|
||||
await waitFor(() => doc.querySelector("[data-active-gcodes]")?.dataset.activeGcodes.includes("M4") ? true : null, "active G-codes reverse spindle");
|
||||
await click('[data-action="spindle-stop"]', "spindle stop");
|
||||
await waitState((state) => state.spindle.direction === "stop" && state.spindle.enabled === false, "spindle stop");
|
||||
await waitState((state) => (
|
||||
state.spindle.direction === "stop"
|
||||
&& state.spindle.enabled === false
|
||||
&& state.linuxCncProcessMonitor.spindle.halPins.on === 0
|
||||
&& state.linuxCncProcessMonitor.spindle.halPins.forward === 0
|
||||
&& state.linuxCncProcessMonitor.spindle.halPins.reverse === 0
|
||||
&& state.linuxCncProcessMonitor.spindle.halPins.speedOut === 0
|
||||
), "spindle stop");
|
||||
await waitFor(() => doc.querySelector("[data-active-gcodes]")?.dataset.activeGcodes.includes("M5") ? true : null, "active G-codes stopped spindle");
|
||||
await click('[data-action="spindle-forward"]', "spindle forward");
|
||||
await waitState((state) => (
|
||||
state.spindle.direction === "forward"
|
||||
&& state.spindle.enabled === true
|
||||
&& state.linuxCncProcessMonitor.spindle.halPins.on === 1
|
||||
&& state.linuxCncProcessMonitor.spindle.halPins.forward === 1
|
||||
&& state.linuxCncProcessMonitor.spindle.halPins.reverse === 0
|
||||
&& state.linuxCncProcessMonitor.spindle.halPins.speedOut > 0
|
||||
), "spindle forward");
|
||||
await waitFor(() => doc.querySelector("[data-active-gcodes]")?.dataset.activeGcodes.includes("M3") ? true : null, "active G-codes forward spindle");
|
||||
await click('[data-action="spindle-stop"]', "spindle stop after forward");
|
||||
await waitState((state) => state.spindle.direction === "stop" && state.spindle.enabled === false, "spindle stop after forward");
|
||||
await click('[data-action="toggle-flood"]', "flood coolant");
|
||||
await waitState((state) => state.coolant.flood === true, "flood coolant");
|
||||
await click('[data-action="block-delete"]', "block delete");
|
||||
|
||||
@@ -313,11 +313,15 @@ for (const action of [
|
||||
"run",
|
||||
"pause",
|
||||
"resume",
|
||||
"pause-resume",
|
||||
"step",
|
||||
"stop",
|
||||
"home-all",
|
||||
"jog-plus",
|
||||
"jog-minus",
|
||||
"spindle-reverse",
|
||||
"spindle-stop",
|
||||
"spindle-forward",
|
||||
"kins-identity",
|
||||
"kins-tcp",
|
||||
"kins-userk",
|
||||
@@ -335,14 +339,61 @@ buttonStore.dispatch({ type: "TOGGLE_POWER" });
|
||||
assert.equal(buttonStore.getState().machine.powerOn, true);
|
||||
buttonStore.dispatch({ type: "HOME" });
|
||||
assert.equal(buttonStore.getState().machine.allHomed, true);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.axes.joint.x, 43);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.axes.joint.y, -32.15);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.axes.joint.z, -11.306);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.axes.joint.x, 0);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.axes.joint.y, 0);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.axes.joint.z, 10);
|
||||
await buttonStore.dispatch({ type: "RUN_FROM_OPERATOR" });
|
||||
assert.equal(buttonStore.getState().machine.mode, "auto");
|
||||
assert.equal(["running", "complete"].includes(buttonStore.getState().runState), true);
|
||||
assert.equal(Boolean(buttonStore.getState().programRuntimeFeedback), true);
|
||||
if (buttonStore.getState().runState === "running") {
|
||||
buttonStore.dispatch({ type: "PAUSE_RESUME" });
|
||||
assert.equal(buttonStore.getState().runState, "paused");
|
||||
assert.equal(buttonStore.getState().machine.interpState, "paused");
|
||||
buttonStore.dispatch({ type: "PAUSE_RESUME" });
|
||||
assert.equal(buttonStore.getState().runState, "running");
|
||||
assert.equal(buttonStore.getState().machine.interpState, "reading");
|
||||
buttonStore.dispatch({ type: "PAUSE_RESUME" });
|
||||
assert.equal(buttonStore.getState().runState, "paused");
|
||||
assert.equal(buttonStore.getState().machine.interpState, "paused");
|
||||
const beforeStepSample = buttonStore.getState().programExecutionSampleIndex;
|
||||
buttonStore.dispatch({ type: "STEP" });
|
||||
assert.equal(buttonStore.getState().runState, "stepping");
|
||||
assert.equal(buttonStore.getState().machine.interpState, "paused");
|
||||
assert.equal(buttonStore.getState().programExecutionSampleIndex > beforeStepSample, true);
|
||||
buttonStore.dispatch({ type: "RESUME" });
|
||||
assert.equal(buttonStore.getState().runState, "running");
|
||||
assert.equal(buttonStore.getState().machine.interpState, "reading");
|
||||
buttonStore.dispatch({ type: "PAUSE" });
|
||||
assert.equal(buttonStore.getState().runState, "paused");
|
||||
assert.equal(buttonStore.getState().machine.interpState, "paused");
|
||||
buttonStore.dispatch({ type: "RESUME" });
|
||||
assert.equal(buttonStore.getState().runState, "running");
|
||||
assert.equal(buttonStore.getState().machine.interpState, "reading");
|
||||
}
|
||||
buttonStore.dispatch({ type: "STOP" });
|
||||
|
||||
const idleInterpRunningStore = createSimulationStore({
|
||||
runState: "running",
|
||||
machine: {
|
||||
powerOn: true,
|
||||
estopActive: false,
|
||||
taskState: "on",
|
||||
mode: "auto",
|
||||
interpState: "idle",
|
||||
interpResumeState: "reading",
|
||||
taskPaused: false,
|
||||
allHomed: true,
|
||||
noForceHoming: false,
|
||||
},
|
||||
});
|
||||
idleInterpRunningStore.dispatch({ type: "PAUSE" });
|
||||
assert.equal(idleInterpRunningStore.getState().runState, "paused");
|
||||
assert.equal(idleInterpRunningStore.getState().machine.interpState, "paused");
|
||||
assert.equal(idleInterpRunningStore.getState().machine.taskPaused, true);
|
||||
idleInterpRunningStore.dispatch({ type: "RESUME" });
|
||||
assert.equal(idleInterpRunningStore.getState().runState, "running");
|
||||
assert.equal(idleInterpRunningStore.getState().machine.interpState, "reading");
|
||||
buttonStore.dispatch({ type: "SET_MODE", mode: "manual" });
|
||||
buttonStore.dispatch({ type: "SET_MODE", mode: "mdi" });
|
||||
buttonStore.dispatch({ type: "RUN_MDI", command: "M428" });
|
||||
@@ -370,10 +421,28 @@ const feedBefore = buttonStore.getState().feed.feedOverride;
|
||||
buttonStore.dispatch({ type: "ADJUST_OVERRIDE", target: "feed", delta: 10 });
|
||||
assert.equal(buttonStore.getState().feed.feedOverride, feedBefore + 10);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.feed.feedOverridePercent, feedBefore + 10);
|
||||
buttonStore.dispatch({ type: "SET_SPINDLE_DIRECTION", direction: "reverse" });
|
||||
assert.equal(buttonStore.getState().spindle.direction, "reverse");
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.enabled, true);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.halPins.on, 1);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.halPins.forward, 0);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.halPins.reverse, 1);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.halPins.speedOut, 1600);
|
||||
buttonStore.dispatch({ type: "SET_SPINDLE_DIRECTION", direction: "stop" });
|
||||
assert.equal(buttonStore.getState().spindle.direction, "stop");
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.enabled, false);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.halPins.on, 0);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.halPins.forward, 0);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.halPins.reverse, 0);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.halPins.speedOut, 0);
|
||||
buttonStore.dispatch({ type: "SET_SPINDLE_DIRECTION", direction: "forward" });
|
||||
assert.equal(buttonStore.getState().spindle.direction, "forward");
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.enabled, true);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.actualRpm, 1600);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.halPins.on, 1);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.halPins.forward, 1);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.halPins.reverse, 0);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.spindle.halPins.speedOut, 1600);
|
||||
buttonStore.dispatch({ type: "TOGGLE_COOLANT", kind: "flood" });
|
||||
assert.equal(buttonStore.getState().coolant.flood, true);
|
||||
assert.equal(buttonStore.getState().linuxCncProcessMonitor.coolant.flood, true);
|
||||
|
||||
Reference in New Issue
Block a user