import React from "react"; import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import { beforeEach, vi } from "vitest"; import { useConfigureSuggestions } from "../../../hooks/use-configure-suggestions"; import { CopilotChat } from "../CopilotChat"; import { CopilotKitProvider } from "../../../providers/CopilotKitProvider"; import { MockStepwiseAgent, runStartedEvent, runFinishedEvent, textChunkEvent, testId, } from "../../../__tests__/utils/test-helpers"; import type { AutoScrollMode } from "../normalize-auto-scroll"; // jsdom doesn't implement scrollTo; pin-to-send mode calls it from a rAF // callback, so without this stub the cleanup throws an unhandled error. beforeEach(() => { HTMLElement.prototype.scrollTo = vi.fn(); }); const STATIC_SUGGESTIONS = [ { title: "Say hello", message: "Hello there!" }, { title: "Get help", message: "Can you help me?" }, ]; const ChatWithStaticAlwaysSuggestions: React.FC<{ autoScroll?: AutoScrollMode | boolean; consumerAgentId?: string; }> = ({ autoScroll, consumerAgentId }) => { useConfigureSuggestions({ suggestions: STATIC_SUGGESTIONS, available: "always", ...(consumerAgentId ? { consumerAgentId } : {}), }); return ; }; function renderChat({ agent, autoScroll, consumerAgentId, }: { agent: MockStepwiseAgent; autoScroll?: AutoScrollMode | boolean; consumerAgentId?: string; }) { return render(
, ); } describe("CopilotChat - static suggestions with available:'always'", () => { it("should show suggestions on the welcome screen", async () => { const agent = new MockStepwiseAgent(); renderChat({ agent, consumerAgentId: "default" }); await waitFor(() => { expect(screen.getByTestId("copilot-welcome-screen")).toBeDefined(); }); await waitFor(() => { expect(screen.getByText("Say hello")).toBeDefined(); expect(screen.getByText("Get help")).toBeDefined(); }); }); it("should show suggestions on the welcome screen with global config (no consumerAgentId)", async () => { const agent = new MockStepwiseAgent(); renderChat({ agent }); await waitFor(() => { expect(screen.getByTestId("copilot-welcome-screen")).toBeDefined(); }); await waitFor(() => { expect(screen.getByText("Say hello")).toBeDefined(); expect(screen.getByText("Get help")).toBeDefined(); }); }); it("should hide suggestions during a run and restore them after", async () => { const agent = new MockStepwiseAgent(); renderChat({ agent, consumerAgentId: "default" }); await waitFor(() => { expect(screen.getByTestId("copilot-welcome-screen")).toBeDefined(); }); await waitFor(() => { expect(screen.getByText("Say hello")).toBeDefined(); }); const input = await screen.findByRole("textbox"); fireEvent.change(input, { target: { value: "Hi!" } }); fireEvent.keyDown(input, { key: "Enter", code: "Enter" }); await waitFor(() => { expect(screen.getByText("Hi!")).toBeDefined(); }); const messageId = testId("msg"); agent.emit(runStartedEvent()); agent.emit(textChunkEvent(messageId, "Hello! How can I help?")); // While the run is in flight, suggestions should be hidden — every run // changes the conversation context, so we wait for the end-of-run reload // before showing them again. await waitFor(() => { expect(screen.queryByText("Say hello")).toBeNull(); expect(screen.queryByText("Get help")).toBeNull(); }); agent.emit(runFinishedEvent()); agent.complete(); await waitFor(() => { expect(screen.getByText("Hello! How can I help?")).toBeDefined(); }); // After the run, the static "always" config repopulates them. await waitFor( () => { expect(screen.getByText("Say hello")).toBeDefined(); expect(screen.getByText("Get help")).toBeDefined(); }, { timeout: 3000 }, ); }); it("should hide suggestions during a run in pin-to-send mode", async () => { const agent = new MockStepwiseAgent(); renderChat({ agent, autoScroll: "pin-to-send" }); await waitFor(() => { expect(screen.getByTestId("copilot-welcome-screen")).toBeDefined(); }); await waitFor(() => { expect(screen.getByText("Say hello")).toBeDefined(); }); const input = await screen.findByRole("textbox"); fireEvent.change(input, { target: { value: "Hi!" } }); fireEvent.keyDown(input, { key: "Enter", code: "Enter" }); await waitFor(() => { expect(screen.getByText("Hi!")).toBeDefined(); }); const messageId = testId("msg"); agent.emit(runStartedEvent()); agent.emit(textChunkEvent(messageId, "Hello! How can I help?")); await waitFor(() => { expect(screen.queryByText("Say hello")).toBeNull(); expect(screen.queryByText("Get help")).toBeNull(); }); agent.emit(runFinishedEvent()); agent.complete(); await waitFor(() => { expect(screen.getByText("Hello! How can I help?")).toBeDefined(); }); await waitFor( () => { expect(screen.getByText("Say hello")).toBeDefined(); expect(screen.getByText("Get help")).toBeDefined(); }, { timeout: 3000 }, ); }); });