import { screen, waitFor } from "@testing-library/react"; import { describe, expect, test } from "bun:test"; import { createElement } from "react"; import { App } from "../../../src/web/app"; import { renderWithProviders } from "../test-utils"; const ACTIVE_PROJECT = { createdAt: "2024-01-01T00:00:00.000Z", description: "", id: "p1", name: "活跃项目", status: "active", updatedAt: "2024-01-01T00:00:00.000Z", }; const ARCHIVED_PROJECT = { createdAt: "2024-01-01T00:00:00.000Z", description: "", id: "p2", name: "归档项目", status: "archived", updatedAt: "2024-01-01T00:00:00.000Z", }; function createMockHandler(projectList?: unknown[]) { const handler = (input: RequestInfo | URL) => { const url = input instanceof Request ? input.url : typeof input === "string" ? input : input.toString(); if (url.includes("/api/meta")) { return new Response( JSON.stringify({ ok: true, service: "test-app", timestamp: new Date().toISOString(), version: "0.1.0", }), { headers: { "Content-Type": "application/json" }, status: 200 }, ); } if (url.includes("/api/projects")) { const items = projectList ?? []; return new Response(JSON.stringify({ items, page: 1, pageSize: 10, total: items.length }), { headers: { "Content-Type": "application/json" }, status: 200, }); } return new Response(JSON.stringify({ error: "Not Found" }), { status: 404, }); }; const mocked = handler as unknown as typeof fetch; globalThis.fetch = mocked; window.fetch = mocked; } describe("ProjectsPage", () => { test("渲染 Tab、搜索框、新建按钮和表格", async () => { createMockHandler(); renderWithProviders(createElement(App), { initialRoute: "/projects" }); await waitFor( () => { expect(screen.getByText("进行中")).not.toBeNull(); }, { timeout: 10000 }, ); expect(screen.getByText("已归档")).not.toBeNull(); expect(screen.getByText("新建项目")).not.toBeNull(); expect(screen.getByPlaceholderText("搜索项目名称或描述")).not.toBeNull(); }); test("新建按钮点击打开弹窗", async () => { createMockHandler(); renderWithProviders(createElement(App), { initialRoute: "/projects" }); await waitFor( () => { expect(screen.getByText("进行中")).not.toBeNull(); }, { timeout: 10000 }, ); const createBtn = screen.getByRole("button", { name: /新建项目/ }); createBtn.click(); await waitFor( () => { expect(document.body.querySelector(".ant-modal")).not.toBeNull(); }, { timeout: 10000 }, ); }); test("active 项目行显示'进入工作台',archived 行不显示", async () => { createMockHandler([ACTIVE_PROJECT, ARCHIVED_PROJECT]); renderWithProviders(createElement(App), { initialRoute: "/projects" }); await waitFor( () => { expect(screen.queryByText("活跃项目")).not.toBeNull(); }, { timeout: 10000 }, ); const enterBtns = screen.getAllByText("进入工作台"); expect(enterBtns.length).toBe(1); const archivedRow = screen.getByText("归档项目").closest("tr"); expect(archivedRow?.textContent).not.toContain("进入工作台"); }); });