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
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");
|
|
});
|
|
});
|
|
|