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.
 
 

136 lines
3.5 KiB

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<Record<string, unknown>>,
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(
<ChatPanel
isOpen
onClose={vi.fn()}
onApplyEdits={onApplyEdits}
/>
);
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(
<ChatPanel
isOpen
onClose={vi.fn()}
onBuildWorkflow={onBuildWorkflow}
/>
);
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(
<ChatPanel
isOpen
onClose={vi.fn()}
onRunAction={onRunAction}
/>
);
await screen.findByText("Run preview");
expect(onRunAction).not.toHaveBeenCalled();
fireEvent.click(screen.getByText("Run now"));
expect(onRunAction).toHaveBeenCalledWith("runSelected");
});
});