1 import { getOccurrences, getOccurrencesBetween } from '../../lib/calendar/recurrence/recurring';
2 import { parse } from '../../lib/calendar/vcal';
4 const stringifyResult = (result) => {
5 return result.map(({ utcStart, utcEnd, occurrenceNumber }) => {
6 return `${utcStart.toISOString()} - ${utcEnd.toISOString()} | ${occurrenceNumber}`;
10 const stringifyResultFull = (result) => {
11 return result.map(({ localStart, localEnd, utcStart, utcEnd, occurrenceNumber }) => {
12 return `${localStart.toISOString()} - ${localEnd.toISOString()} | ${utcStart.toISOString()} - ${utcEnd.toISOString()} | ${occurrenceNumber}`;
16 const stringifyResultSimple = (result) => {
17 return result.map(({ utcStart, utcEnd }) => {
18 return `${utcStart.toISOString()} - ${utcEnd.toISOString()}`;
22 const stringifyLocalResultSimple = (result) => {
23 return result.map(({ localStart, occurrenceNumber }) => {
24 return `${localStart.toISOString()} - ${occurrenceNumber}`;
28 describe('recurring', () => {
31 value: { year: 2019, month: 1, day: 30, hours: 2, minutes: 30, seconds: 0, isUTC: false },
34 tzid: 'Europe/Zurich',
38 value: { year: 2019, month: 1, day: 30, hours: 3, minutes: 30, seconds: 0, isUTC: false },
41 tzid: 'Europe/Zurich',
51 it('should not get occurrences between if it is out of range', () => {
52 const result = getOccurrencesBetween(component, Date.UTC(2018, 3, 1), Date.UTC(2018, 3, 2));
53 expect(result).toEqual([]);
56 it('should get initial occurrences between a range', () => {
57 const result = getOccurrencesBetween(component, Date.UTC(2018, 1, 1), Date.UTC(2019, 1, 3));
59 expect(stringifyResult(result)).toEqual([
60 '2019-01-30T01:30:00.000Z - 2019-01-30T02:30:00.000Z | 1',
61 '2019-01-31T01:30:00.000Z - 2019-01-31T02:30:00.000Z | 2',
62 '2019-02-01T01:30:00.000Z - 2019-02-01T02:30:00.000Z | 3',
63 '2019-02-02T01:30:00.000Z - 2019-02-02T02:30:00.000Z | 4',
67 it('should get occurrences between a range', () => {
68 const result = getOccurrencesBetween(component, Date.UTC(2019, 2, 1), Date.UTC(2019, 2, 3));
70 expect(stringifyResult(result)).toEqual([
71 '2019-03-01T01:30:00.000Z - 2019-03-01T02:30:00.000Z | 31',
72 '2019-03-02T01:30:00.000Z - 2019-03-02T02:30:00.000Z | 32',
76 it('should get occurrences between a dst range', () => {
77 const result = getOccurrencesBetween(component, Date.UTC(2019, 9, 26), Date.UTC(2019, 9, 29));
79 expect(stringifyResultFull(result)).toEqual([
80 '2019-10-26T02:30:00.000Z - 2019-10-26T03:30:00.000Z | 2019-10-26T00:30:00.000Z - 2019-10-26T01:30:00.000Z | 270',
81 '2019-10-27T02:30:00.000Z - 2019-10-27T03:30:00.000Z | 2019-10-27T01:30:00.000Z - 2019-10-27T02:30:00.000Z | 271',
82 '2019-10-28T02:30:00.000Z - 2019-10-28T03:30:00.000Z | 2019-10-28T01:30:00.000Z - 2019-10-28T02:30:00.000Z | 272',
86 it('should get cached occurrences between a range', () => {
88 const result1 = getOccurrencesBetween(component, Date.UTC(2019, 2, 1), Date.UTC(2019, 2, 3), cache);
89 const result2 = getOccurrencesBetween(component, Date.UTC(2019, 2, 1), Date.UTC(2019, 2, 3), cache);
90 expect(result1).toEqual(result2);
93 it('should fill cache if out of range', () => {
95 getOccurrencesBetween(component, Date.UTC(2019, 2, 1), Date.UTC(2019, 2, 3), cache);
96 const result2 = getOccurrencesBetween(component, Date.UTC(2031, 2, 1), Date.UTC(2031, 2, 3), cache);
97 expect(stringifyResult(result2)).toEqual([
98 '2031-03-01T01:30:00.000Z - 2031-03-01T02:30:00.000Z | 4414',
99 '2031-03-02T01:30:00.000Z - 2031-03-02T02:30:00.000Z | 4415',
103 it('should fill occurrences with a count', () => {
104 const component = parse(`
106 DTSTART;VALUE=DATE:20200129
107 DTEND;VALUE=DATE:20200130
108 RRULE:FREQ=WEEKLY;BYDAY=SU,MO,TU,WE,TH,FR,SA;COUNT=3
111 const result = getOccurrencesBetween(component, Date.UTC(2020, 0, 1), Date.UTC(2020, 2, 1), cache);
112 expect(stringifyResultSimple(result)).toEqual([
113 '2020-01-29T00:00:00.000Z - 2020-01-29T00:00:00.000Z',
114 '2020-01-30T00:00:00.000Z - 2020-01-30T00:00:00.000Z',
115 '2020-01-31T00:00:00.000Z - 2020-01-31T00:00:00.000Z',
119 it('should return no occurrences for a count = 0', () => {
120 const component = parse(`
122 DTSTART;VALUE=DATE:20200129
123 DTEND;VALUE=DATE:20200130
124 RRULE:FREQ=DAILY;COUNT=0
127 const result = getOccurrencesBetween(component, Date.UTC(2020, 0, 1), Date.UTC(2020, 2, 1), cache);
128 expect(stringifyResultSimple(result)).toEqual([]);
131 it('should pick a targeted given occurrence ', () => {
132 const component = parse(`
134 DTSTART:20200129T113000Z
135 DTEND:20200129T123000Z
136 RRULE:FREQ=WEEKLY;BYDAY=SU,MO,TU,WE,TH,FR,SA;COUNT=3
139 const result = getOccurrencesBetween(
141 Date.UTC(2020, 0, 29, 11, 30),
142 Date.UTC(2020, 0, 29, 11, 30),
145 expect(stringifyResultSimple(result)).toEqual(['2020-01-29T11:30:00.000Z - 2020-01-29T12:30:00.000Z']);
148 it('should fill occurrences until 31st of Jan in for all day events', () => {
149 const component = parse(`
151 DTSTART;VALUE=DATE:20200129
152 DTEND;VALUE=DATE:20200130
153 RRULE:FREQ=WEEKLY;BYDAY=SU,MO,TU,WE,TH,FR,SA;UNTIL=20200131
156 const result = getOccurrencesBetween(component, Date.UTC(2020, 0, 1), Date.UTC(2020, 2, 1), cache);
157 expect(stringifyResultSimple(result)).toEqual([
158 '2020-01-29T00:00:00.000Z - 2020-01-29T00:00:00.000Z',
159 '2020-01-30T00:00:00.000Z - 2020-01-30T00:00:00.000Z',
160 '2020-01-31T00:00:00.000Z - 2020-01-31T00:00:00.000Z',
164 it('should fill occurrences until 31st of Jan in UTC time', () => {
165 const component = parse(`
167 DTSTART:20200129T130000Z
168 DTEND:20200129T133000Z
169 RRULE:FREQ=WEEKLY;BYDAY=SU,MO,TU,WE,TH,FR,SA;UNTIL=20200131T235959Z
172 const result = getOccurrencesBetween(component, Date.UTC(2020, 0, 1), Date.UTC(2020, 2, 1), cache);
173 expect(stringifyResultSimple(result)).toEqual([
174 '2020-01-29T13:00:00.000Z - 2020-01-29T13:30:00.000Z',
175 '2020-01-30T13:00:00.000Z - 2020-01-30T13:30:00.000Z',
176 '2020-01-31T13:00:00.000Z - 2020-01-31T13:30:00.000Z',
180 it('should fill occurrences until 31st of Jan in Pago Pago time', () => {
181 const component = parse(`
183 DTSTART;TZID=Pacific/Pago_Pago:20200129T000000
184 DTEND;TZID=Europe/Zurich:20200129T133000
185 RRULE:FREQ=WEEKLY;BYDAY=SU,MO,TU,WE,TH,FR,SA;UNTIL=20200201T105959Z
188 const result = getOccurrencesBetween(component, Date.UTC(2020, 0, 1), Date.UTC(2020, 2, 1), cache);
189 expect(stringifyResultSimple(result)).toEqual([
190 '2020-01-29T11:00:00.000Z - 2020-01-29T12:30:00.000Z',
191 '2020-01-30T11:00:00.000Z - 2020-01-30T12:30:00.000Z',
192 '2020-01-31T11:00:00.000Z - 2020-01-31T12:30:00.000Z',
196 it('should fill occurrences for an event starting on a sunday', () => {
197 const component = parse(`
199 RRULE:FREQ=WEEKLY;COUNT=4;BYDAY=SA,SU
200 DTSTART;VALUE=DATE:20200126
201 DTEND;VALUE=DATE:20200127
205 const result = getOccurrencesBetween(component, Date.UTC(2020, 0, 1), Date.UTC(2021, 2, 1), cache);
206 expect(stringifyResultSimple(result)).toEqual([
207 '2020-01-26T00:00:00.000Z - 2020-01-26T00:00:00.000Z',
208 '2020-02-01T00:00:00.000Z - 2020-02-01T00:00:00.000Z',
209 '2020-02-02T00:00:00.000Z - 2020-02-02T00:00:00.000Z',
210 '2020-02-08T00:00:00.000Z - 2020-02-08T00:00:00.000Z',
214 it('should fill occurrences for an event with an exdate', () => {
215 const component = parse(`
217 RRULE:FREQ=DAILY;COUNT=6
218 DTSTART;TZID=Europe/Zurich:20200309T043000
219 DTEND;TZID=Europe/Zurich:20200309T063000
220 EXDATE;TZID=Europe/Zurich:20200311T043000
221 EXDATE;TZID=Europe/Zurich:20200313T043000
225 const result = getOccurrencesBetween(component, Date.UTC(2020, 0, 1), Date.UTC(2021, 4, 1), cache);
226 expect(stringifyResult(result)).toEqual([
227 '2020-03-09T03:30:00.000Z - 2020-03-09T05:30:00.000Z | 1',
228 '2020-03-10T03:30:00.000Z - 2020-03-10T05:30:00.000Z | 2',
229 '2020-03-12T03:30:00.000Z - 2020-03-12T05:30:00.000Z | 4',
230 '2020-03-14T03:30:00.000Z - 2020-03-14T05:30:00.000Z | 6',
234 it('should fill occurrences for an all day event with an exdate', () => {
235 const component = parse(`
237 RRULE:FREQ=DAILY;COUNT=6
238 DTSTART;VALUE=DATE:20200201
239 DTEND;VALUE=DATE:20200202
240 EXDATE;VALUE=DATE:20200201
241 EXDATE;VALUE=DATE:20200202
242 EXDATE;VALUE=DATE:20200203
246 const result = getOccurrencesBetween(component, Date.UTC(2020, 0, 1), Date.UTC(2021, 4, 1), cache);
247 expect(stringifyResultSimple(result)).toEqual([
248 '2020-02-04T00:00:00.000Z - 2020-02-04T00:00:00.000Z',
249 '2020-02-05T00:00:00.000Z - 2020-02-05T00:00:00.000Z',
250 '2020-02-06T00:00:00.000Z - 2020-02-06T00:00:00.000Z',
254 it('should not fill occurrences for an event without rrule', () => {
255 const component = parse(`
257 DTSTART:20200201T030000Z
258 DTEND:20200201T040000Z
262 const result = getOccurrencesBetween(component, Date.UTC(2020, 0, 1), Date.UTC(2021, 4, 1), cache);
263 expect(stringifyResultSimple(result)).toEqual(['2020-02-01T03:00:00.000Z - 2020-02-01T04:00:00.000Z']);
266 it('should fill one occurrence without rrule', () => {
267 const component = parse(`
269 DTSTART:20200201T030000Z
270 DTEND:20200201T040000Z
273 expect(getOccurrences({ component, maxCount: 0 }).length).toBe(0);
274 expect(getOccurrences({ component, maxCount: 1 }).length).toBe(1);
275 expect(getOccurrences({ component, maxCount: 2 }).length).toBe(1);
278 it('should fill no occurrence for rrule with count = 0', () => {
279 const component = parse(`
281 DTSTART:20200201T030000Z
282 DTEND:20200201T040000Z
283 RRULE:FREQ=DAILY;COUNT=0
286 expect(getOccurrences({ component, maxCount: 1 }).length).toBe(0);
289 it('should fill occurrences with max start', () => {
290 const component = parse(`
292 DTSTART:20200201T030000Z
293 DTEND:20200201T040000Z
294 RRULE:FREQ=DAILY;COUNT=6
298 stringifyLocalResultSimple(
302 maxStart: new Date(Date.UTC(2020, 1, 4)),
305 ).toEqual(['2020-02-01T03:00:00.000Z - 1', '2020-02-02T03:00:00.000Z - 2', '2020-02-03T03:00:00.000Z - 3']);
308 it('should fill occurrences for a UTC date with an exdate', () => {
309 const component = parse(`
311 RRULE:FREQ=DAILY;COUNT=6
312 DTSTART:20200201T030000Z
313 DTEND:20200201T040000Z
314 EXDATE:20200202T030000Z
315 EXDATE:20200203T030000Z
316 EXDATE:20200204T030000Z
320 const result = getOccurrencesBetween(component, Date.UTC(2020, 0, 1), Date.UTC(2021, 4, 1), cache);
321 expect(stringifyResultSimple(result)).toEqual([
322 '2020-02-01T03:00:00.000Z - 2020-02-01T04:00:00.000Z',
323 '2020-02-05T03:00:00.000Z - 2020-02-05T04:00:00.000Z',
324 '2020-02-06T03:00:00.000Z - 2020-02-06T04:00:00.000Z',
328 it('should fill occurrences with an end date in another timezone', () => {
329 const component = parse(`
331 RRULE:FREQ=DAILY;COUNT=2;INTERVAL=60
332 DTSTART;TZID=Europe/Zurich:20200901T080000
333 DTEND:20200901T060000Z
337 const result = getOccurrencesBetween(component, Date.UTC(2020, 0, 1), Date.UTC(2021, 4, 1), cache);
338 expect(stringifyResultFull(result)).toEqual([
339 '2020-09-01T08:00:00.000Z - 2020-09-01T06:00:00.000Z | 2020-09-01T06:00:00.000Z - 2020-09-01T06:00:00.000Z | 1',
340 '2020-10-31T08:00:00.000Z - 2020-10-31T07:00:00.000Z | 2020-10-31T07:00:00.000Z - 2020-10-31T07:00:00.000Z | 2',