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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy