import { renderHook } from "@testing-library/react"; import type React from "react"; import { describe, expect, it, vi } from "vitest"; import { z } from "zod"; import type { ReactFrontendTool } from "../../types/frontend-tool"; import type { ReactHumanInTheLoop } from "../../types/human-in-the-loop"; import { CopilotKitProvider, useCopilotKit } from "../CopilotKitProvider"; describe("CopilotKitProvider - Wildcard Tool", () => { describe("Wildcard Frontend Tool", () => { it("should register wildcard frontend tool", () => { const wildcardHandler = vi.fn(); const wildcardTool: ReactFrontendTool = { name: "*", description: "Fallback for undefined tools", handler: wildcardHandler, }; const { result } = renderHook(() => useCopilotKit(), { wrapper: ({ children }) => ( {children} ), }); const retrievedTool = result.current.copilotkit.getTool({ toolName: "*", }); expect(retrievedTool).toBeDefined(); expect(retrievedTool?.name).toBe("*"); expect(retrievedTool?.handler).toBe(wildcardHandler); }); it("should register wildcard alongside specific tools", () => { const specificHandler = vi.fn(); const wildcardHandler = vi.fn(); const specificTool: ReactFrontendTool = { name: "specific", handler: specificHandler, }; const wildcardTool: ReactFrontendTool = { name: "*", handler: wildcardHandler, }; const { result } = renderHook(() => useCopilotKit(), { wrapper: ({ children }) => ( {children} ), }); expect( result.current.copilotkit.getTool({ toolName: "specific" }), ).toBeDefined(); expect( result.current.copilotkit.getTool({ toolName: "*" }), ).toBeDefined(); }); it("should register wildcard with render component", () => { const WildcardRender: React.FC = ({ args }) => (
Unknown tool: {args.toolName}
); const wildcardTool: ReactFrontendTool = { name: "*", description: "Fallback with render", parameters: z.object({ toolName: z.string(), args: z.unknown(), }), render: WildcardRender, }; const { result } = renderHook(() => useCopilotKit(), { wrapper: ({ children }) => ( {children} ), }); const wildcardRender = result.current.copilotkit.renderToolCalls.find( (rc) => rc.name === "*", ); expect(wildcardRender).toBeDefined(); expect(wildcardRender?.render).toBe(WildcardRender); }); it("should support wildcard with agentId", () => { const wildcardHandler = vi.fn(); const wildcardTool: ReactFrontendTool = { name: "*", handler: wildcardHandler, agentId: "specificAgent", }; const { result } = renderHook(() => useCopilotKit(), { wrapper: ({ children }) => ( {children} ), }); const retrievedTool = result.current.copilotkit.getTool({ toolName: "*", agentId: "specificAgent", }); expect(retrievedTool?.agentId).toBe("specificAgent"); }); }); describe("Wildcard Human-in-the-Loop", () => { it("should register wildcard human-in-the-loop tool", () => { const WildcardComponent: React.FC = ({ args }) => (
Unknown interaction: {args.toolName}
); const wildcardHitl: ReactHumanInTheLoop = { name: "*", description: "Fallback interaction", parameters: z.object({ toolName: z.string(), args: z.unknown(), }), render: WildcardComponent, }; const { result } = renderHook(() => useCopilotKit(), { wrapper: ({ children }) => ( {children} ), }); expect( result.current.copilotkit.getTool({ toolName: "*" }), ).toBeDefined(); const wildcardRender = result.current.copilotkit.renderToolCalls.find( (rc) => rc.name === "*", ); expect(wildcardRender).toBeDefined(); expect(wildcardRender?.render).toBe(WildcardComponent); }); it("should support wildcard human-in-the-loop with agentId", () => { const WildcardComponent: React.FC = () =>
Wildcard
; const wildcardHitl: ReactHumanInTheLoop = { name: "*", parameters: z.object({ toolName: z.string(), args: z.unknown(), }), render: WildcardComponent, agentId: "agent1", }; const { result } = renderHook(() => useCopilotKit(), { wrapper: ({ children }) => ( {children} ), }); const retrievedTool = result.current.copilotkit.getTool({ toolName: "*", agentId: "agent1", }); expect(retrievedTool?.agentId).toBe("agent1"); }); }); describe("Wildcard Render Tool Calls", () => { it("should register wildcard in renderToolCalls", () => { const WildcardRender: React.FC = ({ args }) => (
Fallback render
); const renderToolCalls = [ { name: "*", args: z.object({ toolName: z.string(), args: z.unknown(), }), render: WildcardRender, }, ]; const { result } = renderHook(() => useCopilotKit(), { wrapper: ({ children }) => ( {children} ), }); const wildcardRender = result.current.copilotkit.renderToolCalls.find( (rc) => rc.name === "*", ); expect(wildcardRender).toBeDefined(); expect(wildcardRender?.render).toBe(WildcardRender); }); it("should support wildcard render with agentId", () => { const WildcardRender: React.FC = () =>
Agent wildcard
; const renderToolCalls = [ { name: "*", args: z.object({ toolName: z.string(), args: z.unknown(), }), render: WildcardRender, agentId: "agent1", }, ]; const { result } = renderHook(() => useCopilotKit(), { wrapper: ({ children }) => ( {children} ), }); const wildcardRender = result.current.copilotkit.renderToolCalls.find( (rc) => rc.name === "*", ); expect(wildcardRender?.agentId).toBe("agent1"); }); }); describe("Combined wildcard and specific tools", () => { it("should handle both wildcard and specific tools together", () => { const SpecificRender: React.FC = () =>
Specific
; const WildcardRender: React.FC = () =>
Wildcard
; const frontendTools: ReactFrontendTool[] = [ { name: "specificTool", handler: vi.fn(), parameters: z.object({ value: z.string() }), render: SpecificRender, }, { name: "*", handler: vi.fn(), parameters: z.object({ toolName: z.string(), args: z.unknown(), }), render: WildcardRender, }, ]; const { result } = renderHook(() => useCopilotKit(), { wrapper: ({ children }) => ( {children} ), }); // Both tools should be registered expect( result.current.copilotkit.getTool({ toolName: "specificTool" }), ).toBeDefined(); expect( result.current.copilotkit.getTool({ toolName: "*" }), ).toBeDefined(); // Both renders should be registered const specificToolRender = result.current.copilotkit.renderToolCalls.find( (rc) => rc.name === "specificTool", ); const wildcardRender = result.current.copilotkit.renderToolCalls.find( (rc) => rc.name === "*", ); expect(specificToolRender).toBeDefined(); expect(wildcardRender).toBeDefined(); }); }); });