geo/frontend/__tests__/hooks/use-content-data.test.ts

142 lines
4.1 KiB
TypeScript

/**
* useContentData Hook 单元测试
*/
import { describe, it, expect, vi, beforeEach } from "vitest";
import { renderHook, waitFor } from "@testing-library/react";
import { SWRConfig } from "swr";
import type { ReactNode } from "react";
vi.mock("@/lib/api/client", () => ({
fetchWithAuth: vi.fn(),
}));
import { fetchWithAuth } from "@/lib/api/client";
const mockFetchWithAuth = vi.mocked(fetchWithAuth);
import { useContentData } from "@/lib/hooks/use-content-data";
import type { Content } from "@/lib/api/contents";
import type { KnowledgeBase } from "@/lib/api/knowledge";
const noRetryOptions = { shouldRetryOnError: false };
function createWrapper() {
return ({ children }: { children: ReactNode }) =>
SWRConfig({ value: { provider: () => new Map() }, children });
}
describe("useContentData", () => {
beforeEach(() => {
vi.clearAllMocks();
});
const mockContents: Content[] = [
{
id: "content-1",
title: "测试内容",
body: "内容正文",
content_type: "article",
status: "draft",
author_id: "user-1",
tags: ["test"],
created_at: "2024-01-01",
updated_at: "2024-01-01",
},
];
const mockKnowledgeBases: KnowledgeBase[] = [
{
id: "kb-1",
name: "测试知识库",
type: "enterprise",
document_count: 5,
status: "ready",
created_at: "2024-01-01",
},
];
it("应同时获取内容列表和知识库列表", async () => {
mockFetchWithAuth.mockImplementation((url: string) => {
if (url.includes("/api/v1/contents/")) return Promise.resolve(mockContents);
if (url.includes("/api/v1/knowledge/bases")) return Promise.resolve(mockKnowledgeBases);
return Promise.resolve([]);
});
const { result } = renderHook(
() => useContentData({ swrOptions: noRetryOptions }),
{ wrapper: createWrapper() }
);
await waitFor(() => {
expect(result.current.isLoading).toBe(false);
});
expect(result.current.contents).toEqual(mockContents);
expect(result.current.knowledgeBases).toEqual(mockKnowledgeBases);
});
it("应正确暴露 isLoading 状态", async () => {
mockFetchWithAuth.mockImplementation((url: string) => {
if (url.includes("/api/v1/contents/")) return Promise.resolve(mockContents);
if (url.includes("/api/v1/knowledge/bases")) return Promise.resolve(mockKnowledgeBases);
return Promise.resolve([]);
});
const { result } = renderHook(
() => useContentData({ swrOptions: noRetryOptions }),
{ wrapper: createWrapper() }
);
await waitFor(() => {
expect(result.current.isLoading).toBe(false);
});
});
it("应正确暴露 error 状态", async () => {
mockFetchWithAuth.mockRejectedValue(new Error("数据加载失败"));
const { result } = renderHook(
() => useContentData({ swrOptions: noRetryOptions }),
{ wrapper: createWrapper() }
);
await waitFor(() => {
expect(result.current.error).toBeDefined();
expect(result.current.error?.message).toBe("数据加载失败");
});
});
it("应提供 refresh 方法", async () => {
mockFetchWithAuth.mockImplementation((url: string) => {
if (url.includes("/api/v1/contents/")) return Promise.resolve(mockContents);
if (url.includes("/api/v1/knowledge/bases")) return Promise.resolve(mockKnowledgeBases);
return Promise.resolve([]);
});
const { result } = renderHook(
() => useContentData({ swrOptions: noRetryOptions }),
{ wrapper: createWrapper() }
);
await waitFor(() => {
expect(result.current.isLoading).toBe(false);
});
expect(typeof result.current.refreshContents).toBe("function");
expect(typeof result.current.refreshKnowledgeBases).toBe("function");
});
it("数据加载失败时 error 应包含错误信息", async () => {
mockFetchWithAuth.mockRejectedValue(new Error("网络异常"));
const { result } = renderHook(
() => useContentData({ swrOptions: noRetryOptions }),
{ wrapper: createWrapper() }
);
await waitFor(() => {
expect(result.current.error?.message).toBe("网络异常");
});
});
});