import { describe, expect, it } from "@suaveplan/testing/runner"; import { CURRENT_SCHEMA_VERSION } from "../src/constants/constants.js"; import type { ControlSurface } from "../src/types/control-surface.types.js"; import { validateSurface } from "../src/validate/validate.js"; import { walkSurface } from "../src/walk/walk.js"; const fixture: ControlSurface = { id: "round-trip", name: "8-channel mixer", version: CURRENT_SCHEMA_VERSION, createdAt: 1700_000_000_000, updatedAt: 1700_000_001_000, skin: { id: "default", vars: { "--accent": "#0af" } }, root: { type: "group", id: "root", layout: { kind: "stack", direction: "row", gap: 4 }, transform: { position: { x: 0, y: 0 } }, children: Array.from({ length: 8 }, (_, channel) => ({ type: "group", id: `ch-${channel}`, layout: { kind: "stack", direction: "column", gap: 2 }, transform: { position: { x: channel * 60, y: 0 } }, children: [ { type: "control", id: `ch-${channel}-vol`, kind: "slider-v", transform: { position: { x: 0, y: 0 } }, range: { min: 0, max: 1, default: 0.75, units: "lin" }, binding: { kind: "pluginParam", pluginId: "mixer", paramPath: `channels/${channel}/volume`, curve: "log", }, }, { type: "control", id: `ch-${channel}-mute`, kind: "button-latching", transform: { position: { x: 0, y: 80 } }, binding: { kind: "midiOut", portId: "main", channel: 0, cc: 16 + channel, }, }, ], })), }, }; describe("round-trip — JSON → validate → walk → re-serialise", () => { it("preserves every node through JSON.parse(JSON.stringify(...)) and re-validation", { timeout: 5000, }, () => { const first = validateSurface(fixture); expect(first.surface).toBeDefined(); const jsonString = JSON.stringify(first.surface); const parsed = JSON.parse(jsonString); const second = validateSurface(parsed); expect(second.surface).toEqual(first.surface); const ids: string[] = []; walkSurface(second.surface!, (n) => ids.push(n.id)); // 1 root + 8 channel groups + 8 volume + 8 mute = 25 expect(ids.length).toBe(25); expect(ids[0]).toBe("root"); }); });