// @vitest-environment jsdom import { renderHook, waitFor } from "@testing-library/react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { useToolboxTools } from "./useToolboxTools"; const get = vi.fn(); const toast = vi.fn(); vi.mock("@/lib/api/client", () => ({ api: { GET: (...a: unknown[]) => get(...a) }, })); vi.mock("@/components/Toast", () => ({ useToast: () => toast })); describe("useToolboxTools", () => { beforeEach(() => { get.mockReset(); toast.mockReset(); }); afterEach(() => vi.clearAllMocks()); it("加载成功:拉全量描述符,status=ready", async () => { const tools = [{ key: "golden-finger", title: "金手指生成器", is_legacy: false }]; get.mockResolvedValue({ data: { tools }, error: null }); const { result } = renderHook(() => useToolboxTools()); await waitFor(() => expect(result.current.status).toBe("ready")); expect(result.current.tools).toEqual(tools); expect(get).toHaveBeenCalledWith("/skills/toolbox", {}); expect(toast).not.toHaveBeenCalled(); }); it("data.tools 缺省时回退空数组", async () => { get.mockResolvedValue({ data: { tools: null }, error: null }); const { result } = renderHook(() => useToolboxTools()); await waitFor(() => expect(result.current.status).toBe("ready")); expect(result.current.tools).toEqual([]); }); it("后端 error:status=error、弹错误 toast", async () => { get.mockResolvedValue({ data: null, error: { detail: "boom" } }); const { result } = renderHook(() => useToolboxTools()); await waitFor(() => expect(result.current.status).toBe("error")); expect(toast).toHaveBeenCalledWith(expect.any(String), "error"); }); it("请求抛异常:status=error、弹网络异常 toast", async () => { get.mockRejectedValue(new Error("network down")); const { result } = renderHook(() => useToolboxTools()); await waitFor(() => expect(result.current.status).toBe("error")); expect(toast).toHaveBeenCalledWith("工具箱加载异常,请检查网络。", "error"); }); });