fix(FN-4963): stabilize empty-state cache-failure coverage

Fusion-Task-Id: FN-4963
Fusion-Task-Lineage: 791f5e46-c630-4883-89de-942cc85c329b
This commit is contained in:
Fusion (runfusion.ai)
2026-05-18 03:31:24 -07:00
committed by gsxdsm
parent e5d586acc7
commit da9aedd1b1
2 changed files with 14 additions and 10 deletions

View File

@@ -7,6 +7,7 @@ import { act, fireEvent, renderHook, waitFor } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { useChat } from "../useChat";
import * as apiModule from "../../api";
import * as swrCacheModule from "../../utils/swrCache";
import type { ChatSession, ChatMessage } from "@fusion/core";
// Mock the API module
@@ -167,7 +168,7 @@ describe("useChat", () => {
expect(result.current.sessions).toHaveLength(2);
expect(result.current.sessionsLoading).toBe(false);
act(() => {
await act(async () => {
resolveFetch?.({ sessions: [] });
});
@@ -216,19 +217,18 @@ describe("useChat", () => {
});
it("clears stale cache envelope when refresh fails with empty in-memory sessions", async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-04-10T00:02:30.000Z"));
const projectId = "proj-empty-failure";
localStorage.setItem(
chatSessionsCacheKey(projectId),
JSON.stringify({
savedAt: new Date("2026-04-10T00:00:00.000Z").getTime(),
savedAt: Date.now() - 120_000,
data: [makeSession({ id: "session-stale", agentId: "agent-001" })],
}),
);
mockFetchChatSessions.mockRejectedValueOnce(new Error("network down"));
const clearCacheSpy = vi.spyOn(swrCacheModule, "clearCache");
mockFetchChatSessions.mockReset();
mockFetchChatSessions.mockRejectedValue(new Error("network down"));
const { result } = renderHook(() => useChat(projectId));
@@ -238,8 +238,9 @@ describe("useChat", () => {
expect(result.current.sessionsLoading).toBe(false);
});
expect(localStorage.getItem(chatSessionsCacheKey(projectId))).toBeNull();
vi.useRealTimers();
await waitFor(() => {
expect(clearCacheSpy).toHaveBeenCalledWith(chatSessionsCacheKey(projectId));
});
});
it("preserves cache envelope when refresh fails after cached sessions hydrate", async () => {

View File

@@ -339,7 +339,9 @@ export function useChat(
// Fetch sessions
const refreshSessions = useCallback(async () => {
setSessionsLoading(true);
if (sessionsRef.current.length === 0) {
setSessionsLoading(true);
}
try {
const data: ChatSessionListResponse = await fetchChatSessions(projectId);
// Sort by updatedAt descending
@@ -352,7 +354,8 @@ export function useChat(
writeCache(cacheKey, sorted, { maxBytes: 500_000 });
}
} catch {
if (sessionsRef.current.length === 0) {
const cacheHydratedSessions = readCachedSessions(projectId);
if (sessionsRef.current.length === 0 && cacheHydratedSessions.length === 0) {
const cacheKey = getChatSessionsCacheKey(projectId);
if (cacheKey) {
clearCache(cacheKey);