fix: support safe project deletion

This commit is contained in:
2026-08-13 18:45:20 +08:00
parent 1eb36645e4
commit cb88a69012
10 changed files with 458 additions and 3 deletions

View File

@@ -1,7 +1,9 @@
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { MemoryRouter } from "react-router-dom";
import { api } from "../api";
import { ApiError, api } from "../api";
const { refreshMock } = vi.hoisted(() => ({ refreshMock: vi.fn() }));
vi.mock("../components/AppShell", () => ({ AppShell: ({ children }: { children: React.ReactNode }) => <div>{children}</div> }));
vi.mock("../hooks/usePollingResource", () => ({
@@ -71,12 +73,16 @@ vi.mock("../hooks/usePollingResource", () => ({
error: null,
offline: false,
lastClientSuccessAt: new Date().toISOString(),
refresh: vi.fn(),
refresh: refreshMock,
}),
}));
import { AdminPage } from "./AdminPage";
beforeEach(() => {
refreshMock.mockReset();
});
describe("AdminPage active tickets", () => {
it("保留核心排队数据并删除辅助概览模块", () => {
render(<MemoryRouter initialEntries={["/admin"]}><AdminPage /></MemoryRouter>);
@@ -145,6 +151,46 @@ describe("AdminPage active tickets", () => {
expect(screen.queryByRole("combobox", { name: "预计等待时间方式" })).not.toBeInTheDocument();
expect(screen.getByRole("textbox", { name: "游客官方提示" })).toHaveValue("请在入口附近等候。");
expect(screen.getByRole("button", { name: "保存项目" })).toBeVisible();
expect(screen.getByRole("button", { name: "删除项目" })).toBeVisible();
});
it("确认后删除项目,刷新数据并返回列表", async () => {
let resolveDelete!: () => void;
const deleteProject = vi.spyOn(api, "deleteProject").mockImplementation(() => new Promise<void>((resolve) => { resolveDelete = resolve; }));
refreshMock.mockResolvedValueOnce(undefined);
try {
render(<MemoryRouter initialEntries={["/admin/projects/project-1"]}><AdminPage /></MemoryRouter>);
fireEvent.click(screen.getByRole("button", { name: "删除项目" }));
expect(deleteProject).not.toHaveBeenCalled();
fireEvent.click(screen.getByRole("button", { name: "确认删除" }));
await waitFor(() => expect(deleteProject).toHaveBeenCalledWith("project-1"));
const deletingButton = screen.getByRole("button", { name: "正在删除" });
expect(deletingButton).toBeDisabled();
fireEvent.click(deletingButton);
expect(deleteProject).toHaveBeenCalledTimes(1);
resolveDelete();
await waitFor(() => expect(refreshMock).toHaveBeenCalled());
await waitFor(() => expect(screen.getByRole("heading", { name: "项目管理" })).toBeVisible());
} finally {
vi.restoreAllMocks();
}
});
it("删除项目失败时留在维护页并显示服务端消息", async () => {
const deleteProject = vi.spyOn(api, "deleteProject").mockRejectedValue(new ApiError("项目存在活动排队,无法删除", 409));
try {
render(<MemoryRouter initialEntries={["/admin/projects/project-1"]}><AdminPage /></MemoryRouter>);
fireEvent.click(screen.getByRole("button", { name: "删除项目" }));
fireEvent.click(screen.getByRole("button", { name: "确认删除" }));
expect(await screen.findByText("项目存在活动排队,无法删除")).toBeVisible();
expect(screen.getByRole("heading", { name: "东门观光车" })).toBeVisible();
} finally {
vi.restoreAllMocks();
}
});
it("创建项目与维护项目使用相同字段", () => {