import assert from "node:assert/strict"; import { getFiveAxisProfile } from "../../app/src/profiles/index.js"; import { createSimulationStore, validateRunPreconditions } from "../../app/src/state/store.js"; import { gateLinuxCncTaskAction } from "../../app/src/state/linuxcnc-task-policy.js"; const profile = getFiveAxisProfile("gmoccapy-xyzab"); const store = createSimulationStore(); store.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); assert.equal(store.getState().profile.id, profile.id); assert.equal(store.getState().machine.noForceHoming, false); let gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "run blocked: machine must be on"); gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "manual" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "mode blocked: machine must be on before MANUAL"); gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "mdi" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "mode blocked: machine must be on before MDI"); gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "auto" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "mode blocked: machine must be on before AUTO"); store.dispatch({ type: "TOGGLE_POWER" }); gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "manual" }); assert.equal(gate.allowed, true); gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "run blocked: switch to auto mode first"); gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "auto" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "mode blocked: home machine before AUTO"); store.dispatch({ type: "SET_MODE", mode: "auto" }); assert.equal(store.getState().machine.mode, "manual"); assert.equal(store.getState().operatorMessage, "mode blocked: home machine before AUTO"); gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "run blocked: switch to auto mode first"); gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "mdi" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "mode blocked: home machine before MDI"); store.dispatch({ type: "SET_MODE", mode: "manual" }); store.dispatch({ type: "HOME" }); gate = gateLinuxCncTaskAction(store.getState(), { type: "SET_MODE", mode: "auto" }); assert.equal(gate.allowed, true); store.dispatch({ type: "SET_MODE", mode: "auto" }); gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "run blocked: LinuxCNC INI not loaded"); store.dispatch({ type: "ATTACH_INI_CONFIG", profileId: "gmoccapy-xyzab", iniConfig: { profileId: "gmoccapy-xyzab", path: profile.iniPath, sourceText: "[TRAJ]\nCOORDINATES = X Y Z A B\nNO_FORCE_HOMING = 0\n[KINS]\nKINEMATICS = trivkins coordinates=xyzab\n", validation: { ready: true }, traj: { coordinates: "XYZAB", noForceHoming: false }, kinematics: { name: "trivkins", sparm: "coordinates=xyzab" }, kinematicsParameters: profile.kinematicsParameters, kinematicsModuleId: profile.kinematicsModuleId, axisLimits: profile.axisLimits, jointConfig: profile.jointConfig, display: profile.display, rs274ngc: profile.rs274ngc, hal: { ...profile.hal, halcmd: profile.hal.halcmd, initialSets: [], }, halui: profile.halui, emcmot: { servoPeriodNs: 1000000 }, emcio: {}, task: { cycleTimeSeconds: 0.001 }, }, }); gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "run blocked: LinuxCNC machine files not staged"); store.dispatch({ type: "MACHINE_FILE_STAGING_COMPLETE", plan: { profileId: "gmoccapy-xyzab", selectedProgramSourceRel: null, }, save: { fileCount: 2, files: [ { sourceRel: "configs/sim/gmoccapy/gmoccapy_XYZAB.ini", wasmPath: "/work/sim/gmoccapy/gmoccapy_XYZAB.ini", kind: "ini", text: "", bytes: 0, }, ], summary: { gcodeFileCount: 0 }, }, }); gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "run blocked: no machine-file G-code opened for task/HAL session"); store.dispatch({ type: "MACHINE_FILE_STAGING_COMPLETE", plan: { profileId: "gmoccapy-xyzab", selectedProgramSourceRel: "configs/sim/gmoccapy/demos/xyzab-demo.ngc", }, save: { fileCount: 2, files: [ { sourceRel: "configs/sim/gmoccapy/demos/xyzab-demo.ngc", wasmPath: "/work/sim/gmoccapy/demos/xyzab-demo.ngc", kind: "demo", text: "G0 X0\nM2\n", bytes: 9, }, ], summary: { gcodeFileCount: 1 }, }, selectedGcodeSourceRel: "configs/sim/gmoccapy/demos/xyzab-demo.ngc", }); gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "run blocked: task/HAL runtime not ready"); store.dispatch({ type: "ATTACH_TASK_HAL_RUNTIME", runtime: { loaded: true, readiness() { return { loaded: true, taskRuntimeReady: true, motionRuntimeReady: true, halRuntimeReady: true, }; }, }, }); gate = gateLinuxCncTaskAction(store.getState(), { type: "RUN" }); assert.equal(gate.allowed, true); assert.equal(gate.status.canRunAutoStrict, true); assert.equal(gate.status.profileId, "gmoccapy-xyzab"); const runPreconditions = validateRunPreconditions(store.getState(), { requireTaskHalRuntime: false, requireTaskHalSession: false, }); assert.equal(runPreconditions.ok, false); assert.equal(runPreconditions.operatorMessage, "run blocked: unsupported five-axis profile gmoccapy-xyzab"); const manualStore = createSimulationStore(); manualStore.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); manualStore.dispatch({ type: "TOGGLE_POWER" }); gate = gateLinuxCncTaskAction(manualStore.getState(), { type: "JOG", axis: "x", direction: 1 }); assert.equal(gate.allowed, true); gate = gateLinuxCncTaskAction(manualStore.getState(), { type: "HOME" }); assert.equal(gate.allowed, true); manualStore.dispatch({ type: "HOME" }); manualStore.dispatch({ type: "SET_MODE", mode: "mdi" }); gate = gateLinuxCncTaskAction(manualStore.getState(), { type: "RUN_MDI" }); assert.equal(gate.allowed, true); const controlStore = createSimulationStore(); controlStore.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); controlStore.dispatch({ type: "ESTOP" }); gate = gateLinuxCncTaskAction(controlStore.getState(), { type: "TOGGLE_COOLANT", kind: "flood" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "coolant blocked: machine must be on"); gate = gateLinuxCncTaskAction(controlStore.getState(), { type: "SET_SPINDLE_DIRECTION", direction: "forward" }); assert.equal(gate.allowed, false); assert.equal(gate.operatorMessage, "spindle blocked: machine must be on"); controlStore.dispatch({ type: "RESET" }); controlStore.dispatch({ type: "TOGGLE_POWER" }); controlStore.dispatch({ type: "SET_SPINDLE_DIRECTION", direction: "forward" }); assert.equal(controlStore.getState().spindle.enabled, true); assert.equal(controlStore.getState().spindle.direction, "forward"); controlStore.dispatch({ type: "SET_SPINDLE_DIRECTION", direction: "stop" }); assert.equal(controlStore.getState().spindle.enabled, false); assert.equal(controlStore.getState().spindle.direction, "stop"); controlStore.dispatch({ type: "TOGGLE_COOLANT", kind: "flood" }); assert.equal(controlStore.getState().coolant.flood, true); const hardButtonStore = createSimulationStore(); hardButtonStore.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); hardButtonStore.dispatch({ type: "GMOCAPY_HARDWARE_BUTTON", pin: "gmoccapy.v-button.button-1", value: false }); assert.equal(hardButtonStore.getState().machine.powerOn, false); assert.equal(hardButtonStore.getState().operatorMessage, "gmoccapy hardware button falling edge ignored"); hardButtonStore.dispatch({ type: "GMOCAPY_HARDWARE_BUTTON", pin: "gmoccapy.v-button.button-1", value: true }); assert.equal(hardButtonStore.getState().machine.powerOn, true); hardButtonStore.dispatch({ type: "GMOCAPY_HARDWARE_BUTTON", pin: "gmoccapy.v-button.button-4", value: true }); assert.equal(hardButtonStore.getState().machine.mode, "manual"); assert.equal(hardButtonStore.getState().operatorMessage, "mode blocked: home machine before AUTO"); hardButtonStore.dispatch({ type: "GMOCAPY_HARDWARE_BUTTON", location: "bottom", index: 0, value: true }); assert.equal(hardButtonStore.getState().machine.allHomed, true); hardButtonStore.dispatch({ type: "GMOCAPY_HARDWARE_BUTTON", pin: "gmoccapy.v-button.button-4", value: true }); assert.equal(hardButtonStore.getState().machine.mode, "auto"); hardButtonStore.dispatch({ type: "GMOCAPY_HARDWARE_BUTTON", pin: "gmoccapy.v-button.button-6", value: true }); assert.equal(hardButtonStore.getState().gmoccapyGui.activeNativePage, "setup"); assert.equal(hardButtonStore.getState().operatorMessage, "gmoccapy native page diagnostic-only: setup"); hardButtonStore.dispatch({ type: "GMOCAPY_HARDWARE_BUTTON", pin: "gmoccapy.h-button.button-9", value: true }); assert.equal(hardButtonStore.getState().operatorMessage, "gmoccapy hardware button unmapped: gmoccapy.h-button.button-9"); const halPinStore = createSimulationStore(); halPinStore.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.ignore-limits", value: true }); assert.equal(halPinStore.getState().gmoccapyGui.ignoreLimits, true); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL ignore-limits requested"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.optional-stop", value: true }); assert.equal(halPinStore.getState().gmoccapyGui.optionalBlocks, true); assert.equal(halPinStore.getState().gmoccapyGui.optionalStop, false); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL optional-stop -> block delete on"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.blockdelete", value: true }); assert.equal(halPinStore.getState().gmoccapyGui.optionalStop, true); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL blockdelete -> optional stop on"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.unlock-settings", value: false }); assert.equal(halPinStore.getState().gmoccapyGui.settingsUnlockPin, false); assert.equal(halPinStore.getState().gmoccapyGui.setupSensitive, true); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL unlock-settings ignored: unlock_way is use"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.unlock-settings", value: false, halUnlockMode: true }); assert.equal(halPinStore.getState().gmoccapyGui.settingsUnlockMode, "hal"); assert.equal(halPinStore.getState().gmoccapyGui.setupSensitive, false); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL unlock-settings disabled setup"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.unlock-settings", value: true }); assert.equal(halPinStore.getState().gmoccapyGui.settingsUnlockPin, true); assert.equal(halPinStore.getState().gmoccapyGui.setupSensitive, true); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL unlock-settings enabled setup"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.blockheight", value: 12.5 }); assert.equal(halPinStore.getState().gmoccapyGui.blockHeight, 12.5); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL tool measurement output recorded; XYZAB has no [TOOLSENSOR]"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.toolmeasurement", value: true }); assert.equal(halPinStore.getState().gmoccapyGui.toolMeasurement, true); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.messages.test", value: true }); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL user message pin unmapped: gmoccapy_XYZAB.ini defines no MESSAGE_* entries"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.feed.feed-override.counts", value: 12 }); assert.equal(halPinStore.getState().feed.feedOverride, 100); assert.equal(halPinStore.getState().gmoccapyGui.feedOverrideCounts, 12); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL feed counts synchronized"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.feed.feed-override.count-enable", value: true }); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.feed.feed-override.counts", value: 17 }); assert.equal(halPinStore.getState().feed.feedOverride, 105); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL feed counts adjusted"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.rapid.rapid-override.analog-enable", value: true }); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.rapid.rapid-override.direct-value", value: 0.25 }); assert.equal(halPinStore.getState().feed.rapidOverride, 50); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.spindle.spindle-override.direct-value", value: 0.5 }); assert.equal(halPinStore.getState().spindle.override, 100); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL spindle direct-value ignored: analog disabled"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.spindle.spindle-override.analog-enable", value: true }); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.spindle.spindle-override.direct-value", value: 0.5 }); assert.equal(halPinStore.getState().spindle.override, 75); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.spindle.reset-spindle-override", value: false }); assert.equal(halPinStore.getState().spindle.override, 75); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL spindle reset falling edge ignored"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.spindle.reset-spindle-override", value: true }); assert.equal(halPinStore.getState().spindle.override, 100); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL spindle reset to 100"); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.jog.jog-velocity.count-enable", value: true }); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.jog.jog-velocity.counts", value: 2 }); assert.equal(halPinStore.getState().gmoccapyGui.jogVelocity, 380.8); halPinStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.unknown", value: true }); assert.equal(halPinStore.getState().operatorMessage, "gmoccapy HAL pin unmapped: gmoccapy.unknown"); const halJogStore = createSimulationStore(); halJogStore.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); halJogStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.jog.axis.jog-x-plus", value: true }); assert.equal(halJogStore.getState().runState, "idle"); assert.equal(halJogStore.getState().operatorMessage, "gmoccapy HAL jog blocked: jog blocked: machine must be on"); halJogStore.dispatch({ type: "TOGGLE_POWER" }); halJogStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.jog.axis.jog-x-plus", value: true }); assert.equal(halJogStore.getState().runState, "jogging"); assert.equal(halJogStore.getState().axisPose.x, 43); assert.equal(halJogStore.getState().machine.jogIncrement, 0); assert.equal(halJogStore.getState().gmoccapyGui.activeJogPin, "gmoccapy.jog.axis.jog-x-plus"); assert.equal(halJogStore.getState().operatorMessage, "gmoccapy HAL jog X+ continuous"); halJogStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.jog.axis.jog-x-plus", value: false }); assert.equal(halJogStore.getState().runState, "idle"); assert.equal(halJogStore.getState().gmoccapyGui.activeJogPin, null); assert.equal(halJogStore.getState().operatorMessage, "gmoccapy HAL jog X+ released"); halJogStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.jog.jog-inc-2", value: false }); assert.equal(halJogStore.getState().machine.jogIncrement, 0); assert.equal(halJogStore.getState().operatorMessage, "gmoccapy HAL jog increment falling edge ignored"); halJogStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.jog.jog-inc-2", value: true }); assert.equal(halJogStore.getState().machine.jogIncrement, 0.1); assert.equal(halJogStore.getState().gmoccapyGui.jogIncrementIndex, 2); assert.equal(halJogStore.getState().gmoccapyGui.jogIncrementOutput, 0.1); halJogStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.jog.axis.jog-x-plus", value: true }); assert.equal(halJogStore.getState().axisPose.x, 43.1); assert.equal(halJogStore.getState().operatorMessage, "gmoccapy HAL jog X+ 0.1"); halJogStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.jog.jog-inc-5", value: true }); assert.equal(halJogStore.getState().machine.jogIncrement, 31.3563); assert.equal(halJogStore.getState().gmoccapyGui.jogIncrementLabel, "1.2345 in"); halJogStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.jog.turtle-jog", value: true }); assert.equal(halJogStore.getState().gmoccapyGui.turtleJog, true); assert.equal(halJogStore.getState().operatorMessage, "gmoccapy HAL turtle jog on"); const halMessageStore = createSimulationStore(); halMessageStore.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); halMessageStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.delete-message", value: false }); assert.equal(halMessageStore.getState().gmoccapyGui.deletedMessageCount, 0); assert.equal(halMessageStore.getState().operatorMessage, "gmoccapy HAL delete-message falling edge ignored"); halMessageStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.jog.axis.jog-y-minus", value: true }); assert.equal(halMessageStore.getState().operatorMessage, "gmoccapy HAL jog blocked: jog blocked: machine must be on"); halMessageStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.delete-message", value: true }); assert.equal(halMessageStore.getState().gmoccapyGui.error, false); assert.equal(halMessageStore.getState().gmoccapyGui.deletedMessageCount, 1); assert.equal(halMessageStore.getState().operatorMessage, "gmoccapy HAL delete-message cleared alert"); halMessageStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.warning-confirm", value: true }); assert.equal(halMessageStore.getState().gmoccapyGui.warningConfirm, true); assert.equal(halMessageStore.getState().operatorMessage, "gmoccapy HAL warning-confirm asserted"); halMessageStore.dispatch({ type: "GMOCAPY_HAL_PIN", pin: "gmoccapy.warning-confirm", value: false }); assert.equal(halMessageStore.getState().gmoccapyGui.warningConfirm, false); assert.equal(halMessageStore.getState().operatorMessage, "gmoccapy HAL warning-confirm cleared"); const nativePageStore = createSimulationStore(); nativePageStore.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); nativePageStore.dispatch({ type: "GMOCAPY_HARDWARE_BUTTON", pin: "gmoccapy.v-button.button-6", value: true }); assert.equal(nativePageStore.getState().gmoccapyGui.activeNativePage, "setup"); assert.equal(nativePageStore.getState().gmoccapyGui.nativePageMode, "diagnostic-only"); assert.equal(nativePageStore.getState().operatorMessage, "gmoccapy native page diagnostic-only: setup"); nativePageStore.dispatch({ type: "GMOCAPY_HARDWARE_BUTTON", pin: "gmoccapy.h-button.button-3", value: true }); assert.equal(nativePageStore.getState().gmoccapyGui.activeNativePage, "tool-editor"); assert.equal(nativePageStore.getState().operatorMessage, "gmoccapy native page diagnostic-only: tool-editor"); nativePageStore.dispatch({ type: "GMOCAPY_PAGE_ACTION", pageId: "file-load", actionId: "open" }); assert.equal(nativePageStore.getState().gmoccapyGui.filePageStatus, "open"); assert.equal(nativePageStore.getState().operatorMessage.includes("native Gtk chooser diagnostic"), true); nativePageStore.dispatch({ type: "GMOCAPY_TOOL_EDITOR_ACTION", actionId: "save" }); assert.equal(nativePageStore.getState().gmoccapyGui.toolEditorStatus, "writeback-blocked"); assert.equal(nativePageStore.getState().operatorMessage.includes("does not write tool.tbl"), true); const macroBlockedStore = createSimulationStore(); macroBlockedStore.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); macroBlockedStore.dispatch({ type: "GMOCAPY_RUN_MACRO", name: "halo_world" }); assert.equal(macroBlockedStore.getState().gmoccapyGui.macroLastName, "halo_world"); assert.equal(macroBlockedStore.getState().operatorMessage.includes("gmoccapy macro blocked"), true); const macroReadyStore = createSimulationStore(); macroReadyStore.dispatch({ type: "SET_PROFILE", profileId: "gmoccapy-xyzab" }); macroReadyStore.dispatch({ type: "TOGGLE_POWER" }); macroReadyStore.dispatch({ type: "HOME" }); macroReadyStore.dispatch({ type: "SET_MODE", mode: "mdi" }); macroReadyStore.dispatch({ type: "GMOCAPY_RUN_MACRO", name: "increment", args: { xinc: 1.25, yinc: 2.5 }, }); assert.equal(macroReadyStore.getState().gmoccapyGui.activeNativePage, "mdi-macros"); assert.equal(macroReadyStore.getState().gmoccapyGui.macroLastCommand, "O call [1.25] [2.5]"); assert.equal(macroReadyStore.getState().machine.mdiCommand, "O CALL [1.25] [2.5]"); assert.equal(macroReadyStore.getState().operatorMessage, "gmoccapy macro MDI O call [1.25] [2.5]"); console.log("gmoccapy_xyzab_gates_smoke=ok");