1 import type { Item } from '@proton/pass/types';
3 import { ItemUrlMatch, getItemPriorityForUrl } from './match-url';
5 const createMockItem = (urls: string[]) => ({ type: 'login', content: { urls } }) as unknown as Item<'login'>;
6 const filter = { protocol: null, port: null, isPrivate: false };
8 describe('match url', () => {
9 describe('`getItemPriorityForUrl`', () => {
10 test('should return `NO_MATCH` if domains do not match', () => {
11 const item = createMockItem(['https://proton.ch']);
12 const result = getItemPriorityForUrl(item)('pm.me', filter);
13 expect(result).toBe(ItemUrlMatch.NO_MATCH);
16 test('should return `NO_MATCH` if item has no urls', () => {
17 const item = createMockItem([]);
18 const result = getItemPriorityForUrl(item)('pm.me', filter);
19 expect(result).toBe(ItemUrlMatch.NO_MATCH);
22 test('should return `NO_MATCH` if empty domain & item has no urls', () => {
23 const item = createMockItem([]);
24 const result = getItemPriorityForUrl(item)('', filter);
25 expect(result).toBe(ItemUrlMatch.NO_MATCH);
28 test('should return `NO_MATCH` if item URL is a non-valid substring of domain', () => {
29 const item1 = createMockItem(['https://pproton.ch']);
30 const result1 = getItemPriorityForUrl(item1)('proton.ch', filter);
31 expect(result1).toBe(ItemUrlMatch.NO_MATCH);
33 const item2 = createMockItem(['https://p.pproton.ch']);
34 const result2 = getItemPriorityForUrl(item2)('proton.ch', filter);
35 expect(result2).toBe(ItemUrlMatch.NO_MATCH);
38 test('should return `NO_MATCH` if protocols differ', () => {
39 const item1 = createMockItem(['https://proton.ch']);
40 const result1 = getItemPriorityForUrl(item1)('proton.ch', { ...filter, protocol: 'http:' });
41 expect(result1).toBe(ItemUrlMatch.NO_MATCH);
43 const item2 = createMockItem(['ftp://proton.ch']);
44 const result2 = getItemPriorityForUrl(item2)('proton.ch', { ...filter, protocol: 'https:' });
45 expect(result2).toBe(ItemUrlMatch.NO_MATCH);
47 const item3 = createMockItem(['ftp://sub.proton.ch']);
48 const result3 = getItemPriorityForUrl(item3)('proton.ch', { ...filter, protocol: 'https:' });
49 expect(result3).toBe(ItemUrlMatch.NO_MATCH);
52 test('should return `NO_MATCH` if ports differ', () => {
53 const item1 = createMockItem(['https://proton.ch:3002']);
54 const result1 = getItemPriorityForUrl(item1)('proton.ch', { ...filter, port: '3001' });
55 expect(result1).toBe(ItemUrlMatch.NO_MATCH);
57 const item2 = createMockItem(['ftp://proton.ch:3002']);
58 const result2 = getItemPriorityForUrl(item2)('proton.ch', { ...filter, port: '3001' });
59 expect(result2).toBe(ItemUrlMatch.NO_MATCH);
61 const item3 = createMockItem(['ftp://sub.proton.ch:3002']);
62 const result3 = getItemPriorityForUrl(item3)('proton.ch', { ...filter, port: '3001' });
63 expect(result3).toBe(ItemUrlMatch.NO_MATCH);
66 test('should return `NO_MATCH` if deeper private subdomain', () => {
67 const item = createMockItem(['https://a.b.c.me']);
68 const result = getItemPriorityForUrl(item)('b.c.me', { ...filter, isPrivate: true });
69 expect(result).toBe(ItemUrlMatch.NO_MATCH);
72 test('should return `NO_MATCH` on invalid item URLs', () => {
73 const item1 = createMockItem(['https::/proton.ch']);
74 const item2 = createMockItem([',,,,/proton.ch', ' ']);
75 const item3 = createMockItem(['', 'https://proton.me']);
77 expect(getItemPriorityForUrl(item1)('proton.ch', filter)).toBe(ItemUrlMatch.NO_MATCH);
78 expect(getItemPriorityForUrl(item2)('proton.ch', filter)).toBe(ItemUrlMatch.NO_MATCH);
79 expect(getItemPriorityForUrl(item3)('proton.ch', filter)).toBe(ItemUrlMatch.NO_MATCH);
82 test('should return `NO_MATCH` for non exact matches in strict mode', () => {
83 const item1 = createMockItem(['https://example.com']);
84 const result1 = getItemPriorityForUrl(item1)('b.example.com', { ...filter, strict: true });
85 expect(result1).toBe(ItemUrlMatch.NO_MATCH);
87 const item2 = createMockItem(['https://a.b.example.com']);
88 const result2 = getItemPriorityForUrl(item2)('b.example.com', { ...filter, strict: true });
89 expect(result2).toBe(ItemUrlMatch.NO_MATCH);
91 const item3 = createMockItem(['https://a.example.com']);
92 const result3 = getItemPriorityForUrl(item3)('b.example.com', { ...filter, strict: true });
93 expect(result3).toBe(ItemUrlMatch.NO_MATCH);
95 const item4 = createMockItem(['https://sub.example.com']);
96 const result4 = getItemPriorityForUrl(item4)('b.example.com', { ...filter, strict: true });
97 expect(result4).toBe(ItemUrlMatch.NO_MATCH);
100 test('should return `SUB_MATCH` on subdomain match', () => {
101 const item1 = createMockItem(['https://subdomain.pm.me']);
102 const result1 = getItemPriorityForUrl(item1)('pm.me', filter);
103 expect(result1).toBe(ItemUrlMatch.SUB_MATCH);
105 const item2 = createMockItem(['http://nested.subdomain.pm.me']);
106 const result2 = getItemPriorityForUrl(item2)('subdomain.pm.me', filter);
107 expect(result2).toBe(ItemUrlMatch.SUB_MATCH);
110 test('should return `SUB_MATCH` on subdomain accounting for protocol', () => {
111 const item = createMockItem(['http://sub.proton.ch']);
112 const result = getItemPriorityForUrl(item)('proton.ch', { ...filter, protocol: 'http:' });
113 expect(result).toBe(ItemUrlMatch.SUB_MATCH);
116 test('should return `SUB_MATCH` on subdomain accounting for port', () => {
117 const item = createMockItem(['http://sub.proton.ch:3001']);
118 const result = getItemPriorityForUrl(item)('proton.ch', { ...filter, port: '3001' });
119 expect(result).toBe(ItemUrlMatch.SUB_MATCH);
122 test('should return `SUB_MATCH` on subdomain with port if no port filter', () => {
123 const item = createMockItem(['http://sub.proton.ch:3001']);
124 const result = getItemPriorityForUrl(item)('proton.ch', filter);
125 expect(result).toBe(ItemUrlMatch.SUB_MATCH);
128 test('should return `SUB_MATCH` on deeper non-private subdomain matches', () => {
129 const item1 = createMockItem(['https://a.b.c.me']);
130 const result1 = getItemPriorityForUrl(item1)('a.b.c.me', filter);
131 expect(result1).toBe(ItemUrlMatch.SUB_MATCH);
133 const item2 = createMockItem(['https://a.b.c.me']);
134 const result2 = getItemPriorityForUrl(item2)('b.c.me', filter);
135 expect(result2).toBe(ItemUrlMatch.SUB_MATCH);
138 test('should return `SUB_MATCH` on subdomain with query parameters', () => {
139 const item = createMockItem(['https://sub.example.com/path?query=param']);
140 const result = getItemPriorityForUrl(item)('example.com', filter);
141 expect(result).toBe(ItemUrlMatch.SUB_MATCH);
144 test('should return `SUB_MATCH` on exact subdomain in strict mode', () => {
145 const item = createMockItem(['https://example.com', 'https://a.example.com']);
146 const result = getItemPriorityForUrl(item)('a.example.com', { ...filter, strict: true });
147 expect(result).toBe(ItemUrlMatch.SUB_MATCH);
150 test('should return `TOP_MATCH` on top-level domain match', () => {
151 const item1 = createMockItem(['https://pm.me']);
152 const result1 = getItemPriorityForUrl(item1)('pm.me', filter);
153 expect(result1).toBe(ItemUrlMatch.TOP_MATCH);
155 const item2 = createMockItem(['nomatch', 'https://proton.ch']);
156 const result2 = getItemPriorityForUrl(item2)('proton.ch', filter);
157 expect(result2).toBe(ItemUrlMatch.TOP_MATCH);
160 test('should return `TOP_MATCH` on top-level domain accounting for protocol', () => {
161 const item = createMockItem(['ftp://proton.ch']);
162 const result = getItemPriorityForUrl(item)('proton.ch', { ...filter, protocol: 'ftp:' });
163 expect(result).toBe(ItemUrlMatch.TOP_MATCH);
166 test('should return `TOP_MATCH` on top-level domain accounting for port', () => {
167 const item = createMockItem(['http://proton.ch:3001']);
168 const result = getItemPriorityForUrl(item)('proton.ch', { ...filter, port: '3001' });
169 expect(result).toBe(ItemUrlMatch.TOP_MATCH);
172 test('should return `TOP_MATCH` on url with port if no port filter', () => {
173 const item = createMockItem(['http://proton.ch:3001']);
174 const result = getItemPriorityForUrl(item)('proton.ch', filter);
175 expect(result).toBe(ItemUrlMatch.TOP_MATCH);
178 test('should return `TOP_MATCH` when matching by IP address', () => {
179 const item1 = createMockItem(['http://192.168.1.1']);
180 const result1 = getItemPriorityForUrl(item1)('192.168.1.1', filter);
181 expect(result1).toBe(ItemUrlMatch.TOP_MATCH);
183 const item2 = createMockItem(['https://192.168.1.1/path']);
184 const result2 = getItemPriorityForUrl(item2)('192.168.1.1', filter);
185 expect(result2).toBe(ItemUrlMatch.TOP_MATCH);
188 test('should return `TOP_MATCH` on top-level domain with query parameters', () => {
189 const item = createMockItem(['https://example.com/path?query=param']);
190 const result = getItemPriorityForUrl(item)('example.com', filter);
191 expect(result).toBe(ItemUrlMatch.TOP_MATCH);
194 test('should return `TOP_MATCH` on exact domain in strict mode', () => {
195 const item1 = createMockItem(['https://example.com']);
196 const result1 = getItemPriorityForUrl(item1)('example.com', { ...filter, strict: true });
197 expect(result1).toBe(ItemUrlMatch.TOP_MATCH);
199 const item2 = createMockItem(['https://sub.example.com', 'https://example.com']);
200 const result2 = getItemPriorityForUrl(item2)('example.com', { ...filter, strict: true });
201 expect(result2).toBe(ItemUrlMatch.TOP_MATCH);