import React from "react"; import { render } from "@testing-library/react"; import { describe, it, expect, beforeEach, vi } from "vitest"; import { z } from "zod"; import { useComponent } from "../use-component"; import { useFrontendTool } from "../use-frontend-tool"; vi.mock("../use-frontend-tool", () => ({ useFrontendTool: vi.fn(), })); const mockUseFrontendTool = useFrontendTool as ReturnType; describe("useComponent", () => { beforeEach(() => { vi.clearAllMocks(); }); it("registers a component tool with generated default description", () => { const DemoComponent: React.FC<{ city: string }> = ({ city }) => (
{city}
); const Harness: React.FC = () => { useComponent({ name: "showWeatherCard", render: DemoComponent, }); return null; }; render(); expect(mockUseFrontendTool).toHaveBeenCalledTimes(1); const [toolConfig] = mockUseFrontendTool.mock.calls[0] as [ { name: string; description: string; }, ]; expect(toolConfig.name).toBe("showWeatherCard"); expect(toolConfig.description).toContain( 'Use this tool to display the "showWeatherCard" component in the chat.', ); }); it("appends custom description and forwards parameters, agentId, and deps", () => { const weatherSchema = z.object({ city: z.string(), unit: z.enum(["c", "f"]), }); const DemoComponent: React.FC> = ({ city, }) =>
{city}
; const deps = ["v1"] as const; const Harness: React.FC = () => { useComponent( { name: "showWeatherCard", description: "Render a weather card for the selected city.", parameters: weatherSchema, render: DemoComponent, agentId: "weather-agent", }, deps, ); return null; }; render(); expect(mockUseFrontendTool).toHaveBeenCalledTimes(1); const [toolConfig, forwardedDeps] = mockUseFrontendTool.mock.calls[0] as [ { description: string; parameters: typeof weatherSchema; agentId?: string; }, ReadonlyArray, ]; expect(toolConfig.description).toContain( 'Use this tool to display the "showWeatherCard" component in the chat.', ); expect(toolConfig.description).toContain( "Render a weather card for the selected city.", ); expect(toolConfig.parameters).toBe(weatherSchema); expect(toolConfig.agentId).toBe("weather-agent"); expect(forwardedDeps).toBe(deps); }); it("creates a render function that passes args into the component", () => { const DemoComponent: React.FC<{ city: string }> = ({ city }) => (
{city}
); const Harness: React.FC = () => { useComponent({ name: "showWeatherCard", render: DemoComponent, }); return null; }; render(); const [toolConfig] = mockUseFrontendTool.mock.calls[0] as [ { render: (props: { args: { city: string } }) => React.ReactElement; }, ]; const { getByTestId } = render( toolConfig.render({ args: { city: "Paris" } }), ); expect(getByTestId("city").textContent).toBe("Paris"); }); });