import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { renderHook, act } from "@testing-library/react"; import { useConfigItem } from "../useConfigItem"; describe("useConfigItem", () => { beforeEach(() => { vi.useFakeTimers(); }); afterEach(() => { vi.useRealTimers(); vi.clearAllMocks(); }); it("loads data and sets loading state", async () => { const fetchFn = vi.fn().mockResolvedValue("hello"); const saveFn = vi.fn().mockResolvedValue(undefined); const { result } = renderHook(() => useConfigItem({ fetchFn, saveFn })); expect(result.current.loading).toBe(true); await act(async () => { await Promise.resolve(); }); expect(fetchFn).toHaveBeenCalled(); expect(result.current.data).toBe("hello"); expect(result.current.loading).toBe(false); }); it("sets error if fetch rejects", async () => { const fetchFn = vi.fn().mockRejectedValue(new Error("nope")); const saveFn = vi.fn().mockResolvedValue(undefined); const { result } = renderHook(() => useConfigItem({ fetchFn, saveFn })); await act(async () => { await Promise.resolve(); }); expect(result.current.error).toBe("nope"); expect(result.current.loading).toBe(false); }); it("save updates data when mergeOnSave is provided", async () => { const fetchFn = vi.fn().mockResolvedValue({ value: 1 }); const saveFn = vi.fn().mockResolvedValue(undefined); const { result } = renderHook(() => useConfigItem<{ value: number }, { delta: number }>({ fetchFn, saveFn, mergeOnSave: (prev, update) => prev ? { ...prev, value: prev.value + update.delta } : prev, }) ); await act(async () => { await Promise.resolve(); }); expect(result.current.data).toEqual({ value: 1 }); await act(async () => { await result.current.save({ delta: 2 }); }); expect(saveFn).toHaveBeenCalledWith({ delta: 2 }); expect(result.current.data).toEqual({ value: 3 }); }); it("saveError is set when save fails", async () => { const fetchFn = vi.fn().mockResolvedValue("ok"); const saveFn = vi.fn().mockRejectedValue(new Error("save failed")); const { result } = renderHook(() => useConfigItem({ fetchFn, saveFn })); await act(async () => { await Promise.resolve(); }); await act(async () => { await expect(result.current.save("test")).rejects.toThrow("save failed"); }); expect(result.current.saveError).toBe("save failed"); }); });