fugitsit
Version:
Small library that wraps ICAL.js and provide more convenient means for editing
1,197 lines (1,121 loc) • 157 kB
JavaScript
/**
* @copyright Copyright (c) 2019 Georg Ehrke
*
* @author Georg Ehrke <georg-nextcloud@ehrke.email>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import { getParserManager, parseICSAndGetAllOccurrencesBetween } from '../../../src/index.js';
import ICalendarParser from '../../../src/parsers/icalendarParser.js';
import DateTimeValue from '../../../src/values/dateTimeValue.js'
import DurationValue from '../../../src/values/durationValue.js';
jest.mock('../../../src/factories/dateFactory.js')
it('ParserManager should provide a list of supported file-types', () => {
const parserManager = getParserManager()
expect(parserManager.getAllSupportedFileTypes()).toEqual(['text/calendar'])
})
it('ParserManager should provide a parser for text/calendar', () => {
const parserManager = getParserManager()
const icsParser = parserManager.getParserForFileType('text/calendar')
expect(icsParser instanceof ICalendarParser).toEqual(true)
})
it('Parser + Expansion + RDATE + RDATE-Period + Recurrence-Exceptions', () => {
const ics = getAsset('recurring-infinitely-with-rdates')
const start = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 6, 1, 0, 0, 0)))
const end = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 7, 30, 23, 59, 59)))
const iterator = parseICSAndGetAllOccurrencesBetween(ics, start, end)
/** @type {EventComponent} */
const event1 = iterator.next().value
expect(event1.title).toEqual('weekly recurring event')
expect(event1.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1561964400')
expect(event1.startDate.jsDate.toISOString()).toEqual('2019-07-01T07:00:00.000Z')
expect(event1.endDate.jsDate.toISOString()).toEqual('2019-07-01T08:00:00.000Z')
expect(event1.isRecurring()).toEqual(true)
expect(event1.canCreateRecurrenceExceptions()).toEqual(true)
expect(event1.isRecurrenceException()).toEqual(false)
expect(event1.modifiesFuture()).toEqual(false)
expect(event1.canModifyAllDay()).toEqual(false)
/** @type {EventComponent} */
const event2 = iterator.next().value
expect(event2.title).toEqual('weekly recurring event')
expect(event2.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1562569200')
expect(event2.startDate.jsDate.toISOString()).toEqual('2019-07-08T07:00:00.000Z')
expect(event2.endDate.jsDate.toISOString()).toEqual('2019-07-08T08:00:00.000Z')
expect(event2.isRecurring()).toEqual(true)
expect(event2.canCreateRecurrenceExceptions()).toEqual(true)
expect(event2.isRecurrenceException()).toEqual(false)
expect(event2.modifiesFuture()).toEqual(false)
expect(event2.canModifyAllDay()).toEqual(false)
/** @type {EventComponent} */
const event3 = iterator.next().value
expect(event3.title).toEqual('weekly recurring event exception 1')
expect(event3.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1563174000')
expect(event3.startDate.jsDate.toISOString()).toEqual('2019-07-17T07:00:00.000Z')
expect(event3.endDate.jsDate.toISOString()).toEqual('2019-07-17T08:00:00.000Z')
expect(event3.isRecurring()).toEqual(false)
expect(event3.canCreateRecurrenceExceptions()).toEqual(false)
expect(event3.isRecurrenceException()).toEqual(true)
expect(event3.modifiesFuture()).toEqual(false)
expect(event3.canModifyAllDay()).toEqual(false)
// RDATE;TZID=Europe/Berlin:20190719T080000
/** @type {EventComponent} */
const event4 = iterator.next().value
expect(event4.title).toEqual('weekly recurring event')
expect(event4.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1563516000')
expect(event4.startDate.jsDate.toISOString()).toEqual('2019-07-19T06:00:00.000Z')
expect(event4.endDate.jsDate.toISOString()).toEqual('2019-07-19T07:00:00.000Z')
expect(event4.isRecurring()).toEqual(true)
expect(event4.canCreateRecurrenceExceptions()).toEqual(true)
expect(event4.isRecurrenceException()).toEqual(false)
expect(event4.modifiesFuture()).toEqual(false)
expect(event4.canModifyAllDay()).toEqual(false)
// RDATE;TZID=America/New_York:20190719T090000 and RECURRENCE-ID;TZID=Europe/Berlin:20190719T150000
/** @type {EventComponent} */
const event5 = iterator.next().value
expect(event5.title).toEqual('weekly recurring event exception - recurrence-id with different timezone')
expect(event5.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1563541200')
expect(event5.startDate.jsDate.toISOString()).toEqual('2019-07-20T14:00:00.000Z')
expect(event5.endDate.jsDate.toISOString()).toEqual('2019-07-21T02:00:00.000Z')
expect(event5.isRecurring()).toEqual(false)
expect(event5.canCreateRecurrenceExceptions()).toEqual(false)
expect(event5.isRecurrenceException()).toEqual(true)
expect(event5.modifiesFuture()).toEqual(false)
expect(event5.canModifyAllDay()).toEqual(false)
/** @type {EventComponent} */
const event6 = iterator.next().value
expect(event6.title).toEqual('weekly recurring event')
expect(event6.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1563778800')
expect(event6.startDate.jsDate.toISOString()).toEqual('2019-07-22T07:00:00.000Z')
expect(event6.endDate.jsDate.toISOString()).toEqual('2019-07-22T08:00:00.000Z')
expect(event6.isRecurring()).toEqual(true)
expect(event6.canCreateRecurrenceExceptions()).toEqual(true)
expect(event6.isRecurrenceException()).toEqual(false)
expect(event6.modifiesFuture()).toEqual(false)
expect(event6.canModifyAllDay()).toEqual(false)
/** @type {EventComponent} */
const event7 = iterator.next().value
expect(event7.title).toEqual('weekly recurring event exception 2')
expect(event7.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1564383600')
expect(event7.startDate.jsDate.toISOString()).toEqual('2019-07-31T07:00:00.000Z')
expect(event7.endDate.jsDate.toISOString()).toEqual('2019-07-31T08:00:00.000Z')
expect(event7.isRecurring()).toEqual(false)
expect(event7.canCreateRecurrenceExceptions()).toEqual(false)
expect(event7.isRecurrenceException()).toEqual(true)
expect(event7.modifiesFuture()).toEqual(false)
expect(event7.canModifyAllDay()).toEqual(false)
// RDATE;VALUE=PERIOD:20190801T070000Z/PT3H
/** @type {EventComponent} */
const event8 = iterator.next().value
expect(event8.title).toEqual('weekly recurring event')
expect(event8.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1564642800')
expect(event8.startDate.jsDate.toISOString()).toEqual('2019-08-01T07:00:00.000Z')
expect(event8.endDate.jsDate.toISOString()).toEqual('2019-08-01T10:00:00.000Z')
expect(event8.isRecurring()).toEqual(true)
expect(event8.canCreateRecurrenceExceptions()).toEqual(true)
expect(event8.isRecurrenceException()).toEqual(false)
expect(event8.modifiesFuture()).toEqual(false)
expect(event8.canModifyAllDay()).toEqual(false)
// RDATE;VALUE=PERIOD:20190802T070000Z/20190802T083000Z
/** @type {EventComponent} */
const event9 = iterator.next().value
expect(event9.title).toEqual('weekly recurring event')
expect(event9.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1564729200')
expect(event9.startDate.jsDate.toISOString()).toEqual('2019-08-02T07:00:00.000Z')
expect(event9.endDate.jsDate.toISOString()).toEqual('2019-08-02T08:30:00.000Z')
expect(event9.isRecurring()).toEqual(true)
expect(event9.canCreateRecurrenceExceptions()).toEqual(true)
expect(event9.isRecurrenceException()).toEqual(false)
expect(event9.modifiesFuture()).toEqual(false)
expect(event9.canModifyAllDay()).toEqual(false)
/** @type {EventComponent} */
const event10 = iterator.next().value
expect(event10.title).toEqual('weekly recurring event')
expect(event10.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1564988400')
expect(event10.startDate.jsDate.toISOString()).toEqual('2019-08-05T07:00:00.000Z')
expect(event10.endDate.jsDate.toISOString()).toEqual('2019-08-05T08:00:00.000Z')
expect(event10.isRecurring()).toEqual(true)
expect(event10.canCreateRecurrenceExceptions()).toEqual(true)
expect(event10.isRecurrenceException()).toEqual(false)
expect(event10.modifiesFuture()).toEqual(false)
expect(event10.canModifyAllDay()).toEqual(false)
/** @type {EventComponent} */
const event11 = iterator.next().value
expect(event11.title).toEqual('weekly recurring event')
expect(event11.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1565593200')
expect(event11.startDate.jsDate.toISOString()).toEqual('2019-08-12T07:00:00.000Z')
expect(event11.endDate.jsDate.toISOString()).toEqual('2019-08-12T08:00:00.000Z')
expect(event11.isRecurring()).toEqual(true)
expect(event11.canCreateRecurrenceExceptions()).toEqual(true)
expect(event11.isRecurrenceException()).toEqual(false)
expect(event11.modifiesFuture()).toEqual(false)
expect(event11.canModifyAllDay()).toEqual(false)
// EXDATE;TZID=Europe/Berlin:20190819T090000
// RDATE;VALUE=PERIOD:20190824T070000Z/PT3H
/** @type {EventComponent} */
const event12 = iterator.next().value
expect(event12.title).toEqual('weekly recurring event exception for VALUE=PERIOD')
expect(event12.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1566630000')
expect(event12.startDate.jsDate.toISOString()).toEqual('2019-08-24T11:00:00.000Z')
expect(event12.endDate.jsDate.toISOString()).toEqual('2019-08-30T21:00:00.000Z')
expect(event12.isRecurring()).toEqual(false)
expect(event12.canCreateRecurrenceExceptions()).toEqual(false)
expect(event12.isRecurrenceException()).toEqual(true)
expect(event12.modifiesFuture()).toEqual(false)
expect(event12.canModifyAllDay()).toEqual(false)
/** @type {EventComponent} */
const event13 = iterator.next().value
expect(event13.title).toEqual('weekly recurring event')
expect(event13.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1566802800')
expect(event13.startDate.jsDate.toISOString()).toEqual('2019-08-26T07:00:00.000Z')
expect(event13.endDate.jsDate.toISOString()).toEqual('2019-08-26T08:00:00.000Z')
expect(event13.isRecurring()).toEqual(true)
expect(event13.canCreateRecurrenceExceptions()).toEqual(true)
expect(event13.isRecurrenceException()).toEqual(false)
expect(event13.modifiesFuture()).toEqual(false)
expect(event13.canModifyAllDay()).toEqual(false)
// Verify there are no more events
expect(iterator.next().value).toEqual(undefined)
})
it('Parser + Expansion + RDATE + RDATE-Period + Recurrence-Exceptions with range THISANDFUTURE', () => {
const ics = getAsset('recurring-with-recurrence-id-range')
const start = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 6, 1, 0, 0, 0)))
const end = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 8, 15, 23, 59, 59)))
const iterator = parseICSAndGetAllOccurrencesBetween(ics, start, end)
/** @type {EventComponent} */
const event1 = iterator.next().value
expect(event1.title).toEqual('weekly recurring event')
expect(event1.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1561964400')
expect(event1.startDate.jsDate.toISOString()).toEqual('2019-07-01T07:00:00.000Z')
expect(event1.endDate.jsDate.toISOString()).toEqual('2019-07-01T08:00:00.000Z')
expect(event1.isRecurring()).toEqual(true)
expect(event1.canCreateRecurrenceExceptions()).toEqual(true)
expect(event1.isRecurrenceException()).toEqual(false)
expect(event1.modifiesFuture()).toEqual(false)
/** @type {EventComponent} */
const event2 = iterator.next().value
expect(event2.title).toEqual('weekly recurring event')
expect(event2.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1562569200')
expect(event2.startDate.jsDate.toISOString()).toEqual('2019-07-08T07:00:00.000Z')
expect(event2.endDate.jsDate.toISOString()).toEqual('2019-07-08T08:00:00.000Z')
expect(event2.isRecurring()).toEqual(true)
expect(event2.canCreateRecurrenceExceptions()).toEqual(true)
expect(event2.isRecurrenceException()).toEqual(false)
expect(event2.modifiesFuture()).toEqual(false)
/** @type {EventComponent} */
const event3 = iterator.next().value
expect(event3.title).toEqual('weekly recurring event exception 1')
expect(event3.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1563174000')
expect(event3.startDate.jsDate.toISOString()).toEqual('2019-07-17T07:00:00.000Z')
expect(event3.endDate.jsDate.toISOString()).toEqual('2019-07-17T08:00:00.000Z')
expect(event3.isRecurring()).toEqual(false)
expect(event3.canCreateRecurrenceExceptions()).toEqual(false)
expect(event3.isRecurrenceException()).toEqual(true)
expect(event3.modifiesFuture()).toEqual(false)
// RDATE;TZID=Europe/Berlin:20190719T080000
/** @type {EventComponent} */
const event4 = iterator.next().value
expect(event4.title).toEqual('weekly recurring event')
expect(event4.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1563516000')
expect(event4.startDate.jsDate.toISOString()).toEqual('2019-07-19T06:00:00.000Z')
expect(event4.endDate.jsDate.toISOString()).toEqual('2019-07-19T07:00:00.000Z')
expect(event4.isRecurring()).toEqual(true)
expect(event4.canCreateRecurrenceExceptions()).toEqual(true)
expect(event4.isRecurrenceException()).toEqual(false)
expect(event4.modifiesFuture()).toEqual(false)
// RDATE;TZID=America/New_York:20190719T090000 and RECURRENCE-ID;TZID=Europe/Berlin:20190719T150000
/** @type {EventComponent} */
const event5 = iterator.next().value
expect(event5.title).toEqual('weekly recurring event exception - recurrence-id with different timezone')
expect(event5.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1563541200')
expect(event5.startDate.jsDate.toISOString()).toEqual('2019-07-20T14:00:00.000Z')
expect(event5.endDate.jsDate.toISOString()).toEqual('2019-07-21T02:00:00.000Z')
expect(event5.isRecurring()).toEqual(false)
expect(event5.canCreateRecurrenceExceptions()).toEqual(false)
expect(event5.isRecurrenceException()).toEqual(true)
expect(event5.modifiesFuture()).toEqual(false)
/** @type {EventComponent} */
const event6 = iterator.next().value
expect(event6.title).toEqual('weekly recurring event')
expect(event6.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1563778800')
expect(event6.startDate.jsDate.toISOString()).toEqual('2019-07-22T07:00:00.000Z')
expect(event6.endDate.jsDate.toISOString()).toEqual('2019-07-22T08:00:00.000Z')
expect(event6.isRecurring()).toEqual(true)
expect(event6.canCreateRecurrenceExceptions()).toEqual(true)
expect(event6.isRecurrenceException()).toEqual(false)
expect(event6.modifiesFuture()).toEqual(false)
/** @type {EventComponent} */
const event7 = iterator.next().value
expect(event7.title).toEqual('weekly recurring event exception 2')
expect(event7.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1564383600')
expect(event7.startDate.jsDate.toISOString()).toEqual('2019-07-31T07:00:00.000Z')
expect(event7.endDate.jsDate.toISOString()).toEqual('2019-07-31T08:00:00.000Z')
expect(event7.isRecurring()).toEqual(false)
expect(event7.canCreateRecurrenceExceptions()).toEqual(false)
expect(event7.isRecurrenceException()).toEqual(true)
expect(event7.modifiesFuture()).toEqual(false)
// RDATE;VALUE=PERIOD:20190801T070000Z/PT3H
/** @type {EventComponent} */
const event8 = iterator.next().value
expect(event8.title).toEqual('weekly recurring event')
expect(event8.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1564642800')
expect(event8.startDate.jsDate.toISOString()).toEqual('2019-08-01T07:00:00.000Z')
expect(event8.endDate.jsDate.toISOString()).toEqual('2019-08-01T10:00:00.000Z')
expect(event8.isRecurring()).toEqual(true)
expect(event8.canCreateRecurrenceExceptions()).toEqual(true)
expect(event8.isRecurrenceException()).toEqual(false)
expect(event8.modifiesFuture()).toEqual(false)
// RDATE;VALUE=PERIOD:20190802T070000Z/20190802T083000Z
/** @type {EventComponent} */
const event9 = iterator.next().value
expect(event9.title).toEqual('weekly recurring event')
expect(event9.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1564729200')
expect(event9.startDate.jsDate.toISOString()).toEqual('2019-08-02T07:00:00.000Z')
expect(event9.endDate.jsDate.toISOString()).toEqual('2019-08-02T08:30:00.000Z')
expect(event9.isRecurring()).toEqual(true)
expect(event9.canCreateRecurrenceExceptions()).toEqual(true)
expect(event9.isRecurrenceException()).toEqual(false)
expect(event9.modifiesFuture()).toEqual(false)
/** @type {EventComponent} */
const event10 = iterator.next().value
expect(event10.title).toEqual('weekly recurring event')
expect(event10.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1564988400')
expect(event10.startDate.jsDate.toISOString()).toEqual('2019-08-05T07:00:00.000Z')
expect(event10.endDate.jsDate.toISOString()).toEqual('2019-08-05T08:00:00.000Z')
expect(event10.isRecurring()).toEqual(true)
expect(event10.canCreateRecurrenceExceptions()).toEqual(true)
expect(event10.isRecurrenceException()).toEqual(false)
expect(event10.modifiesFuture()).toEqual(false)
/** @type {EventComponent} */
const event11 = iterator.next().value
expect(event11.title).toEqual('weekly recurring event')
expect(event11.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1565593200')
expect(event11.startDate.jsDate.toISOString()).toEqual('2019-08-12T07:00:00.000Z')
expect(event11.endDate.jsDate.toISOString()).toEqual('2019-08-12T08:00:00.000Z')
expect(event11.isRecurring()).toEqual(true)
expect(event11.canCreateRecurrenceExceptions()).toEqual(true)
expect(event11.isRecurrenceException()).toEqual(false)
expect(event11.modifiesFuture()).toEqual(false)
// EXDATE;TZID=Europe/Berlin:20190819T090000
// RDATE;VALUE=PERIOD:20190824T070000Z/PT3H
/** @type {EventComponent} */
const event12 = iterator.next().value
expect(event12.title).toEqual('weekly recurring event exception for VALUE=PERIOD')
expect(event12.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1566630000')
expect(event12.startDate.jsDate.toISOString()).toEqual('2019-08-24T11:00:00.000Z')
expect(event12.endDate.jsDate.toISOString()).toEqual('2019-08-30T21:00:00.000Z')
expect(event12.isRecurring()).toEqual(false)
expect(event12.canCreateRecurrenceExceptions()).toEqual(true)
expect(event12.isRecurrenceException()).toEqual(true)
expect(event12.modifiesFuture()).toEqual(true)
/** @type {EventComponent} */
const event13 = iterator.next().value
expect(event13.title).toEqual('weekly recurring event exception for VALUE=PERIOD')
expect(event13.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1566802800')
expect(event13.startDate.jsDate.toISOString()).toEqual('2019-08-26T11:00:00.000Z')
expect(event13.endDate.jsDate.toISOString()).toEqual('2019-09-01T21:00:00.000Z')
expect(event13.isRecurring()).toEqual(false)
expect(event13.canCreateRecurrenceExceptions()).toEqual(true)
expect(event13.isRecurrenceException()).toEqual(true)
expect(event13.modifiesFuture()).toEqual(true)
/** @type {EventComponent} */
const event14 = iterator.next().value
expect(event14.title).toEqual('weekly recurring event exception for VALUE=PERIOD')
expect(event14.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1567407600')
expect(event14.startDate.jsDate.toISOString()).toEqual('2019-09-02T11:00:00.000Z')
expect(event14.endDate.jsDate.toISOString()).toEqual('2019-09-08T21:00:00.000Z')
expect(event14.isRecurring()).toEqual(false)
expect(event14.canCreateRecurrenceExceptions()).toEqual(true)
expect(event14.isRecurrenceException()).toEqual(true)
expect(event14.modifiesFuture()).toEqual(true)
/** @type {EventComponent} */
const event15 = iterator.next().value
expect(event15.title).toEqual('weekly recurring event exception for VALUE=PERIOD')
expect(event15.id).toEqual('41CBE812-F77C-471A-A481-D6A18CCAAA99###1568012400')
expect(event15.startDate.jsDate.toISOString()).toEqual('2019-09-09T11:00:00.000Z')
expect(event15.endDate.jsDate.toISOString()).toEqual('2019-09-15T21:00:00.000Z')
expect(event15.isRecurring()).toEqual(false)
expect(event15.canCreateRecurrenceExceptions()).toEqual(true)
expect(event15.isRecurrenceException()).toEqual(true)
expect(event15.modifiesFuture()).toEqual(true)
// Verify there are no more events
expect(iterator.next().value).toEqual(undefined)
})
it('Delete simple recurrence - this', () => {
const ics = getAsset('recurring-infinitely-with-rdates')
const start = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 6, 1, 0, 0, 0)))
const end = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 8, 30, 23, 59, 59)))
const iterator = parseICSAndGetAllOccurrencesBetween(ics, start, end)
for (let i = 0; i < 14; i++) {
iterator.next()
}
const event15 = iterator.next().value
expect(event15.removeThisOccurrence()).toEqual(false)
expect(event15.toICSEntireSeries()).toEqual('BEGIN:VCALENDAR\r\n' +
'CALSCALE:GREGORIAN\r\n' +
'VERSION:2.0\r\n' +
'PRODID:-//Apple Inc.//Mac OS X 10.14.5//EN\r\n' +
'BEGIN:VEVENT\r\n' +
'TRANSP:OPAQUE\r\n' +
'DTEND;TZID=Europe/Berlin:20190701T100000\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'EXDATE;TZID=Europe/Berlin:20190819T090000\r\n' +
'EXDATE;TZID=Europe/Berlin:20190909T090000\r\n' +
'DTSTAMP:20300101T000000Z\r\n' +
'SEQUENCE:1\r\n' +
'SUMMARY:weekly recurring event\r\n' +
'LAST-MODIFIED:20300101T000000Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190701T090000\r\n' +
'CREATED:20190703T172822Z\r\n' +
'RRULE:FREQ=WEEKLY\r\n' +
'RDATE;TZID=America/New_York:20190719T090000\r\n' +
'RDATE;TZID=Europe/Berlin:20190719T080000\r\n' +
'RDATE;VALUE=PERIOD:20190801T070000Z/20190801T100000Z,20190802T070000Z/20190\r\n' +
' 802T083000Z,20190824T070000Z/PT3H\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190717T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception 1\r\n' +
'LAST-MODIFIED:20190703T172903Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190717T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190715T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190731T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception 2\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190731T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190729T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190714T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception bogus - recurrence-id doesn\'t matc\r\n' +
' h\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190714T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190703T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=America/New_York:20190720T220000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception - recurrence-id with different tim\r\n' +
' ezone\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190720T160000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190719T150000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190830T230000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception for VALUE=PERIOD\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART:20190824T110000Z\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID:20190824T070000Z\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VTIMEZONE\r\n' +
'TZID:Europe/Berlin\r\n' +
'BEGIN:DAYLIGHT\r\n' +
'TZOFFSETFROM:+0100\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\n' +
'DTSTART:19810329T020000\r\n' +
'TZNAME:CEST\r\n' +
'TZOFFSETTO:+0200\r\n' +
'END:DAYLIGHT\r\n' +
'BEGIN:STANDARD\r\n' +
'TZOFFSETFROM:+0200\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\n' +
'DTSTART:19961027T030000\r\n' +
'TZNAME:CET\r\n' +
'TZOFFSETTO:+0100\r\n' +
'END:STANDARD\r\n' +
'END:VTIMEZONE\r\n' +
'BEGIN:VTIMEZONE\r\n' +
'TZID:America/New_York\r\n' +
'BEGIN:DAYLIGHT\r\n' +
'TZOFFSETFROM:-0500\r\n' +
'TZOFFSETTO:-0400\r\n' +
'TZNAME:EDT\r\n' +
'DTSTART:19700308T020000\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\r\n' +
'END:DAYLIGHT\r\n' +
'BEGIN:STANDARD\r\n' +
'TZOFFSETFROM:-0400\r\n' +
'TZOFFSETTO:-0500\r\n' +
'TZNAME:EST\r\n' +
'DTSTART:19701101T020000\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\r\n' +
'END:STANDARD\r\n' +
'END:VTIMEZONE\r\n' +
'END:VCALENDAR')
})
it('Delete simple recurrence - this and all future', () => {
const ics = getAsset('recurring-infinitely-with-rdates')
const start = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 6, 1, 0, 0, 0)))
const end = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 8, 30, 23, 59, 59)))
const iterator = parseICSAndGetAllOccurrencesBetween(ics, start, end)
for (let i = 0; i < 14; i++) {
iterator.next()
}
const event15 = iterator.next().value
expect(event15.removeThisOccurrence(true)).toEqual(false)
expect(event15.toICSEntireSeries()).toEqual('BEGIN:VCALENDAR\r\n' +
'CALSCALE:GREGORIAN\r\n' +
'VERSION:2.0\r\n' +
'PRODID:-//Apple Inc.//Mac OS X 10.14.5//EN\r\n' +
'BEGIN:VEVENT\r\n' +
'TRANSP:OPAQUE\r\n' +
'DTEND;TZID=Europe/Berlin:20190701T100000\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'EXDATE;TZID=Europe/Berlin:20190819T090000\r\n' +
'DTSTAMP:20300101T000000Z\r\n' +
'SEQUENCE:1\r\n' +
'SUMMARY:weekly recurring event\r\n' +
'LAST-MODIFIED:20300101T000000Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190701T090000\r\n' +
'CREATED:20190703T172822Z\r\n' +
'RRULE:FREQ=WEEKLY;UNTIL=20190909T065959Z\r\n' +
'RDATE;TZID=America/New_York:20190719T090000\r\n' +
'RDATE;TZID=Europe/Berlin:20190719T080000\r\n' +
'RDATE;VALUE=PERIOD:20190801T070000Z/20190801T100000Z,20190802T070000Z/20190\r\n' +
' 802T083000Z,20190824T070000Z/PT3H\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190717T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception 1\r\n' +
'LAST-MODIFIED:20190703T172903Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190717T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190715T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190731T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception 2\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190731T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190729T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190714T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception bogus - recurrence-id doesn\'t matc\r\n' +
' h\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190714T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190703T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=America/New_York:20190720T220000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception - recurrence-id with different tim\r\n' +
' ezone\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190720T160000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190719T150000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190830T230000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception for VALUE=PERIOD\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART:20190824T110000Z\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID:20190824T070000Z\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VTIMEZONE\r\n' +
'TZID:Europe/Berlin\r\n' +
'BEGIN:DAYLIGHT\r\n' +
'TZOFFSETFROM:+0100\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\n' +
'DTSTART:19810329T020000\r\n' +
'TZNAME:CEST\r\n' +
'TZOFFSETTO:+0200\r\n' +
'END:DAYLIGHT\r\n' +
'BEGIN:STANDARD\r\n' +
'TZOFFSETFROM:+0200\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\n' +
'DTSTART:19961027T030000\r\n' +
'TZNAME:CET\r\n' +
'TZOFFSETTO:+0100\r\n' +
'END:STANDARD\r\n' +
'END:VTIMEZONE\r\n' +
'BEGIN:VTIMEZONE\r\n' +
'TZID:America/New_York\r\n' +
'BEGIN:DAYLIGHT\r\n' +
'TZOFFSETFROM:-0500\r\n' +
'TZOFFSETTO:-0400\r\n' +
'TZNAME:EDT\r\n' +
'DTSTART:19700308T020000\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\r\n' +
'END:DAYLIGHT\r\n' +
'BEGIN:STANDARD\r\n' +
'TZOFFSETFROM:-0400\r\n' +
'TZOFFSETTO:-0500\r\n' +
'TZNAME:EST\r\n' +
'DTSTART:19701101T020000\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\r\n' +
'END:STANDARD\r\n' +
'END:VTIMEZONE\r\n' +
'END:VCALENDAR')
})
it('Delete first item this', () => {
const ics = getAsset('recurring-infinitely-with-rdates')
const start = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 6, 1, 0, 0, 0)))
const end = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 8, 30, 23, 59, 59)))
const iterator = parseICSAndGetAllOccurrencesBetween(ics, start, end)
const event1 = iterator.next().value
expect(event1.removeThisOccurrence()).toEqual(false)
expect(event1.toICSEntireSeries()).toEqual('BEGIN:VCALENDAR\r\n' +
'CALSCALE:GREGORIAN\r\n' +
'VERSION:2.0\r\n' +
'PRODID:-//Apple Inc.//Mac OS X 10.14.5//EN\r\n' +
'BEGIN:VEVENT\r\n' +
'TRANSP:OPAQUE\r\n' +
'DTEND;TZID=Europe/Berlin:20190701T100000\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'EXDATE;TZID=Europe/Berlin:20190819T090000\r\n' +
'EXDATE;TZID=Europe/Berlin:20190701T090000\r\n' +
'DTSTAMP:20300101T000000Z\r\n' +
'SEQUENCE:1\r\n' +
'SUMMARY:weekly recurring event\r\n' +
'LAST-MODIFIED:20300101T000000Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190701T090000\r\n' +
'CREATED:20190703T172822Z\r\n' +
'RRULE:FREQ=WEEKLY\r\n' +
'RDATE;TZID=America/New_York:20190719T090000\r\n' +
'RDATE;TZID=Europe/Berlin:20190719T080000\r\n' +
'RDATE;VALUE=PERIOD:20190801T070000Z/PT3H,20190802T070000Z/20190802T083000Z,\r\n' +
' 20190824T070000Z/PT3H\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190717T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception 1\r\n' +
'LAST-MODIFIED:20190703T172903Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190717T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190715T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190731T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception 2\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190731T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190729T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190714T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception bogus - recurrence-id doesn\'t matc\r\n' +
' h\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190714T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190703T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=America/New_York:20190720T220000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception - recurrence-id with different tim\r\n' +
' ezone\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190720T160000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190719T150000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190830T230000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception for VALUE=PERIOD\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART:20190824T110000Z\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID:20190824T070000Z\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VTIMEZONE\r\n' +
'TZID:Europe/Berlin\r\n' +
'BEGIN:DAYLIGHT\r\n' +
'TZOFFSETFROM:+0100\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\n' +
'DTSTART:19810329T020000\r\n' +
'TZNAME:CEST\r\n' +
'TZOFFSETTO:+0200\r\n' +
'END:DAYLIGHT\r\n' +
'BEGIN:STANDARD\r\n' +
'TZOFFSETFROM:+0200\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\n' +
'DTSTART:19961027T030000\r\n' +
'TZNAME:CET\r\n' +
'TZOFFSETTO:+0100\r\n' +
'END:STANDARD\r\n' +
'END:VTIMEZONE\r\n' +
'BEGIN:VTIMEZONE\r\n' +
'TZID:America/New_York\r\n' +
'BEGIN:DAYLIGHT\r\n' +
'TZOFFSETFROM:-0500\r\n' +
'TZOFFSETTO:-0400\r\n' +
'TZNAME:EDT\r\n' +
'DTSTART:19700308T020000\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\r\n' +
'END:DAYLIGHT\r\n' +
'BEGIN:STANDARD\r\n' +
'TZOFFSETFROM:-0400\r\n' +
'TZOFFSETTO:-0500\r\n' +
'TZNAME:EST\r\n' +
'DTSTART:19701101T020000\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\r\n' +
'END:STANDARD\r\n' +
'END:VTIMEZONE\r\n' +
'END:VCALENDAR')
})
it('Delete first item this and future', () => {
const ics = getAsset('recurring-infinitely-with-rdates')
const start = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 6, 1, 0, 0, 0)))
const end = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 8, 30, 23, 59, 59)))
const iterator = parseICSAndGetAllOccurrencesBetween(ics, start, end)
const event1 = iterator.next().value
expect(event1.removeThisOccurrence(true)).toEqual(true)
})
it('Delete no-range recurrence-exception this', () => {
const ics = getAsset('recurring-infinitely-with-rdates')
const start = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 6, 1, 0, 0, 0)))
const end = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 8, 30, 23, 59, 59)))
const iterator = parseICSAndGetAllOccurrencesBetween(ics, start, end)
for (let i = 0; i < 2; i++) {
iterator.next()
}
const event3 = iterator.next().value
expect(event3.removeThisOccurrence()).toEqual(false)
expect(event3.toICSEntireSeries()).toEqual('BEGIN:VCALENDAR\r\n' +
'CALSCALE:GREGORIAN\r\n' +
'VERSION:2.0\r\n' +
'PRODID:-//Apple Inc.//Mac OS X 10.14.5//EN\r\n' +
'BEGIN:VEVENT\r\n' +
'TRANSP:OPAQUE\r\n' +
'DTEND;TZID=Europe/Berlin:20190701T100000\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'EXDATE;TZID=Europe/Berlin:20190819T090000\r\n' +
'EXDATE;TZID=Europe/Berlin:20190715T090000\r\n' +
'DTSTAMP:20300101T000000Z\r\n' +
'SEQUENCE:1\r\n' +
'SUMMARY:weekly recurring event\r\n' +
'LAST-MODIFIED:20300101T000000Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190701T090000\r\n' +
'CREATED:20190703T172822Z\r\n' +
'RRULE:FREQ=WEEKLY\r\n' +
'RDATE;TZID=America/New_York:20190719T090000\r\n' +
'RDATE;TZID=Europe/Berlin:20190719T080000\r\n' +
'RDATE;VALUE=PERIOD:20190801T070000Z/PT3H,20190802T070000Z/20190802T083000Z,\r\n' +
' 20190824T070000Z/PT3H\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190731T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception 2\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190731T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190729T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190714T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception bogus - recurrence-id doesn\'t matc\r\n' +
' h\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190714T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190703T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=America/New_York:20190720T220000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception - recurrence-id with different tim\r\n' +
' ezone\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190720T160000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190719T150000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190830T230000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception for VALUE=PERIOD\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART:20190824T110000Z\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID:20190824T070000Z\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VTIMEZONE\r\n' +
'TZID:Europe/Berlin\r\n' +
'BEGIN:DAYLIGHT\r\n' +
'TZOFFSETFROM:+0100\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\n' +
'DTSTART:19810329T020000\r\n' +
'TZNAME:CEST\r\n' +
'TZOFFSETTO:+0200\r\n' +
'END:DAYLIGHT\r\n' +
'BEGIN:STANDARD\r\n' +
'TZOFFSETFROM:+0200\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\n' +
'DTSTART:19961027T030000\r\n' +
'TZNAME:CET\r\n' +
'TZOFFSETTO:+0100\r\n' +
'END:STANDARD\r\n' +
'END:VTIMEZONE\r\n' +
'BEGIN:VTIMEZONE\r\n' +
'TZID:America/New_York\r\n' +
'BEGIN:DAYLIGHT\r\n' +
'TZOFFSETFROM:-0500\r\n' +
'TZOFFSETTO:-0400\r\n' +
'TZNAME:EDT\r\n' +
'DTSTART:19700308T020000\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\r\n' +
'END:DAYLIGHT\r\n' +
'BEGIN:STANDARD\r\n' +
'TZOFFSETFROM:-0400\r\n' +
'TZOFFSETTO:-0500\r\n' +
'TZNAME:EST\r\n' +
'DTSTART:19701101T020000\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\r\n' +
'END:STANDARD\r\n' +
'END:VTIMEZONE\r\n' +
'END:VCALENDAR')
})
it('Delete no-range recurrence-exception this and all future', () => {
const ics = getAsset('recurring-infinitely-with-rdates')
const start = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 6, 1, 0, 0, 0)))
const end = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 8, 30, 23, 59, 59)))
const iterator = parseICSAndGetAllOccurrencesBetween(ics, start, end)
for (let i = 0; i < 2; i++) {
iterator.next()
}
const event3 = iterator.next().value
expect(event3.removeThisOccurrence(true)).toEqual(false)
expect(event3.toICSEntireSeries()).toEqual('BEGIN:VCALENDAR\r\n' +
'CALSCALE:GREGORIAN\r\n' +
'VERSION:2.0\r\n' +
'PRODID:-//Apple Inc.//Mac OS X 10.14.5//EN\r\n' +
'BEGIN:VEVENT\r\n' +
'TRANSP:OPAQUE\r\n' +
'DTEND;TZID=Europe/Berlin:20190701T100000\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTSTAMP:20300101T000000Z\r\n' +
'SEQUENCE:1\r\n' +
'SUMMARY:weekly recurring event\r\n' +
'LAST-MODIFIED:20300101T000000Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190701T090000\r\n' +
'CREATED:20190703T172822Z\r\n' +
'RRULE:FREQ=WEEKLY;UNTIL=20190715T065959Z\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190714T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception bogus - recurrence-id doesn\'t matc\r\n' +
' h\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190714T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190703T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VTIMEZONE\r\n' +
'TZID:Europe/Berlin\r\n' +
'BEGIN:DAYLIGHT\r\n' +
'TZOFFSETFROM:+0100\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\n' +
'DTSTART:19810329T020000\r\n' +
'TZNAME:CEST\r\n' +
'TZOFFSETTO:+0200\r\n' +
'END:DAYLIGHT\r\n' +
'BEGIN:STANDARD\r\n' +
'TZOFFSETFROM:+0200\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\n' +
'DTSTART:19961027T030000\r\n' +
'TZNAME:CET\r\n' +
'TZOFFSETTO:+0100\r\n' +
'END:STANDARD\r\n' +
'END:VTIMEZONE\r\n' +
'END:VCALENDAR')
})
it('Delete range recurrence-exception this (exact match)', () => {
const ics = getAsset('recurring-with-recurrence-id-range')
const start = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 6, 1, 0, 0, 0)))
const end = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 8, 15, 23, 59, 59)))
const iterator = parseICSAndGetAllOccurrencesBetween(ics, start, end)
for (let i = 0; i < 11; i++) {
iterator.next()
}
const event12 = iterator.next().value
expect(event12.removeThisOccurrence()).toEqual(false)
expect(event12.toICSEntireSeries()).toEqual('BEGIN:VCALENDAR\r\n' +
'CALSCALE:GREGORIAN\r\n' +
'VERSION:2.0\r\n' +
'PRODID:-//Apple Inc.//Mac OS X 10.14.5//EN\r\n' +
'BEGIN:VEVENT\r\n' +
'TRANSP:OPAQUE\r\n' +
'DTEND;TZID=Europe/Berlin:20190701T100000\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'EXDATE;TZID=Europe/Berlin:20190819T090000\r\n' +
'DTSTAMP:20300101T000000Z\r\n' +
'SEQUENCE:1\r\n' +
'SUMMARY:weekly recurring event\r\n' +
'LAST-MODIFIED:20300101T000000Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190701T090000\r\n' +
'CREATED:20190703T172822Z\r\n' +
'RRULE:FREQ=WEEKLY\r\n' +
'RDATE;TZID=America/New_York:20190719T090000\r\n' +
'RDATE;TZID=Europe/Berlin:20190719T080000\r\n' +
'RDATE;VALUE=PERIOD:20190801T070000Z/20190801T100000Z,20190802T070000Z/20190\r\n' +
' 802T083000Z\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190717T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception 1\r\n' +
'LAST-MODIFIED:20190703T172903Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190717T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190715T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190731T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception 2\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190731T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190729T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190714T100000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception bogus - recurrence-id doesn\'t matc\r\n' +
' h\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190714T090000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190703T090000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=America/New_York:20190720T220000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception - recurrence-id with different tim\r\n' +
' ezone\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190720T160000\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;TZID=Europe/Berlin:20190719T150000\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'DTEND;TZID=Europe/Berlin:20190830T230000\r\n' +
'TRANSP:OPAQUE\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'SUMMARY:weekly recurring event exception for VALUE=PERIOD\r\n' +
'LAST-MODIFIED:20190703T172914Z\r\n' +
'DTSTAMP:20190703T172836Z\r\n' +
'DTSTART:20190824T110000Z\r\n' +
'SEQUENCE:0\r\n' +
'RECURRENCE-ID;RANGE=THISANDFUTURE:20190824T070000Z\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VTIMEZONE\r\n' +
'TZID:Europe/Berlin\r\n' +
'BEGIN:DAYLIGHT\r\n' +
'TZOFFSETFROM:+0100\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\n' +
'DTSTART:19810329T020000\r\n' +
'TZNAME:CEST\r\n' +
'TZOFFSETTO:+0200\r\n' +
'END:DAYLIGHT\r\n' +
'BEGIN:STANDARD\r\n' +
'TZOFFSETFROM:+0200\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\n' +
'DTSTART:19961027T030000\r\n' +
'TZNAME:CET\r\n' +
'TZOFFSETTO:+0100\r\n' +
'END:STANDARD\r\n' +
'END:VTIMEZONE\r\n' +
'BEGIN:VTIMEZONE\r\n' +
'TZID:America/New_York\r\n' +
'BEGIN:DAYLIGHT\r\n' +
'TZOFFSETFROM:-0500\r\n' +
'TZOFFSETTO:-0400\r\n' +
'TZNAME:EDT\r\n' +
'DTSTART:19700308T020000\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\r\n' +
'END:DAYLIGHT\r\n' +
'BEGIN:STANDARD\r\n' +
'TZOFFSETFROM:-0400\r\n' +
'TZOFFSETTO:-0500\r\n' +
'TZNAME:EST\r\n' +
'DTSTART:19701101T020000\r\n' +
'RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\r\n' +
'END:STANDARD\r\n' +
'END:VTIMEZONE\r\n' +
'END:VCALENDAR')
})
it('Delete range recurrence-exception this and all future (exact match)', () => {
const ics = getAsset('recurring-with-recurrence-id-range')
const start = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 6, 1, 0, 0, 0)))
const end = DateTimeValue.fromJSDate(new Date(Date.UTC(2019, 8, 15, 23, 59, 59)))
const iterator = parseICSAndGetAllOccurrencesBetween(ics, start, end)
for (let i = 0; i < 11; i++) {
iterator.next()
}
const event12 = iterator.next().value
expect(event12.removeThisOccurrence(true)).toEqual(false)
expect(event12.toICSEntireSeries()).toEqual('BEGIN:VCALENDAR\r\n' +
'CALSCALE:GREGORIAN\r\n' +
'VERSION:2.0\r\n' +
'PRODID:-//Apple Inc.//Mac OS X 10.14.5//EN\r\n' +
'BEGIN:VEVENT\r\n' +
'TRANSP:OPAQUE\r\n' +
'DTEND;TZID=Europe/Berlin:20190701T100000\r\n' +
'X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC\r\n' +
'UID:41CBE812-F77C-471A-A481-D6A18CCAAA99\r\n' +
'EXDATE;TZID=Europe/Berlin:20190819T090000\r\n' +
'DTSTAMP:20300101T000000Z\r\n' +
'SEQUENCE:1\r\n' +
'SUMMARY:weekly recurring event\r\n' +
'LAST-MODIFIED:20300101T000000Z\r\n' +
'DTSTART;TZID=Europe/Berlin:20190701T090000\r\n' +
'CREATED:20190703T172822Z\r\n' +
'RRULE:FREQ=WEEKLY;UNTIL=20190824T065959Z\r\n' +
'RDATE;TZID=America/New_York:20190719T090000\r\n' +
'RDATE;TZID=Europe/Berlin:20190719T080000\r\n' +
'RDATE;VALUE=PERIOD:20190801T070000Z/20190801T100000Z,20190802T070000Z/20190\r\n' +
' 802T083000Z\r\n' +
'END:VEVENT\r\n' +
'BEGIN:VEVENT\r\n' +
'CREATED:20190703T172822Z\r\n' +
'UID:41CBE812-F77C-471