diff --git a/tests/edge_protocol.test.ts b/tests/edge_protocol.test.ts index e1050db..197ee1f 100644 --- a/tests/edge_protocol.test.ts +++ b/tests/edge_protocol.test.ts @@ -54,6 +54,41 @@ describe("gateway -> backend frames", () => { expect(printers.every((p) => typeof p.printer_id === "string" && p.printer_id.length > 0)).toBe(true); }); + it("accepts a stage, including stage 0", () => { + // `stage` is Bambu's `stg_cur`: what the printer is doing when it is not + // laying down plastic. 0 means printing, and a schema or serialiser that + // treats 0 as absent loses the distinction that makes the field worth + // having - a printer at 14% and layer 0 is mid-bed-levelling at stage 54 + // and genuinely stuck at stage 0. + for (const stage of [0, 13, 54]) { + check(EdgeClientMessageSchema, { + type: "telemetry", + printers: [{ printer_id: "p1p", name: "P1P", percent: 14, layer: 0, stage }], + }); + } + + // The assertion that makes the loop above mean anything. This schema + // permits unknown properties, so `{ stage: 54 }` validates whether or + // not `stage` is declared - verified, it does. Rejecting a *wrongly + // typed* stage is what proves the field is really in the schema, so this + // is what fails if someone removes it. + expect( + Value.Check(EdgeClientMessageSchema, { + type: "telemetry", + printers: [{ printer_id: "p1p", name: "P1P", stage: "54" }], + }), + ).toBe(false); + }); + + it("still accepts telemetry with no stage at all", () => { + // The field is additive: the committed live capture predates it, and a + // gateway that has not been updated yet simply omits it. + check(EdgeClientMessageSchema, { + type: "telemetry", + printers: [{ printer_id: "p1p", name: "P1P", percent: 0 }], + }); + }); + it("rejects a telemetry batch whose printer has no id", () => { // printer_id and name are the only required fields; everything else is // genuinely unknowable for a printer that has only just connected.