Files
findr-api/test/mqtt-topics.test.ts
T
mars3142 cadc280761 Scaffold Fastify + Drizzle API with pick-by-light
Layered: routes -> services -> repositories -> db, over PostgreSQL 18 with
split roles (findr_migrator for DDL, findr_app for DML). Keycloak JWT auth
with per-endpoint scope guards. Drizzle migrations run with the DDL role at
container start.

Pick-by-light: one ESP32 controller drives one WS2812 chain through several
boxes; each box owns a contiguous LED slice. MQTT contract in
src/lib/mqtt-topics.ts / docs/mqtt.md. /v1/pick controls light/idle/off and
/v1/boxes + /v1/controllers manage the strip mapping.

Reference resource /v1/parts wired end to end. Vitest, Biome, multi-stage
Dockerfile, local compose.yml with Postgres.

Signed-off-by: Peter Siegmund <mars3142@noreply.mars3142.dev>
2026-09-03 01:07:35 +02:00

54 lines
1.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
boxNumberFromTopic,
idleCommand,
offCommand,
pickCommand,
topics,
} from "../src/lib/mqtt-topics.js";
describe("mqtt topic builders", () => {
const t = topics("findr");
it("builds the command and state topics for a box", () => {
expect(t.boxConfig(2)).toBe("findr/box/2/config");
expect(t.cmdLight(2)).toBe("findr/box/2/cmd/light");
expect(t.stateLight(2)).toBe("findr/box/2/state/light");
expect(t.ctrlOnline("abc")).toBe("findr/controller/abc/state/online");
expect(t.allBoxState()).toBe("findr/box/+/state/+");
expect(t.allControllerState()).toBe("findr/controller/+/state/+");
});
it("extracts the box number from a topic", () => {
expect(boxNumberFromTopic("findr/box/7/state/light")).toBe(7);
expect(boxNumberFromTopic("findr/box/x/state/light")).toBeNull();
expect(boxNumberFromTopic("other/box/7/state/light")).toBeNull();
});
it("respects a custom prefix", () => {
const p = topics("lab");
expect(p.cmdLight(3)).toBe("lab/box/3/cmd/light");
expect(boxNumberFromTopic("lab/box/3/evt/button", "lab")).toBe(3);
});
});
describe("light command builders", () => {
it("pick lights exactly the given bins", () => {
const cmd = pickCommand([{ cell: "D4", ledIndex: 27, mode: "take" }], {
seconds: 30,
requestId: "r1",
});
expect(cmd).toEqual({
effect: "pick",
bins: [{ cell: "D4", ledIndex: 27, mode: "take" }],
seconds: 30,
requestId: "r1",
});
});
it("idle and off carry just the effect", () => {
expect(idleCommand().effect).toBe("idle");
expect(offCommand().effect).toBe("off");
});
});