@react-native-harness/platform-android 1.1.0-rc.2 → 1.1.0-rc.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +9 -2
  2. package/dist/__tests__/adb.test.js +283 -10
  3. package/dist/__tests__/avd-config.test.d.ts +2 -0
  4. package/dist/__tests__/avd-config.test.d.ts.map +1 -0
  5. package/dist/__tests__/avd-config.test.js +174 -0
  6. package/dist/__tests__/ci-action.test.d.ts +2 -0
  7. package/dist/__tests__/ci-action.test.d.ts.map +1 -0
  8. package/dist/__tests__/ci-action.test.js +46 -0
  9. package/dist/__tests__/emulator-startup.test.d.ts +2 -0
  10. package/dist/__tests__/emulator-startup.test.d.ts.map +1 -0
  11. package/dist/__tests__/emulator-startup.test.js +19 -0
  12. package/dist/__tests__/environment.test.d.ts +2 -0
  13. package/dist/__tests__/environment.test.d.ts.map +1 -0
  14. package/dist/__tests__/environment.test.js +51 -0
  15. package/dist/__tests__/instance.test.d.ts +2 -0
  16. package/dist/__tests__/instance.test.d.ts.map +1 -0
  17. package/dist/__tests__/instance.test.js +423 -0
  18. package/dist/adb.d.ts +23 -0
  19. package/dist/adb.d.ts.map +1 -1
  20. package/dist/adb.js +265 -16
  21. package/dist/app-monitor.d.ts.map +1 -1
  22. package/dist/app-monitor.js +27 -7
  23. package/dist/assertions.d.ts +5 -0
  24. package/dist/assertions.d.ts.map +1 -0
  25. package/dist/assertions.js +6 -0
  26. package/dist/avd-config.d.ts +41 -0
  27. package/dist/avd-config.d.ts.map +1 -0
  28. package/dist/avd-config.js +173 -0
  29. package/dist/config.d.ts +77 -0
  30. package/dist/config.d.ts.map +1 -1
  31. package/dist/config.js +5 -0
  32. package/dist/emulator-startup.d.ts +3 -0
  33. package/dist/emulator-startup.d.ts.map +1 -0
  34. package/dist/emulator-startup.js +17 -0
  35. package/dist/emulator.d.ts +6 -0
  36. package/dist/emulator.d.ts.map +1 -0
  37. package/dist/emulator.js +27 -0
  38. package/dist/environment.d.ts +28 -0
  39. package/dist/environment.d.ts.map +1 -0
  40. package/dist/environment.js +295 -0
  41. package/dist/errors.d.ts +7 -0
  42. package/dist/errors.d.ts.map +1 -0
  43. package/dist/errors.js +14 -0
  44. package/dist/factory.d.ts.map +1 -1
  45. package/dist/factory.js +3 -0
  46. package/dist/index.d.ts +3 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +3 -0
  49. package/dist/instance.d.ts +6 -0
  50. package/dist/instance.d.ts.map +1 -0
  51. package/dist/instance.js +234 -0
  52. package/dist/reader.d.ts +6 -0
  53. package/dist/reader.d.ts.map +1 -0
  54. package/dist/reader.js +57 -0
  55. package/dist/runner.d.ts +2 -2
  56. package/dist/runner.d.ts.map +1 -1
  57. package/dist/runner.js +12 -52
  58. package/dist/targets.d.ts +1 -1
  59. package/dist/targets.d.ts.map +1 -1
  60. package/dist/targets.js +2 -0
  61. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  62. package/dist/types.d.ts +381 -0
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/types.js +107 -0
  65. package/package.json +4 -4
  66. package/src/__tests__/adb.test.ts +419 -15
  67. package/src/__tests__/avd-config.test.ts +206 -0
  68. package/src/__tests__/ci-action.test.ts +81 -0
  69. package/src/__tests__/emulator-startup.test.ts +32 -0
  70. package/src/__tests__/environment.test.ts +87 -0
  71. package/src/__tests__/instance.test.ts +610 -0
  72. package/src/adb.ts +423 -16
  73. package/src/app-monitor.ts +56 -18
  74. package/src/avd-config.ts +290 -0
  75. package/src/config.ts +8 -0
  76. package/src/emulator-startup.ts +28 -0
  77. package/src/environment.ts +510 -0
  78. package/src/errors.ts +19 -0
  79. package/src/factory.ts +4 -0
  80. package/src/index.ts +7 -1
  81. package/src/instance.ts +380 -0
  82. package/src/runner.ts +23 -69
  83. package/src/targets.ts +11 -8
@@ -0,0 +1,380 @@
1
+ import {
2
+ AppNotInstalledError,
3
+ CreateAppMonitorOptions,
4
+ DeviceNotFoundError,
5
+ type HarnessPlatformInitOptions,
6
+ HarnessPlatformRunner,
7
+ } from '@react-native-harness/platforms';
8
+ import type { Config as HarnessConfig } from '@react-native-harness/config';
9
+ import { logger } from '@react-native-harness/tools';
10
+ import {
11
+ AndroidPlatformConfig,
12
+ assertAndroidDeviceEmulator,
13
+ assertAndroidDevicePhysical,
14
+ } from './config.js';
15
+ import {
16
+ isAvdCompatible,
17
+ readAvdConfig,
18
+ resolveAvdCachingEnabled,
19
+ } from './avd-config.js';
20
+ import { getAdbId } from './adb-id.js';
21
+ import * as adb from './adb.js';
22
+ import {
23
+ applyHarnessDebugHttpHost,
24
+ clearHarnessDebugHttpHost,
25
+ } from './shared-prefs.js';
26
+ import { getDeviceName } from './utils.js';
27
+ import { createAndroidAppMonitor } from './app-monitor.js';
28
+ import { HarnessAppPathError, HarnessEmulatorConfigError } from './errors.js';
29
+ import {
30
+ ensureAndroidEmulatorEnvironment,
31
+ getHostAndroidSystemImageArch,
32
+ } from './environment.js';
33
+ import { isInteractive } from '@react-native-harness/tools';
34
+ import fs from 'node:fs';
35
+ import type { AppMonitor } from '@react-native-harness/platforms';
36
+
37
+ const androidInstanceLogger = logger.child('android-instance');
38
+
39
+ const createNoopAppMonitor = (): AppMonitor => ({
40
+ start: async () => undefined,
41
+ stop: async () => undefined,
42
+ dispose: async () => undefined,
43
+ addListener: () => undefined,
44
+ removeListener: () => undefined,
45
+ });
46
+
47
+ const getHarnessAppPath = (): string => {
48
+ const appPath = process.env.HARNESS_APP_PATH;
49
+
50
+ if (!appPath) {
51
+ throw new HarnessAppPathError('missing');
52
+ }
53
+
54
+ if (!fs.existsSync(appPath)) {
55
+ throw new HarnessAppPathError('invalid', appPath);
56
+ }
57
+
58
+ return appPath;
59
+ };
60
+
61
+ const configureAndroidRuntime = async (
62
+ adbId: string,
63
+ config: AndroidPlatformConfig,
64
+ harnessConfig: HarnessConfig
65
+ ): Promise<number> => {
66
+ const metroPort = harnessConfig.metroPort;
67
+
68
+ await Promise.all([
69
+ adb.reversePort(adbId, metroPort),
70
+ adb.reversePort(adbId, 8080),
71
+ adb.setHideErrorDialogs(adbId, true),
72
+ applyHarnessDebugHttpHost(adbId, config.bundleId, `localhost:${metroPort}`),
73
+ ]);
74
+
75
+ return adb.getAppUid(adbId, config.bundleId);
76
+ };
77
+
78
+ const startAndWaitForBoot = async ({
79
+ emulatorName,
80
+ signal,
81
+ mode,
82
+ }: {
83
+ emulatorName: string;
84
+ signal: AbortSignal;
85
+ mode?: Parameters<typeof adb.startEmulator>[1];
86
+ }): Promise<string> => {
87
+ await adb.startEmulator(emulatorName, mode);
88
+ return adb.waitForBoot(emulatorName, signal);
89
+ };
90
+
91
+ const recreateAvd = async ({
92
+ emulatorConfig,
93
+ }: {
94
+ emulatorConfig: Extract<
95
+ AndroidPlatformConfig['device'],
96
+ { type: 'emulator' }
97
+ >;
98
+ }): Promise<void> => {
99
+ if (!emulatorConfig.avd) {
100
+ throw new HarnessEmulatorConfigError(emulatorConfig.name);
101
+ }
102
+
103
+ await adb.createAvd({
104
+ name: emulatorConfig.name,
105
+ apiLevel: emulatorConfig.avd.apiLevel,
106
+ profile: emulatorConfig.avd.profile,
107
+ diskSize: emulatorConfig.avd.diskSize,
108
+ heapSize: emulatorConfig.avd.heapSize,
109
+ });
110
+ };
111
+
112
+ const prepareCachedAvd = async ({
113
+ emulatorConfig,
114
+ signal,
115
+ }: {
116
+ emulatorConfig: Extract<
117
+ AndroidPlatformConfig['device'],
118
+ { type: 'emulator' }
119
+ >;
120
+ signal: AbortSignal;
121
+ }): Promise<string> => {
122
+ const emulatorName = emulatorConfig.name;
123
+ const hostArch = getHostAndroidSystemImageArch();
124
+ const hasExistingAvd = await adb.hasAvd(emulatorName);
125
+ const avdConfig = hasExistingAvd ? await readAvdConfig(emulatorName) : null;
126
+ const compatibility =
127
+ avdConfig == null
128
+ ? { compatible: false as const, reason: 'Missing AVD config.ini.' }
129
+ : isAvdCompatible({
130
+ emulator: emulatorConfig,
131
+ avdConfig,
132
+ hostArch,
133
+ });
134
+
135
+ if (!hasExistingAvd || !compatibility.compatible) {
136
+ logger.info(
137
+ hasExistingAvd
138
+ ? 'Recreating incompatible Android emulator %s...'
139
+ : 'Creating Android emulator %s...',
140
+ emulatorName
141
+ );
142
+
143
+ if (hasExistingAvd && !compatibility.compatible) {
144
+ androidInstanceLogger.debug(
145
+ 'Android AVD %s is not reusable: %s',
146
+ emulatorName,
147
+ compatibility.reason
148
+ );
149
+ await adb.deleteAvd(emulatorName);
150
+ }
151
+
152
+ await recreateAvd({ emulatorConfig });
153
+
154
+ const generationAdbId = await startAndWaitForBoot({
155
+ emulatorName,
156
+ signal,
157
+ mode: 'clean-snapshot-generation',
158
+ });
159
+
160
+ logger.info('Saving Android emulator snapshot for %s...', emulatorName);
161
+ await adb.stopEmulator(generationAdbId);
162
+ await adb.waitForEmulatorDisconnect(generationAdbId, signal);
163
+ } else {
164
+ logger.info('Using cached Android emulator %s...', emulatorName);
165
+ }
166
+
167
+ return startAndWaitForBoot({
168
+ emulatorName,
169
+ signal,
170
+ mode: 'snapshot-reuse',
171
+ });
172
+ };
173
+
174
+ export const getAndroidEmulatorPlatformInstance = async (
175
+ config: AndroidPlatformConfig,
176
+ harnessConfig: HarnessConfig,
177
+ init: HarnessPlatformInitOptions
178
+ ): Promise<HarnessPlatformRunner> => {
179
+ assertAndroidDeviceEmulator(config.device);
180
+ const detectNativeCrashes = harnessConfig.detectNativeCrashes ?? true;
181
+ const emulatorConfig = config.device;
182
+ const emulatorName = emulatorConfig.name;
183
+ const avdConfig = emulatorConfig.avd;
184
+ const avdCachingEnabled = resolveAvdCachingEnabled({
185
+ avd: avdConfig,
186
+ isInteractive: isInteractive(),
187
+ });
188
+
189
+ let adbId = await getAdbId(emulatorConfig);
190
+ let startedByHarness = false;
191
+
192
+ androidInstanceLogger.debug(
193
+ 'resolved Android emulator %s with adb id %s',
194
+ emulatorConfig.name,
195
+ adbId ?? 'not-found'
196
+ );
197
+
198
+ if (!adbId) {
199
+ if (!avdConfig) {
200
+ throw new HarnessEmulatorConfigError(emulatorConfig.name);
201
+ }
202
+
203
+ await ensureAndroidEmulatorEnvironment(avdConfig.apiLevel);
204
+
205
+ adbId = avdCachingEnabled
206
+ ? await prepareCachedAvd({
207
+ emulatorConfig,
208
+ signal: init.signal,
209
+ })
210
+ : await (async () => {
211
+ if (!(await adb.hasAvd(emulatorConfig.name))) {
212
+ logger.info('Creating Android emulator %s...', emulatorName);
213
+ androidInstanceLogger.debug(
214
+ 'creating Android AVD %s before startup',
215
+ emulatorConfig.name
216
+ );
217
+ await recreateAvd({ emulatorConfig });
218
+ } else {
219
+ logger.info('Using existing Android emulator %s...', emulatorName);
220
+ }
221
+
222
+ androidInstanceLogger.debug(
223
+ 'starting Android emulator %s',
224
+ emulatorConfig.name
225
+ );
226
+ return startAndWaitForBoot({
227
+ emulatorName: emulatorConfig.name,
228
+ signal: init.signal,
229
+ });
230
+ })();
231
+
232
+ startedByHarness = true;
233
+
234
+ androidInstanceLogger.debug(
235
+ 'Android emulator %s connected as %s',
236
+ emulatorConfig.name,
237
+ adbId
238
+ );
239
+ } else if (emulatorConfig.avd) {
240
+ await ensureAndroidEmulatorEnvironment(emulatorConfig.avd.apiLevel);
241
+ }
242
+
243
+ if (!adbId) {
244
+ throw new DeviceNotFoundError(getDeviceName(emulatorConfig));
245
+ }
246
+
247
+ androidInstanceLogger.debug(
248
+ 'waiting for Android emulator %s to finish booting',
249
+ adbId
250
+ );
251
+
252
+ const isInstalled = await adb.isAppInstalled(adbId, config.bundleId);
253
+
254
+ if (!isInstalled) {
255
+ const appPath = getHarnessAppPath();
256
+ await adb.installApp(adbId, appPath);
257
+ }
258
+
259
+ const appUid = await configureAndroidRuntime(adbId, config, harnessConfig);
260
+
261
+ return {
262
+ startApp: async (options) => {
263
+ await adb.startApp(
264
+ adbId,
265
+ config.bundleId,
266
+ config.activityName,
267
+ (options as typeof config.appLaunchOptions | undefined) ??
268
+ config.appLaunchOptions
269
+ );
270
+ },
271
+ restartApp: async (options) => {
272
+ await adb.stopApp(adbId, config.bundleId);
273
+ await adb.startApp(
274
+ adbId,
275
+ config.bundleId,
276
+ config.activityName,
277
+ (options as typeof config.appLaunchOptions | undefined) ??
278
+ config.appLaunchOptions
279
+ );
280
+ },
281
+ stopApp: async () => {
282
+ await adb.stopApp(adbId, config.bundleId);
283
+ },
284
+ dispose: async () => {
285
+ await adb.stopApp(adbId, config.bundleId);
286
+ await clearHarnessDebugHttpHost(adbId, config.bundleId);
287
+ await adb.setHideErrorDialogs(adbId, false);
288
+
289
+ if (startedByHarness) {
290
+ logger.info('Shutting down Android emulator %s...', emulatorName);
291
+ await adb.stopEmulator(adbId);
292
+ }
293
+ },
294
+ isAppRunning: async () => {
295
+ return await adb.isAppRunning(adbId, config.bundleId);
296
+ },
297
+ createAppMonitor: (options?: CreateAppMonitorOptions) => {
298
+ if (!detectNativeCrashes) {
299
+ return createNoopAppMonitor();
300
+ }
301
+
302
+ return createAndroidAppMonitor({
303
+ adbId,
304
+ bundleId: config.bundleId,
305
+ appUid,
306
+ crashArtifactWriter: options?.crashArtifactWriter,
307
+ });
308
+ },
309
+ };
310
+ };
311
+
312
+ export const getAndroidPhysicalDevicePlatformInstance = async (
313
+ config: AndroidPlatformConfig,
314
+ harnessConfig: HarnessConfig
315
+ ): Promise<HarnessPlatformRunner> => {
316
+ assertAndroidDevicePhysical(config.device);
317
+ const detectNativeCrashes = harnessConfig.detectNativeCrashes ?? true;
318
+
319
+ const adbId = await getAdbId(config.device);
320
+
321
+ if (!adbId) {
322
+ throw new DeviceNotFoundError(getDeviceName(config.device));
323
+ }
324
+
325
+ const isInstalled = await adb.isAppInstalled(adbId, config.bundleId);
326
+
327
+ if (!isInstalled) {
328
+ throw new AppNotInstalledError(
329
+ config.bundleId,
330
+ getDeviceName(config.device)
331
+ );
332
+ }
333
+
334
+ const appUid = await configureAndroidRuntime(adbId, config, harnessConfig);
335
+
336
+ return {
337
+ startApp: async (options) => {
338
+ await adb.startApp(
339
+ adbId,
340
+ config.bundleId,
341
+ config.activityName,
342
+ (options as typeof config.appLaunchOptions | undefined) ??
343
+ config.appLaunchOptions
344
+ );
345
+ },
346
+ restartApp: async (options) => {
347
+ await adb.stopApp(adbId, config.bundleId);
348
+ await adb.startApp(
349
+ adbId,
350
+ config.bundleId,
351
+ config.activityName,
352
+ (options as typeof config.appLaunchOptions | undefined) ??
353
+ config.appLaunchOptions
354
+ );
355
+ },
356
+ stopApp: async () => {
357
+ await adb.stopApp(adbId, config.bundleId);
358
+ },
359
+ dispose: async () => {
360
+ await adb.stopApp(adbId, config.bundleId);
361
+ await clearHarnessDebugHttpHost(adbId, config.bundleId);
362
+ await adb.setHideErrorDialogs(adbId, false);
363
+ },
364
+ isAppRunning: async () => {
365
+ return await adb.isAppRunning(adbId, config.bundleId);
366
+ },
367
+ createAppMonitor: (options?: CreateAppMonitorOptions) => {
368
+ if (!detectNativeCrashes) {
369
+ return createNoopAppMonitor();
370
+ }
371
+
372
+ return createAndroidAppMonitor({
373
+ adbId,
374
+ bundleId: config.bundleId,
375
+ appUid,
376
+ crashArtifactWriter: options?.crashArtifactWriter,
377
+ });
378
+ },
379
+ };
380
+ };
package/src/runner.ts CHANGED
@@ -1,93 +1,47 @@
1
1
  import {
2
- DeviceNotFoundError,
3
- AppNotInstalledError,
4
- CreateAppMonitorOptions,
5
2
  HarnessPlatformRunner,
3
+ type HarnessPlatformInitOptions,
6
4
  } from '@react-native-harness/platforms';
7
5
  import type { Config as HarnessConfig } from '@react-native-harness/config';
8
6
  import {
9
7
  AndroidPlatformConfigSchema,
10
8
  type AndroidPlatformConfig,
9
+ isAndroidDeviceEmulator,
11
10
  } from './config.js';
12
- import { getAdbId } from './adb-id.js';
13
- import * as adb from './adb.js';
14
11
  import {
15
- applyHarnessDebugHttpHost,
16
- clearHarnessDebugHttpHost,
17
- } from './shared-prefs.js';
18
- import { getDeviceName } from './utils.js';
19
- import { createAndroidAppMonitor } from './app-monitor.js';
12
+ getAndroidEmulatorPlatformInstance,
13
+ getAndroidPhysicalDevicePlatformInstance,
14
+ } from './instance.js';
15
+ import {
16
+ ensureAndroidEmulatorEnvironment,
17
+ ensureAndroidPhysicalDeviceEnvironment,
18
+ initializeAndroidProcessEnv,
19
+ } from './environment.js';
20
20
 
21
21
  const getAndroidRunner = async (
22
22
  config: AndroidPlatformConfig,
23
- harnessConfig: HarnessConfig
23
+ harnessConfig: HarnessConfig,
24
+ init: HarnessPlatformInitOptions
24
25
  ): Promise<HarnessPlatformRunner> => {
25
26
  const parsedConfig = AndroidPlatformConfigSchema.parse(config);
26
- const adbId = await getAdbId(parsedConfig.device);
27
27
 
28
- if (!adbId) {
29
- throw new DeviceNotFoundError(getDeviceName(parsedConfig.device));
30
- }
28
+ initializeAndroidProcessEnv();
31
29
 
32
- const isInstalled = await adb.isAppInstalled(adbId, parsedConfig.bundleId);
30
+ if (isAndroidDeviceEmulator(parsedConfig.device)) {
31
+ if (parsedConfig.device.avd) {
32
+ await ensureAndroidEmulatorEnvironment(parsedConfig.device.avd.apiLevel);
33
+ }
33
34
 
34
- if (!isInstalled) {
35
- throw new AppNotInstalledError(
36
- parsedConfig.bundleId,
37
- getDeviceName(parsedConfig.device)
35
+ return getAndroidEmulatorPlatformInstance(
36
+ parsedConfig,
37
+ harnessConfig,
38
+ init
38
39
  );
39
40
  }
40
41
 
41
- const metroPort = harnessConfig.metroPort;
42
-
43
- await Promise.all([
44
- adb.reversePort(adbId, metroPort),
45
- adb.reversePort(adbId, 8080),
46
- adb.reversePort(adbId, harnessConfig.webSocketPort),
47
- adb.setHideErrorDialogs(adbId, true),
48
- applyHarnessDebugHttpHost(adbId, parsedConfig.bundleId, `localhost:${metroPort}`),
49
- ]);
50
- const appUid = await adb.getAppUid(adbId, parsedConfig.bundleId);
42
+ await ensureAndroidPhysicalDeviceEnvironment();
51
43
 
52
- return {
53
- startApp: async (options) => {
54
- await adb.startApp(
55
- adbId,
56
- parsedConfig.bundleId,
57
- parsedConfig.activityName,
58
- (options as typeof parsedConfig.appLaunchOptions | undefined) ??
59
- parsedConfig.appLaunchOptions
60
- );
61
- },
62
- restartApp: async (options) => {
63
- await adb.stopApp(adbId, parsedConfig.bundleId);
64
- await adb.startApp(
65
- adbId,
66
- parsedConfig.bundleId,
67
- parsedConfig.activityName,
68
- (options as typeof parsedConfig.appLaunchOptions | undefined) ??
69
- parsedConfig.appLaunchOptions
70
- );
71
- },
72
- stopApp: async () => {
73
- await adb.stopApp(adbId, parsedConfig.bundleId);
74
- },
75
- dispose: async () => {
76
- await adb.stopApp(adbId, parsedConfig.bundleId);
77
- await clearHarnessDebugHttpHost(adbId, parsedConfig.bundleId);
78
- await adb.setHideErrorDialogs(adbId, false);
79
- },
80
- isAppRunning: async () => {
81
- return await adb.isAppRunning(adbId, parsedConfig.bundleId);
82
- },
83
- createAppMonitor: (options?: CreateAppMonitorOptions) =>
84
- createAndroidAppMonitor({
85
- adbId,
86
- bundleId: parsedConfig.bundleId,
87
- appUid,
88
- crashArtifactWriter: options?.crashArtifactWriter,
89
- }),
90
- };
44
+ return getAndroidPhysicalDevicePlatformInstance(parsedConfig, harnessConfig);
91
45
  };
92
46
 
93
47
  export default getAndroidRunner;
package/src/targets.ts CHANGED
@@ -1,7 +1,10 @@
1
- import { RunTarget } from "@react-native-harness/platforms";
1
+ import { RunTarget } from '@react-native-harness/platforms';
2
2
  import * as adb from './adb.js';
3
+ import { ensureAndroidDiscoveryEnvironment } from './environment.js';
3
4
 
4
5
  export const getRunTargets = async (): Promise<RunTarget[]> => {
6
+ await ensureAndroidDiscoveryEnvironment();
7
+
5
8
  const [avds, connectedDevices] = await Promise.all([
6
9
  adb.getAvds(),
7
10
  adb.getConnectedDevices(),
@@ -15,9 +18,9 @@ export const getRunTargets = async (): Promise<RunTarget[]> => {
15
18
  name: avd,
16
19
  platform: 'android',
17
20
  description: 'Android emulator',
18
- device: {
19
- name: avd,
20
- },
21
+ device: {
22
+ name: avd,
23
+ },
21
24
  });
22
25
  }
23
26
 
@@ -27,10 +30,10 @@ export const getRunTargets = async (): Promise<RunTarget[]> => {
27
30
  name: `${device.manufacturer} ${device.model}`,
28
31
  platform: 'android',
29
32
  description: `Physical device (${device.id})`,
30
- device: {
31
- manufacturer: device.manufacturer,
32
- model: device.model,
33
- },
33
+ device: {
34
+ manufacturer: device.manufacturer,
35
+ model: device.model,
36
+ },
34
37
  });
35
38
  }
36
39