@@ -4,8 +4,80 @@ import {
44 validateDomainOrPattern ,
55 parseDomainList ,
66 isDomainMatchedByPattern ,
7+ parseDomainWithProtocol ,
78} from './domain-patterns' ;
89
10+ describe ( 'parseDomainWithProtocol' , ( ) => {
11+ it ( 'should parse domain without protocol as "both"' , ( ) => {
12+ expect ( parseDomainWithProtocol ( 'github.com' ) ) . toEqual ( {
13+ domain : 'github.com' ,
14+ protocol : 'both' ,
15+ } ) ;
16+ } ) ;
17+
18+ it ( 'should parse http:// prefix as "http"' , ( ) => {
19+ expect ( parseDomainWithProtocol ( 'http://github.com' ) ) . toEqual ( {
20+ domain : 'github.com' ,
21+ protocol : 'http' ,
22+ } ) ;
23+ } ) ;
24+
25+ it ( 'should parse https:// prefix as "https"' , ( ) => {
26+ expect ( parseDomainWithProtocol ( 'https://github.com' ) ) . toEqual ( {
27+ domain : 'github.com' ,
28+ protocol : 'https' ,
29+ } ) ;
30+ } ) ;
31+
32+ it ( 'should strip trailing slash' , ( ) => {
33+ expect ( parseDomainWithProtocol ( 'github.com/' ) ) . toEqual ( {
34+ domain : 'github.com' ,
35+ protocol : 'both' ,
36+ } ) ;
37+ expect ( parseDomainWithProtocol ( 'http://github.com/' ) ) . toEqual ( {
38+ domain : 'github.com' ,
39+ protocol : 'http' ,
40+ } ) ;
41+ expect ( parseDomainWithProtocol ( 'https://github.com/' ) ) . toEqual ( {
42+ domain : 'github.com' ,
43+ protocol : 'https' ,
44+ } ) ;
45+ } ) ;
46+
47+ it ( 'should trim whitespace' , ( ) => {
48+ expect ( parseDomainWithProtocol ( ' github.com ' ) ) . toEqual ( {
49+ domain : 'github.com' ,
50+ protocol : 'both' ,
51+ } ) ;
52+ expect ( parseDomainWithProtocol ( ' http://github.com ' ) ) . toEqual ( {
53+ domain : 'github.com' ,
54+ protocol : 'http' ,
55+ } ) ;
56+ } ) ;
57+
58+ it ( 'should handle wildcard patterns with protocol' , ( ) => {
59+ expect ( parseDomainWithProtocol ( 'http://*.example.com' ) ) . toEqual ( {
60+ domain : '*.example.com' ,
61+ protocol : 'http' ,
62+ } ) ;
63+ expect ( parseDomainWithProtocol ( 'https://*.secure.com' ) ) . toEqual ( {
64+ domain : '*.secure.com' ,
65+ protocol : 'https' ,
66+ } ) ;
67+ } ) ;
68+
69+ it ( 'should handle subdomains with protocol' , ( ) => {
70+ expect ( parseDomainWithProtocol ( 'http://api.github.com' ) ) . toEqual ( {
71+ domain : 'api.github.com' ,
72+ protocol : 'http' ,
73+ } ) ;
74+ expect ( parseDomainWithProtocol ( 'https://secure.api.github.com' ) ) . toEqual ( {
75+ domain : 'secure.api.github.com' ,
76+ protocol : 'https' ,
77+ } ) ;
78+ } ) ;
79+ } ) ;
80+
981describe ( 'isWildcardPattern' , ( ) => {
1082 it ( 'should detect asterisk wildcard' , ( ) => {
1183 expect ( isWildcardPattern ( '*.github.com' ) ) . toBe ( true ) ;
@@ -156,14 +228,45 @@ describe('validateDomainOrPattern', () => {
156228 expect ( ( ) => validateDomainOrPattern ( '*.*.com' ) ) . toThrow ( "too many wildcard segments" ) ;
157229 } ) ;
158230 } ) ;
231+
232+ describe ( 'protocol-prefixed domains' , ( ) => {
233+ it ( 'should accept valid http:// prefixed domains' , ( ) => {
234+ expect ( ( ) => validateDomainOrPattern ( 'http://github.com' ) ) . not . toThrow ( ) ;
235+ expect ( ( ) => validateDomainOrPattern ( 'http://api.github.com' ) ) . not . toThrow ( ) ;
236+ } ) ;
237+
238+ it ( 'should accept valid https:// prefixed domains' , ( ) => {
239+ expect ( ( ) => validateDomainOrPattern ( 'https://github.com' ) ) . not . toThrow ( ) ;
240+ expect ( ( ) => validateDomainOrPattern ( 'https://secure.example.com' ) ) . not . toThrow ( ) ;
241+ } ) ;
242+
243+ it ( 'should accept protocol-prefixed wildcard patterns' , ( ) => {
244+ expect ( ( ) => validateDomainOrPattern ( 'http://*.example.com' ) ) . not . toThrow ( ) ;
245+ expect ( ( ) => validateDomainOrPattern ( 'https://*.secure.com' ) ) . not . toThrow ( ) ;
246+ } ) ;
247+
248+ it ( 'should reject protocol prefix with empty domain' , ( ) => {
249+ expect ( ( ) => validateDomainOrPattern ( 'http://' ) ) . toThrow ( 'cannot be empty' ) ;
250+ expect ( ( ) => validateDomainOrPattern ( 'https://' ) ) . toThrow ( 'cannot be empty' ) ;
251+ } ) ;
252+
253+ it ( 'should reject overly broad patterns even with protocol prefix' , ( ) => {
254+ expect ( ( ) => validateDomainOrPattern ( 'http://*' ) ) . toThrow ( "matches all domains" ) ;
255+ expect ( ( ) => validateDomainOrPattern ( 'https://*.*' ) ) . toThrow ( "too broad" ) ;
256+ } ) ;
257+ } ) ;
159258} ) ;
160259
161260describe ( 'parseDomainList' , ( ) => {
162261 it ( 'should separate plain domains from patterns' , ( ) => {
163262 const result = parseDomainList ( [ 'github.com' , '*.gitlab.com' , 'example.com' ] ) ;
164- expect ( result . plainDomains ) . toEqual ( [ 'github.com' , 'example.com' ] ) ;
263+ expect ( result . plainDomains ) . toEqual ( [
264+ { domain : 'github.com' , protocol : 'both' } ,
265+ { domain : 'example.com' , protocol : 'both' } ,
266+ ] ) ;
165267 expect ( result . patterns ) . toHaveLength ( 1 ) ;
166268 expect ( result . patterns [ 0 ] . original ) . toBe ( '*.gitlab.com' ) ;
269+ expect ( result . patterns [ 0 ] . protocol ) . toBe ( 'both' ) ;
167270 } ) ;
168271
169272 it ( 'should convert patterns to regex' , ( ) => {
@@ -173,7 +276,11 @@ describe('parseDomainList', () => {
173276
174277 it ( 'should handle all plain domains' , ( ) => {
175278 const result = parseDomainList ( [ 'github.com' , 'gitlab.com' , 'example.com' ] ) ;
176- expect ( result . plainDomains ) . toEqual ( [ 'github.com' , 'gitlab.com' , 'example.com' ] ) ;
279+ expect ( result . plainDomains ) . toEqual ( [
280+ { domain : 'github.com' , protocol : 'both' } ,
281+ { domain : 'gitlab.com' , protocol : 'both' } ,
282+ { domain : 'example.com' , protocol : 'both' } ,
283+ ] ) ;
177284 expect ( result . patterns ) . toHaveLength ( 0 ) ;
178285 } ) ;
179286
@@ -193,46 +300,118 @@ describe('parseDomainList', () => {
193300 expect ( result . plainDomains ) . toHaveLength ( 0 ) ;
194301 expect ( result . patterns ) . toHaveLength ( 0 ) ;
195302 } ) ;
303+
304+ describe ( 'protocol parsing' , ( ) => {
305+ it ( 'should parse http:// prefix as http protocol' , ( ) => {
306+ const result = parseDomainList ( [ 'http://github.com' ] ) ;
307+ expect ( result . plainDomains ) . toEqual ( [
308+ { domain : 'github.com' , protocol : 'http' } ,
309+ ] ) ;
310+ } ) ;
311+
312+ it ( 'should parse https:// prefix as https protocol' , ( ) => {
313+ const result = parseDomainList ( [ 'https://github.com' ] ) ;
314+ expect ( result . plainDomains ) . toEqual ( [
315+ { domain : 'github.com' , protocol : 'https' } ,
316+ ] ) ;
317+ } ) ;
318+
319+ it ( 'should handle mixed protocols' , ( ) => {
320+ const result = parseDomainList ( [ 'http://api.example.com' , 'https://secure.example.com' , 'example.com' ] ) ;
321+ expect ( result . plainDomains ) . toEqual ( [
322+ { domain : 'api.example.com' , protocol : 'http' } ,
323+ { domain : 'secure.example.com' , protocol : 'https' } ,
324+ { domain : 'example.com' , protocol : 'both' } ,
325+ ] ) ;
326+ } ) ;
327+
328+ it ( 'should handle protocol-prefixed wildcard patterns' , ( ) => {
329+ const result = parseDomainList ( [ 'http://*.example.com' , 'https://*.secure.com' ] ) ;
330+ expect ( result . patterns ) . toEqual ( [
331+ { original : '*.example.com' , regex : '^.*\\.example\\.com$' , protocol : 'http' } ,
332+ { original : '*.secure.com' , regex : '^.*\\.secure\\.com$' , protocol : 'https' } ,
333+ ] ) ;
334+ } ) ;
335+
336+ it ( 'should strip trailing slash after protocol' , ( ) => {
337+ const result = parseDomainList ( [ 'http://github.com/' , 'https://example.com/' ] ) ;
338+ expect ( result . plainDomains ) . toEqual ( [
339+ { domain : 'github.com' , protocol : 'http' } ,
340+ { domain : 'example.com' , protocol : 'https' } ,
341+ ] ) ;
342+ } ) ;
343+ } ) ;
196344} ) ;
197345
198346describe ( 'isDomainMatchedByPattern' , ( ) => {
199347 it ( 'should match domain against leading wildcard' , ( ) => {
200- const patterns = [ { original : '*.github.com' , regex : '^.*\\.github\\.com$' } ] ;
201- expect ( isDomainMatchedByPattern ( 'api.github.com' , patterns ) ) . toBe ( true ) ;
202- expect ( isDomainMatchedByPattern ( 'raw.github.com' , patterns ) ) . toBe ( true ) ;
348+ const patterns = [ { original : '*.github.com' , regex : '^.*\\.github\\.com$' , protocol : 'both' as const } ] ;
349+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'both' } , patterns ) ) . toBe ( true ) ;
350+ expect ( isDomainMatchedByPattern ( { domain : 'raw.github.com' , protocol : 'both' } , patterns ) ) . toBe ( true ) ;
203351 } ) ;
204352
205353 it ( 'should not match domain that does not fit pattern' , ( ) => {
206- const patterns = [ { original : '*.github.com' , regex : '^.*\\.github\\.com$' } ] ;
207- expect ( isDomainMatchedByPattern ( 'github.com' , patterns ) ) . toBe ( false ) ;
208- expect ( isDomainMatchedByPattern ( 'gitlab.com' , patterns ) ) . toBe ( false ) ;
209- expect ( isDomainMatchedByPattern ( 'notgithub.com' , patterns ) ) . toBe ( false ) ;
354+ const patterns = [ { original : '*.github.com' , regex : '^.*\\.github\\.com$' , protocol : 'both' as const } ] ;
355+ expect ( isDomainMatchedByPattern ( { domain : 'github.com' , protocol : 'both' } , patterns ) ) . toBe ( false ) ;
356+ expect ( isDomainMatchedByPattern ( { domain : 'gitlab.com' , protocol : 'both' } , patterns ) ) . toBe ( false ) ;
357+ expect ( isDomainMatchedByPattern ( { domain : 'notgithub.com' , protocol : 'both' } , patterns ) ) . toBe ( false ) ;
210358 } ) ;
211359
212360 it ( 'should match against middle wildcard' , ( ) => {
213- const patterns = [ { original : 'api-*.example.com' , regex : '^api-.*\\.example\\.com$' } ] ;
214- expect ( isDomainMatchedByPattern ( 'api-v1.example.com' , patterns ) ) . toBe ( true ) ;
215- expect ( isDomainMatchedByPattern ( 'api-test.example.com' , patterns ) ) . toBe ( true ) ;
216- expect ( isDomainMatchedByPattern ( 'api.example.com' , patterns ) ) . toBe ( false ) ;
361+ const patterns = [ { original : 'api-*.example.com' , regex : '^api-.*\\.example\\.com$' , protocol : 'both' as const } ] ;
362+ expect ( isDomainMatchedByPattern ( { domain : 'api-v1.example.com' , protocol : 'both' } , patterns ) ) . toBe ( true ) ;
363+ expect ( isDomainMatchedByPattern ( { domain : 'api-test.example.com' , protocol : 'both' } , patterns ) ) . toBe ( true ) ;
364+ expect ( isDomainMatchedByPattern ( { domain : 'api.example.com' , protocol : 'both' } , patterns ) ) . toBe ( false ) ;
217365 } ) ;
218366
219367 it ( 'should match against any pattern in list' , ( ) => {
220368 const patterns = [
221- { original : '*.github.com' , regex : '^.*\\.github\\.com$' } ,
222- { original : '*.gitlab.com' , regex : '^.*\\.gitlab\\.com$' } ,
369+ { original : '*.github.com' , regex : '^.*\\.github\\.com$' , protocol : 'both' as const } ,
370+ { original : '*.gitlab.com' , regex : '^.*\\.gitlab\\.com$' , protocol : 'both' as const } ,
223371 ] ;
224- expect ( isDomainMatchedByPattern ( 'api.github.com' , patterns ) ) . toBe ( true ) ;
225- expect ( isDomainMatchedByPattern ( 'api.gitlab.com' , patterns ) ) . toBe ( true ) ;
226- expect ( isDomainMatchedByPattern ( 'api.bitbucket.com' , patterns ) ) . toBe ( false ) ;
372+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'both' } , patterns ) ) . toBe ( true ) ;
373+ expect ( isDomainMatchedByPattern ( { domain : 'api.gitlab.com' , protocol : 'both' } , patterns ) ) . toBe ( true ) ;
374+ expect ( isDomainMatchedByPattern ( { domain : 'api.bitbucket.com' , protocol : 'both' } , patterns ) ) . toBe ( false ) ;
227375 } ) ;
228376
229377 it ( 'should be case-insensitive' , ( ) => {
230- const patterns = [ { original : '*.GitHub.com' , regex : '^.*\\.GitHub\\.com$' } ] ;
231- expect ( isDomainMatchedByPattern ( 'API.GITHUB.COM' , patterns ) ) . toBe ( true ) ;
232- expect ( isDomainMatchedByPattern ( 'api.github.com' , patterns ) ) . toBe ( true ) ;
378+ const patterns = [ { original : '*.GitHub.com' , regex : '^.*\\.GitHub\\.com$' , protocol : 'both' as const } ] ;
379+ expect ( isDomainMatchedByPattern ( { domain : 'API.GITHUB.COM' , protocol : 'both' } , patterns ) ) . toBe ( true ) ;
380+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'both' } , patterns ) ) . toBe ( true ) ;
233381 } ) ;
234382
235383 it ( 'should return false for empty pattern list' , ( ) => {
236- expect ( isDomainMatchedByPattern ( 'api.github.com' , [ ] ) ) . toBe ( false ) ;
384+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'both' } , [ ] ) ) . toBe ( false ) ;
385+ } ) ;
386+
387+ describe ( 'protocol compatibility' , ( ) => {
388+ it ( 'should match when pattern has "both" protocol' , ( ) => {
389+ const patterns = [ { original : '*.github.com' , regex : '^.*\\.github\\.com$' , protocol : 'both' as const } ] ;
390+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'http' } , patterns ) ) . toBe ( true ) ;
391+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'https' } , patterns ) ) . toBe ( true ) ;
392+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'both' } , patterns ) ) . toBe ( true ) ;
393+ } ) ;
394+
395+ it ( 'should not fully cover "both" domain with single protocol pattern' , ( ) => {
396+ const httpPatterns = [ { original : '*.github.com' , regex : '^.*\\.github\\.com$' , protocol : 'http' as const } ] ;
397+ const httpsPatterns = [ { original : '*.github.com' , regex : '^.*\\.github\\.com$' , protocol : 'https' as const } ] ;
398+ // A domain that needs "both" cannot be fully covered by a single-protocol pattern
399+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'both' } , httpPatterns ) ) . toBe ( false ) ;
400+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'both' } , httpsPatterns ) ) . toBe ( false ) ;
401+ } ) ;
402+
403+ it ( 'should match when protocols match exactly' , ( ) => {
404+ const httpPatterns = [ { original : '*.github.com' , regex : '^.*\\.github\\.com$' , protocol : 'http' as const } ] ;
405+ const httpsPatterns = [ { original : '*.github.com' , regex : '^.*\\.github\\.com$' , protocol : 'https' as const } ] ;
406+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'http' } , httpPatterns ) ) . toBe ( true ) ;
407+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'https' } , httpsPatterns ) ) . toBe ( true ) ;
408+ } ) ;
409+
410+ it ( 'should not match when protocols do not match' , ( ) => {
411+ const httpPatterns = [ { original : '*.github.com' , regex : '^.*\\.github\\.com$' , protocol : 'http' as const } ] ;
412+ const httpsPatterns = [ { original : '*.github.com' , regex : '^.*\\.github\\.com$' , protocol : 'https' as const } ] ;
413+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'https' } , httpPatterns ) ) . toBe ( false ) ;
414+ expect ( isDomainMatchedByPattern ( { domain : 'api.github.com' , protocol : 'http' } , httpsPatterns ) ) . toBe ( false ) ;
415+ } ) ;
237416 } ) ;
238417} ) ;
0 commit comments