import { act, renderHook, waitFor } from "@testing-library/react"; import type { ReactNode } from "react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { useSessions } from "@/hooks/useSessions"; import * as api from "@/lib/api"; import { ClientProvider } from "@/providers/ClientProvider"; vi.mock("@/lib/api", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, listSessions: vi.fn(), deleteSession: vi.fn(), fetchSessionMessages: vi.fn(), }; }); function fakeClient() { return { status: "open" as const, defaultChatId: null as string | null, onStatus: () => () => {}, onChat: () => () => {}, sendMessage: vi.fn(), newChat: vi.fn(), attach: vi.fn(), connect: vi.fn(), close: vi.fn(), updateUrl: vi.fn(), }; } function wrap(client: ReturnType) { return function Wrapper({ children }: { children: ReactNode }) { return ( {children} ); }; } describe("useSessions", () => { beforeEach(() => { vi.mocked(api.listSessions).mockReset(); vi.mocked(api.deleteSession).mockReset(); vi.mocked(api.fetchSessionMessages).mockReset(); }); it("removes a session from the local list after delete succeeds", async () => { vi.mocked(api.listSessions).mockResolvedValue([ { key: "websocket:chat-a", channel: "websocket", chatId: "chat-a", createdAt: "2026-04-16T10:00:00Z", updatedAt: "2026-04-16T10:00:00Z", preview: "Alpha", }, { key: "websocket:chat-b", channel: "websocket", chatId: "chat-b", createdAt: "2026-04-16T11:00:00Z", updatedAt: "2026-04-16T11:00:00Z", preview: "Beta", }, ]); vi.mocked(api.deleteSession).mockResolvedValue(true); const { result } = renderHook(() => useSessions(), { wrapper: wrap(fakeClient()), }); await waitFor(() => expect(result.current.sessions).toHaveLength(2)); await act(async () => { await result.current.deleteChat("websocket:chat-a"); }); expect(api.deleteSession).toHaveBeenCalledWith("tok", "websocket:chat-a"); expect(result.current.sessions.map((s) => s.key)).toEqual(["websocket:chat-b"]); }); it("keeps the session in the list when delete fails", async () => { vi.mocked(api.listSessions).mockResolvedValue([ { key: "websocket:chat-a", channel: "websocket", chatId: "chat-a", createdAt: "2026-04-16T10:00:00Z", updatedAt: "2026-04-16T10:00:00Z", preview: "Alpha", }, ]); vi.mocked(api.deleteSession).mockRejectedValue(new Error("boom")); const { result } = renderHook(() => useSessions(), { wrapper: wrap(fakeClient()), }); await waitFor(() => expect(result.current.sessions).toHaveLength(1)); await expect( act(async () => { await result.current.deleteChat("websocket:chat-a"); }), ).rejects.toThrow("boom"); expect(result.current.sessions.map((s) => s.key)).toEqual(["websocket:chat-a"]); }); });