xref: /expo/apps/test-suite/tests/TaskManager.js (revision 4a05dfd5)
1import * as TaskManager from 'expo-task-manager';
2import * as Location from 'expo-location';
3
4import * as TestUtils from '../TestUtils';
5
6const DEFINED_TASK_NAME = 'defined task';
7const UNDEFINED_TASK_NAME = 'undefined task';
8
9export const name = 'TaskManager';
10
11export async function test(t) {
12  const shouldSkipTestsRequiringPermissions = await TestUtils.shouldSkipTestsRequiringPermissionsAsync();
13  const describeWithPermissions = shouldSkipTestsRequiringPermissions ? t.xdescribe : t.describe;
14  const locationOptions = {
15    accuracy: Location.Accuracy.Low,
16    showsBackgroundLocationIndicator: false,
17  };
18  /*
19  Some of these tests cause Expo to crash on device farm with the following error:
20  "sdkUnversionedTestSuite failed: java.lang.NullPointerException: Attempt to invoke interface method
21  'java.util.Map org.unimodules.interfaces.taskManager.TaskInterface.getOptions()' on a null object reference"
22
23  getOptions() is being called from within LocationTaskConsumer.java in the expo-location module
24  several times without checking for null
25  */
26  t.describe('TaskManager', () => {
27    t.describe('isTaskDefined()', () => {
28      t.it('returns true if task is defined', () => {
29        t.expect(TaskManager.isTaskDefined(DEFINED_TASK_NAME)).toBe(true);
30      });
31      t.it('returns false if task is not defined', () => {
32        t.expect(TaskManager.isTaskDefined(UNDEFINED_TASK_NAME)).toBe(false);
33      });
34    });
35
36    describeWithPermissions('isTaskRegisteredAsync()', async () => {
37      t.beforeAll(async () => {
38        await Location.startLocationUpdatesAsync(DEFINED_TASK_NAME);
39      });
40
41      t.it('returns true for registered tasks', async () => {
42        t.expect(await TaskManager.isTaskRegisteredAsync(DEFINED_TASK_NAME)).toBe(true);
43      });
44
45      t.it('returns false for unregistered tasks', async () => {
46        t.expect(await TaskManager.isTaskRegisteredAsync(UNDEFINED_TASK_NAME)).toBe(false);
47      });
48
49      t.afterAll(async () => {
50        await Location.stopLocationUpdatesAsync(DEFINED_TASK_NAME);
51      });
52    });
53
54    describeWithPermissions('getTaskOptionsAsync()', async () => {
55      let taskOptions;
56
57      t.it('returns null for unregistered tasks', async () => {
58        taskOptions = await TaskManager.getTaskOptionsAsync(DEFINED_TASK_NAME);
59        t.expect(taskOptions).toBe(null);
60      });
61
62      t.it('returns correct options after register', async () => {
63        await Location.startLocationUpdatesAsync(DEFINED_TASK_NAME, locationOptions);
64        taskOptions = await TaskManager.getTaskOptionsAsync(DEFINED_TASK_NAME);
65        t.expect(taskOptions).toEqual(t.jasmine.objectContaining(locationOptions));
66      });
67
68      t.it('returns null when unregistered', async () => {
69        await Location.stopLocationUpdatesAsync(DEFINED_TASK_NAME);
70        taskOptions = await TaskManager.getTaskOptionsAsync(DEFINED_TASK_NAME);
71        t.expect(taskOptions).toBe(null);
72      });
73    });
74
75    describeWithPermissions('getRegisteredTasksAsync()', async () => {
76      let registeredTasks;
77
78      t.it('returns empty array if there are no tasks', async () => {
79        registeredTasks = await TaskManager.getRegisteredTasksAsync();
80        t.expect(registeredTasks).toBeDefined();
81        t.expect(registeredTasks.length).toBe(0);
82      });
83
84      t.it('returns correct array after registering the task', async () => {
85        await Location.startLocationUpdatesAsync(DEFINED_TASK_NAME, locationOptions);
86
87        registeredTasks = await TaskManager.getRegisteredTasksAsync();
88
89        t.expect(registeredTasks).toBeDefined();
90        t.expect(registeredTasks.length).toBe(1);
91        t.expect(registeredTasks.find(task => task.taskName === DEFINED_TASK_NAME)).toEqual(
92          t.jasmine.objectContaining({
93            taskName: DEFINED_TASK_NAME,
94            taskType: 'location',
95            options: locationOptions,
96          })
97        );
98      });
99
100      t.afterAll(async () => {
101        await Location.stopLocationUpdatesAsync(DEFINED_TASK_NAME);
102      });
103    });
104
105    describeWithPermissions('unregisterAllTasksAsync()', () => {
106      t.it('unregisters tasks correctly', async () => {
107        await Location.startLocationUpdatesAsync(DEFINED_TASK_NAME, locationOptions);
108        await TaskManager.unregisterAllTasksAsync();
109
110        t.expect(await TaskManager.isTaskRegisteredAsync(DEFINED_TASK_NAME)).toBe(false);
111        t.expect((await TaskManager.getRegisteredTasksAsync()).length).toBe(0);
112        t.expect(await Location.hasStartedLocationUpdatesAsync(DEFINED_TASK_NAME)).toBe(false);
113      });
114    });
115
116    describeWithPermissions('rejections', () => {
117      t.it('should reject when trying to unregister task with different consumer', async () => {
118        await Location.startLocationUpdatesAsync(DEFINED_TASK_NAME, locationOptions);
119
120        let error;
121        try {
122          await Location.stopGeofencingAsync(DEFINED_TASK_NAME, locationOptions);
123        } catch (e) {
124          error = e;
125        }
126        t.expect(error).toBeDefined();
127        t.expect(error.message).toMatch(/Invalid task consumer/);
128
129        await Location.stopLocationUpdatesAsync(DEFINED_TASK_NAME);
130      });
131    });
132  });
133}
134
135// Empty task so we can properly test some methods.
136TaskManager.defineTask(DEFINED_TASK_NAME, () => {});
137