180 lines
5.0 KiB
JavaScript
180 lines
5.0 KiB
JavaScript
import { act, renderHook } from "@testing-library/react";
|
|
import { afterEach, beforeEach, expect, test, vi } from "vitest";
|
|
import { setSelectedAppCode } from "@/shared/api/request";
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
appCode: "lalu",
|
|
confirm: vi.fn(),
|
|
createH5Link: vi.fn(),
|
|
deleteH5Link: vi.fn(),
|
|
listH5Links: vi.fn(),
|
|
queryFn: null,
|
|
queryOptions: null,
|
|
reload: vi.fn(),
|
|
showToast: vi.fn(),
|
|
updateH5Link: vi.fn()
|
|
}));
|
|
|
|
vi.mock("@/app/app-scope/AppScopeProvider.jsx", () => ({
|
|
useAppScope: () => ({ appCode: mocks.appCode })
|
|
}));
|
|
|
|
vi.mock("@/features/app-config/api", () => ({
|
|
createH5Link: mocks.createH5Link,
|
|
deleteH5Link: mocks.deleteH5Link,
|
|
listH5Links: mocks.listH5Links,
|
|
updateH5Link: mocks.updateH5Link
|
|
}));
|
|
|
|
vi.mock("@/features/app-config/permissions.js", () => ({
|
|
useAppConfigAbilities: () => ({ canUpdate: true, canView: true })
|
|
}));
|
|
|
|
vi.mock("@/shared/hooks/useAdminQuery.js", () => ({
|
|
useAdminQuery: (queryFn, options) => {
|
|
mocks.queryFn = queryFn;
|
|
mocks.queryOptions = options;
|
|
return {
|
|
data: { items: [], total: 0 },
|
|
error: "",
|
|
loading: false,
|
|
reload: mocks.reload
|
|
};
|
|
}
|
|
}));
|
|
|
|
vi.mock("@/shared/ui/ConfirmProvider.jsx", () => ({
|
|
useConfirm: () => mocks.confirm
|
|
}));
|
|
|
|
vi.mock("@/shared/ui/ToastProvider.jsx", () => ({
|
|
useToast: () => ({ showToast: mocks.showToast })
|
|
}));
|
|
|
|
import { useH5ConfigPage } from "./useH5ConfigPage.js";
|
|
|
|
beforeEach(() => {
|
|
mocks.appCode = "lalu";
|
|
mocks.confirm.mockResolvedValue(true);
|
|
mocks.createH5Link.mockResolvedValue({});
|
|
mocks.deleteH5Link.mockResolvedValue({ deleted: true });
|
|
mocks.listH5Links.mockResolvedValue({ items: [], total: 0 });
|
|
mocks.reload.mockResolvedValue({ items: [], total: 0 });
|
|
mocks.updateH5Link.mockResolvedValue({});
|
|
setSelectedAppCode("lalu");
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.clearAllMocks();
|
|
setSelectedAppCode("lalu");
|
|
});
|
|
|
|
test("uses appCode in the H5 query key and read request", async () => {
|
|
const { rerender } = renderHook(() => useH5ConfigPage());
|
|
|
|
expect(mocks.queryOptions.queryKey).toEqual(["app-config", "h5-links", "lalu"]);
|
|
await mocks.queryFn();
|
|
expect(mocks.listH5Links).toHaveBeenLastCalledWith("lalu");
|
|
|
|
mocks.appCode = "huwaa";
|
|
setSelectedAppCode("huwaa");
|
|
rerender();
|
|
|
|
expect(mocks.queryOptions.queryKey).toEqual(["app-config", "h5-links", "huwaa"]);
|
|
await mocks.queryFn();
|
|
expect(mocks.listH5Links).toHaveBeenLastCalledWith("huwaa");
|
|
});
|
|
|
|
test("closes an edit dialog when the selected App changes", () => {
|
|
const item = {
|
|
appCode: "lalu",
|
|
key: "achievement",
|
|
label: "成就",
|
|
updatedAtMs: 1000,
|
|
url: "https://h5.example.com/achievement"
|
|
};
|
|
const { result, rerender } = renderHook(() => useH5ConfigPage());
|
|
|
|
act(() => result.current.openEdit(item));
|
|
expect(result.current.activeAction).toBe("edit");
|
|
|
|
mocks.appCode = "huwaa";
|
|
setSelectedAppCode("huwaa");
|
|
rerender();
|
|
|
|
expect(result.current.activeAction).toBe("");
|
|
expect(result.current.editingItem).toBeNull();
|
|
expect(result.current.form).toEqual({ key: "", label: "", url: "" });
|
|
});
|
|
|
|
test("does not submit stale form state after an App switch", async () => {
|
|
const { result, rerender } = renderHook(() => useH5ConfigPage());
|
|
|
|
act(() => {
|
|
result.current.openEdit({
|
|
appCode: "lalu",
|
|
key: "achievement",
|
|
label: "成就",
|
|
updatedAtMs: 1000,
|
|
url: "https://h5.example.com/achievement"
|
|
});
|
|
});
|
|
|
|
mocks.appCode = "huwaa";
|
|
setSelectedAppCode("huwaa");
|
|
rerender();
|
|
await act(async () => {
|
|
await result.current.submitEdit({ preventDefault: vi.fn() });
|
|
});
|
|
|
|
expect(mocks.createH5Link).not.toHaveBeenCalled();
|
|
expect(mocks.updateH5Link).not.toHaveBeenCalled();
|
|
expect(mocks.showToast).toHaveBeenCalledWith("应用已切换,请重新操作", "warning");
|
|
});
|
|
|
|
test("pins an update mutation to the App that owns the edited row", async () => {
|
|
const { result } = renderHook(() => useH5ConfigPage());
|
|
|
|
act(() => {
|
|
result.current.openEdit({
|
|
appCode: "lalu",
|
|
key: "achievement",
|
|
label: "成就",
|
|
updatedAtMs: 1000,
|
|
url: "https://h5.example.com/achievement"
|
|
});
|
|
});
|
|
await act(async () => {
|
|
await result.current.submitEdit({ preventDefault: vi.fn() });
|
|
});
|
|
|
|
expect(mocks.updateH5Link).toHaveBeenCalledWith("lalu", "achievement", {
|
|
key: "achievement",
|
|
label: "成就",
|
|
url: "https://h5.example.com/achievement"
|
|
});
|
|
});
|
|
|
|
test("aborts delete when App changes while confirmation is open", async () => {
|
|
let resolveConfirm;
|
|
mocks.confirm.mockReturnValue(new Promise((resolve) => {
|
|
resolveConfirm = resolve;
|
|
}));
|
|
const { result, rerender } = renderHook(() => useH5ConfigPage());
|
|
let pendingDelete;
|
|
|
|
act(() => {
|
|
pendingDelete = result.current.removeH5Link({ key: "achievement", label: "成就" });
|
|
});
|
|
mocks.appCode = "huwaa";
|
|
setSelectedAppCode("huwaa");
|
|
rerender();
|
|
await act(async () => {
|
|
resolveConfirm(true);
|
|
await pendingDelete;
|
|
});
|
|
|
|
expect(mocks.deleteH5Link).not.toHaveBeenCalled();
|
|
expect(mocks.showToast).toHaveBeenCalledWith("应用已切换,请重新操作", "warning");
|
|
});
|