1+ import { render , screen } from "@testing-library/react" ;
2+ import "@testing-library/jest-dom" ;
3+ import { describe , it , beforeEach } from "@jest/globals" ;
4+ import ToolResults from "../ToolResults" ;
5+ import { Tool } from "@modelcontextprotocol/sdk/types.js" ;
6+ import { cacheToolOutputSchemas } from "@/utils/schemaUtils" ;
7+
8+ describe ( "ToolResults" , ( ) => {
9+ const mockTool : Tool = {
10+ name : "testTool" ,
11+ description : "Test tool" ,
12+ inputSchema : {
13+ type : "object" ,
14+ properties : { } ,
15+ } ,
16+ outputSchema : {
17+ type : "object" ,
18+ properties : {
19+ result : { type : "string" } ,
20+ } ,
21+ required : [ "result" ] ,
22+ } ,
23+ } ;
24+
25+ beforeEach ( ( ) => {
26+ cacheToolOutputSchemas ( [ mockTool ] ) ;
27+ } ) ;
28+
29+ describe ( "Content Compatibility Validation" , ( ) => {
30+ it ( "should accept single text block with matching JSON" , ( ) => {
31+ const toolResult = {
32+ content : [ { type : "text" , text : '{"result": "success"}' } ] ,
33+ structuredContent : { result : "success" } ,
34+ } ;
35+
36+ render ( < ToolResults toolResult = { toolResult } selectedTool = { mockTool } /> ) ;
37+
38+ expect ( screen . getByText ( / F o u n d m a t c h i n g J S O N c o n t e n t .* i n s i n g l e t e x t b l o c k / ) ) . toBeInTheDocument ( ) ;
39+ } ) ;
40+
41+ it ( "should accept multiple text blocks with one matching JSON" , ( ) => {
42+ const toolResult = {
43+ content : [
44+ { type : "text" , text : "Processing..." } ,
45+ { type : "text" , text : '{"result": "success"}' } ,
46+ { type : "text" , text : "Done!" } ,
47+ ] ,
48+ structuredContent : { result : "success" } ,
49+ } ;
50+
51+ render ( < ToolResults toolResult = { toolResult } selectedTool = { mockTool } /> ) ;
52+
53+ expect ( screen . getByText ( / F o u n d m a t c h i n g J S O N c o n t e n t .* a m o n g m u l t i p l e t e x t b l o c k s / ) ) . toBeInTheDocument ( ) ;
54+ } ) ;
55+
56+ it ( "should accept mixed content types with matching JSON" , ( ) => {
57+ const toolResult = {
58+ content : [
59+ { type : "text" , text : "Result:" } ,
60+ { type : "text" , text : '{"result": "success"}' } ,
61+ { type : "image" , data : "base64data" , mimeType : "image/png" } ,
62+ { type : "resource" , resource : { uri : "file://test.txt" } } ,
63+ ] ,
64+ structuredContent : { result : "success" } ,
65+ } ;
66+
67+ render ( < ToolResults toolResult = { toolResult } selectedTool = { mockTool } /> ) ;
68+
69+ expect ( screen . getByText ( / F o u n d m a t c h i n g J S O N c o n t e n t .* w i t h a d d i t i o n a l c o n t e n t b l o c k s / ) ) . toBeInTheDocument ( ) ;
70+ } ) ;
71+
72+ it ( "should reject when no text blocks are present" , ( ) => {
73+ const toolResult = {
74+ content : [
75+ { type : "image" , data : "base64data" , mimeType : "image/png" } ,
76+ ] ,
77+ structuredContent : { result : "success" } ,
78+ } ;
79+
80+ render ( < ToolResults toolResult = { toolResult } selectedTool = { mockTool } /> ) ;
81+
82+ expect ( screen . getByText ( / N o t e x t c o n t e n t b l o c k s f o u n d t o m a t c h s t r u c t u r e d c o n t e n t / ) ) . toBeInTheDocument ( ) ;
83+ } ) ;
84+
85+ it ( "should reject when no text blocks contain matching JSON" , ( ) => {
86+ const toolResult = {
87+ content : [
88+ { type : "text" , text : "Some text" } ,
89+ { type : "text" , text : '{"different": "data"}' } ,
90+ ] ,
91+ structuredContent : { result : "success" } ,
92+ } ;
93+
94+ render ( < ToolResults toolResult = { toolResult } selectedTool = { mockTool } /> ) ;
95+
96+ expect ( screen . getByText ( / N o t e x t c o n t e n t b l o c k c o n t a i n s J S O N m a t c h i n g s t r u c t u r e d c o n t e n t / ) ) . toBeInTheDocument ( ) ;
97+ } ) ;
98+
99+ it ( "should reject when text blocks contain invalid JSON" , ( ) => {
100+ const toolResult = {
101+ content : [
102+ { type : "text" , text : "Not JSON" } ,
103+ { type : "text" , text : '{"invalid": json}' } ,
104+ ] ,
105+ structuredContent : { result : "success" } ,
106+ } ;
107+
108+ render ( < ToolResults toolResult = { toolResult } selectedTool = { mockTool } /> ) ;
109+
110+ expect ( screen . getByText ( / N o t e x t c o n t e n t b l o c k c o n t a i n s J S O N m a t c h i n g s t r u c t u r e d c o n t e n t / ) ) . toBeInTheDocument ( ) ;
111+ } ) ;
112+
113+ it ( "should handle empty text blocks gracefully" , ( ) => {
114+ const toolResult = {
115+ content : [
116+ { type : "text" , text : "" } ,
117+ { type : "text" , text : '{"result": "success"}' } ,
118+ ] ,
119+ structuredContent : { result : "success" } ,
120+ } ;
121+
122+ render ( < ToolResults toolResult = { toolResult } selectedTool = { mockTool } /> ) ;
123+
124+ expect ( screen . getByText ( / F o u n d m a t c h i n g J S O N c o n t e n t .* a m o n g m u l t i p l e t e x t b l o c k s / ) ) . toBeInTheDocument ( ) ;
125+ } ) ;
126+
127+ it ( "should not show compatibility check when tool has no output schema" , ( ) => {
128+ const toolWithoutSchema : Tool = {
129+ name : "noSchemaTool" ,
130+ description : "Tool without schema" ,
131+ inputSchema : {
132+ type : "object" ,
133+ properties : { } ,
134+ } ,
135+ } ;
136+
137+ const toolResult = {
138+ content : [ { type : "text" , text : '{"any": "data"}' } ] ,
139+ structuredContent : { any : "data" } ,
140+ } ;
141+
142+ render ( < ToolResults toolResult = { toolResult } selectedTool = { toolWithoutSchema } /> ) ;
143+
144+ // Should not show any compatibility messages
145+ expect ( screen . queryByText ( / F o u n d m a t c h i n g J S O N c o n t e n t / ) ) . not . toBeInTheDocument ( ) ;
146+ expect ( screen . queryByText ( / N o t e x t c o n t e n t b l o c k s f o u n d / ) ) . not . toBeInTheDocument ( ) ;
147+ expect ( screen . queryByText ( / N o t e x t c o n t e n t b l o c k c o n t a i n s J S O N / ) ) . not . toBeInTheDocument ( ) ;
148+ } ) ;
149+ } ) ;
150+
151+ describe ( "Structured Content Validation" , ( ) => {
152+ it ( "should show validation success for valid structured content" , ( ) => {
153+ const toolResult = {
154+ content : [ ] ,
155+ structuredContent : { result : "success" } ,
156+ } ;
157+
158+ render ( < ToolResults toolResult = { toolResult } selectedTool = { mockTool } /> ) ;
159+
160+ expect ( screen . getByText ( / V a l i d a c c o r d i n g t o o u t p u t s c h e m a / ) ) . toBeInTheDocument ( ) ;
161+ } ) ;
162+
163+ it ( "should show validation error for invalid structured content" , ( ) => {
164+ const toolResult = {
165+ content : [ ] ,
166+ structuredContent : { result : 123 } , // Should be string
167+ } ;
168+
169+ render ( < ToolResults toolResult = { toolResult } selectedTool = { mockTool } /> ) ;
170+
171+ expect ( screen . getByText ( / V a l i d a t i o n E r r o r : / ) ) . toBeInTheDocument ( ) ;
172+ } ) ;
173+
174+ it ( "should show error when structured content is missing for tool with output schema" , ( ) => {
175+ const toolResult = {
176+ content : [ { type : "text" , text : "Some result" } ] ,
177+ // No structuredContent
178+ } ;
179+
180+ render ( < ToolResults toolResult = { toolResult } selectedTool = { mockTool } /> ) ;
181+
182+ expect ( screen . getByText ( / T o o l h a s a n o u t p u t s c h e m a b u t d i d n o t r e t u r n s t r u c t u r e d c o n t e n t / ) ) . toBeInTheDocument ( ) ;
183+ } ) ;
184+ } ) ;
185+ } ) ;
0 commit comments