1import * as Calendar from 'expo-calendar';
2import { UnavailabilityError } from 'expo-modules-core';
3import { Platform } from 'react-native';
4
5import * as TestUtils from '../TestUtils';
6
7export const name = 'CalendarReminders';
8
9async function createTestReminderAsync(calendarId) {
10  return await Calendar.createReminderAsync(calendarId, {
11    title: 'Reminder to buy a ticket',
12    startDate: new Date(2019, 3, 3, 9, 0, 0),
13    dueDate: new Date(2019, 3, 3, 23, 59, 59),
14  });
15}
16
17async function getFirstCalendarForRemindersAsync() {
18  const calendars = await Calendar.getCalendarsAsync(Calendar.EntityTypes.REMINDER);
19  return calendars[0] && calendars[0].id;
20}
21
22function expectMethodsToReject(t, methods) {
23  for (const methodName of methods) {
24    t.describe(`${methodName}()`, () => {
25      t.it('rejects with UnavailabilityError on unsupported platform', async () => {
26        let error;
27        try {
28          await Calendar[methodName]();
29        } catch (e) {
30          error = e;
31        }
32        t.expect(error instanceof UnavailabilityError).toBe(true);
33        t.expect(error.message).toBe(new UnavailabilityError('Calendar', methodName).message);
34      });
35    });
36  }
37}
38
39function testReminderShape(t, reminder) {
40  t.expect(reminder).toBeDefined();
41  t.expect(typeof reminder.id).toBe('string');
42  t.expect(typeof reminder.calendarId).toBe('string');
43  t.expect(typeof reminder.title).toBe('string');
44  // t.expect(typeof reminder.startDate).toBe('string');
45  // t.expect(typeof reminder.dueDate).toBe('string');
46  t.expect(typeof reminder.completed).toBe('boolean');
47}
48
49export async function test(t) {
50  const shouldSkipTestsRequiringPermissions = await TestUtils.shouldSkipTestsRequiringPermissionsAsync();
51  const describeWithPermissions = shouldSkipTestsRequiringPermissions ? t.xdescribe : t.describe;
52
53  describeWithPermissions('CalendarReminders', () => {
54    if (Platform.OS !== 'ios') {
55      expectMethodsToReject(t, [
56        'requestRemindersPermissionsAsync',
57        'getRemindersAsync',
58        'getReminderAsync',
59        'createReminderAsync',
60        'updateReminderAsync',
61        'deleteReminderAsync',
62      ]);
63      return;
64    }
65
66    let calendarId = null;
67
68    t.beforeAll(async () => {
69      calendarId = await Calendar.createCalendarAsync({
70        title: 'Expo Reminders Calendar',
71        entityType: Calendar.EntityTypes.REMINDER,
72      });
73    });
74
75    t.describe('requestRemindersPermissionsAsync()', () => {
76      t.it('requests for Reminders permissions', async () => {
77        const results = await Calendar.requestRemindersPermissionsAsync();
78
79        t.expect(results.granted).toBe(true);
80        t.expect(results.status).toBe('granted');
81      });
82    });
83
84    t.describe('createReminderAsync()', () => {
85      let reminderId;
86
87      t.it('creates a reminder', async () => {
88        reminderId = await createTestReminderAsync(calendarId);
89
90        t.expect(reminderId).toBeDefined();
91        t.expect(typeof reminderId).toBe('string');
92      });
93
94      t.afterAll(async () => {
95        await Calendar.deleteReminderAsync(reminderId);
96      });
97    });
98
99    t.describe('getRemindersAsync()', () => {
100      let reminderId;
101
102      t.beforeAll(async () => {
103        reminderId = await createTestReminderAsync(calendarId);
104      });
105
106      t.it('returns an array of reminders', async () => {
107        const reminders = await Calendar.getRemindersAsync(
108          [calendarId],
109          Calendar.ReminderStatus.INCOMPLETE,
110          new Date(2019, 3, 2),
111          new Date(2019, 3, 5)
112        );
113
114        t.expect(Array.isArray(reminders)).toBe(true);
115        t.expect(reminders.length).toBe(1);
116        t.expect(reminders[0].id).toBe(reminderId);
117        testReminderShape(t, reminders[0]);
118      });
119
120      t.afterAll(async () => {
121        await Calendar.deleteReminderAsync(reminderId);
122      });
123    });
124
125    t.describe('getReminderAsync()', () => {
126      let reminderId;
127
128      t.beforeAll(async () => {
129        reminderId = await createTestReminderAsync(calendarId);
130      });
131
132      t.it('returns an array of reminders', async () => {
133        const reminder = await Calendar.getReminderAsync(reminderId);
134
135        t.expect(reminder).toBeDefined();
136        t.expect(reminder.id).toBe(reminderId);
137        testReminderShape(t, reminder);
138      });
139
140      t.afterAll(async () => {
141        await Calendar.deleteReminderAsync(reminderId);
142      });
143    });
144
145    t.describe('updateReminderAsync()', () => {
146      let reminderId;
147
148      t.beforeAll(async () => {
149        reminderId = await createTestReminderAsync(calendarId);
150      });
151
152      t.it('updates a reminder', async () => {
153        const dueDate = new Date();
154        dueDate.setMilliseconds(0);
155
156        const updatedReminderId = await Calendar.updateReminderAsync(reminderId, { dueDate });
157        const reminder = await Calendar.getReminderAsync(updatedReminderId);
158
159        t.expect(updatedReminderId).toBe(reminderId);
160        t.expect(reminder.dueDate).toBe(dueDate.toISOString());
161      });
162
163      t.afterAll(async () => {
164        await Calendar.deleteReminderAsync(reminderId);
165      });
166    });
167
168    t.describe('deleteReminderAsync()', () => {
169      let reminderId;
170
171      t.beforeAll(async () => {
172        reminderId = await createTestReminderAsync(calendarId);
173      });
174
175      t.it('deletes a reminder', async () => {
176        await Calendar.deleteReminderAsync(reminderId);
177        let error;
178
179        try {
180          await Calendar.getReminderAsync(reminderId);
181        } catch (e) {
182          error = e;
183        }
184        t.expect(error).toBeDefined();
185        t.expect(error instanceof Error).toBe(true);
186        t.expect(error.code).toBe('E_REMINDER_NOT_FOUND');
187      });
188
189      t.afterAll(async () => {
190        await Calendar.deleteReminderAsync(reminderId);
191      });
192    });
193
194    t.afterAll(async () => {
195      await Calendar.deleteCalendarAsync(calendarId);
196    });
197  });
198}
199