const { parseRRULE, } = require('../../../../../modules/caldav/icalendar/rrule-parser'); describe('RRULE Parser', () => { it('should return null for empty RRULE', () => { expect(parseRRULE('')).toBeNull(); expect(parseRRULE(null)).toBeNull(); }); it('should return null for RRULE without FREQ', () => { expect(parseRRULE('INTERVAL=2')).toBeNull(); }); describe('Daily Recurrence', () => { it('should parse daily RRULE', () => { const result = parseRRULE('FREQ=DAILY'); expect(result.recurrence_type).toBe('daily'); expect(result.recurrence_interval).toBe(1); }); it('should parse daily with interval', () => { const result = parseRRULE('FREQ=DAILY;INTERVAL=3'); expect(result.recurrence_type).toBe('daily'); expect(result.recurrence_interval).toBe(3); }); }); describe('Weekly Recurrence', () => { it('should parse weekly RRULE', () => { const result = parseRRULE('FREQ=WEEKLY'); expect(result.recurrence_type).toBe('weekly'); expect(result.recurrence_interval).toBe(1); }); it('should parse weekly with BYDAY', () => { const result = parseRRULE('FREQ=WEEKLY;BYDAY=MO,WE,FR'); expect(result.recurrence_type).toBe('weekly'); expect(result.recurrence_weekdays).toEqual([1, 3, 5]); }); it('should parse weekly with interval and BYDAY', () => { const result = parseRRULE('FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,TH'); expect(result.recurrence_type).toBe('weekly'); expect(result.recurrence_interval).toBe(2); expect(result.recurrence_weekdays).toEqual([2, 4]); }); }); describe('Monthly Recurrence', () => { it('should parse monthly with BYMONTHDAY', () => { const result = parseRRULE('FREQ=MONTHLY;BYMONTHDAY=15'); expect(result.recurrence_type).toBe('monthly'); expect(result.recurrence_month_day).toBe(15); }); it('should parse monthly last day', () => { const result = parseRRULE('FREQ=MONTHLY;BYMONTHDAY=-1'); expect(result.recurrence_type).toBe('monthly_last_day'); }); it('should parse monthly weekday (2nd Thursday)', () => { const result = parseRRULE('FREQ=MONTHLY;BYDAY=2TH'); expect(result.recurrence_type).toBe('monthly_weekday'); expect(result.recurrence_week_of_month).toBe(2); expect(result.recurrence_weekday).toBe(4); }); it('should parse monthly weekday (last Friday)', () => { const result = parseRRULE('FREQ=MONTHLY;BYDAY=-1FR'); expect(result.recurrence_type).toBe('monthly_weekday'); expect(result.recurrence_week_of_month).toBe(-1); expect(result.recurrence_weekday).toBe(5); }); it('should parse monthly with interval', () => { const result = parseRRULE('FREQ=MONTHLY;INTERVAL=3;BYMONTHDAY=10'); expect(result.recurrence_type).toBe('monthly'); expect(result.recurrence_interval).toBe(3); expect(result.recurrence_month_day).toBe(10); }); }); describe('Yearly Recurrence', () => { it('should parse yearly RRULE', () => { const result = parseRRULE('FREQ=YEARLY'); expect(result.recurrence_type).toBe('yearly'); expect(result.recurrence_interval).toBe(1); }); it('should parse yearly with interval', () => { const result = parseRRULE('FREQ=YEARLY;INTERVAL=2'); expect(result.recurrence_type).toBe('yearly'); expect(result.recurrence_interval).toBe(2); }); }); describe('UNTIL (End Date)', () => { it('should parse UNTIL date', () => { const result = parseRRULE('FREQ=DAILY;UNTIL=20261231T120000Z'); expect(result.recurrence_type).toBe('daily'); expect(result.recurrence_end_date).toBeInstanceOf(Date); expect(result.recurrence_end_date.getFullYear()).toBe(2026); expect(result.recurrence_end_date.getMonth()).toBe(11); expect(result.recurrence_end_date.getDate()).toBe(31); }); it('should parse weekly with BYDAY and UNTIL', () => { const result = parseRRULE( 'FREQ=WEEKLY;BYDAY=MO,FR;UNTIL=20270101T000000Z' ); expect(result.recurrence_type).toBe('weekly'); expect(result.recurrence_weekdays).toEqual([1, 5]); expect(result.recurrence_end_date).toBeInstanceOf(Date); }); }); describe('Round-trip compatibility', () => { const testCases = [ { rrule: 'FREQ=DAILY', type: 'daily' }, { rrule: 'FREQ=DAILY;INTERVAL=2', type: 'daily', interval: 2 }, { rrule: 'FREQ=WEEKLY;BYDAY=MO,WE,FR', type: 'weekly', weekdays: [1, 3, 5], }, { rrule: 'FREQ=MONTHLY;BYMONTHDAY=15', type: 'monthly', monthDay: 15, }, { rrule: 'FREQ=MONTHLY;BYMONTHDAY=-1', type: 'monthly_last_day' }, { rrule: 'FREQ=MONTHLY;BYDAY=2TH', type: 'monthly_weekday', week: 2, weekday: 4, }, { rrule: 'FREQ=YEARLY', type: 'yearly' }, ]; testCases.forEach(({ rrule, type }) => { it(`should parse ${type} RRULE correctly`, () => { const result = parseRRULE(rrule); expect(result).not.toBeNull(); expect(result.recurrence_type).toBe(type); }); }); }); });