import { describe, expect, it } from "vitest"; import { columnsForLayout, reconcileChartSlots, swapChartSlots, type ChartSlot } from "./chart-window-slots"; describe("fixed chart slots", () => { it("maps supported layouts to grid columns", () => { expect([columnsForLayout("one"), columnsForLayout("two"), columnsForLayout("four")]).toEqual([1, 2, 2]); }); it("keeps chart positions when publications update in another order", () => { const slots: ChartSlot[] = ["flow", null, "pressure", "plans"]; expect(reconcileChartSlots(slots, ["plans", "pressure", "flow"], 2)).toBe(slots); }); it("leaves deleted positions vacant without moving surviving charts", () => { expect(reconcileChartSlots(["pressure", "flow", "plans", null], ["pressure", "plans"], 2)) .toEqual(["pressure", null, "plans", null]); }); it("fills the earliest vacant slots before appending a padded row", () => { expect(reconcileChartSlots(["pressure", null, "flow", null], ["new-1", "flow", "new-2", "pressure", "new-3"], 2)) .toEqual(["pressure", "new-1", "flow", "new-2", "new-3", null]); }); it("uses vacancies created by a deletion in the same update", () => { expect(reconcileChartSlots(["pressure", "removed", "flow", null], ["pressure", "flow", "new"], 2)) .toEqual(["pressure", "new", "flow", null]); }); it("preserves linear positions when the column count changes", () => { const slots: ChartSlot[] = ["a", null, "b", "c", "d", null]; expect(reconcileChartSlots(slots, ["a", "b", "c", "d"], 1)).toEqual(["a", null, "b", "c", "d"]); expect(reconcileChartSlots(slots, ["a", "b", "c", "d"], 2)).toBe(slots); }); it("trims only empty trailing rows, retaining leading and middle vacancies", () => { expect(reconcileChartSlots([null, null, "a", null, null, null, null, null], ["a"], 2)) .toEqual([null, null, "a", null]); expect(reconcileChartSlots(["a", null, null, null], ["a"], 2)).toEqual(["a", null]); expect(reconcileChartSlots(["a", null, null, null], [], 2)).toEqual([]); }); it("builds default slots in available order and never duplicates a chart", () => { expect(reconcileChartSlots([], ["a", "b", "a"], 2)).toEqual(["a", "b"]); expect(reconcileChartSlots(["a", "a", "b", null], ["a", "b", "c"], 2)).toEqual(["a", "c", "b", null]); }); it("swaps occupied slots without inserting or shifting adjacent charts", () => { const slots: ChartSlot[] = ["a", "b", "c", "d"]; expect(swapChartSlots(slots, 0, 2)).toEqual(["c", "b", "a", "d"]); expect(slots).toEqual(["a", "b", "c", "d"]); }); it("swaps across rows and permits an empty destination", () => { expect(swapChartSlots(["a", "b", "c", "d", "e", null, null, null], 0, 5)) .toEqual([null, "b", "c", "d", "e", "a", null, null]); }); it("keeps the original array for invalid or unchanged swaps", () => { const slots: ChartSlot[] = ["a", null, null]; for (const [source, target] of [[-1, 1], [0, 3], [3, 0], [0.5, 1], [0, Number.NaN], [0, 0], [1, 2]]) { expect(swapChartSlots(slots, source, target)).toBe(slots); } }); });