import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import type { BlobResourceContents, ContentBlock, TextResourceContents, } from "@modelcontextprotocol/sdk/types.js"; import { renderWithMantine, screen } from "../../../test/renderWithMantine"; import { ContentViewer } from "./ContentViewer"; // Stub the lazy highlighter so JSON/XML/CSS branches are assertable // synchronously (its real dynamic-import behavior is covered in // CodeHighlight.test.tsx). vi.mock("../CodeHighlight/CodeHighlight", () => ({ CodeHighlight: ({ language, code }: { language: string; code: string }) => (
      {code}
    
), })); const toBase64 = (text: string): string => Buffer.from(text, "utf-8").toString("base64"); describe("ContentViewer", () => { it("renders text content as-is when not JSON", () => { const block: ContentBlock = { type: "text", text: "hello world" }; renderWithMantine(); expect(screen.getByText("hello world")).toBeInTheDocument(); }); it("pretty-prints JSON text", () => { const block: ContentBlock = { type: "text", text: '{"a":1}' }; renderWithMantine(); expect(screen.getByText(/"a": 1/)).toBeInTheDocument(); }); it("falls back to raw text when JSON is malformed", () => { const block: ContentBlock = { type: "text", text: "{ broken" }; renderWithMantine(); expect(screen.getByText("{ broken")).toBeInTheDocument(); }); it("renders a copy overlay when copyable", () => { const block: ContentBlock = { type: "text", text: "hello" }; renderWithMantine(); expect(screen.getByRole("button")).toBeInTheDocument(); }); it("does not render a copy overlay by default", () => { const block: ContentBlock = { type: "text", text: "hello" }; renderWithMantine(); expect(screen.queryByRole("button")).not.toBeInTheDocument(); }); it("renders an image block", () => { const block: ContentBlock = { type: "image", mimeType: "image/png", data: "AAAA", }; renderWithMantine(); expect(screen.getByRole("img")).toHaveAttribute( "src", "data:image/png;base64,AAAA", ); }); it("renders an audio block", () => { const block: ContentBlock = { type: "audio", mimeType: "audio/mp3", data: "BBBB", }; const { container } = renderWithMantine(); const source = container.querySelector("source"); expect(source).toHaveAttribute("src", "data:audio/mp3;base64,BBBB"); }); it("renders a text resource block", () => { const block: ContentBlock = { type: "resource", resource: { uri: "file:///foo", text: "embedded text" }, }; renderWithMantine(); expect(screen.getByText("embedded text")).toBeInTheDocument(); }); it("renders a blob resource block with placeholder", () => { const block: ContentBlock = { type: "resource", resource: { uri: "file:///bar", blob: "abc", mimeType: "application/octet-stream", }, }; renderWithMantine(); expect(screen.getByText("[blob: file:///bar]")).toBeInTheDocument(); }); it("renders a resource_link with name", () => { const block: ContentBlock = { type: "resource_link", uri: "ui://app", name: "Cool App", }; renderWithMantine(); expect(screen.getByText("Cool App")).toBeInTheDocument(); }); it("falls back to URI when resource_link has no name", () => { const block = { type: "resource_link", uri: "ui://app", } as unknown as ContentBlock; renderWithMantine(); expect(screen.getByText("ui://app")).toBeInTheDocument(); }); it("renders a resource_link statically (no expand control)", () => { const block: ContentBlock = { type: "resource_link", uri: "ui://app", name: "Cool App", description: "An app", mimeType: "text/html", }; renderWithMantine(); expect(screen.getByText("Cool App")).toBeInTheDocument(); expect(screen.getByText("An app")).toBeInTheDocument(); expect(screen.getByText("text/html")).toBeInTheDocument(); expect(screen.queryByRole("button")).not.toBeInTheDocument(); }); it("renders nothing for unknown block types", () => { renderWithMantine(); expect(screen.queryByRole("img")).not.toBeInTheDocument(); expect(screen.queryByRole("button")).not.toBeInTheDocument(); }); it("renders plain text in a wrapping code block by default", () => { const block: ContentBlock = { type: "text", text: "some long command" }; const { container } = renderWithMantine(); expect(container.querySelector(".mantine-Code-root")).toHaveAttribute( "data-variant", "wrapping", ); }); it("renders plain text in a non-wrapping code block when wrap is false", () => { const block: ContentBlock = { type: "text", text: "some long command" }; const { container } = renderWithMantine( , ); const code = container.querySelector(".mantine-Code-root"); expect(code).toHaveAttribute("data-variant", "nowrap"); // Full value exposed on hover since it may be clipped with an ellipsis. expect(code).toHaveAttribute("title", "some long command"); }); it("does not set a title tooltip when wrapping (default)", () => { const block: ContentBlock = { type: "text", text: "some long command" }; const { container } = renderWithMantine(); expect(container.querySelector(".mantine-Code-root")).not.toHaveAttribute( "title", ); }); it("renders text as markdown when mimeType is text/markdown", () => { const block: ContentBlock = { type: "text", text: "# Title\n\nSome **bold** text.", }; renderWithMantine(); expect( screen.getByRole("heading", { level: 1, name: "Title" }), ).toBeInTheDocument(); expect(screen.getByText("bold")).toBeInTheDocument(); }); it("accepts mimeType with parameters (e.g. text/markdown; charset=utf-8)", () => { const block: ContentBlock = { type: "text", text: "# Heading" }; renderWithMantine( , ); expect( screen.getByRole("heading", { level: 1, name: "Heading" }), ).toBeInTheDocument(); }); it("falls back to code rendering for non-markdown mime types", () => { const block: ContentBlock = { type: "text", text: "# not markdown" }; renderWithMantine(); expect(screen.getByText("# not markdown")).toBeInTheDocument(); // No

generated by react-markdown expect(screen.queryByRole("heading", { level: 1 })).not.toBeInTheDocument(); }); it("renders a copy overlay for markdown content when copyable", () => { const block: ContentBlock = { type: "text", text: "# hi" }; renderWithMantine( , ); expect(screen.getByRole("button")).toBeInTheDocument(); }); it("highlights a JSON text block when mimeType is application/json", () => { const block: ContentBlock = { type: "text", text: '{"a":1}' }; renderWithMantine( , ); const probe = screen.getByTestId("code-highlight"); expect(probe).toHaveAttribute("data-language", "json"); expect(probe.textContent).toContain('"a": 1'); }); it("renders nothing when neither block nor contents is provided", () => { const { container } = renderWithMantine(); // MantineProvider injects a