4 changed files with 315 additions and 2 deletions
@ -0,0 +1,147 @@ |
|||||
|
import { describe, it, expect, vi, beforeEach } from "vitest"; |
||||
|
import { fireEvent, render, screen } from "@testing-library/react"; |
||||
|
import { ReactFlowProvider } from "@xyflow/react"; |
||||
|
import { VideoInputNode } from "@/components/nodes/VideoInputNode"; |
||||
|
|
||||
|
const TRY_LABEL = "\u5c1d\u8bd5:"; |
||||
|
const KEYFRAMES_LABEL = "\u9996\u5c3e\u5e27\u751f\u6210\u89c6\u9891"; |
||||
|
const FIRST_FRAME_LABEL = "\u9996\u5e27\u751f\u6210\u89c6\u9891"; |
||||
|
const FIRST_FRAME_NODE_LABEL = "\u9996\u5e27"; |
||||
|
const LAST_FRAME_NODE_LABEL = "\u5c3e\u5e27"; |
||||
|
|
||||
|
const mockUpdateNodeData = vi.fn(); |
||||
|
let addNodeSequence = 0; |
||||
|
const mockAddNode = vi.fn((type: string) => `${type}-${++addNodeSequence}`); |
||||
|
const mockOnConnect = vi.fn(); |
||||
|
|
||||
|
vi.mock("@/store/workflowStore", () => ({ |
||||
|
useWorkflowStore: vi.fn((selector) => selector({ |
||||
|
updateNodeData: mockUpdateNodeData, |
||||
|
addNode: mockAddNode, |
||||
|
onConnect: mockOnConnect, |
||||
|
currentNodeIds: [], |
||||
|
groups: {}, |
||||
|
nodes: [ |
||||
|
{ |
||||
|
id: "video-1", |
||||
|
type: "videoInput", |
||||
|
position: { x: 120, y: 160 }, |
||||
|
measured: { width: 300, height: 280 }, |
||||
|
style: { width: 300, height: 280 }, |
||||
|
data: {}, |
||||
|
}, |
||||
|
], |
||||
|
getNodesWithComments: vi.fn(() => []), |
||||
|
markCommentViewed: vi.fn(), |
||||
|
setNavigationTarget: vi.fn(), |
||||
|
})), |
||||
|
})); |
||||
|
|
||||
|
vi.mock("@/utils/videoFile", () => ({ |
||||
|
readVideoFile: vi.fn((file: File) => Promise.resolve({ |
||||
|
video: `data:video/mp4;base64,${file.name}`, |
||||
|
filename: file.name, |
||||
|
format: file.type, |
||||
|
duration: 3, |
||||
|
dimensions: { width: 1280, height: 720 }, |
||||
|
})), |
||||
|
})); |
||||
|
|
||||
|
function TestWrapper({ children }: { children: React.ReactNode }) { |
||||
|
return <ReactFlowProvider>{children}</ReactFlowProvider>; |
||||
|
} |
||||
|
|
||||
|
describe("VideoInputNode", () => { |
||||
|
const defaultProps = { |
||||
|
id: "video-1", |
||||
|
type: "videoInput" as const, |
||||
|
data: { |
||||
|
video: null, |
||||
|
videoRef: undefined, |
||||
|
filename: null, |
||||
|
duration: null, |
||||
|
dimensions: null, |
||||
|
format: null, |
||||
|
}, |
||||
|
selected: false, |
||||
|
isConnectable: true, |
||||
|
positionAbsoluteX: 0, |
||||
|
positionAbsoluteY: 0, |
||||
|
zIndex: 0, |
||||
|
dragging: false, |
||||
|
deletable: true, |
||||
|
selectable: true, |
||||
|
parentId: undefined, |
||||
|
dragHandle: undefined, |
||||
|
}; |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
addNodeSequence = 0; |
||||
|
vi.clearAllMocks(); |
||||
|
}); |
||||
|
|
||||
|
it("renders video generation shortcuts when empty", () => { |
||||
|
render( |
||||
|
<TestWrapper> |
||||
|
<VideoInputNode {...defaultProps} /> |
||||
|
</TestWrapper> |
||||
|
); |
||||
|
|
||||
|
expect(screen.getByText(TRY_LABEL)).toBeInTheDocument(); |
||||
|
expect(screen.getByRole("button", { name: KEYFRAMES_LABEL })).toBeInTheDocument(); |
||||
|
expect(screen.getByRole("button", { name: FIRST_FRAME_LABEL })).toBeInTheDocument(); |
||||
|
}); |
||||
|
|
||||
|
it("labels the current node as first frame and links it to a generate video node", () => { |
||||
|
render( |
||||
|
<TestWrapper> |
||||
|
<VideoInputNode {...defaultProps} /> |
||||
|
</TestWrapper> |
||||
|
); |
||||
|
|
||||
|
fireEvent.click(screen.getByRole("button", { name: FIRST_FRAME_LABEL })); |
||||
|
|
||||
|
expect(mockUpdateNodeData).toHaveBeenCalledWith("video-1", { |
||||
|
label: FIRST_FRAME_NODE_LABEL, |
||||
|
}); |
||||
|
expect(mockAddNode).toHaveBeenCalledWith("generateVideo", { x: 600, y: 160 }); |
||||
|
expect(mockOnConnect).toHaveBeenCalledWith({ |
||||
|
source: "video-1", |
||||
|
sourceHandle: "video", |
||||
|
target: "generateVideo-1", |
||||
|
targetHandle: "video", |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
it("creates an empty last-frame video node and links both videos to a generate video node", () => { |
||||
|
render( |
||||
|
<TestWrapper> |
||||
|
<VideoInputNode {...defaultProps} /> |
||||
|
</TestWrapper> |
||||
|
); |
||||
|
|
||||
|
fireEvent.click(screen.getByRole("button", { name: KEYFRAMES_LABEL })); |
||||
|
|
||||
|
expect(mockUpdateNodeData).toHaveBeenCalledWith("video-1", { |
||||
|
label: FIRST_FRAME_NODE_LABEL, |
||||
|
}); |
||||
|
expect(mockAddNode).toHaveBeenCalledWith( |
||||
|
"videoInput", |
||||
|
{ x: 120, y: 492 }, |
||||
|
{ label: LAST_FRAME_NODE_LABEL } |
||||
|
); |
||||
|
expect(mockAddNode).toHaveBeenCalledWith("generateVideo", { x: 600, y: 316 }); |
||||
|
expect(mockOnConnect).toHaveBeenCalledWith({ |
||||
|
source: "video-1", |
||||
|
sourceHandle: "video", |
||||
|
target: "generateVideo-2", |
||||
|
targetHandle: "video", |
||||
|
}); |
||||
|
expect(mockOnConnect).toHaveBeenCalledWith({ |
||||
|
source: "videoInput-1", |
||||
|
sourceHandle: "video", |
||||
|
target: "generateVideo-2", |
||||
|
targetHandle: "video", |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
Loading…
Reference in new issue