-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathContentViewer.test.tsx
More file actions
145 lines (129 loc) · 5.17 KB
/
Copy pathContentViewer.test.tsx
File metadata and controls
145 lines (129 loc) · 5.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import { describe, it, expect } from "vitest";
import type { ContentBlock } from "@modelcontextprotocol/sdk/types.js";
import { renderWithMantine, screen } from "../../../test/renderWithMantine";
import { ContentViewer } from "./ContentViewer";
describe("ContentViewer", () => {
it("renders text content as-is when not JSON", () => {
const block: ContentBlock = { type: "text", text: "hello world" };
renderWithMantine(<ContentViewer block={block} />);
expect(screen.getByText("hello world")).toBeInTheDocument();
});
it("pretty-prints JSON text", () => {
const block: ContentBlock = { type: "text", text: '{"a":1}' };
renderWithMantine(<ContentViewer block={block} />);
expect(screen.getByText(/"a": 1/)).toBeInTheDocument();
});
it("falls back to raw text when JSON is malformed", () => {
const block: ContentBlock = { type: "text", text: "{ broken" };
renderWithMantine(<ContentViewer block={block} />);
expect(screen.getByText("{ broken")).toBeInTheDocument();
});
it("renders a copy overlay when copyable", () => {
const block: ContentBlock = { type: "text", text: "hello" };
renderWithMantine(<ContentViewer block={block} copyable />);
expect(screen.getByRole("button")).toBeInTheDocument();
});
it("does not render a copy overlay by default", () => {
const block: ContentBlock = { type: "text", text: "hello" };
renderWithMantine(<ContentViewer block={block} />);
expect(screen.queryByRole("button")).not.toBeInTheDocument();
});
it("renders an image block", () => {
const block: ContentBlock = {
type: "image",
mimeType: "image/png",
data: "AAAA",
};
renderWithMantine(<ContentViewer block={block} />);
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(<ContentViewer block={block} />);
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(<ContentViewer block={block} />);
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(<ContentViewer block={block} />);
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(<ContentViewer block={block} />);
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(<ContentViewer block={block} />);
expect(screen.getByText("ui://app")).toBeInTheDocument();
});
it("renders nothing for unknown block types", () => {
renderWithMantine(<ContentViewer block={{ type: "unknown" } as never} />);
expect(screen.queryByRole("img")).not.toBeInTheDocument();
expect(screen.queryByRole("button")).not.toBeInTheDocument();
});
it("renders text as markdown when mimeType is text/markdown", () => {
const block: ContentBlock = {
type: "text",
text: "# Title\n\nSome **bold** text.",
};
renderWithMantine(<ContentViewer block={block} mimeType="text/markdown" />);
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(
<ContentViewer block={block} mimeType="text/markdown; charset=utf-8" />,
);
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(<ContentViewer block={block} mimeType="text/plain" />);
expect(screen.getByText("# not markdown")).toBeInTheDocument();
// No <h1> 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(
<ContentViewer block={block} mimeType="text/markdown" copyable />,
);
expect(screen.getByRole("button")).toBeInTheDocument();
});
});