import { describe, it, expect, vi, afterEach } from "vitest";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { userEvent } from "@testing-library/user-event";
import { AgentOnboardingModal } from "../AgentOnboardingModal";
let streamHandlers: any;
let respondCount = 0;
const originalScrollHeightDescriptor = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "scrollHeight");
vi.mock("../../api", () => ({
startAgentOnboardingStreaming: vi.fn().mockResolvedValue({ sessionId: "onb-1" }),
fetchModels: vi.fn().mockResolvedValue({ models: [], favoriteProviders: [], favoriteModels: [] }),
connectAgentOnboardingStream: vi.fn().mockImplementation((_sessionId, _projectId, handlers) => {
streamHandlers = handlers;
setTimeout(() => handlers.onQuestion?.({ id: "q1", type: "text", question: "What should this agent primarily help with?" }), 0);
return { close: vi.fn(), isConnected: vi.fn(() => true) };
}),
respondToAgentOnboarding: vi.fn().mockImplementation(() => {
respondCount += 1;
if (respondCount === 1) {
setTimeout(() => streamHandlers?.onQuestion?.({ id: "q2", type: "text", question: "Second question" }), 0);
} else {
setTimeout(() => streamHandlers?.onSummary?.({
name: "Docs Reviewer",
role: "reviewer",
instructionsText: "Review docs",
thinkingLevel: "medium",
maxTurns: 20,
}), 0);
}
return Promise.resolve({ type: "question", data: {} });
}),
retryAgentOnboardingSession: vi.fn().mockResolvedValue({ success: true }),
stopAgentOnboardingGeneration: vi.fn().mockResolvedValue({ success: true }),
cancelAgentOnboarding: vi.fn().mockResolvedValue(undefined),
createAgent: vi.fn().mockResolvedValue({ id: "agent-1" }),
}));
afterEach(() => {
respondCount = 0;
streamHandlers = undefined;
if (originalScrollHeightDescriptor) {
Object.defineProperty(HTMLTextAreaElement.prototype, "scrollHeight", originalScrollHeightDescriptor);
} else {
Reflect.deleteProperty(HTMLTextAreaElement.prototype, "scrollHeight");
}
});
describe("AgentOnboardingModal", () => {
it("walks onboarding flow through summary and create", async () => {
const onCreated = vi.fn();
render(
,
);
fireEvent.change(screen.getByLabelText("What do you want this agent to do?"), { target: { value: "Review docs" } });
fireEvent.click(screen.getByText("Start onboarding"));
await screen.findByText("What should this agent primarily help with?");
fireEvent.change(screen.getByLabelText("What should this agent primarily help with?"), { target: { value: "Docs" } });
fireEvent.click(screen.getByText("Continue"));
await screen.findByText("Second question");
fireEvent.change(screen.getByLabelText("Second question"), { target: { value: "More docs" } });
fireEvent.click(screen.getByText("Continue"));
await screen.findByText("Review generated configuration");
fireEvent.click(screen.getByText("Create agent"));
await waitFor(() => {
expect(onCreated).toHaveBeenCalled();
});
});
describe("autosize", () => {
it("grows the intent textarea up to the 640px cap", async () => {
Object.defineProperty(HTMLTextAreaElement.prototype, "scrollHeight", {
configurable: true,
get() {
const value = (this as HTMLTextAreaElement).value;
if (!value) return 24;
if (value.includes("cap")) return 800;
return 200;
},
});
render(
,
);
const textarea = screen.getByLabelText("What do you want this agent to do?") as HTMLTextAreaElement;
await userEvent.type(textarea, "Draft onboarding intent");
await waitFor(() => {
expect(textarea.style.height).toBe("200px");
});
await userEvent.type(textarea, " cap");
await waitFor(() => {
expect(textarea.style.height).toBe("640px");
});
});
});
});