继续实现仿真测试程序

结论:真实浏览器仿真页面新增多测试程序选择和运行能力,覆盖直线、Z 轴轮廓、增量、圆弧和 G81 钻孔,并接入 Node、browser 与 release gate 验证。
This commit is contained in:
2026-06-16 21:13:09 +08:00
parent 24e1fc18b1
commit ddd5b78999
10 changed files with 461 additions and 41 deletions

View File

@@ -33,44 +33,95 @@
throw new Error("real simulation page did not expose ready state");
}
try {
const frame = await loadFrame("../../runtime/ui/simulation/index.html");
const doc = frame.contentDocument;
const state = await waitForState(frame);
function assertRenderedState(doc, state) {
const polyline = doc.querySelector("[data-toolpath-polyline]");
const rows = [...doc.querySelectorAll("[data-motion-row]")];
const programRows = [...doc.querySelectorAll("[data-program-line]")];
const canonicalOutput = doc.querySelector("[data-canonical-output]")?.textContent ?? "";
if (doc.body.dataset.simulationReady !== "true") {
throw new Error("simulation body readiness flag not true");
throw new Error(`simulation body readiness flag not true for ${state.program?.id}`);
}
if (state.apiName !== "real-browser-simulation-state") {
throw new Error("simulation state API name drift");
}
if (state.summary.motionEventCount < 5) {
throw new Error("simulation motion event count too low");
if (state.summary.motionEventCount < 2) {
throw new Error(`simulation motion event count too low for ${state.program?.id}`);
}
if (!canonicalOutput.includes("canon_event=")) {
throw new Error(`simulation canonical output missing events for ${state.program?.id}`);
}
if (!polyline?.getAttribute("points")) {
throw new Error(`simulation toolpath polyline missing points for ${state.program?.id}`);
}
if (rows.length !== state.motion.length) {
throw new Error(`simulation motion table row count drift for ${state.program?.id}`);
}
if (programRows.length !== state.summary.programLineCount) {
throw new Error(`simulation program row count drift for ${state.program?.id}`);
}
if (!doc.querySelector("[data-toolpath-svg]")?.getAttribute("viewBox")) {
throw new Error(`simulation SVG viewBox missing for ${state.program?.id}`);
}
if (doc.body.dataset.simulationProgramId !== state.program?.id) {
throw new Error(`simulation body program id drift for ${state.program?.id}`);
}
}
try {
const frame = await loadFrame("../../runtime/ui/simulation/index.html");
const doc = frame.contentDocument;
const state = await waitForState(frame);
const canonicalOutput = doc.querySelector("[data-canonical-output]")?.textContent ?? "";
const api = frame.contentWindow?.linuxCncRealSimulationApi;
assertRenderedState(doc, state);
if (!canonicalOutput.includes("canon_event=STRAIGHT_FEED line=2 x=1 y=0 z=0")) {
throw new Error("simulation canonical output missing LinuxCNC feed event");
}
if (!polyline?.getAttribute("points")?.includes("1,0")) {
if (!doc.querySelector("[data-toolpath-polyline]")?.getAttribute("points")?.includes("1,0")) {
throw new Error("simulation toolpath polyline missing expected point");
}
if (rows.length !== state.motion.length) {
throw new Error("simulation motion table row count drift");
}
if (programRows.length < 6) {
throw new Error("simulation program rows missing");
}
if (doc.querySelector('[data-axis="x"]')?.textContent !== "0.000") {
throw new Error("simulation final X axis drift");
}
if (doc.querySelector('[data-axis="y"]')?.textContent !== "0.000") {
throw new Error("simulation final Y axis drift");
}
if (!doc.querySelector("[data-toolpath-svg]")?.getAttribute("viewBox")) {
throw new Error("simulation SVG viewBox missing");
if (!api?.getPrograms || !api?.runProgramById) {
throw new Error("simulation API missing program controls");
}
const programs = api.getPrograms();
if (programs.length < 5) {
throw new Error("simulation test program inventory too small");
}
for (const program of programs) {
const nextState = await api.runProgramById(program.id);
assertRenderedState(doc, nextState);
if (nextState.program.id !== program.id) {
throw new Error(`simulation API returned wrong program id for ${program.id}`);
}
for (const motionType of program.expectedMotionTypes) {
if (!nextState.summary.motionTypes.includes(motionType)) {
throw new Error(`simulation program ${program.id} missing motion type ${motionType}`);
}
}
}
const arcState = await api.runProgramById("arc-g2-g3");
const arcPoints = doc.querySelector("[data-toolpath-polyline]")?.getAttribute("points") ?? "";
if (!arcState.summary.motionTypes.includes("ARC_FEED")) {
throw new Error("arc simulation did not produce ARC_FEED");
}
if (!arcPoints.includes("1,-1") || !arcPoints.includes("0,0")) {
throw new Error(`arc simulation toolpath points did not use canonical arc endpoints: ${arcPoints}`);
}
const drillState = await api.runProgramById("drill-g81");
if (drillState.motion.filter(({ type }) => type === "STRAIGHT_FEED").length < 3) {
throw new Error("drill simulation did not produce expected feed plunges");
}
status.textContent = "browser_real_simulation_page_smoke=ok";