hyapp-admin-platform/src/features/resources/hooks/useResourceListPageDelete.test.jsx
2026-07-05 14:55:43 +08:00

159 lines
5.2 KiB
JavaScript

import { act, renderHook } from "@testing-library/react";
import { afterEach, beforeEach, expect, test, vi } from "vitest";
import { useResourceListPage } from "./useResourcePages.js";
const mocks = vi.hoisted(() => ({
batchDeleteResources: vi.fn(),
can: vi.fn(),
confirm: vi.fn(),
deleteResource: vi.fn(),
reload: vi.fn(),
showToast: vi.fn(),
usePaginatedQuery: vi.fn(),
}));
vi.mock("@/app/auth/AuthProvider.jsx", () => ({
useAuth: () => ({ can: mocks.can }),
}));
vi.mock("@/shared/hooks/usePaginatedQuery.js", () => ({
usePaginatedQuery: mocks.usePaginatedQuery,
}));
vi.mock("@/shared/ui/ConfirmProvider.jsx", () => ({
useConfirm: () => mocks.confirm,
}));
vi.mock("@/shared/ui/ToastProvider.jsx", () => ({
useToast: () => ({ showToast: mocks.showToast }),
}));
vi.mock("@/features/resources/api", async (importOriginal) => ({
...(await importOriginal()),
batchDeleteResources: mocks.batchDeleteResources,
deleteResource: mocks.deleteResource,
}));
beforeEach(() => {
mocks.can.mockReturnValue(true);
mocks.confirm.mockResolvedValue(true);
mocks.batchDeleteResources.mockResolvedValue([]);
mocks.deleteResource.mockResolvedValue({});
mocks.reload.mockResolvedValue(undefined);
mocks.usePaginatedQuery.mockReturnValue({
data: resourcePage(),
error: null,
loading: false,
reload: mocks.reload,
});
});
afterEach(() => {
vi.clearAllMocks();
});
test("deleting a resource hides only that row without reloading the list", async () => {
const { result } = renderHook(() => useResourceListPage());
let deletedResourceIds = [];
await act(async () => {
deletedResourceIds = await result.current.deleteResources([resourceFixture({ resourceId: 11 })]);
});
expect(deletedResourceIds).toEqual([11]);
expect(mocks.deleteResource).toHaveBeenCalledWith(11);
expect(mocks.reload).not.toHaveBeenCalled();
expect(result.current.data.items.map((resource) => resource.resourceId)).toEqual([12]);
expect(mocks.showToast).toHaveBeenCalledWith("资源已删除", "success");
});
test("batch resource delete hides successful rows without reloading the list", async () => {
const { result } = renderHook(() => useResourceListPage());
let deletedResourceIds = [];
await act(async () => {
deletedResourceIds = await result.current.deleteResources([
resourceFixture({ resourceId: 11 }),
resourceFixture({ resourceId: 12 }),
]);
});
expect(deletedResourceIds).toEqual([11, 12]);
expect(mocks.batchDeleteResources).toHaveBeenCalledWith([11, 12]);
expect(mocks.deleteResource).not.toHaveBeenCalled();
expect(mocks.reload).not.toHaveBeenCalled();
expect(result.current.data.items).toEqual([]);
expect(mocks.showToast).toHaveBeenCalledWith("已删除 2 个资源", "success");
});
test("failed batch resource delete keeps all rows visible", async () => {
mocks.usePaginatedQuery.mockReturnValue({
data: {
items: [
resourceFixture({ resourceId: 11 }),
resourceFixture({ resourceId: 12 }),
resourceFixture({ resourceId: 13 }),
],
page: 1,
pageSize: 50,
total: 3,
},
error: null,
loading: false,
reload: mocks.reload,
});
mocks.batchDeleteResources.mockRejectedValueOnce(new Error("delete failed"));
const { result } = renderHook(() => useResourceListPage());
let deletedResourceIds = [];
await act(async () => {
deletedResourceIds = await result.current.deleteResources([
resourceFixture({ resourceId: 11 }),
resourceFixture({ resourceId: 12 }),
resourceFixture({ resourceId: 13 }),
]);
});
expect(deletedResourceIds).toEqual([]);
expect(mocks.batchDeleteResources).toHaveBeenCalledWith([11, 12, 13]);
expect(mocks.deleteResource).not.toHaveBeenCalled();
expect(result.current.data.items.map((resource) => resource.resourceId)).toEqual([11, 12, 13]);
expect(mocks.showToast).toHaveBeenCalledWith("delete failed", "error");
});
test("failed resource delete keeps the row visible", async () => {
mocks.deleteResource.mockRejectedValueOnce(new Error("delete failed"));
const { result } = renderHook(() => useResourceListPage());
let deletedResourceIds = [];
await act(async () => {
deletedResourceIds = await result.current.deleteResources([resourceFixture({ resourceId: 11 })]);
});
expect(deletedResourceIds).toEqual([]);
expect(mocks.reload).not.toHaveBeenCalled();
expect(result.current.data.items.map((resource) => resource.resourceId)).toEqual([11, 12]);
expect(mocks.showToast).toHaveBeenCalledWith("delete failed", "error");
});
function resourcePage() {
return {
items: [resourceFixture({ resourceId: 11, name: "Rose" }), resourceFixture({ resourceId: 12, name: "Ring" })],
page: 1,
pageSize: 50,
total: 2,
};
}
function resourceFixture(patch = {}) {
return {
coinPrice: 10,
name: "Rose",
resourceCode: "gift_rose",
resourceId: 11,
resourceType: "gift",
status: "active",
...patch,
};
}