Files
KDL_WORK/kdl-wasm/web/tests/integration/abb120SuiteArtifacts.test.ts
2026-06-28 20:58:18 +08:00

85 lines
3.5 KiB
TypeScript

import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
import { runAbb120Suite } from "../../src/suites/abb120Suite.js";
import { parseGrl } from "../../src/grl/parser/index.js";
import { compileSemanticProgram } from "../../src/grl/semantic/index.js";
import { ABB_IRB120_ZERO_JOINTS } from "../fixtures/abbIrb120.js";
const WEB_ROOT = join(dirname(fileURLToPath(import.meta.url)), "../..");
const PROGRAM_DIR = join(WEB_ROOT, "tests", "fixtures", "abb120", "programs");
const APP_DIR = join(WEB_ROOT, "app");
const PROGRAM_NAMES = [
"A120_00_Smoke.grl",
"A120_10_JointPickPlace.grl",
"A120_20_CartesianBlend.grl",
"A120_30_IOWaitPulse.grl",
"A120_40_ErrorDiagnostics.grl",
"A120_50_OperationProcess.grl"
];
function loadPrograms() {
return PROGRAM_NAMES.map((name) => ({
name,
text: readFileSync(join(PROGRAM_DIR, name), "utf8")
}));
}
describe("ABB120 suite artifacts", () => {
it("ships six parseable GRL programs with source maps and KDL bridge requests", () => {
for (const program of loadPrograms()) {
const ast = parseGrl(program.text);
const ir = compileSemanticProgram(ast, {
startJoints: [...ABB_IRB120_ZERO_JOINTS],
sampleTime: 0.02
});
expect(ast.kind).toBe("Program");
expect(ir.moduleName).toMatch(/^A120/);
expect(ir.sourceMap.length + ir.kdlBridge.motionRequests.length + ir.kdlBridge.pathRequests.length).toBeGreaterThan(0);
}
});
it("creates job, post, roundtrip, report, delivery, and screenshot evidence paths", () => {
const job = runAbb120Suite(loadPrograms(), { now: "2026-06-27T12:00:00.000Z" });
expect(job.job_id).toBe("A120-JOB-20260627120000-doc");
expect(job.robot.robotId).toBe("abb_irb120_3_58");
expect(job.programs.map((program) => program.name)).toEqual(PROGRAM_NAMES);
expect(job.post.filenames).toEqual(expect.arrayContaining([
"A120Smoke.mod",
"A120Smoke.ls",
"A120Smoke.src"
]));
expect(job.roundtrip.status).toMatch(/pass|warn/);
expect(job.report_id).toBe("A120-REPORT-20260627120000");
expect(job.artifacts).toMatchObject({
jobJson: "A120-JOB-20260627120000-doc/job.json",
reportHtml: "A120-JOB-20260627120000-doc/reports/A120-REPORT-20260627120000.html",
deliveryPackageJson: "A120-JOB-20260627120000-doc/delivery/package.json",
desktopScreenshot: "A120-JOB-20260627120000-doc/screenshots/virtual-controller-desktop.png",
mobileScreenshot: "A120-JOB-20260627120000-doc/screenshots/virtual-controller-mobile.png"
});
});
it("has an HTML virtual controller entry with required panels", () => {
const html = readFileSync(join(APP_DIR, "virtual-controller.html"), "utf8");
const css = readFileSync(join(APP_DIR, "virtual-controller.css"), "utf8");
const js = readFileSync(join(APP_DIR, "virtual-controller.js"), "utf8");
expect(html).toContain("ABB120 Station");
expect(html).toContain("Path: pick_place");
expect(html).toContain("W2-JOB-latest");
expect(html).toContain("working2-abb120-spec");
expect(html).toContain("Controller");
expect(html).toContain("Motion Queue");
expect(html).toContain("Reports");
expect(html).toContain('src="./virtual-controller.js"');
expect(html).not.toContain('src="./virtual-controller.ts"');
expect(css).toContain(".viewport");
expect(css).toContain("@media");
expect(js).toContain("data-command");
expect(js).toContain("data-tab");
});
});