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