import { act, renderHook, waitFor } from "@testing-library/react"; import type { ReactNode } from "react"; import { describe, expect, it, vi } from "vitest"; import { useSidebarState } from "@/hooks/useSidebarState"; import type { NanobotClient } from "@/lib/nanobot-client"; import type { SidebarStatePayload } from "@/lib/types"; import { ClientProvider } from "@/providers/ClientProvider"; describe("useSidebarState", () => { it("serializes full-state writes so an older request cannot overwrite a newer update", async () => { let resolveFirstWrite: (() => void) | null = null; let sidebarStateUpdateHandler: ((state: SidebarStatePayload) => void) | null = null; const setSidebarState = vi.fn() .mockImplementationOnce((state: SidebarStatePayload) => new Promise( (resolve) => { resolveFirstWrite = () => resolve(state); }, )) .mockImplementation(async (state: SidebarStatePayload) => state); const client = { status: "open" as const, onStatus: () => () => {}, onSidebarStateUpdate: (handler: (state: SidebarStatePayload) => void) => { sidebarStateUpdateHandler = handler; return () => { sidebarStateUpdateHandler = null; }; }, setSidebarState, } as unknown as NanobotClient; vi.stubGlobal("fetch", vi.fn().mockResolvedValue({ ok: true, status: 200, json: async () => ({}), })); const wrapper = ({ children }: { children: ReactNode }) => ( {children} ); const { result } = renderHook(() => useSidebarState([], false), { wrapper }); await waitFor(() => expect(result.current.loading).toBe(false)); act(() => { void result.current.update((current) => ({ ...current, title_overrides: { "websocket:a": "First" }, })); void result.current.update((current) => ({ ...current, title_overrides: { "websocket:a": "Second" }, })); }); expect(setSidebarState).toHaveBeenCalledTimes(1); act(() => { sidebarStateUpdateHandler?.(setSidebarState.mock.calls[0]?.[0]); }); expect(result.current.state.title_overrides).toEqual({ "websocket:a": "Second", }); act(() => resolveFirstWrite?.()); await waitFor(() => expect(setSidebarState).toHaveBeenCalledTimes(2)); expect(setSidebarState.mock.calls[1]?.[0]).toEqual(expect.objectContaining({ title_overrides: { "websocket:a": "Second" }, })); }); });