import React from "react"; import { render, screen, fireEvent } from "@testing-library/react"; import { describe, it, expect, vi } from "vitest"; import { CopilotChatInput } from "../CopilotChatInput"; import { CopilotKitProvider } from "../../../providers/CopilotKitProvider"; import { CopilotChatConfigurationProvider } from "../../../providers/CopilotChatConfigurationProvider"; // Wrapper to provide required context const TestWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
{children}
); describe("CopilotChatInput Slot System E2E Tests", () => { // ============================================================================ // 1. TAILWIND CLASS TESTS // ============================================================================ describe("1. Tailwind Class Slot Override", () => { describe("textArea slot", () => { it("should apply tailwind class string to textArea", () => { const { container } = render( , ); const textAreaEl = container.querySelector(".border-blue-500"); expect(textAreaEl).toBeDefined(); }); it("should override default textArea className", () => { const { container } = render( , ); expect(container.querySelector(".custom-textarea-class")).toBeDefined(); }); }); describe("sendButton slot", () => { it("should apply tailwind class string to sendButton", () => { const { container } = render( , ); const sendBtn = container.querySelector(".bg-green-500"); expect(sendBtn).toBeDefined(); }); }); describe("startTranscribeButton slot", () => { it("should apply tailwind class string to startTranscribeButton", () => { const { container } = render( {}} startTranscribeButton="bg-red-500 rounded" /> , ); const transcribeBtn = container.querySelector(".bg-red-500"); // Button may only appear when transcription is enabled }); }); describe("cancelTranscribeButton slot", () => { it("should apply tailwind class string to cancelTranscribeButton", () => { const { container } = render( {}} cancelTranscribeButton="bg-gray-500" /> , ); const cancelBtn = container.querySelector(".bg-gray-500"); // Button appears in transcribe mode }); }); describe("finishTranscribeButton slot", () => { it("should apply tailwind class string to finishTranscribeButton", () => { const { container } = render( {}} finishTranscribeButton="bg-purple-500" /> , ); const finishBtn = container.querySelector(".bg-purple-500"); // Button appears in transcribe mode }); }); describe("addMenuButton slot", () => { it("should apply tailwind class string to addMenuButton", () => { const { container } = render( {} }]} addMenuButton="bg-yellow-500" /> , ); const addBtn = container.querySelector(".bg-yellow-500"); // Button appears when toolsMenu is provided }); }); describe("audioRecorder slot", () => { it("should apply tailwind class string to audioRecorder", () => { const { container } = render( , ); const recorder = container.querySelector(".border-dashed"); // Recorder appears in transcribe mode }); }); }); // ============================================================================ // 2. PROPERTIES (onClick, etc.) TESTS // ============================================================================ describe("2. Properties Slot Override", () => { describe("textArea props", () => { it("should pass placeholder prop to textArea", async () => { render( , ); const textarea = await screen.findByPlaceholderText( "Custom placeholder...", ); expect(textarea).toBeDefined(); }); it("should pass disabled prop to textArea", () => { render( , ); const textarea = screen.queryByTestId("disabled-textarea"); if (textarea) { expect(textarea.hasAttribute("disabled")).toBe(true); } }); it("should pass onKeyDown prop to textArea", async () => { const handleKeyDown = vi.fn(); render( , ); const textarea = await screen.findByRole("textbox"); fireEvent.keyDown(textarea, { key: "a" }); // Handler should be called }); it("should pass autoFocus prop to textArea", () => { render( , ); const textarea = document.querySelector("textarea"); // autoFocus behavior may vary }); }); describe("sendButton props", () => { it("should pass onClick handler to sendButton", () => { const handleClick = vi.fn(); render( , ); const sendBtn = screen.queryByTestId("send-btn"); if (sendBtn) { fireEvent.click(sendBtn); expect(handleClick).toHaveBeenCalled(); } }); it("should pass disabled prop to sendButton", () => { render( , ); const sendBtn = screen.queryByTestId("disabled-send"); if (sendBtn) { expect(sendBtn.hasAttribute("disabled")).toBe(true); } }); it("should pass aria-label prop to sendButton", () => { render( , ); const sendBtn = document.querySelector("[aria-label='Submit message']"); expect(sendBtn).toBeDefined(); }); }); describe("addMenuButton props", () => { it("should pass onClick handler to addMenuButton", () => { const handleClick = vi.fn(); render( {} }]} addMenuButton={ { onClick: handleClick, "data-testid": "add-menu" } as any } /> , ); const addBtn = screen.queryByTestId("add-menu"); if (addBtn) { fireEvent.click(addBtn); } }); }); describe("user props override pre-set props", () => { it("user disabled should override default disabled state", () => { render( , ); const sendBtn = screen.queryByTestId("override-send"); // User's disabled=false should take effect }); }); }); // ============================================================================ // 3. CUSTOM COMPONENT TESTS // ============================================================================ describe("3. Custom Component Slot Override", () => { describe("textArea custom component", () => { it("should render custom textArea component", () => { const CustomTextArea = React.forwardRef( ({ value, onChange, ...props }, ref) => (