2 changed files with 109 additions and 2 deletions
@ -0,0 +1,107 @@ |
|||
import { describe, it, expect, vi, beforeEach } from "vitest"; |
|||
import { fireEvent, render, screen } from "@testing-library/react"; |
|||
|
|||
import { CanvasOutlineDrawer } from "@/components/CanvasOutlineDrawer"; |
|||
|
|||
const translations: Record<string, string> = { |
|||
"canvasOutline.title": "Canvas outline", |
|||
"canvasOutline.group": "Group", |
|||
"canvasOutline.nodeFallback": "Node", |
|||
"canvasOutline.searchPlaceholder": "Search nodes", |
|||
"canvasOutline.empty": "No nodes on the canvas", |
|||
"canvasOutline.noSearchResults": "No matching nodes", |
|||
"canvasOutline.totalNodes": "{count} nodes", |
|||
"canvasOutline.groupNodeCount": "{count} nodes", |
|||
"canvasOutline.expandGroup": "Expand group", |
|||
"canvasOutline.collapseGroup": "Collapse group", |
|||
"node.imageInput": "Image Input", |
|||
"node.prompt": "Prompt", |
|||
}; |
|||
|
|||
vi.mock("@/i18n", () => ({ |
|||
useI18n: () => ({ |
|||
t: (key: string, values?: Record<string, string | number>) => { |
|||
let text = translations[key] ?? key; |
|||
if (values) { |
|||
for (const [name, value] of Object.entries(values)) { |
|||
text = text.replace(`{${name}}`, String(value)); |
|||
} |
|||
} |
|||
return text; |
|||
}, |
|||
}), |
|||
})); |
|||
|
|||
const mockSelectSingleNode = vi.fn(); |
|||
const mockSetNavigationTarget = vi.fn(); |
|||
const mockUseWorkflowStore = vi.fn(); |
|||
|
|||
vi.mock("@/store/workflowStore", () => ({ |
|||
useWorkflowStore: (selector: (state: unknown) => unknown) => mockUseWorkflowStore(selector), |
|||
})); |
|||
|
|||
const createState = () => ({ |
|||
nodes: [ |
|||
{ |
|||
id: "image-1", |
|||
type: "imageInput", |
|||
position: { x: 0, y: 0 }, |
|||
data: { customTitle: "Hero image" }, |
|||
}, |
|||
{ |
|||
id: "group-node-group-1", |
|||
type: "group", |
|||
position: { x: 100, y: 100 }, |
|||
data: { groupId: "group-1" }, |
|||
}, |
|||
{ |
|||
id: "prompt-1", |
|||
type: "prompt", |
|||
parentId: "group-node-group-1", |
|||
groupId: "group-1", |
|||
position: { x: 20, y: 30 }, |
|||
data: {}, |
|||
}, |
|||
], |
|||
groups: { |
|||
"group-1": { |
|||
id: "group-1", |
|||
name: "Storyboard", |
|||
color: "neutral", |
|||
position: { x: 100, y: 100 }, |
|||
size: { width: 400, height: 300 }, |
|||
}, |
|||
}, |
|||
selectSingleNode: mockSelectSingleNode, |
|||
setNavigationTarget: mockSetNavigationTarget, |
|||
}); |
|||
|
|||
describe("CanvasOutlineDrawer", () => { |
|||
beforeEach(() => { |
|||
vi.clearAllMocks(); |
|||
mockUseWorkflowStore.mockImplementation((selector) => selector(createState())); |
|||
}); |
|||
|
|||
it("renders root nodes, grouped child nodes, and navigates to clicked nodes", () => { |
|||
render(<CanvasOutlineDrawer open onClose={vi.fn()} />); |
|||
|
|||
expect(screen.getByText("Hero image")).toBeInTheDocument(); |
|||
expect(screen.getByText("Storyboard")).toBeInTheDocument(); |
|||
expect(screen.getByText("Prompt")).toBeInTheDocument(); |
|||
expect(screen.getByText("2 nodes")).toBeInTheDocument(); |
|||
|
|||
fireEvent.click(screen.getByTitle("Hero image")); |
|||
|
|||
expect(mockSelectSingleNode).toHaveBeenCalledWith("image-1"); |
|||
expect(mockSetNavigationTarget).toHaveBeenCalledWith("image-1"); |
|||
}); |
|||
|
|||
it("navigates to the backing group node when a group row is clicked", () => { |
|||
render(<CanvasOutlineDrawer open onClose={vi.fn()} />); |
|||
|
|||
fireEvent.click(screen.getByTitle("Storyboard")); |
|||
|
|||
expect(mockSelectSingleNode).toHaveBeenCalledWith("group-node-group-1"); |
|||
expect(mockSetNavigationTarget).toHaveBeenCalledWith("group-node-group-1"); |
|||
}); |
|||
}); |
|||
Loading…
Reference in new issue