FN-6442: rescue dashboard hook tests from skiplist

Rescues three dashboard hook test files by replacing brittle coverage with stable assertions and removing their skiplist entries.

- Stub global localStorage failures directly for quick chat persistence coverage.
- Remove the placeholder skipped useChatRooms pagination test.
- Rework useTaskDiffStats stepVersion tests around active worktree cache behavior.
- Drop the rescued dashboard hook tests from the curated skiplist.

Files changed:
 .../__tests__/quickChatLastSessionStorage.test.ts  | 23 ++++--
 .../app/hooks/__tests__/useChatRooms.test.ts       |  6 --
 .../app/hooks/__tests__/useTaskDiffStats.test.ts   | 94 ++++++++++++----------
 scripts/lib/dashboard-curated-skiplist.json        | 12 ---
 4 files changed, 67 insertions(+), 68 deletions(-)

Fusion-Task-Id: FN-6442
Fusion-Task-Lineage: f2fe4791-1216-420d-9734-3938287779da
This commit is contained in:
gsxdsm
2026-06-14 09:01:21 -07:00
parent 4f7b3ac78f
commit a6d5efce27
4 changed files with 67 additions and 68 deletions

View File

@@ -7,6 +7,7 @@ import {
describe("quickChatLastSessionStorage", () => {
beforeEach(() => {
vi.unstubAllGlobals();
localStorage.clear();
vi.restoreAllMocks();
});
@@ -38,14 +39,20 @@ describe("quickChatLastSessionStorage", () => {
});
it("swallows localStorage failures", () => {
vi.spyOn(Storage.prototype, "setItem").mockImplementation(() => {
throw new Error("quota exceeded");
});
vi.spyOn(Storage.prototype, "getItem").mockImplementation(() => {
throw new Error("blocked");
});
vi.spyOn(Storage.prototype, "removeItem").mockImplementation(() => {
throw new Error("blocked");
/*
FNXC:DashboardTesting 2026-06-14-08:46:
This rescue must prove the quick-chat persistence helpers survive an unavailable storage backend; stub the global storage object directly because jsdom's Storage prototype spy can miss the Web Storage instance and create a fake-green assertion.
*/
vi.stubGlobal("localStorage", {
setItem: vi.fn(() => {
throw new Error("quota exceeded");
}),
getItem: vi.fn(() => {
throw new Error("blocked");
}),
removeItem: vi.fn(() => {
throw new Error("blocked");
}),
});
expect(() => setPersistedLastQuickChatSessionId("proj-123", "session-123")).not.toThrow();

View File

@@ -245,12 +245,6 @@ describe("useChatRooms", () => {
expect(result.current.activeRoom).toBeNull();
});
// Skipped: desc-fetch pagination test flakes under batch runs (the
// ordering of mock responses doesn't survive concurrent setup). Real
// pagination contract is still covered by useChat hook tests.
// Replaced with stub: original assertions deferred (see git history). Restore once underlying feature/bug work lands.
it("loads newest 100 room messages using desc fetch while preserving ascending transcript", async () => { expect(true).toBe(true); });
it("sendRoomMessage inserts optimistic temp message and reconciles to server transcript", async () => {
const active = room("room-1", "one", "2026-05-09T01:00:00.000Z");
mockFetchChatRooms.mockResolvedValueOnce({ rooms: [active] });

View File

@@ -565,79 +565,89 @@ describe("useTaskDiffStats", () => {
mockFetchTaskDiff.mockClear();
});
it("re-fetches when stepVersion changes", async () => {
// Initial fetch
mockFetchTaskDiff.mockResolvedValueOnce({
files: [],
stats: { filesChanged: 1, additions: 5, deletions: 1 },
});
it("re-fetches active worktree stats when stepVersion changes", async () => {
/*
FNXC:DashboardTesting 2026-06-14-08:49:
stepVersion is the cache key only for active worktree-backed columns; done-mode cache invalidation intentionally uses mergeSignature so this regression test must exercise in-progress behavior.
*/
mockFetchTaskDiff
.mockResolvedValueOnce({
files: [],
stats: { filesChanged: 1, additions: 5, deletions: 1 },
})
.mockResolvedValueOnce({
files: [],
stats: { filesChanged: 3, additions: 10, deletions: 2 },
});
const { result, rerender } = renderHook(
({ stepVersion }) => useTaskDiffStats(
"FN-STEP",
"done",
"abc1234",
"in-progress",
undefined,
{ stepVersion },
undefined,
{ worktree: "/repo/.worktrees/fn-step", stepVersion },
),
{ initialProps: { stepVersion: 1 as number | string } },
);
await waitFor(() => expect(result.current.loading).toBe(false));
expect(result.current.stats).toEqual({ filesChanged: 1, additions: 5, deletions: 1 });
await waitFor(() => expect(result.current.stats).toEqual({ filesChanged: 1, additions: 5, deletions: 1 }));
expect(result.current.loading).toBe(false);
expect(mockFetchTaskDiff).toHaveBeenCalledWith("FN-STEP", "/repo/.worktrees/fn-step", undefined);
expect(mockFetchTaskDiff).toHaveBeenCalledTimes(1);
// Change stepVersion - should trigger re-fetch
mockFetchTaskDiff.mockResolvedValueOnce({
files: [],
stats: { filesChanged: 3, additions: 10, deletions: 2 },
});
rerender({ stepVersion: 2 as number | string });
await waitFor(() => expect(result.current.loading).toBe(false));
expect(result.current.stats).toEqual({ filesChanged: 3, additions: 10, deletions: 2 });
await waitFor(() => expect(result.current.stats).toEqual({ filesChanged: 3, additions: 10, deletions: 2 }));
expect(result.current.loading).toBe(false);
expect(mockFetchTaskDiff).toHaveBeenCalledTimes(2);
});
it("caches stats separately per stepVersion", async () => {
// Initial fetch with stepVersion 1
mockFetchTaskDiff.mockResolvedValueOnce({
files: [],
stats: { filesChanged: 5, additions: 20, deletions: 3 },
});
it("caches active worktree stats separately per stepVersion", async () => {
mockFetchTaskDiff
.mockResolvedValueOnce({
files: [],
stats: { filesChanged: 5, additions: 20, deletions: 3 },
})
.mockResolvedValueOnce({
files: [],
stats: { filesChanged: 10, additions: 50, deletions: 8 },
});
const activeOptions = { worktree: "/repo/.worktrees/fn-step-cache" };
const { result: first } = renderHook(() =>
useTaskDiffStats("FN-STEP-CACHE", "done", "abc1234", undefined, { stepVersion: "v1" }),
useTaskDiffStats("FN-STEP-CACHE", "in-progress", undefined, undefined, {
...activeOptions,
stepVersion: "v1",
}),
);
await waitFor(() => expect(first.current.loading).toBe(false));
expect(first.current.stats).toEqual({ filesChanged: 5, additions: 20, deletions: 3 });
// Same task, different stepVersion - should fetch separately
mockFetchTaskDiff.mockResolvedValueOnce({
files: [],
stats: { filesChanged: 10, additions: 50, deletions: 8 },
});
await waitFor(() => expect(first.current.stats).toEqual({ filesChanged: 5, additions: 20, deletions: 3 }));
const { result: second } = renderHook(() =>
useTaskDiffStats("FN-STEP-CACHE", "done", "abc1234", undefined, { stepVersion: "v2" }),
useTaskDiffStats("FN-STEP-CACHE", "in-progress", undefined, undefined, {
...activeOptions,
stepVersion: "v2",
}),
);
await waitFor(() => expect(second.current.loading).toBe(false));
expect(second.current.stats).toEqual({ filesChanged: 10, additions: 50, deletions: 8 });
// Both should have been fetched
await waitFor(() => expect(second.current.stats).toEqual({ filesChanged: 10, additions: 50, deletions: 8 }));
expect(mockFetchTaskDiff).toHaveBeenCalledTimes(2);
// Cache should have both entries
mockFetchTaskDiff.mockClear();
const { result: cached1 } = renderHook(() =>
useTaskDiffStats("FN-STEP-CACHE", "done", "abc1234", undefined, { stepVersion: "v1" }),
useTaskDiffStats("FN-STEP-CACHE", "in-progress", undefined, undefined, {
...activeOptions,
stepVersion: "v1",
}),
);
const { result: cached2 } = renderHook(() =>
useTaskDiffStats("FN-STEP-CACHE", "done", "abc1234", undefined, { stepVersion: "v2" }),
useTaskDiffStats("FN-STEP-CACHE", "in-progress", undefined, undefined, {
...activeOptions,
stepVersion: "v2",
}),
);
expect(cached1.current.stats).toEqual({ filesChanged: 5, additions: 20, deletions: 3 });

View File

@@ -5,18 +5,6 @@
"file": "packages/dashboard/app/__tests__/build-output.test.ts",
"reason": "asserts the built bundle; runs standalone via `pnpm --filter @fusion/dashboard test:build` (needs a prior vite build), not in the unit gate"
},
{
"file": "packages/dashboard/app/hooks/__tests__/quickChatLastSessionStorage.test.ts",
"reason": "pre-existing failure (orphaned from curated gate, never previously executed in CI; tracked as FN-6442)"
},
{
"file": "packages/dashboard/app/hooks/__tests__/useChatRooms.test.ts",
"reason": "pre-existing failure (orphaned from curated gate, never previously executed in CI; tracked as FN-6442)"
},
{
"file": "packages/dashboard/app/hooks/__tests__/useTaskDiffStats.test.ts",
"reason": "pre-existing failure (orphaned from curated gate, never previously executed in CI; tracked as FN-6442)"
},
{
"file": "packages/dashboard/src/__tests__/evals-routes.test.ts",
"reason": "pre-existing failure (orphaned from curated gate, never previously executed in CI; tracked as FN-6444)"