import React from "react"; import { render, screen } from "@testing-library/react"; import { describe, it, expect, vi } from "vitest"; import { CopilotChat } from "../CopilotChat"; import { CopilotChatView } from "../CopilotChatView"; import { CopilotKitProvider } from "../../../providers/CopilotKitProvider"; import { CopilotChatConfigurationProvider } from "../../../providers/CopilotChatConfigurationProvider"; import { MockStepwiseAgent } from "../../../__tests__/utils/test-helpers"; // Create a mock agent for testing const createMockAgent = () => new MockStepwiseAgent(); // Wrapper to provide required context with mock agent const TestWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => { const mockAgent = createMockAgent(); return ( {children} ); }; describe("CopilotChat Slot System E2E Tests", () => { // ============================================================================ // 1. TAILWIND CLASS TESTS - CHATVIEW SLOT // ============================================================================ describe("1. Tailwind Class Slot Override - chatView Slot", () => { describe("chatView slot", () => { it("should apply tailwind class string to chatView", () => { const { container } = render( , ); const chatView = container.querySelector(".bg-gradient-to-b"); expect(chatView).toBeDefined(); expect(chatView?.classList.contains("rounded-xl")).toBe(true); expect(chatView?.classList.contains("shadow-2xl")).toBe(true); }); it("should apply custom background color via tailwind class", () => { const { container } = render( , ); const chatView = container.querySelector(".bg-blue-50"); expect(chatView).toBeDefined(); }); }); }); // ============================================================================ // 2. PROPERTY PASSING TESTS - CHATVIEW SLOT // ============================================================================ describe("2. Property Passing - chatView Slot", () => { describe("chatView slot", () => { it("should pass custom props to chatView", () => { render( , ); const chatView = screen.queryByTestId("custom-chat-view"); expect(chatView).toBeDefined(); }); it("should pass className through props object", () => { const { container } = render( , ); const chatView = container.querySelector(".custom-class-from-props"); expect(chatView).toBeDefined(); }); }); }); // ============================================================================ // 3. CUSTOM COMPONENT TESTS - CHATVIEW SLOT // ============================================================================ describe("3. Custom Component - chatView Slot", () => { it("should allow custom component for chatView", () => { const CustomChatView: React.FC = ({ messages, isRunning, ...props }) => ( Custom Chat Interface {messages?.map((m: any) => ( {m.content} ))} {isRunning ? "Processing..." : "Ready"} ); render( , ); const custom = screen.queryByTestId("custom-chat-view-component"); expect(custom).toBeDefined(); expect(custom?.textContent).toContain("Custom Chat Interface"); }); it("should pass messages to custom chatView component", () => { const receivedProps: any[] = []; const CustomChatView: React.FC = (props) => { receivedProps.push(props); return ( Messages: {props.messages?.length ?? 0} ); }; render( , ); expect(receivedProps.length).toBeGreaterThan(0); expect(receivedProps[0]).toHaveProperty("messages"); expect(receivedProps[0]).toHaveProperty("isRunning"); }); it("should pass all CopilotChatView props to custom component", () => { const receivedProps: any[] = []; const CustomChatView: React.FC = (props) => { receivedProps.push(props); return ; }; render( , ); expect(receivedProps.length).toBeGreaterThan(0); const props = receivedProps[0]; // Check that standard CopilotChatViewProps are passed expect(props).toHaveProperty("messages"); expect(props).toHaveProperty("isRunning"); expect(props).toHaveProperty("onSubmitMessage"); }); }); // ============================================================================ // 4. DRILL-DOWN INTO CHATVIEW SUB-SLOTS VIA PROPS OBJECT // ============================================================================ describe("4. Drill-down into CopilotChatView Sub-slots via Props Object", () => { it("should allow customizing nested messageView slot via props", () => { const { container } = render( , ); const messageView = container.querySelector(".custom-message-view-class"); expect(messageView).toBeDefined(); }); it("should allow customizing nested input slot via props", () => { const { container } = render( , ); const input = container.querySelector(".custom-input-class"); expect(input).toBeDefined(); }); it("should allow customizing nested scrollView slot via props", () => { const { container } = render( , ); const scrollView = container.querySelector(".custom-scroll-view"); expect(scrollView).toBeDefined(); }); it("should allow customizing nested input slot via props", () => { const { container } = render( , ); const input = container.querySelector(".custom-input"); expect(input).toBeDefined(); }); }); // ============================================================================ // 5. CUSTOM CHATVIEW COMPONENT // ============================================================================ describe("5. Custom ChatView Component for Complex Customization", () => { it("should allow custom chatView component with full control", () => { const CustomChatView: React.FC = (props) => ( ); const { container } = render( , ); expect(screen.queryByTestId("fully-custom-chat")).toBeDefined(); expect(container.querySelector(".custom-chat-layout")).toBeDefined(); }); }); // ============================================================================ // 6. CLASSNAME OVERRIDE TESTS // ============================================================================ describe("6. className Override with Tailwind Strings", () => { it("should apply tailwind string to chatView as className", () => { const { container } = render( , ); const chatView = container.querySelector(".h-full"); expect(chatView).toBeDefined(); expect(chatView?.classList.contains("min-h-0")).toBe(true); expect(chatView?.classList.contains("flex-col")).toBe(true); }); it("should merge chatView tailwind classes with CopilotChatView defaults", () => { const { container } = render( , ); const chatView = container.querySelector(".custom-override-class"); expect(chatView).toBeDefined(); }); }); // ============================================================================ // 7. COPILOTCHAT-SPECIFIC PROPS // ============================================================================ describe("7. CopilotChat-specific Props", () => { it("should support agentId prop", () => { // Create wrapper with the custom-agent registered const customAgent = createMockAgent(); const { container } = render( , ); // Component should render without errors expect(container.firstChild).toBeDefined(); }); it("should support threadId prop", () => { const { container } = render( , ); expect(container.firstChild).toBeDefined(); }); it("should support labels prop for customization", () => { render( , ); const input = screen.queryByPlaceholderText("Custom placeholder text..."); expect(input).toBeDefined(); }); }); // ============================================================================ // 8. INTEGRATION TESTS // ============================================================================ describe("8. Integration Tests", () => { it("should render CopilotChat with all default components", () => { const { container } = render( , ); // Should render the chat interface expect(container.firstChild).toBeDefined(); }); it("should combine chatView customization with nested slot customization via props", () => { const { container } = render( , ); expect(container.querySelector(".root-chat-view")).toBeDefined(); expect(container.querySelector(".custom-messages")).toBeDefined(); expect(container.querySelector(".custom-input")).toBeDefined(); expect(container.querySelector(".custom-scroll")).toBeDefined(); }); it("should work with mixed props and tailwind classes", () => { const { container } = render( , ); const chatView = container.querySelector(".mixed-class"); expect(chatView).toBeDefined(); }); it("should handle transcription-related props", () => { const { container } = render( , ); // Component should render without errors even with transcription features expect(container.firstChild).toBeDefined(); }); }); // ============================================================================ // 9. CALLBACK AND HANDLER TESTS // ============================================================================ describe("9. Callback and Handler Tests", () => { it("should render CopilotChat and allow callback customization via custom component", () => { const onSubmitMessage = vi.fn(); const CustomChatView: React.FC = (props) => { // Use the provided onSubmitMessage or our custom one return ; }; render( , ); // The component should render without errors expect(onSubmitMessage).not.toHaveBeenCalled(); }); it("should support suggestions rendering", () => { // Note: CopilotChat manages suggestions internally via useAutoSuggestions // We test that the chatView slot receives and renders suggestions render( , ); // CopilotChat should render without errors // Actual suggestion rendering depends on agent state }); }); });