import { describe, it, expect, vi, beforeEach } from "vitest"; import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import { ChatPanel } from "@/components/ChatPanel"; import type { EditOperation } from "@/lib/chat/editOperations"; const chatState = vi.hoisted(() => ({ messages: [] as Array>, sendMessage: vi.fn(), setMessages: vi.fn(), status: "ready", })); vi.mock("@ai-sdk/react", () => ({ useChat: () => ({ messages: chatState.messages, sendMessage: chatState.sendMessage, setMessages: chatState.setMessages, status: chatState.status, }), })); vi.mock("ai", () => ({ DefaultChatTransport: vi.fn(function DefaultChatTransport() { return {}; }), })); describe("ChatPanel", () => { beforeEach(() => { vi.clearAllMocks(); chatState.messages = []; chatState.status = "ready"; Element.prototype.scrollIntoView = vi.fn(); }); it("previews editWorkflow tool calls instead of applying them immediately", async () => { const operations: EditOperation[] = [ { type: "addNode", nodeType: "prompt", data: { prompt: "hello" } }, ]; const onApplyEdits = vi.fn(); chatState.messages = [ { id: "assistant-1", role: "assistant", parts: [ { type: "tool-editWorkflow", state: "output-available", toolCallId: "edit-1", input: { operations, explanation: "Add a prompt node" }, }, ], }, ]; render( ); await screen.findByText("Operation preview"); expect(onApplyEdits).not.toHaveBeenCalled(); fireEvent.click(screen.getByText("Apply edits")); expect(onApplyEdits).toHaveBeenCalledWith(operations); }); it("previews createWorkflow tool calls instead of building immediately", async () => { const onBuildWorkflow = vi.fn().mockResolvedValue(undefined); chatState.messages = [ { id: "assistant-1", role: "assistant", parts: [ { type: "tool-createWorkflow", state: "output-available", toolCallId: "create-1", input: { description: "Make a product photo workflow" }, }, ], }, ]; render( ); await screen.findByText("Candidate workflow"); expect(onBuildWorkflow).not.toHaveBeenCalled(); fireEvent.click(screen.getByText("Apply workflow")); await waitFor(() => { expect(onBuildWorkflow).toHaveBeenCalledWith("Make a product photo workflow"); }); }); it("previews runCanvasAction tool calls instead of running immediately", async () => { const onRunAction = vi.fn(); chatState.messages = [ { id: "assistant-1", role: "assistant", parts: [ { type: "tool-runCanvasAction", state: "output-available", toolCallId: "run-1", input: { action: "runSelected", explanation: "Run selected nodes" }, }, ], }, ]; render( ); await screen.findByText("Run preview"); expect(onRunAction).not.toHaveBeenCalled(); fireEvent.click(screen.getByText("Run now")); expect(onRunAction).toHaveBeenCalledWith("runSelected"); }); });