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