Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / packages / shared / test / calendar / ics.spec.ts
blobf40e537d75fe7481b8b1ac15e77e2ff0ad443daa
1 import {
2     parseWithRecovery,
3     reformatDateTimes,
4     reformatLineBreaks,
5     unfoldLines,
6 } from '../../lib/calendar/icsSurgery/ics';
8 describe('reformatLineBreaks()', () => {
9     it('should reformat line breaks with RFC 7896 properties', () => {
10         const vcal = `BEGIN:VCALENDAR
11 VERSION:2.0
12 PRODID:-//Office Holidays Ltd.//EN
13 X-WR-CALNAME:United Kingdom Holidays
14 X-WR-CALDESC:Public Holidays in United Kingdom. Provided by http://www.officeholidays.com
15 REFRESH-INTERVAL;VALUE=DURATION:PT48H
16 X-PUBLISHED-TTL:PT48H
17 CALSCALE:GREGORIAN
18 METHOD:PUBLISH
19 X-MS-OLK-FORCEINSPECTOROPEN:TRUE
20 BEGIN:VEVENT
21 CLASS:PUBLIC
22 UID:2022-01-04GB-SCT1027lieuregion@www.officeholidays.com
23 CREATED:20220109T153551Z
24 DESCRIPTION: This additional days holiday for New Year in the UK is observed only in Scotland
25 \\n\\nScotland\\n\\nInformation provided by www.officeholidays.com
26 URL:https://www.officeholidays.com/holidays/united-kingdom/scotland/day-after-new-years-day
27 DTSTART;VALUE=DATE:20220104
28 DTEND;VALUE=DATE:20220105
29 DTSTAMP:20080101T000000Z
30 LOCATION:Scotland
31 PRIORITY:5
32 LAST-MODIFIED:20191229T000000Z
33 SEQUENCE:1
34 SUMMARY;LANGUAGE=en-us:Day after New Year's Day (in lieu) (Regional Holiday)
35 TRANSP:OPAQUE
36 X-MICROSOFT-CDO-BUSYSTATUS:BUSY
37 X-MICROSOFT-CDO-IMPORTANCE:1
38 X-MICROSOFT-DISALLOW-COUNTER:FALSE
39 X-MS-OLK-ALLOWEXTERNCHECK:TRUE
40 X-MS-OLK-AUTOFILLLOCATION:FALSE
41 X-MICROSOFT-CDO-ALLDAYEVENT:TRUE
42 X-MICROSOFT-MSNCALENDAR-ALLDAYEVENT:TRUE
43 X-MS-OLK-CONFTYPE:0
44 END:VEVENT
45 END:VCALENDAR`;
46         expect(reformatLineBreaks(vcal)).toEqual(`BEGIN:VCALENDAR
47 VERSION:2.0
48 PRODID:-//Office Holidays Ltd.//EN
49 X-WR-CALNAME:United Kingdom Holidays
50 X-WR-CALDESC:Public Holidays in United Kingdom. Provided by http://www.officeholidays.com
51 REFRESH-INTERVAL;VALUE=DURATION:PT48H
52 X-PUBLISHED-TTL:PT48H
53 CALSCALE:GREGORIAN
54 METHOD:PUBLISH
55 X-MS-OLK-FORCEINSPECTOROPEN:TRUE
56 BEGIN:VEVENT
57 CLASS:PUBLIC
58 UID:2022-01-04GB-SCT1027lieuregion@www.officeholidays.com
59 CREATED:20220109T153551Z
60 DESCRIPTION: This additional days holiday for New Year in the UK is observed only in Scotland
61  \\n\\nScotland\\n\\nInformation provided by www.officeholidays.com
62 URL:https://www.officeholidays.com/holidays/united-kingdom/scotland/day-after-new-years-day
63 DTSTART;VALUE=DATE:20220104
64 DTEND;VALUE=DATE:20220105
65 DTSTAMP:20080101T000000Z
66 LOCATION:Scotland
67 PRIORITY:5
68 LAST-MODIFIED:20191229T000000Z
69 SEQUENCE:1
70 SUMMARY;LANGUAGE=en-us:Day after New Year's Day (in lieu) (Regional Holiday)
71 TRANSP:OPAQUE
72 X-MICROSOFT-CDO-BUSYSTATUS:BUSY
73 X-MICROSOFT-CDO-IMPORTANCE:1
74 X-MICROSOFT-DISALLOW-COUNTER:FALSE
75 X-MS-OLK-ALLOWEXTERNCHECK:TRUE
76 X-MS-OLK-AUTOFILLLOCATION:FALSE
77 X-MICROSOFT-CDO-ALLDAYEVENT:TRUE
78 X-MICROSOFT-MSNCALENDAR-ALLDAYEVENT:TRUE
79 X-MS-OLK-CONFTYPE:0
80 END:VEVENT
81 END:VCALENDAR`);
82     });
83 });
85 describe('unfoldLines()', () => {
86     it('unfolds a properly folded ICS', () => {
87         expect(
88             unfoldLines(
89                 `BEGIN:VCALENDAR
90 VERSION:2.0
91 BEGIN:VEVENT
92 CLASS:PUBLIC
93 DESCRIPTION:Join us for a look at new product updates so you ca
94  n do more with your content and accelerate your workflows.
96  Hooray!
97 LOCATION:Multiple
98   lines
99 SUMMARY:The Drop: Fall Launch
100 TRANSP:TRANSPARENT
101 DTSTART:20221025T130000Z
102 DTEND:20221026T070000Z
103 URL:https://experience.dropbox.com/events-webinars/thedigitaldr
104  op-fall2022
105 END:VEVENT
106 END:VCALENDAR`,
107                 '\n'
108             )
109         ).toEqual(`BEGIN:VCALENDAR
110 VERSION:2.0
111 BEGIN:VEVENT
112 CLASS:PUBLIC
113 DESCRIPTION:Join us for a look at new product updates so you can do more with your content and accelerate your workflows.\nHooray!
114 LOCATION:Multiple lines
115 SUMMARY:The Drop: Fall Launch
116 TRANSP:TRANSPARENT
117 DTSTART:20221025T130000Z
118 DTEND:20221026T070000Z
119 URL:https://experience.dropbox.com/events-webinars/thedigitaldrop-fall2022
120 END:VEVENT
121 END:VCALENDAR`);
122     });
125 describe('reformatDateTimes()', () => {
126     it('reformats too short or too long DTSTAMP, DTSTART, DTEND, LAST-MODIFIED', () => {
127         expect(
128             reformatDateTimes(`BEGIN:VCALENDAR
129 VERSION:2.0
130 BEGIN:VEVENT
131 DTSTAMP:20221010T1200
132 DTSTART:20221111T13
133 DTEND:20221111T1430
134 LAST-MODIFIED:20221010T120049375Z
135 END:VEVENT
136 END:VCALENDAR`)
137         ).toEqual(`BEGIN:VCALENDAR
138 VERSION:2.0
139 BEGIN:VEVENT
140 DTSTAMP:20221010T120000
141 DTSTART:20221111T130000
142 DTEND:20221111T143000
143 LAST-MODIFIED:20221010T120049Z
144 END:VEVENT
145 END:VCALENDAR`);
146     });
148     it('reformats date-time properties with a time zone', () => {
149         expect(
150             reformatDateTimes(`BEGIN:VCALENDAR
151 VERSION:2.0
152 BEGIN:VEVENT
153 DTSTAMP;TZID=America/Guatemala:20221010T1200
154 END:VEVENT
155 END:VCALENDAR`)
156         ).toEqual(`BEGIN:VCALENDAR
157 VERSION:2.0
158 BEGIN:VEVENT
159 DTSTAMP;TZID=America/Guatemala:20221010T120000
160 END:VEVENT
161 END:VCALENDAR`);
162     });
164     it('reformats folded date-time properties', () => {
165         expect(
166             reformatDateTimes(`BEGIN:VCALENDAR
167 VERSION:2.0
168 BEGIN:VEVENT
169 DTEND;TZID==/mozilla.org/20050126_1/America/Guatemala:2022
170  1010T1200
171 END:VEVENT
172 END:VCALENDAR`)
173         ).toEqual(`BEGIN:VCALENDAR
174 VERSION:2.0
175 BEGIN:VEVENT
176 DTEND;TZID==/mozilla.org/20050126_1/America/Guatemala:20221010T120000
177 END:VEVENT
178 END:VCALENDAR`);
179     });
181     it('reformats untrimmed date-time properties', () => {
182         expect(
183             reformatDateTimes(`BEGIN:VCALENDAR
184 VERSION:2.0
185 BEGIN:VEVENT
186 DTSTART:20221010T1200
187 DTEND: 20221004T103000
188 END:VEVENT
189 END:VCALENDAR`)
190         ).toEqual(`BEGIN:VCALENDAR
191 VERSION:2.0
192 BEGIN:VEVENT
193 DTSTART:20221010T120000
194 DTEND:20221004T103000
195 END:VEVENT
196 END:VCALENDAR`);
197     });
199     it('reformats date-time properties with ISO format', () => {
200         expect(
201             reformatDateTimes(`BEGIN:VCALENDAR
202 VERSION:2.0
203 BEGIN:VEVENT
204 DTSTAMP:2022-09-02T23:59:59.999
205 DTSTART:2022-10-04T09:30:00.000Z
206 DTEND:2022-10-05T12:30:00.000ZZ
207 END:VEVENT
208 END:VCALENDAR`)
209         ).toEqual(`BEGIN:VCALENDAR
210 VERSION:2.0
211 BEGIN:VEVENT
212 DTSTAMP:20220902T235959
213 DTSTART:20221004T093000Z
214 DTEND:20221005T123000Z
215 END:VEVENT
216 END:VCALENDAR`);
217     });
219     it('reformats date-time properties with "Deutsche Bahn format"', () => {
220         expect(
221             reformatDateTimes(`BEGIN:VCALENDAR
222 VERSION:2.0
223 BEGIN:VEVENT
224 DTSTART;TZID=Europe/Berlin:2023-06-21T082400
225 DTEND;TZID=Europe/Berlin:2023-06-21T165400
226 DTSTAMP:2023-06-13T212500Z
227 END:VEVENT
228 END:VCALENDAR`)
229         ).toEqual(`BEGIN:VCALENDAR
230 VERSION:2.0
231 BEGIN:VEVENT
232 DTSTART;TZID=Europe/Berlin:20230621T082400
233 DTEND;TZID=Europe/Berlin:20230621T165400
234 DTSTAMP:20230613T212500Z
235 END:VEVENT
236 END:VCALENDAR`);
237     });
239     it('reformats date properties with "Deutsche Bahn format"', () => {
240         expect(
241             reformatDateTimes(`BEGIN:VCALENDAR
242 VERSION:2.0
243 BEGIN:VEVENT
244 DTSTART;VALUE=DATE:2023-06-21
245 DTEND;VALUE=DATE:2023-06-22
246 DTSTAMP:2023-06-13T212500Z
247 END:VEVENT
248 END:VCALENDAR`)
249         ).toEqual(`BEGIN:VCALENDAR
250 VERSION:2.0
251 BEGIN:VEVENT
252 DTSTART;VALUE=DATE:20230621
253 DTEND;VALUE=DATE:20230622
254 DTSTAMP:20230613T212500Z
255 END:VEVENT
256 END:VCALENDAR`);
257     });
259     it('reformats all-day date-time properties missing', () => {
260         expect(
261             reformatDateTimes(`BEGIN:VCALENDAR
262 VERSION:2.0
263 BEGIN:VEVENT
264 DTSTART:20221004
265 END:VEVENT
266 END:VCALENDAR`)
267         ).toEqual(`BEGIN:VCALENDAR
268 VERSION:2.0
269 BEGIN:VEVENT
270 DTSTART;VALUE=DATE:20221004
271 END:VEVENT
272 END:VCALENDAR`);
273     });
275     it('reformats date-time properties with uncapitalized markers', () => {
276         expect(
277             reformatDateTimes(`BEGIN:VCALENDAR
278 VERSION:2.0
279 BEGIN:VEVENT
280 DTSTAMP:20221004t155959z
281 DTSTART:20221004t155959
282 DTEND:2022-10-05t12:30:00.000zz
283 END:VEVENT
284 END:VCALENDAR`)
285         ).toEqual(`BEGIN:VCALENDAR
286 VERSION:2.0
287 BEGIN:VEVENT
288 DTSTAMP:20221004T155959Z
289 DTSTART:20221004T155959
290 DTEND:20221005T123000Z
291 END:VEVENT
292 END:VCALENDAR`);
293     });
296 describe('parseWithRecovery()', () => {
297     it('should parse vevent with bad enclosing and bad line breaks', () => {
298         const result = parseWithRecovery(`BEGIN:VCALENDAR
299 METHOD:REQUEST
300 PRODID:Microsoft Exchange Server 2010
301 VERSION:2.0
302 BEGIN:VEVENT
303 DTSTAMP:20190719T130854Z
304 UID:7E018059-2165-4170-B32F-6936E88E61E5
305 DTSTART;TZID=America/New_York:20190719T120000
306 DTEND;TZID=Europe/Zurich:20190719T130000
307 CATEGORIES:ANNIVERSARY,PERSONAL,SPECIAL OCCASION
308 SUMMARY:Our Blissful Anniversary
312 Wonderful!
313 LOCATION:A
315  secret
319 place
320 END:VEVENT`);
322         expect(result).toEqual({
323             component: 'vcalendar',
324             method: { value: 'REQUEST' },
325             version: { value: '2.0' },
326             prodid: { value: 'Microsoft Exchange Server 2010' },
327             components: [
328                 {
329                     component: 'vevent',
330                     uid: {
331                         value: '7E018059-2165-4170-B32F-6936E88E61E5',
332                     },
333                     dtstamp: {
334                         value: { year: 2019, month: 7, day: 19, hours: 13, minutes: 8, seconds: 54, isUTC: true },
335                     },
336                     dtstart: {
337                         value: { year: 2019, month: 7, day: 19, hours: 12, minutes: 0, seconds: 0, isUTC: false },
338                         parameters: { tzid: 'America/New_York' },
339                     },
340                     dtend: {
341                         value: { year: 2019, month: 7, day: 19, hours: 13, minutes: 0, seconds: 0, isUTC: false },
342                         parameters: { tzid: 'Europe/Zurich' },
343                     },
344                     categories: [
345                         {
346                             value: ['ANNIVERSARY', 'PERSONAL', 'SPECIAL OCCASION'],
347                         },
348                     ],
349                     summary: {
350                         value: 'Our Blissful Anniversary---Wonderful!',
351                     },
352                     location: {
353                         value: 'A secret...place',
354                     },
355                 },
356             ],
357         });
358     });
360     it('should parse vevent with mixed bad line breaks', () => {
361         const result = parseWithRecovery(`BEGIN:VCALENDAR
362 METHOD:REQUEST\r\nPRODID:Microsoft Exchange Server 2010
363 VERSION:2.0
364 BEGIN:VEVENT
365 DTSTAMP:20190719T130854Z
366 UID:7E018059-2165-4170-B32F-6936E88E61E5
367 DTSTART;TZID=America/New_York:20190719T120000
368 DTEND;TZID=Europe/Zurich:20190719T130000
369 CATEGORIES:ANNIVERSARY,PERSONAL,SPECIAL OCCASION
370 SUMMARY:Our Blissful Anniversary
374 Wonderful!
375 LOCATION:A
377  secret
381 place
382 END:VEVENT
383 END:VCALENDAR`);
385         expect(result).toEqual({
386             component: 'vcalendar',
387             method: { value: 'REQUEST' },
388             version: { value: '2.0' },
389             prodid: { value: 'Microsoft Exchange Server 2010' },
390             components: [
391                 {
392                     component: 'vevent',
393                     uid: {
394                         value: '7E018059-2165-4170-B32F-6936E88E61E5',
395                     },
396                     dtstamp: {
397                         value: { year: 2019, month: 7, day: 19, hours: 13, minutes: 8, seconds: 54, isUTC: true },
398                     },
399                     dtstart: {
400                         value: { year: 2019, month: 7, day: 19, hours: 12, minutes: 0, seconds: 0, isUTC: false },
401                         parameters: { tzid: 'America/New_York' },
402                     },
403                     dtend: {
404                         value: { year: 2019, month: 7, day: 19, hours: 13, minutes: 0, seconds: 0, isUTC: false },
405                         parameters: { tzid: 'Europe/Zurich' },
406                     },
407                     categories: [
408                         {
409                             value: ['ANNIVERSARY', 'PERSONAL', 'SPECIAL OCCASION'],
410                         },
411                     ],
412                     summary: {
413                         value: 'Our Blissful Anniversary---Wonderful!',
414                     },
415                     location: {
416                         value: 'A secret...place',
417                     },
418                 },
419             ],
420         });
421     });
423     it('should parse vevent with badly formatted date-time properties', () => {
424         const result = parseWithRecovery(`BEGIN:VCALENDAR
425 VERSION:2.0
426 BEGIN:VEVENT
427 DTSTAMP:20190719T1308
428 UID:7E018059-2165-4170-B32F-6936E88E61E5
429 DTSTART;TZID=America/New_York:2019-07-19T12:00:00:000
430 DTEND: 20290719
431 LAST-MODIFIED : 20190719t1308zZ
432 END:VEVENT
433 END:VCALENDAR`);
435         expect(result).toEqual({
436             component: 'vcalendar',
437             version: { value: '2.0' },
438             components: [
439                 {
440                     component: 'vevent',
441                     uid: {
442                         value: '7E018059-2165-4170-B32F-6936E88E61E5',
443                     },
444                     dtstamp: {
445                         value: { year: 2019, month: 7, day: 19, hours: 13, minutes: 8, seconds: 0, isUTC: false },
446                     },
447                     dtstart: {
448                         value: { year: 2019, month: 7, day: 19, hours: 12, minutes: 0, seconds: 0, isUTC: false },
449                         parameters: { tzid: 'America/New_York' },
450                     },
451                     dtend: {
452                         value: { year: 2029, month: 7, day: 19 },
453                         parameters: { type: 'date' },
454                     },
455                     'last-modified': {
456                         value: { year: 2019, month: 7, day: 19, hours: 13, minutes: 8, seconds: 0, isUTC: true },
457                     },
458                 },
459             ],
460         });
461     });
463     it('should parse vevent with ISO-formatted date-time properties', () => {
464         const result = parseWithRecovery(`BEGIN:VCALENDAR
465 VERSION:2.0
466 BEGIN:VEVENT
467 DTSTAMP:20230202T091854Z
468 UID:537emc1okj91qjup2ape67987975464123154@google.com
469 DTSTART:2023-02-04T09:30:00.000Z
470 DTEND:2023-02-04T09:30:00.000Z
471 RECURRENCE-ID:2023-02-04T10:30:00.000Z
472 END:VEVENT
473 END:VCALENDAR`);
475         expect(result).toEqual({
476             component: 'vcalendar',
477             version: { value: '2.0' },
478             components: [
479                 {
480                     component: 'vevent',
481                     uid: {
482                         value: '537emc1okj91qjup2ape67987975464123154@google.com',
483                     },
484                     dtstamp: {
485                         value: { year: 2023, month: 2, day: 2, hours: 9, minutes: 18, seconds: 54, isUTC: true },
486                     },
487                     dtstart: {
488                         value: { year: 2023, month: 2, day: 4, hours: 9, minutes: 30, seconds: 0, isUTC: true },
489                     },
490                     dtend: {
491                         value: { year: 2023, month: 2, day: 4, hours: 9, minutes: 30, seconds: 0, isUTC: true },
492                     },
493                     'recurrence-id': {
494                         value: { year: 2023, month: 2, day: 4, hours: 10, minutes: 30, seconds: 0, isUTC: true },
495                     },
496                 },
497             ],
498         });
499     });
501     it('should parse vevent with missing ORGANIZER value parameter', () => {
502         const result = parseWithRecovery(`
503 BEGIN:VCALENDAR
504 BEGIN:VEVENT
505 CLASS:PUBLIC
506 DTSTART:20230304T080000Z
507 DTSTAMP:20230112T203527Z
508 DTEND:20230306T153000Z
509 LOCATION:Sixt South Melbourne, 101-109 Thistlethwaite Street, 3205 South Melbourne, AU
510 TRANSP:TRANSPARENT
511 SEQUENCE:0
512 STATUS:CONFIRMED
513 SUMMARY:Your rental car from Sixt
514 UID:SIXT_XXXXXX
515 END:VEVENT
516 END:VCALENDAR
517         `);
519         // We can notice that the malformed ORGANIZER field has been omitted during the parsing
520         expect(result).toEqual({
521             component: 'vcalendar',
522             components: [
523                 {
524                     component: 'vevent',
525                     class: { value: 'PUBLIC' },
526                     dtstart: {
527                         value: { year: 2023, month: 3, day: 4, hours: 8, minutes: 0, seconds: 0, isUTC: true },
528                     },
529                     dtstamp: {
530                         value: { year: 2023, month: 1, day: 12, hours: 20, minutes: 35, seconds: 27, isUTC: true },
531                     },
532                     dtend: {
533                         value: { year: 2023, month: 3, day: 6, hours: 15, minutes: 30, seconds: 0, isUTC: true },
534                     },
535                     location: {
536                         value: 'Sixt South Melbourne, 101-109 Thistlethwaite Street, 3205 South Melbourne, AU',
537                     },
538                     transp: { value: 'TRANSPARENT' },
539                     sequence: { value: 0 },
540                     status: { value: 'CONFIRMED' },
541                     summary: { value: 'Your rental car from Sixt' },
542                     uid: { value: 'SIXT_XXXXXX' },
543                 },
544             ],
545         });
546     });