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