You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

161 lines
4.4 KiB

import { act, render, waitFor } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { WorkflowNode } from "@/types";
import { useWorkflowStore } from "@/store/workflowStore";
import { useCanvasContextMenuActions } from "@/hooks/useCanvasContextMenuActions";
import { authFetch } from "@/utils/authFetch";
const messageSuccess = vi.fn();
const messageWarning = vi.fn();
const messageError = vi.fn();
let capturedOnAction: ((action: string) => void) | null = null;
vi.mock("antd", () => ({
App: {
useApp: () => ({
message: {
success: messageSuccess,
warning: messageWarning,
error: messageError,
},
}),
},
}));
vi.mock("@/utils/authFetch", () => ({
authFetch: vi.fn(),
}));
vi.mock("@/components/CanvasContextMenu", async () => {
const actual = await vi.importActual<typeof import("@/components/CanvasContextMenu")>("@/components/CanvasContextMenu");
return {
...actual,
CanvasContextMenu: ({ onAction }: { onAction: (action: string) => void }) => {
capturedOnAction = onAction;
return null;
},
};
});
function makeImageNode(): WorkflowNode {
return {
id: "image-1",
type: "imageInput",
position: { x: 0, y: 0 },
data: {
image: "https://example.com/image.png",
filename: "image.png",
dimensions: null,
},
} as WorkflowNode;
}
function renderActions(node = makeImageNode()) {
useWorkflowStore.setState({
nodes: [node],
edges: [],
hasUnsavedChanges: false,
});
function TestComponent() {
const actions = useCanvasContextMenuActions({
contextMenu: {
mode: "node",
nodeId: node.id,
position: { x: 10, y: 10 },
flowPosition: { x: 10, y: 10 },
targetMediaUrl: "https://example.com/image.png",
targetImageUrl: "https://example.com/image.png",
canReviewMedia: true,
},
nodes: [node],
edges: [],
canUndo: false,
canRedo: false,
getCanvasFlowCenter: () => ({ centerX: 0, centerY: 0 }),
createNodesFromUploadedFiles: vi.fn(),
onCloseContextMenu: vi.fn(),
});
return <>{actions.menu}</>;
}
return render(<TestComponent />);
}
describe("useCanvasContextMenuActions media review", () => {
beforeEach(() => {
capturedOnAction = null;
vi.useRealTimers();
});
afterEach(() => {
messageSuccess.mockClear();
messageWarning.mockClear();
messageError.mockClear();
vi.mocked(authFetch).mockReset();
});
it("stores reviewing status and saves approved review result", async () => {
vi.mocked(authFetch).mockResolvedValue(
new Response(JSON.stringify({
status: "0000",
message: "ok",
data: { reviewStatus: 1 },
}), { status: 200 })
);
renderActions();
act(() => {
capturedOnAction?.("reviewMedia");
});
expect(useWorkflowStore.getState().nodes[0].data.mediaReview).toMatchObject({
status: "reviewing",
url: "https://example.com/image.png",
});
await waitFor(() => expect(useWorkflowStore.getState().nodes[0].data.mediaReview).toMatchObject({
status: "approved",
reviewStatus: 1,
message: "ok",
url: "https://example.com/image.png",
}));
expect(messageSuccess).toHaveBeenCalledWith("校验成功");
});
it("saves rejected review result and warns with response message", async () => {
vi.mocked(authFetch).mockResolvedValue(
new Response(JSON.stringify({
status: "0000",
message: "not ok",
data: { reviewStatus: -1 },
}), { status: 200 })
);
renderActions();
act(() => {
capturedOnAction?.("reviewMedia");
});
await waitFor(() => expect(useWorkflowStore.getState().nodes[0].data.mediaReview).toMatchObject({
status: "rejected",
reviewStatus: -1,
message: "not ok",
}));
expect(messageWarning).toHaveBeenCalledWith("校验失败");
});
it("clears reviewing status and shows an error when review request fails", async () => {
vi.mocked(authFetch).mockResolvedValue(
new Response(JSON.stringify({ success: false, error: "request failed" }), { status: 500 })
);
renderActions();
act(() => {
capturedOnAction?.("reviewMedia");
});
await waitFor(() => expect(useWorkflowStore.getState().nodes[0].data.mediaReview).toBeUndefined());
expect(messageError).toHaveBeenCalledWith("request failed");
});
});