From f6795317a897302caa68b65639618b03bb1eb617 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Fri, 24 Jul 2026 00:28:55 -0700 Subject: [PATCH] fix(dashboard-tests): useTasks column normalization asserts the post-cutover contract b2a7425c7 replaced the six-legacy-id whitelist with normalizeColumnId: custom workflow column ids pass through untouched, only structurally unusable values (non-string/empty) fall back to triage. The two normalization tests now assert both halves of that invariant instead of the deleted whitelist behavior. Co-Authored-By: Claude Fable 5 --- .../app/hooks/__tests__/useTasks.test.ts | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/packages/dashboard/app/hooks/__tests__/useTasks.test.ts b/packages/dashboard/app/hooks/__tests__/useTasks.test.ts index c801d5bf0a..9e143ce8af 100644 --- a/packages/dashboard/app/hooks/__tests__/useTasks.test.ts +++ b/packages/dashboard/app/hooks/__tests__/useTasks.test.ts @@ -299,20 +299,31 @@ describe("useTasks", () => { expect(writePayload).toHaveLength(500); }); - it("normalizes invalid column values from initial fetch to triage", async () => { - const malformedTask = { + /* + FNXC:ColumnNormalization 2026-07-24-00:20: + b2a7425c7 (IR-driven lifecycle cutover) replaced the six-legacy-id whitelist with + normalizeColumnId: custom workflow column ids are real ids and must pass through + untouched; only structurally unusable values (non-string/empty) fall back to triage. + */ + it("passes custom column ids through and normalizes structurally invalid columns to triage", async () => { + const customColumnTask = { ...createMockTask({ id: "FN-099" }), column: "unknown-column", } as unknown as Task; - mockFetchTasks.mockResolvedValueOnce([malformedTask]); + const malformedTask = { + ...createMockTask({ id: "FN-098" }), + column: "", + } as unknown as Task; + mockFetchTasks.mockResolvedValueOnce([customColumnTask, malformedTask]); const { result } = renderHook(() => useTasks()); await waitFor(() => { - expect(result.current.tasks).toHaveLength(1); + expect(result.current.tasks).toHaveLength(2); }); - expect(result.current.tasks[0].column).toBe("triage"); + expect(result.current.tasks.find((t) => t.id === "FN-099")?.column).toBe("unknown-column"); + expect(result.current.tasks.find((t) => t.id === "FN-098")?.column).toBe("triage"); }); it("exposes refreshTasks and performs exactly one additional fetch when called", async () => { @@ -775,7 +786,9 @@ describe("useTasks", () => { expect(result.current.tasks[0].id).toBe("FN-002"); }); - it("normalizes invalid column values from SSE created events", async () => { + it("passes custom column ids through and normalizes structurally invalid columns from SSE created events", async () => { + // FNXC:ColumnNormalization 2026-07-24-00:20: see the initial-fetch variant — post-b2a7425c7, + // string column ids are custom-workflow-valid; only non-string/empty falls back to triage. mockFetchTasks.mockResolvedValueOnce([]); const { result } = renderHook(() => useTasks()); @@ -783,17 +796,23 @@ describe("useTasks", () => { expect(MockEventSource.instances).toHaveLength(1); }); - const malformedTask = { + const customColumnTask = { ...createMockTask({ id: "FN-003" }), column: "bad-column", } as unknown as Task; + const malformedTask = { + ...createMockTask({ id: "FN-004" }), + column: "", + } as unknown as Task; act(() => { + MockEventSource.instances[0]._emit("task:created", customColumnTask); MockEventSource.instances[0]._emit("task:created", malformedTask); }); - expect(result.current.tasks).toHaveLength(1); - expect(result.current.tasks[0].column).toBe("triage"); + expect(result.current.tasks).toHaveLength(2); + expect(result.current.tasks.find((t) => t.id === "FN-003")?.column).toBe("bad-column"); + expect(result.current.tasks.find((t) => t.id === "FN-004")?.column).toBe("triage"); }); });