1
+ import { describe , it , expect , vi , beforeEach , afterEach } from "vitest"
2
+ import { getProxyForUrl } from "./proxy"
3
+
4
+ describe ( "proxy" , ( ) => {
5
+ let originalEnv : NodeJS . ProcessEnv
6
+
7
+ beforeEach ( ( ) => {
8
+ // Save original environment
9
+ originalEnv = { ...process . env }
10
+ // Clear relevant proxy environment variables
11
+ delete process . env . http_proxy
12
+ delete process . env . HTTP_PROXY
13
+ delete process . env . https_proxy
14
+ delete process . env . HTTPS_PROXY
15
+ delete process . env . ftp_proxy
16
+ delete process . env . FTP_PROXY
17
+ delete process . env . all_proxy
18
+ delete process . env . ALL_PROXY
19
+ delete process . env . no_proxy
20
+ delete process . env . NO_PROXY
21
+ delete process . env . npm_config_proxy
22
+ delete process . env . npm_config_http_proxy
23
+ delete process . env . npm_config_https_proxy
24
+ delete process . env . npm_config_no_proxy
25
+ } )
26
+
27
+ afterEach ( ( ) => {
28
+ // Restore original environment
29
+ process . env = originalEnv
30
+ } )
31
+
32
+ describe ( "getProxyForUrl" , ( ) => {
33
+ describe ( "basic proxy resolution" , ( ) => {
34
+ it ( "should return proxy when httpProxy parameter is provided" , ( ) => {
35
+ const result = getProxyForUrl (
36
+ "http://example.com" ,
37
+ "http://proxy.example.com:8080" ,
38
+ undefined
39
+ )
40
+ expect ( result ) . toBe ( "http://proxy.example.com:8080" )
41
+ } )
42
+
43
+ it ( "should return empty string when no proxy is configured" , ( ) => {
44
+ const result = getProxyForUrl ( "http://example.com" , undefined , undefined )
45
+ expect ( result ) . toBe ( "" )
46
+ } )
47
+
48
+ it ( "should use environment variable when httpProxy parameter is not provided" , ( ) => {
49
+ process . env . http_proxy = "http://env-proxy.example.com:8080"
50
+
51
+ const result = getProxyForUrl ( "http://example.com" , undefined , undefined )
52
+ expect ( result ) . toBe ( "http://env-proxy.example.com:8080" )
53
+ } )
54
+
55
+ it ( "should prefer httpProxy parameter over environment variables" , ( ) => {
56
+ process . env . http_proxy = "http://env-proxy.example.com:8080"
57
+
58
+ const result = getProxyForUrl (
59
+ "http://example.com" ,
60
+ "http://param-proxy.example.com:8080" ,
61
+ undefined
62
+ )
63
+ expect ( result ) . toBe ( "http://param-proxy.example.com:8080" )
64
+ } )
65
+ } )
66
+
67
+ describe ( "protocol-specific proxy resolution" , ( ) => {
68
+ it ( "should use http_proxy for HTTP URLs" , ( ) => {
69
+ process . env . http_proxy = "http://http-proxy.example.com:8080"
70
+ process . env . https_proxy = "http://https-proxy.example.com:8080"
71
+
72
+ const result = getProxyForUrl ( "http://example.com" , undefined , undefined )
73
+ expect ( result ) . toBe ( "http://http-proxy.example.com:8080" )
74
+ } )
75
+
76
+ it ( "should use https_proxy for HTTPS URLs" , ( ) => {
77
+ process . env . http_proxy = "http://http-proxy.example.com:8080"
78
+ process . env . https_proxy = "http://https-proxy.example.com:8080"
79
+
80
+ const result = getProxyForUrl ( "https://example.com" , undefined , undefined )
81
+ expect ( result ) . toBe ( "http://https-proxy.example.com:8080" )
82
+ } )
83
+
84
+ it ( "should use ftp_proxy for FTP URLs" , ( ) => {
85
+ process . env . ftp_proxy = "http://ftp-proxy.example.com:8080"
86
+
87
+ const result = getProxyForUrl ( "ftp://example.com" , undefined , undefined )
88
+ expect ( result ) . toBe ( "http://ftp-proxy.example.com:8080" )
89
+ } )
90
+
91
+ it ( "should fall back to all_proxy when protocol-specific proxy is not set" , ( ) => {
92
+ process . env . all_proxy = "http://all-proxy.example.com:8080"
93
+
94
+ const result = getProxyForUrl ( "http://example.com" , undefined , undefined )
95
+ expect ( result ) . toBe ( "http://all-proxy.example.com:8080" )
96
+ } )
97
+ } )
98
+
99
+ describe ( "npm config proxy resolution" , ( ) => {
100
+ it ( "should use npm_config_http_proxy" , ( ) => {
101
+ process . env . npm_config_http_proxy = "http://npm-http-proxy.example.com:8080"
102
+
103
+ const result = getProxyForUrl ( "http://example.com" , undefined , undefined )
104
+ expect ( result ) . toBe ( "http://npm-http-proxy.example.com:8080" )
105
+ } )
106
+
107
+ it ( "should use npm_config_proxy as fallback" , ( ) => {
108
+ process . env . npm_config_proxy = "http://npm-proxy.example.com:8080"
109
+
110
+ const result = getProxyForUrl ( "http://example.com" , undefined , undefined )
111
+ expect ( result ) . toBe ( "http://npm-proxy.example.com:8080" )
112
+ } )
113
+
114
+ it ( "should prefer protocol-specific over npm_config_proxy" , ( ) => {
115
+ process . env . http_proxy = "http://http-proxy.example.com:8080"
116
+ process . env . npm_config_proxy = "http://npm-proxy.example.com:8080"
117
+
118
+ const result = getProxyForUrl ( "http://example.com" , undefined , undefined )
119
+ expect ( result ) . toBe ( "http://http-proxy.example.com:8080" )
120
+ } )
121
+ } )
122
+
123
+ describe ( "proxy URL normalization" , ( ) => {
124
+ it ( "should add protocol scheme when missing" , ( ) => {
125
+ const result = getProxyForUrl (
126
+ "http://example.com" ,
127
+ "proxy.example.com:8080" ,
128
+ undefined
129
+ )
130
+ expect ( result ) . toBe ( "http://proxy.example.com:8080" )
131
+ } )
132
+
133
+ it ( "should not modify proxy URL when scheme is present" , ( ) => {
134
+ const result = getProxyForUrl (
135
+ "http://example.com" ,
136
+ "https://proxy.example.com:8080" ,
137
+ undefined
138
+ )
139
+ expect ( result ) . toBe ( "https://proxy.example.com:8080" )
140
+ } )
141
+
142
+ it ( "should use target URL protocol for missing scheme" , ( ) => {
143
+ const result = getProxyForUrl (
144
+ "https://example.com" ,
145
+ "proxy.example.com:8080" ,
146
+ undefined
147
+ )
148
+ expect ( result ) . toBe ( "https://proxy.example.com:8080" )
149
+ } )
150
+ } )
151
+
152
+ describe ( "NO_PROXY handling" , ( ) => {
153
+ it ( "should not proxy when host is in noProxy parameter" , ( ) => {
154
+ const result = getProxyForUrl (
155
+ "http://example.com" ,
156
+ "http://proxy.example.com:8080" ,
157
+ "example.com"
158
+ )
159
+ expect ( result ) . toBe ( "" )
160
+ } )
161
+
162
+ it ( "should not proxy when host is in NO_PROXY environment variable" , ( ) => {
163
+ process . env . NO_PROXY = "example.com"
164
+
165
+ const result = getProxyForUrl (
166
+ "http://example.com" ,
167
+ "http://proxy.example.com:8080" ,
168
+ undefined
169
+ )
170
+ expect ( result ) . toBe ( "" )
171
+ } )
172
+
173
+ it ( "should prefer noProxy parameter over NO_PROXY environment" , ( ) => {
174
+ process . env . NO_PROXY = "other.com"
175
+
176
+ const result = getProxyForUrl (
177
+ "http://example.com" ,
178
+ "http://proxy.example.com:8080" ,
179
+ "example.com"
180
+ )
181
+ expect ( result ) . toBe ( "" )
182
+ } )
183
+
184
+ it ( "should handle wildcard NO_PROXY" , ( ) => {
185
+ const result = getProxyForUrl (
186
+ "http://example.com" ,
187
+ "http://proxy.example.com:8080" ,
188
+ "*"
189
+ )
190
+ expect ( result ) . toBe ( "" )
191
+ } )
192
+
193
+ it ( "should handle comma-separated NO_PROXY list" , ( ) => {
194
+ const result = getProxyForUrl (
195
+ "http://example.com" ,
196
+ "http://proxy.example.com:8080" ,
197
+ "other.com,example.com,another.com"
198
+ )
199
+ expect ( result ) . toBe ( "" )
200
+ } )
201
+
202
+ it ( "should handle space-separated NO_PROXY list" , ( ) => {
203
+ const result = getProxyForUrl (
204
+ "http://example.com" ,
205
+ "http://proxy.example.com:8080" ,
206
+ "other.com example.com another.com"
207
+ )
208
+ expect ( result ) . toBe ( "" )
209
+ } )
210
+
211
+ it ( "should handle wildcard subdomain matching" , ( ) => {
212
+ const result = getProxyForUrl (
213
+ "http://sub.example.com" ,
214
+ "http://proxy.example.com:8080" ,
215
+ "*.example.com"
216
+ )
217
+ expect ( result ) . toBe ( "" )
218
+ } )
219
+
220
+ it ( "should handle domain suffix matching" , ( ) => {
221
+ const result = getProxyForUrl (
222
+ "http://sub.example.com" ,
223
+ "http://proxy.example.com:8080" ,
224
+ ".example.com"
225
+ )
226
+ expect ( result ) . toBe ( "" )
227
+ } )
228
+
229
+ it ( "should match port-specific NO_PROXY rules" , ( ) => {
230
+ const result = getProxyForUrl (
231
+ "http://example.com:8080" ,
232
+ "http://proxy.example.com:8080" ,
233
+ "example.com:8080"
234
+ )
235
+ expect ( result ) . toBe ( "" )
236
+ } )
237
+
238
+ it ( "should not match when ports differ in NO_PROXY rule" , ( ) => {
239
+ const result = getProxyForUrl (
240
+ "http://example.com:8080" ,
241
+ "http://proxy.example.com:8080" ,
242
+ "example.com:9090"
243
+ )
244
+ expect ( result ) . toBe ( "http://proxy.example.com:8080" )
245
+ } )
246
+
247
+ it ( "should handle case-insensitive NO_PROXY matching" , ( ) => {
248
+ const result = getProxyForUrl (
249
+ "http://EXAMPLE.COM" ,
250
+ "http://proxy.example.com:8080" ,
251
+ "example.com"
252
+ )
253
+ expect ( result ) . toBe ( "" )
254
+ } )
255
+ } )
256
+
257
+ describe ( "default ports" , ( ) => {
258
+ it ( "should use default HTTP port 80" , ( ) => {
259
+ const result = getProxyForUrl (
260
+ "http://example.com" ,
261
+ "http://proxy.example.com:8080" ,
262
+ "example.com:80"
263
+ )
264
+ expect ( result ) . toBe ( "" )
265
+ } )
266
+
267
+ it ( "should use default HTTPS port 443" , ( ) => {
268
+ const result = getProxyForUrl (
269
+ "https://example.com" ,
270
+ "http://proxy.example.com:8080" ,
271
+ "example.com:443"
272
+ )
273
+ expect ( result ) . toBe ( "" )
274
+ } )
275
+
276
+ it ( "should use default FTP port 21" , ( ) => {
277
+ const result = getProxyForUrl (
278
+ "ftp://example.com" ,
279
+ "http://proxy.example.com:8080" ,
280
+ "example.com:21"
281
+ )
282
+ expect ( result ) . toBe ( "" )
283
+ } )
284
+
285
+ it ( "should use default WebSocket port 80" , ( ) => {
286
+ const result = getProxyForUrl (
287
+ "ws://example.com" ,
288
+ "http://proxy.example.com:8080" ,
289
+ "example.com:80"
290
+ )
291
+ expect ( result ) . toBe ( "" )
292
+ } )
293
+
294
+ it ( "should use default secure WebSocket port 443" , ( ) => {
295
+ const result = getProxyForUrl (
296
+ "wss://example.com" ,
297
+ "http://proxy.example.com:8080" ,
298
+ "example.com:443"
299
+ )
300
+ expect ( result ) . toBe ( "" )
301
+ } )
302
+ } )
303
+
304
+ describe ( "edge cases" , ( ) => {
305
+ it ( "should return empty string for URLs without protocol" , ( ) => {
306
+ const result = getProxyForUrl (
307
+ "example.com" ,
308
+ "http://proxy.example.com:8080" ,
309
+ undefined
310
+ )
311
+ expect ( result ) . toBe ( "" )
312
+ } )
313
+
314
+ it ( "should return empty string for URLs without hostname" , ( ) => {
315
+ const result = getProxyForUrl (
316
+ "http://" ,
317
+ "http://proxy.example.com:8080" ,
318
+ undefined
319
+ )
320
+ expect ( result ) . toBe ( "" )
321
+ } )
322
+
323
+ it ( "should handle IPv6 addresses" , ( ) => {
324
+ const result = getProxyForUrl (
325
+ "http://[2001:db8::1]:8080" ,
326
+ "http://proxy.example.com:8080" ,
327
+ undefined
328
+ )
329
+ expect ( result ) . toBe ( "http://proxy.example.com:8080" )
330
+ } )
331
+
332
+ it ( "should handle IPv6 addresses in NO_PROXY" , ( ) => {
333
+ const result = getProxyForUrl (
334
+ "http://[2001:db8::1]:8080" ,
335
+ "http://proxy.example.com:8080" ,
336
+ "[2001:db8::1]:8080"
337
+ )
338
+ expect ( result ) . toBe ( "" )
339
+ } )
340
+
341
+ it ( "should handle empty NO_PROXY entries" , ( ) => {
342
+ const result = getProxyForUrl (
343
+ "http://example.com" ,
344
+ "http://proxy.example.com:8080" ,
345
+ ",, example.com ,,"
346
+ )
347
+ expect ( result ) . toBe ( "" )
348
+ } )
349
+
350
+ it ( "should handle null proxy configuration" , ( ) => {
351
+ const result = getProxyForUrl ( "http://example.com" , null , null )
352
+ expect ( result ) . toBe ( "" )
353
+ } )
354
+
355
+ it ( "should be case-insensitive for environment variable names" , ( ) => {
356
+ process . env . HTTP_PROXY = "http://upper-proxy.example.com:8080"
357
+ process . env . http_proxy = "http://lower-proxy.example.com:8080"
358
+
359
+ // Should prefer lowercase
360
+ const result = getProxyForUrl ( "http://example.com" , undefined , undefined )
361
+ expect ( result ) . toBe ( "http://lower-proxy.example.com:8080" )
362
+ } )
363
+
364
+ it ( "should fall back to uppercase environment variables" , ( ) => {
365
+ process . env . HTTP_PROXY = "http://upper-proxy.example.com:8080"
366
+ // Don't set lowercase version
367
+
368
+ const result = getProxyForUrl ( "http://example.com" , undefined , undefined )
369
+ expect ( result ) . toBe ( "http://upper-proxy.example.com:8080" )
370
+ } )
371
+ } )
372
+ } )
373
+ } )
0 commit comments