xref: /expo/apps/test-suite/TestUtils.js (revision 191a2fb0)
1'use strict';
2
3import { Platform, UnavailabilityError } from '@unimodules/core';
4import Constants from 'expo-constants';
5import { isDeviceFarm } from './utils/Environment';
6import ExponentTest from './ExponentTest';
7
8function browserSupportsWebGL() {
9  try {
10    const canvas = document.createElement('canvas');
11    return (
12      !!window.WebGLRenderingContext &&
13      (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'))
14    );
15  } catch (e) {
16    return false;
17  }
18}
19
20function optionalRequire(requirer) {
21  try {
22    return requirer();
23  } catch (e) {
24    // eslint-disable-next-line
25    return;
26  }
27}
28
29// List of all modules for tests. Each file path must be statically present for
30// the packager to pick them all up.
31export function getTestModules() {
32  if (Platform.OS === 'web') {
33    const modules = [
34      optionalRequire(() => require('./tests/Asset')),
35      optionalRequire(() => require('./tests/SVG')),
36      optionalRequire(() => require('./tests/Basic')),
37      optionalRequire(() => require('./tests/Constants')),
38      optionalRequire(() => require('./tests/SVG')),
39      optionalRequire(() => require('./tests/Contacts')),
40      optionalRequire(() => require('./tests/Crypto')),
41      optionalRequire(() => require('./tests/Font')),
42      optionalRequire(() => require('./tests/Random')),
43      optionalRequire(() => require('./tests/Localization')),
44    ];
45
46    if (browserSupportsWebGL()) {
47      modules.push(optionalRequire(() => require('./tests/GLView')));
48    }
49
50    if (ExponentTest && !ExponentTest.isInCI) {
51      // modules.push(optionalRequire(() => require('./tests/Speech')));
52    }
53    return modules.filter(Boolean);
54  }
55
56  const modules = [
57    require('./tests/Basic'),
58    optionalRequire(() => require('./tests/Application')),
59    optionalRequire(() => require('./tests/Asset')),
60    optionalRequire(() => require('./tests/Constants')),
61    optionalRequire(() => require('./tests/Crypto')),
62    optionalRequire(() => require('./tests/Device')),
63    optionalRequire(() => require('./tests/GLView')),
64    optionalRequire(() => require('./tests/Haptics')),
65    optionalRequire(() => require('./tests/Localization')),
66    optionalRequire(() => require('./tests/Network')),
67    optionalRequire(() => require('./tests/SecureStore')),
68    optionalRequire(() => require('./tests/Segment')),
69    optionalRequire(() => require('./tests/SQLite')),
70    optionalRequire(() => require('./tests/Random')),
71  ];
72
73  if (global.DETOX) {
74    modules.push(
75      modules.push(optionalRequire(() => require('./tests/Permissions'))),
76      modules.push(optionalRequire(() => require('./tests/Calendar'))),
77      modules.push(optionalRequire(() => require('./tests/Video'))),
78      modules.push(optionalRequire(() => require('./tests/Audio')))
79    );
80  } else {
81    modules.push(
82      optionalRequire(() => require('./tests/Speech')),
83      optionalRequire(() => require('./tests/Recording')),
84      optionalRequire(() => require('./tests/FileSystem')),
85      optionalRequire(() => require('./tests/ScreenOrientation')),
86      optionalRequire(() => require('./tests/Payments')),
87      optionalRequire(() => require('./tests/AdMobInterstitial')),
88      optionalRequire(() => require('./tests/AdMobRewarded')),
89      optionalRequire(() => require('./tests/FBBannerAd'))
90    );
91  }
92
93  if (!global.DETOX && !isDeviceFarm()) {
94    // Times out sometimes
95    modules.push(
96      optionalRequire(() => require('./tests/AdMobPublisherBanner')),
97      optionalRequire(() => require('./tests/AdMobBanner'))
98    );
99    // Invalid placementId in CI (all tests fail)
100    modules.push(optionalRequire(() => require('./tests/FBNativeAd')));
101    // Requires interaction (sign in popup)
102    modules.push(optionalRequire(() => require('./tests/GoogleSignIn')));
103    // Popup to request device's location which uses Google's location service
104    modules.push(optionalRequire(() => require('./tests/Location')));
105    // Fails to redirect because of malformed URL in published version with release channel parameter
106    modules.push(optionalRequire(() => require('./tests/Linking')));
107    // Requires permission
108    modules.push(optionalRequire(() => require('./tests/Calendar')));
109    modules.push(optionalRequire(() => require('./tests/Contacts')));
110    modules.push(optionalRequire(() => require('./tests/Permissions')));
111    modules.push(optionalRequire(() => require('./tests/MediaLibrary')));
112    modules.push(optionalRequire(() => require('./tests/Notifications')));
113    if (Constants.isDevice) {
114      modules.push(optionalRequire(() => require('./tests/Battery')));
115      modules.push(optionalRequire(() => require('./tests/Brightness')));
116    }
117    // Crashes app when mounting component
118    modules.push(optionalRequire(() => require('./tests/Video')));
119    // "sdkUnversionedTestSuite failed: java.lang.NullPointerException: Attempt to invoke interface method
120    // 'java.util.Map org.unimodules.interfaces.taskManager.TaskInterface.getOptions()' on a null object reference"
121    modules.push(optionalRequire(() => require('./tests/TaskManager')));
122    // Audio tests are flaky in CI due to asynchronous fetching of resources
123    modules.push(optionalRequire(() => require('./tests/Audio')));
124    // The Camera tests are flaky on iOS, i.e. they fail randomly
125    if (Constants.isDevice && Platform.OS === 'android')
126      modules.push(optionalRequire(() => require('./tests/Camera')));
127  }
128  if (Platform.OS === 'android') modules.push(optionalRequire(() => require('./tests/JSC')));
129  if (Constants.isDevice) {
130    modules.push(optionalRequire(() => require('./tests/Cellular')));
131    modules.push(optionalRequire(() => require('./tests/BarCodeScanner')));
132  }
133  return modules.filter(Boolean);
134}
135
136export async function acceptPermissionsAndRunCommandAsync(fn) {
137  if (!ExponentTest) {
138    return await fn();
139  }
140
141  const results = await Promise.all([
142    ExponentTest.action({
143      selectorType: 'text',
144      selectorValue: 'Allow',
145      actionType: 'click',
146      delay: 1000,
147      timeout: 100,
148    }),
149    fn(),
150  ]);
151
152  return results[1];
153}
154
155export async function shouldSkipTestsRequiringPermissionsAsync() {
156  if (!ExponentTest || !ExponentTest.shouldSkipTestsRequiringPermissionsAsync) {
157    return false;
158  }
159  return ExponentTest.shouldSkipTestsRequiringPermissionsAsync();
160}
161
162export async function expectMethodToBeUnavailableAsync(expect, method) {
163  const error = await expectMethodToThrowAsync(method);
164  expect(error instanceof UnavailabilityError).toBeTruthy();
165}
166
167export async function expectMethodToThrowAsync(method) {
168  try {
169    await method();
170  } catch (error) {
171    return error;
172  }
173}
174