Skip to content

Commit 01246a1

Browse files
jaggederestclaude
andcommitted
test: add comprehensive tests for proxy.ts
- Add 38 test cases covering all proxy resolution functionality - Test basic proxy resolution, protocol-specific handling, npm config - Test proxy URL normalization and NO_PROXY bypass logic - Test environment variable handling (case-insensitive) - Test default ports, IPv6 addresses, and edge cases - Achieve comprehensive coverage without memory issues 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent e638f58 commit 01246a1

File tree

1 file changed

+373
-0
lines changed

1 file changed

+373
-0
lines changed

src/proxy.test.ts

Lines changed: 373 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,373 @@
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

Comments
 (0)