import fetchMock from 'fetch-mock' import timeGridPlugin from '@fullcalendar/timegrid' import { EventSourceInput } from '@fullcalendar/core' import iCalendarPlugin from '@fullcalendar/icalendar' import oneHourMeeting from './data/oneHourMeeting.js' import recurringWeekly from './data/recurringWeekly.js' import mungedOneHourMeeting from './data/mungedOneHourMeeting.js' import meetingWithMungedStart from './data/meetingWithMungedStart.js' import alldayEvent from './data/alldayEvent.js' import timedMeetingWithoutEnd from './data/timedMeetingWithoutEnd.js' import timedMeetingWithDuration from './data/timedMeetingWithDuration.js' import dataWithRecurrenceId from './data/recurrenceId.js' import { CalendarWrapper } from '../lib/wrappers/CalendarWrapper.js' import { TimeGridViewWrapper } from '../lib/wrappers/TimeGridViewWrapper.js' describe('addICalEventSource with day view', () => { const ICAL_MIME_TYPE = 'text/calendar' pushOptions({ plugins: [iCalendarPlugin, timeGridPlugin], initialDate: '2019-04-15', // The start of the week for oneHourMeeting initialView: 'timeGridDay', timeZone: 'Europe/Paris', }) afterEach(() => { fetchMock.restore() }) it('adds a one-hour long meeting', (done) => { loadICalendarWith(oneHourMeeting, () => { setTimeout(() => { assertEventCount(1) done() }, 100) }) }) it('adds a repeating weekly meeting', (done) => { loadICalendarWith(recurringWeekly, () => { setTimeout(() => { assertEventCount(1) const event = currentCalendar.getEvents()[0] // test non-date props expect(event.title).toBe('Weekly Monday meeting') expect(event.url).toBe('https://fullcalendar.io/') expect(event.extendedProps.description).toBe('this is the description') expect(event.extendedProps.location).toBe('this is the location') done() }, 100) }) }) it('adds an all day event', (done) => { loadICalendarWith(alldayEvent, () => { setTimeout(() => { assertEventCount(1) const events = currentCalendar.getEvents() events.forEach((event) => expect(event.allDay).toBeTruthy()) // test non-date props expect(events[0].title).toBe('First conference') expect(events[0].url).toBe('https://fullcalendar.io/') expect(events[0].extendedProps.description).toBe('this is the description') expect(events[0].extendedProps.location).toBe('this is the location') done() }, 100) }) }) it('ignores a munged event', (done) => { loadICalendarWith(mungedOneHourMeeting, () => { setTimeout(() => { assertEventCount(0) done() }, 100) }) }) it('ignores a meeting with a munged start', (done) => { loadICalendarWith(meetingWithMungedStart, () => { setTimeout(() => { assertEventCount(0) done() }, 100) }) }) it('sets default duration when forceEventDuration is enabled and no end or duration included in the VEVENT', (done) => { loadICalendarWith( timedMeetingWithoutEnd, () => { setTimeout(() => { assertEventCount(1) const event = currentCalendar.getEvents()[0] expect(event.end.getHours()).toEqual(event.start.getHours() + 3) done() }, 100) }, (source) => { initCalendar({ forceEventDuration: true, defaultTimedEventDuration: '03:00', }).addEventSource(source) }, ) }) it('sets end to null when forceEventDuration is disabled and no end or duration included in the VEVENT', (done) => { loadICalendarWith( timedMeetingWithoutEnd, () => { setTimeout(() => { assertEventCount(1) const event = currentCalendar.getEvents()[0] expect(event.end).toBe(null) done() }, 100) }, (source) => { initCalendar({ defaultTimedEventDuration: '03:00', forceEventDuration: false, }).addEventSource(source) }, ) }) it('does not override iCal DURATION in VEVENT', (done) => { loadICalendarWith( timedMeetingWithDuration, () => { setTimeout(() => { assertEventCount(1) const event = currentCalendar.getEvents()[0] expect(event.end.getHours()).toEqual(event.start.getHours() + 4) done() }, 100) }, (source) => { initCalendar({ forceEventDuration: true, defaultTimedEventDuration: '03:00', }).addEventSource(source) }, ) }) // https://github.com/fullcalendar/fullcalendar/issues/6451 it('respects RECURRENCE-ID and does not render double events', (done) => { loadICalendarWith( dataWithRecurrenceId, () => { setTimeout(() => { let timeGridWrapper = new TimeGridViewWrapper(currentCalendar).timeGrid let eventEls = timeGridWrapper.getEventEls() expect(eventEls.length).toBe(1) done() }, 100) }, (source) => { initCalendar({ initialDate: '2021-07-08', }).addEventSource(source) }, ) }) it('does not reload data on next', (done) => { let requestCnt = 0 const givenUrl = window.location.href + '/my-feed.php' fetchMock.get(/my-feed\.php/, () => { requestCnt++ return { headers: { 'content-type': ICAL_MIME_TYPE }, body: timedMeetingWithDuration, } }) initCalendar().addEventSource({ url: givenUrl, format: 'ics' } as EventSourceInput) setTimeout(() => { assertEventCount(1) currentCalendar.next() expect(requestCnt).toBe(1) done() }, 100) }) function loadICalendarWith( rawICal: string, assertions: () => void, calendarSetup?: (source: EventSourceInput) => void, ) { const givenUrl = window.location.href + '/my-feed.php' fetchMock.get(/my-feed\.php/, { headers: { 'content-type': ICAL_MIME_TYPE }, body: rawICal, }) const source = { url: givenUrl, format: 'ics' } as EventSourceInput if (calendarSetup) { calendarSetup(source) } else { initCalendar().addEventSource(source) } const [requestUrl] = fetchMock.lastCall() const requestParamStr = new URL(requestUrl).searchParams.toString() expect(requestParamStr).toBe('') assertions() } // Checks to make sure all events have been rendered and that the calendar // has internal info on all the events. function assertEventCount(expectedCount: number) { expect(currentCalendar.getEvents().length).toEqual(expectedCount) let calendarWrapper = new CalendarWrapper(currentCalendar) expect(calendarWrapper.getEventEls().length).toEqual(expectedCount) } })