6 } from '../../lib/calendar/icsSurgery/ics';
8 describe('reformatLineBreaks()', () => {
9 it('should reformat line breaks with RFC 7896 properties', () => {
10 const vcal = `BEGIN:VCALENDAR
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
19 X-MS-OLK-FORCEINSPECTOROPEN:TRUE
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
32 LAST-MODIFIED:20191229T000000Z
34 SUMMARY;LANGUAGE=en-us:Day after New Year's Day (in lieu) (Regional Holiday)
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
46 expect(reformatLineBreaks(vcal)).toEqual(`BEGIN:VCALENDAR
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
55 X-MS-OLK-FORCEINSPECTOROPEN:TRUE
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
68 LAST-MODIFIED:20191229T000000Z
70 SUMMARY;LANGUAGE=en-us:Day after New Year's Day (in lieu) (Regional Holiday)
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
85 describe('unfoldLines()', () => {
86 it('unfolds a properly folded ICS', () => {
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.
99 SUMMARY:The Drop: Fall Launch
101 DTSTART:20221025T130000Z
102 DTEND:20221026T070000Z
103 URL:https://experience.dropbox.com/events-webinars/thedigitaldr
109 ).toEqual(`BEGIN:VCALENDAR
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
117 DTSTART:20221025T130000Z
118 DTEND:20221026T070000Z
119 URL:https://experience.dropbox.com/events-webinars/thedigitaldrop-fall2022
125 describe('reformatDateTimes()', () => {
126 it('reformats too short or too long DTSTAMP, DTSTART, DTEND, LAST-MODIFIED', () => {
128 reformatDateTimes(`BEGIN:VCALENDAR
131 DTSTAMP:20221010T1200
134 LAST-MODIFIED:20221010T120049375Z
137 ).toEqual(`BEGIN:VCALENDAR
140 DTSTAMP:20221010T120000
141 DTSTART:20221111T130000
142 DTEND:20221111T143000
143 LAST-MODIFIED:20221010T120049Z
148 it('reformats date-time properties with a time zone', () => {
150 reformatDateTimes(`BEGIN:VCALENDAR
153 DTSTAMP;TZID=America/Guatemala:20221010T1200
156 ).toEqual(`BEGIN:VCALENDAR
159 DTSTAMP;TZID=America/Guatemala:20221010T120000
164 it('reformats folded date-time properties', () => {
166 reformatDateTimes(`BEGIN:VCALENDAR
169 DTEND;TZID==/mozilla.org/20050126_1/America/Guatemala:2022
173 ).toEqual(`BEGIN:VCALENDAR
176 DTEND;TZID==/mozilla.org/20050126_1/America/Guatemala:20221010T120000
181 it('reformats untrimmed date-time properties', () => {
183 reformatDateTimes(`BEGIN:VCALENDAR
186 DTSTART:20221010T1200
187 DTEND: 20221004T103000
190 ).toEqual(`BEGIN:VCALENDAR
193 DTSTART:20221010T120000
194 DTEND:20221004T103000
199 it('reformats date-time properties with ISO format', () => {
201 reformatDateTimes(`BEGIN:VCALENDAR
204 DTSTAMP:2022-09-02T23:59:59.999
205 DTSTART:2022-10-04T09:30:00.000Z
206 DTEND:2022-10-05T12:30:00.000ZZ
209 ).toEqual(`BEGIN:VCALENDAR
212 DTSTAMP:20220902T235959
213 DTSTART:20221004T093000Z
214 DTEND:20221005T123000Z
219 it('reformats date-time properties with "Deutsche Bahn format"', () => {
221 reformatDateTimes(`BEGIN:VCALENDAR
224 DTSTART;TZID=Europe/Berlin:2023-06-21T082400
225 DTEND;TZID=Europe/Berlin:2023-06-21T165400
226 DTSTAMP:2023-06-13T212500Z
229 ).toEqual(`BEGIN:VCALENDAR
232 DTSTART;TZID=Europe/Berlin:20230621T082400
233 DTEND;TZID=Europe/Berlin:20230621T165400
234 DTSTAMP:20230613T212500Z
239 it('reformats date properties with "Deutsche Bahn format"', () => {
241 reformatDateTimes(`BEGIN:VCALENDAR
244 DTSTART;VALUE=DATE:2023-06-21
245 DTEND;VALUE=DATE:2023-06-22
246 DTSTAMP:2023-06-13T212500Z
249 ).toEqual(`BEGIN:VCALENDAR
252 DTSTART;VALUE=DATE:20230621
253 DTEND;VALUE=DATE:20230622
254 DTSTAMP:20230613T212500Z
259 it('reformats all-day date-time properties missing', () => {
261 reformatDateTimes(`BEGIN:VCALENDAR
267 ).toEqual(`BEGIN:VCALENDAR
270 DTSTART;VALUE=DATE:20221004
275 it('reformats date-time properties with uncapitalized markers', () => {
277 reformatDateTimes(`BEGIN:VCALENDAR
280 DTSTAMP:20221004t155959z
281 DTSTART:20221004t155959
282 DTEND:2022-10-05t12:30:00.000zz
285 ).toEqual(`BEGIN:VCALENDAR
288 DTSTAMP:20221004T155959Z
289 DTSTART:20221004T155959
290 DTEND:20221005T123000Z
296 describe('parseWithRecovery()', () => {
297 it('should parse vevent with bad enclosing and bad line breaks', () => {
298 const result = parseWithRecovery(`BEGIN:VCALENDAR
300 PRODID:Microsoft Exchange Server 2010
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
322 expect(result).toEqual({
323 component: 'vcalendar',
324 method: { value: 'REQUEST' },
325 version: { value: '2.0' },
326 prodid: { value: 'Microsoft Exchange Server 2010' },
331 value: '7E018059-2165-4170-B32F-6936E88E61E5',
334 value: { year: 2019, month: 7, day: 19, hours: 13, minutes: 8, seconds: 54, isUTC: true },
337 value: { year: 2019, month: 7, day: 19, hours: 12, minutes: 0, seconds: 0, isUTC: false },
338 parameters: { tzid: 'America/New_York' },
341 value: { year: 2019, month: 7, day: 19, hours: 13, minutes: 0, seconds: 0, isUTC: false },
342 parameters: { tzid: 'Europe/Zurich' },
346 value: ['ANNIVERSARY', 'PERSONAL', 'SPECIAL OCCASION'],
350 value: 'Our Blissful Anniversary---Wonderful!',
353 value: 'A secret...place',
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
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
385 expect(result).toEqual({
386 component: 'vcalendar',
387 method: { value: 'REQUEST' },
388 version: { value: '2.0' },
389 prodid: { value: 'Microsoft Exchange Server 2010' },
394 value: '7E018059-2165-4170-B32F-6936E88E61E5',
397 value: { year: 2019, month: 7, day: 19, hours: 13, minutes: 8, seconds: 54, isUTC: true },
400 value: { year: 2019, month: 7, day: 19, hours: 12, minutes: 0, seconds: 0, isUTC: false },
401 parameters: { tzid: 'America/New_York' },
404 value: { year: 2019, month: 7, day: 19, hours: 13, minutes: 0, seconds: 0, isUTC: false },
405 parameters: { tzid: 'Europe/Zurich' },
409 value: ['ANNIVERSARY', 'PERSONAL', 'SPECIAL OCCASION'],
413 value: 'Our Blissful Anniversary---Wonderful!',
416 value: 'A secret...place',
423 it('should parse vevent with badly formatted date-time properties', () => {
424 const result = parseWithRecovery(`BEGIN:VCALENDAR
427 DTSTAMP:20190719T1308
428 UID:7E018059-2165-4170-B32F-6936E88E61E5
429 DTSTART;TZID=America/New_York:2019-07-19T12:00:00:000
431 LAST-MODIFIED : 20190719t1308zZ
435 expect(result).toEqual({
436 component: 'vcalendar',
437 version: { value: '2.0' },
442 value: '7E018059-2165-4170-B32F-6936E88E61E5',
445 value: { year: 2019, month: 7, day: 19, hours: 13, minutes: 8, seconds: 0, isUTC: false },
448 value: { year: 2019, month: 7, day: 19, hours: 12, minutes: 0, seconds: 0, isUTC: false },
449 parameters: { tzid: 'America/New_York' },
452 value: { year: 2029, month: 7, day: 19 },
453 parameters: { type: 'date' },
456 value: { year: 2019, month: 7, day: 19, hours: 13, minutes: 8, seconds: 0, isUTC: true },
463 it('should parse vevent with ISO-formatted date-time properties', () => {
464 const result = parseWithRecovery(`BEGIN:VCALENDAR
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
475 expect(result).toEqual({
476 component: 'vcalendar',
477 version: { value: '2.0' },
482 value: '537emc1okj91qjup2ape67987975464123154@google.com',
485 value: { year: 2023, month: 2, day: 2, hours: 9, minutes: 18, seconds: 54, isUTC: true },
488 value: { year: 2023, month: 2, day: 4, hours: 9, minutes: 30, seconds: 0, isUTC: true },
491 value: { year: 2023, month: 2, day: 4, hours: 9, minutes: 30, seconds: 0, isUTC: true },
494 value: { year: 2023, month: 2, day: 4, hours: 10, minutes: 30, seconds: 0, isUTC: true },
501 it('should parse vevent with missing ORGANIZER value parameter', () => {
502 const result = parseWithRecovery(`
506 DTSTART:20230304T080000Z
507 DTSTAMP:20230112T203527Z
508 DTEND:20230306T153000Z
509 LOCATION:Sixt South Melbourne, 101-109 Thistlethwaite Street, 3205 South Melbourne, AU
513 SUMMARY:Your rental car from Sixt
519 // We can notice that the malformed ORGANIZER field has been omitted during the parsing
520 expect(result).toEqual({
521 component: 'vcalendar',
525 class: { value: 'PUBLIC' },
527 value: { year: 2023, month: 3, day: 4, hours: 8, minutes: 0, seconds: 0, isUTC: true },
530 value: { year: 2023, month: 1, day: 12, hours: 20, minutes: 35, seconds: 27, isUTC: true },
533 value: { year: 2023, month: 3, day: 6, hours: 15, minutes: 30, seconds: 0, isUTC: true },
536 value: 'Sixt South Melbourne, 101-109 Thistlethwaite Street, 3205 South Melbourne, AU',
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' },