1
+ import React from "react" ;
2
+ import { render , waitFor } from "@testing-library/react" ;
3
+ import App from "../App" ;
4
+ import { DEFAULT_INSPECTOR_CONFIG } from "../lib/constants" ;
5
+
6
+ // Mock auth dependencies first
7
+ jest . mock ( "@modelcontextprotocol/sdk/client/auth.js" , ( ) => ( {
8
+ auth : jest . fn ( ) ,
9
+ } ) ) ;
10
+
11
+ jest . mock ( "../lib/oauth-state-machine" , ( ) => ( {
12
+ OAuthStateMachine : jest . fn ( ) ,
13
+ } ) ) ;
14
+
15
+ jest . mock ( "../lib/auth" , ( ) => ( {
16
+ InspectorOAuthClientProvider : jest . fn ( ) . mockImplementation ( ( ) => ( {
17
+ tokens : jest . fn ( ) . mockResolvedValue ( null ) ,
18
+ clear : jest . fn ( ) ,
19
+ } ) ) ,
20
+ DebugInspectorOAuthClientProvider : jest . fn ( ) ,
21
+ } ) ) ;
22
+
23
+ // Mock the config utils
24
+ jest . mock ( "../utils/configUtils" , ( ) => ( {
25
+ ...jest . requireActual ( "../utils/configUtils" ) ,
26
+ getMCPProxyAddress : jest . fn ( ( ) => "http://localhost:6277" ) ,
27
+ getMCPProxyAuthToken : jest . fn ( ( config ) => ( {
28
+ token : config . MCP_PROXY_AUTH_TOKEN . value ,
29
+ header : "X-MCP-Proxy-Auth" ,
30
+ } ) ) ,
31
+ getInitialTransportType : jest . fn ( ( ) => "stdio" ) ,
32
+ getInitialSseUrl : jest . fn ( ( ) => "http://localhost:3001/sse" ) ,
33
+ getInitialCommand : jest . fn ( ( ) => "mcp-server-everything" ) ,
34
+ getInitialArgs : jest . fn ( ( ) => "" ) ,
35
+ initializeInspectorConfig : jest . fn ( ( ) => DEFAULT_INSPECTOR_CONFIG ) ,
36
+ saveInspectorConfig : jest . fn ( ) ,
37
+ } ) ) ;
38
+
39
+ // Mock other dependencies
40
+ jest . mock ( "../lib/hooks/useConnection" , ( ) => ( {
41
+ useConnection : ( ) => ( {
42
+ connectionStatus : "disconnected" ,
43
+ serverCapabilities : null ,
44
+ mcpClient : null ,
45
+ requestHistory : [ ] ,
46
+ makeRequest : jest . fn ( ) ,
47
+ sendNotification : jest . fn ( ) ,
48
+ handleCompletion : jest . fn ( ) ,
49
+ completionsSupported : false ,
50
+ connect : jest . fn ( ) ,
51
+ disconnect : jest . fn ( ) ,
52
+ } ) ,
53
+ } ) ) ;
54
+
55
+ jest . mock ( "../lib/hooks/useDraggablePane" , ( ) => ( {
56
+ useDraggablePane : ( ) => ( {
57
+ height : 300 ,
58
+ handleDragStart : jest . fn ( ) ,
59
+ } ) ,
60
+ useDraggableSidebar : ( ) => ( {
61
+ width : 320 ,
62
+ isDragging : false ,
63
+ handleDragStart : jest . fn ( ) ,
64
+ } ) ,
65
+ } ) ) ;
66
+
67
+ jest . mock ( "../components/Sidebar" , ( ) => ( {
68
+ __esModule : true ,
69
+ default : ( ) => < div > Sidebar</ div > ,
70
+ } ) ) ;
71
+
72
+ // Mock fetch
73
+ global . fetch = jest . fn ( ) ;
74
+
75
+ describe ( "App - Config Endpoint" , ( ) => {
76
+ beforeEach ( ( ) => {
77
+ jest . clearAllMocks ( ) ;
78
+ ( global . fetch as jest . Mock ) . mockResolvedValue ( {
79
+ json : ( ) =>
80
+ Promise . resolve ( {
81
+ defaultEnvironment : { TEST_ENV : "test" } ,
82
+ defaultCommand : "test-command" ,
83
+ defaultArgs : "test-args" ,
84
+ } ) ,
85
+ } ) ;
86
+ } ) ;
87
+
88
+ afterEach ( ( ) => {
89
+ jest . clearAllMocks ( ) ;
90
+
91
+ // Reset getMCPProxyAuthToken to default behavior
92
+ const { getMCPProxyAuthToken } = require ( "../utils/configUtils" ) ;
93
+ getMCPProxyAuthToken . mockImplementation ( ( config ) => ( {
94
+ token : config . MCP_PROXY_AUTH_TOKEN . value ,
95
+ header : "X-MCP-Proxy-Auth" ,
96
+ } ) ) ;
97
+ } ) ;
98
+
99
+ test ( "sends X-MCP-Proxy-Auth header when fetching config with proxy auth token" , async ( ) => {
100
+ const mockConfig = {
101
+ ...DEFAULT_INSPECTOR_CONFIG ,
102
+ MCP_PROXY_AUTH_TOKEN : {
103
+ ...DEFAULT_INSPECTOR_CONFIG . MCP_PROXY_AUTH_TOKEN ,
104
+ value : "test-proxy-token" ,
105
+ } ,
106
+ } ;
107
+
108
+ // Mock initializeInspectorConfig to return our test config
109
+ const { initializeInspectorConfig } = require ( "../utils/configUtils" ) ;
110
+ initializeInspectorConfig . mockReturnValue ( mockConfig ) ;
111
+
112
+ render ( < App /> ) ;
113
+
114
+ await waitFor ( ( ) => {
115
+ expect ( global . fetch ) . toHaveBeenCalledWith (
116
+ "http://localhost:6277/config" ,
117
+ {
118
+ headers : {
119
+ "X-MCP-Proxy-Auth" : "Bearer test-proxy-token" ,
120
+ } ,
121
+ }
122
+ ) ;
123
+ } ) ;
124
+ } ) ;
125
+
126
+ test ( "does not send auth header when proxy auth token is empty" , async ( ) => {
127
+ const mockConfig = {
128
+ ...DEFAULT_INSPECTOR_CONFIG ,
129
+ MCP_PROXY_AUTH_TOKEN : {
130
+ ...DEFAULT_INSPECTOR_CONFIG . MCP_PROXY_AUTH_TOKEN ,
131
+ value : "" ,
132
+ } ,
133
+ } ;
134
+
135
+ // Mock initializeInspectorConfig to return our test config
136
+ const { initializeInspectorConfig } = require ( "../utils/configUtils" ) ;
137
+ initializeInspectorConfig . mockReturnValue ( mockConfig ) ;
138
+
139
+ render ( < App /> ) ;
140
+
141
+ await waitFor ( ( ) => {
142
+ expect ( global . fetch ) . toHaveBeenCalledWith (
143
+ "http://localhost:6277/config" ,
144
+ {
145
+ headers : { } ,
146
+ }
147
+ ) ;
148
+ } ) ;
149
+ } ) ;
150
+
151
+ test ( "uses custom header name if getMCPProxyAuthToken returns different header" , async ( ) => {
152
+ const mockConfig = {
153
+ ...DEFAULT_INSPECTOR_CONFIG ,
154
+ MCP_PROXY_AUTH_TOKEN : {
155
+ ...DEFAULT_INSPECTOR_CONFIG . MCP_PROXY_AUTH_TOKEN ,
156
+ value : "test-proxy-token" ,
157
+ } ,
158
+ } ;
159
+
160
+ // Mock to return a custom header name
161
+ const { getMCPProxyAuthToken, initializeInspectorConfig } = require ( "../utils/configUtils" ) ;
162
+ getMCPProxyAuthToken . mockReturnValue ( {
163
+ token : "test-proxy-token" ,
164
+ header : "X-Custom-Auth" ,
165
+ } ) ;
166
+ initializeInspectorConfig . mockReturnValue ( mockConfig ) ;
167
+
168
+ render ( < App /> ) ;
169
+
170
+ await waitFor ( ( ) => {
171
+ expect ( global . fetch ) . toHaveBeenCalledWith (
172
+ "http://localhost:6277/config" ,
173
+ {
174
+ headers : {
175
+ "X-Custom-Auth" : "Bearer test-proxy-token" ,
176
+ } ,
177
+ }
178
+ ) ;
179
+ } ) ;
180
+ } ) ;
181
+
182
+ test ( "config endpoint response updates app state" , async ( ) => {
183
+ const mockConfig = {
184
+ ...DEFAULT_INSPECTOR_CONFIG ,
185
+ MCP_PROXY_AUTH_TOKEN : {
186
+ ...DEFAULT_INSPECTOR_CONFIG . MCP_PROXY_AUTH_TOKEN ,
187
+ value : "test-proxy-token" ,
188
+ } ,
189
+ } ;
190
+
191
+ const { initializeInspectorConfig } = require ( "../utils/configUtils" ) ;
192
+ initializeInspectorConfig . mockReturnValue ( mockConfig ) ;
193
+
194
+ const { container } = render ( < App /> ) ;
195
+
196
+ await waitFor ( ( ) => {
197
+ expect ( global . fetch ) . toHaveBeenCalledTimes ( 1 ) ;
198
+ } ) ;
199
+
200
+ // Verify the fetch was called with correct parameters
201
+ expect ( global . fetch ) . toHaveBeenCalledWith (
202
+ "http://localhost:6277/config" ,
203
+ expect . objectContaining ( {
204
+ headers : expect . objectContaining ( {
205
+ "X-MCP-Proxy-Auth" : "Bearer test-proxy-token" ,
206
+ } ) ,
207
+ } )
208
+ ) ;
209
+ } ) ;
210
+
211
+ test ( "handles config endpoint errors gracefully" , async ( ) => {
212
+ const mockConfig = {
213
+ ...DEFAULT_INSPECTOR_CONFIG ,
214
+ MCP_PROXY_AUTH_TOKEN : {
215
+ ...DEFAULT_INSPECTOR_CONFIG . MCP_PROXY_AUTH_TOKEN ,
216
+ value : "test-proxy-token" ,
217
+ } ,
218
+ } ;
219
+
220
+ const { initializeInspectorConfig } = require ( "../utils/configUtils" ) ;
221
+ initializeInspectorConfig . mockReturnValue ( mockConfig ) ;
222
+
223
+ // Mock fetch to reject
224
+ ( global . fetch as jest . Mock ) . mockRejectedValue ( new Error ( "Network error" ) ) ;
225
+
226
+ // Spy on console.error
227
+ const consoleErrorSpy = jest . spyOn ( console , "error" ) . mockImplementation ( ) ;
228
+
229
+ render ( < App /> ) ;
230
+
231
+ await waitFor ( ( ) => {
232
+ expect ( consoleErrorSpy ) . toHaveBeenCalledWith (
233
+ "Error fetching default environment:" ,
234
+ expect . any ( Error )
235
+ ) ;
236
+ } ) ;
237
+
238
+ consoleErrorSpy . mockRestore ( ) ;
239
+ } ) ;
240
+ } ) ;
0 commit comments