@react-native-harness/platform-android 1.2.0 → 1.4.0-rc.1

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 (41) hide show
  1. package/dist/__tests__/app-monitor.test.js +180 -102
  2. package/dist/__tests__/crash-diagnostics.test.d.ts +2 -0
  3. package/dist/__tests__/crash-diagnostics.test.d.ts.map +1 -0
  4. package/dist/__tests__/crash-diagnostics.test.js +119 -0
  5. package/dist/__tests__/crash-reporter.test.d.ts +2 -0
  6. package/dist/__tests__/crash-reporter.test.d.ts.map +1 -0
  7. package/dist/__tests__/crash-reporter.test.js +150 -0
  8. package/dist/__tests__/instance.test.js +133 -24
  9. package/dist/adb.d.ts +4 -0
  10. package/dist/adb.d.ts.map +1 -1
  11. package/dist/adb.js +42 -2
  12. package/dist/app-session.d.ts +17 -0
  13. package/dist/app-session.d.ts.map +1 -0
  14. package/dist/app-session.js +209 -0
  15. package/dist/crash-diagnostics.d.ts +40 -0
  16. package/dist/crash-diagnostics.d.ts.map +1 -0
  17. package/dist/crash-diagnostics.js +256 -0
  18. package/dist/crash-reporter.d.ts +12 -0
  19. package/dist/crash-reporter.d.ts.map +1 -0
  20. package/dist/crash-reporter.js +150 -0
  21. package/dist/device-state.d.ts +6 -0
  22. package/dist/device-state.d.ts.map +1 -0
  23. package/dist/device-state.js +142 -0
  24. package/dist/instance.d.ts +1 -1
  25. package/dist/instance.d.ts.map +1 -1
  26. package/dist/instance.js +32 -59
  27. package/dist/runner.d.ts.map +1 -1
  28. package/dist/runner.js +1 -1
  29. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  30. package/package.json +4 -4
  31. package/src/__tests__/crash-diagnostics.test.ts +144 -0
  32. package/src/__tests__/crash-reporter.test.ts +167 -0
  33. package/src/__tests__/instance.test.ts +174 -31
  34. package/src/adb.ts +61 -2
  35. package/src/app-session.ts +300 -0
  36. package/src/crash-diagnostics.ts +471 -0
  37. package/src/crash-reporter.ts +263 -0
  38. package/src/instance.ts +56 -91
  39. package/src/runner.ts +7 -3
  40. package/test/setup.ts +1 -0
  41. package/src/app-monitor.ts +0 -577
package/src/instance.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  AppNotInstalledError,
3
- CreateAppMonitorOptions,
4
3
  DeviceNotFoundError,
5
4
  type HarnessPlatformInitOptions,
6
5
  HarnessPlatformRunner,
@@ -24,7 +23,6 @@ import {
24
23
  clearHarnessDebugHttpHost,
25
24
  } from './shared-prefs.js';
26
25
  import { getDeviceName } from './utils.js';
27
- import { createAndroidAppMonitor } from './app-monitor.js';
28
26
  import { HarnessAppPathError, HarnessEmulatorConfigError } from './errors.js';
29
27
  import {
30
28
  ensureAndroidEmulatorAvailable,
@@ -33,18 +31,10 @@ import {
33
31
  } from './environment.js';
34
32
  import { isInteractive } from '@react-native-harness/tools';
35
33
  import fs from 'node:fs';
36
- import type { AppMonitor } from '@react-native-harness/platforms';
34
+ import { createAndroidAppSession } from './app-session.js';
37
35
 
38
36
  const androidInstanceLogger = logger.child('android-instance');
39
37
 
40
- const createNoopAppMonitor = (): AppMonitor => ({
41
- start: async () => undefined,
42
- stop: async () => undefined,
43
- dispose: async () => undefined,
44
- addListener: () => undefined,
45
- removeListener: () => undefined,
46
- });
47
-
48
38
  const getHarnessAppPath = (): string => {
49
39
  const appPath = process.env.HARNESS_APP_PATH;
50
40
 
@@ -76,7 +66,7 @@ const getOptionalHarnessAppPath = (): string | undefined => {
76
66
  const configureAndroidRuntime = async (
77
67
  adbId: string,
78
68
  config: AndroidPlatformConfig,
79
- harnessConfig: HarnessConfig,
69
+ harnessConfig: HarnessConfig
80
70
  ): Promise<number> => {
81
71
  const metroPort = harnessConfig.metroPort;
82
72
 
@@ -153,14 +143,14 @@ const prepareCachedAvd = async ({
153
143
  hasExistingAvd
154
144
  ? 'Recreating incompatible Android emulator %s...'
155
145
  : 'Creating Android emulator %s...',
156
- emulatorName,
146
+ emulatorName
157
147
  );
158
148
 
159
149
  if (hasExistingAvd && !compatibility.compatible) {
160
150
  androidInstanceLogger.debug(
161
151
  'Android AVD %s is not reusable: %s',
162
152
  emulatorName,
163
- compatibility.reason,
153
+ compatibility.reason
164
154
  );
165
155
  await adb.deleteAvd(emulatorName);
166
156
  }
@@ -190,10 +180,9 @@ const prepareCachedAvd = async ({
190
180
  export const getAndroidEmulatorPlatformInstance = async (
191
181
  config: AndroidPlatformConfig,
192
182
  harnessConfig: HarnessConfig,
193
- init: HarnessPlatformInitOptions,
183
+ init: HarnessPlatformInitOptions
194
184
  ): Promise<HarnessPlatformRunner> => {
195
185
  assertAndroidDeviceEmulator(config.device);
196
- const detectNativeCrashes = harnessConfig.detectNativeCrashes ?? true;
197
186
  const permissionsEnabled = harnessConfig.permissions ?? false;
198
187
  const emulatorConfig = config.device;
199
188
  const emulatorName = emulatorConfig.name;
@@ -209,7 +198,7 @@ export const getAndroidEmulatorPlatformInstance = async (
209
198
  androidInstanceLogger.debug(
210
199
  'resolved Android emulator %s with adb id %s',
211
200
  emulatorConfig.name,
212
- adbId ?? 'not-found',
201
+ adbId ?? 'not-found'
213
202
  );
214
203
 
215
204
  if (!adbId) {
@@ -229,7 +218,7 @@ export const getAndroidEmulatorPlatformInstance = async (
229
218
  logger.info('Creating Android emulator %s...', emulatorName);
230
219
  androidInstanceLogger.debug(
231
220
  'creating Android AVD %s before startup',
232
- emulatorConfig.name,
221
+ emulatorConfig.name
233
222
  );
234
223
  await recreateAvd({ emulatorConfig });
235
224
  } else {
@@ -238,7 +227,7 @@ export const getAndroidEmulatorPlatformInstance = async (
238
227
 
239
228
  androidInstanceLogger.debug(
240
229
  'starting Android emulator %s',
241
- emulatorConfig.name,
230
+ emulatorConfig.name
242
231
  );
243
232
  return startAndWaitForBoot({
244
233
  emulatorName: emulatorConfig.name,
@@ -251,7 +240,7 @@ export const getAndroidEmulatorPlatformInstance = async (
251
240
  androidInstanceLogger.debug(
252
241
  'Android emulator %s connected as %s',
253
242
  emulatorConfig.name,
254
- adbId,
243
+ adbId
255
244
  );
256
245
  }
257
246
 
@@ -261,7 +250,7 @@ export const getAndroidEmulatorPlatformInstance = async (
261
250
 
262
251
  androidInstanceLogger.debug(
263
252
  'waiting for Android emulator %s to finish booting',
264
- adbId,
253
+ adbId
265
254
  );
266
255
 
267
256
  const isInstalled = await adb.isAppInstalled(adbId, config.bundleId);
@@ -282,27 +271,30 @@ export const getAndroidEmulatorPlatformInstance = async (
282
271
  }
283
272
 
284
273
  return {
285
- startApp: async (options) => {
286
- await adb.startApp(
287
- adbId,
288
- config.bundleId,
289
- config.activityName,
290
- (options as typeof config.appLaunchOptions | undefined) ??
291
- config.appLaunchOptions,
292
- );
293
- },
294
- restartApp: async (options) => {
274
+ createAppSession: async (options) => {
295
275
  await adb.stopApp(adbId, config.bundleId);
296
- await adb.startApp(
297
- adbId,
298
- config.bundleId,
299
- config.activityName,
276
+ const launchOptions =
300
277
  (options as typeof config.appLaunchOptions | undefined) ??
301
- config.appLaunchOptions,
302
- );
303
- },
304
- stopApp: async () => {
305
- await adb.stopApp(adbId, config.bundleId);
278
+ config.appLaunchOptions;
279
+
280
+ return await createAndroidAppSession({
281
+ appUid,
282
+ bundleId: config.bundleId,
283
+ startApp: () =>
284
+ adb.startApp(
285
+ adbId,
286
+ config.bundleId,
287
+ config.activityName,
288
+ launchOptions
289
+ ),
290
+ stopApp: () => adb.stopApp(adbId, config.bundleId),
291
+ getAppPid: () => adb.getAppPid(adbId, config.bundleId),
292
+ getLogcatTimestamp: () => adb.getLogcatTimestamp(adbId),
293
+ startLogcat: (args) => adb.startLogcat(adbId, args),
294
+ getDropboxOutput: () => adb.getDropboxPrint(adbId),
295
+ getExitInfo: () => adb.getActivityExitInfo(adbId, config.bundleId),
296
+ crashArtifactWriter: init.crashArtifactWriter,
297
+ });
306
298
  },
307
299
  dispose: async () => {
308
300
  await adb.stopApp(adbId, config.bundleId);
@@ -314,30 +306,15 @@ export const getAndroidEmulatorPlatformInstance = async (
314
306
  await adb.stopEmulator(adbId);
315
307
  }
316
308
  },
317
- isAppRunning: async () => {
318
- return await adb.isAppRunning(adbId, config.bundleId);
319
- },
320
- createAppMonitor: (options?: CreateAppMonitorOptions) => {
321
- if (!detectNativeCrashes) {
322
- return createNoopAppMonitor();
323
- }
324
-
325
- return createAndroidAppMonitor({
326
- adbId,
327
- bundleId: config.bundleId,
328
- appUid,
329
- crashArtifactWriter: options?.crashArtifactWriter,
330
- });
331
- },
332
309
  };
333
310
  };
334
311
 
335
312
  export const getAndroidPhysicalDevicePlatformInstance = async (
336
313
  config: AndroidPlatformConfig,
337
314
  harnessConfig: HarnessConfig,
315
+ init?: HarnessPlatformInitOptions
338
316
  ): Promise<HarnessPlatformRunner> => {
339
317
  assertAndroidDevicePhysical(config.device);
340
- const detectNativeCrashes = harnessConfig.detectNativeCrashes ?? true;
341
318
  const permissionsEnabled = harnessConfig.permissions ?? false;
342
319
 
343
320
  const adbId = await getAdbId(config.device);
@@ -351,7 +328,7 @@ export const getAndroidPhysicalDevicePlatformInstance = async (
351
328
  if (!isInstalled) {
352
329
  throw new AppNotInstalledError(
353
330
  config.bundleId,
354
- getDeviceName(config.device),
331
+ getDeviceName(config.device)
355
332
  );
356
333
  }
357
334
 
@@ -362,47 +339,35 @@ export const getAndroidPhysicalDevicePlatformInstance = async (
362
339
  }
363
340
 
364
341
  return {
365
- startApp: async (options) => {
366
- await adb.startApp(
367
- adbId,
368
- config.bundleId,
369
- config.activityName,
370
- (options as typeof config.appLaunchOptions | undefined) ??
371
- config.appLaunchOptions,
372
- );
373
- },
374
- restartApp: async (options) => {
342
+ createAppSession: async (options) => {
375
343
  await adb.stopApp(adbId, config.bundleId);
376
- await adb.startApp(
377
- adbId,
378
- config.bundleId,
379
- config.activityName,
344
+ const launchOptions =
380
345
  (options as typeof config.appLaunchOptions | undefined) ??
381
- config.appLaunchOptions,
382
- );
383
- },
384
- stopApp: async () => {
385
- await adb.stopApp(adbId, config.bundleId);
346
+ config.appLaunchOptions;
347
+
348
+ return await createAndroidAppSession({
349
+ appUid,
350
+ bundleId: config.bundleId,
351
+ startApp: () =>
352
+ adb.startApp(
353
+ adbId,
354
+ config.bundleId,
355
+ config.activityName,
356
+ launchOptions
357
+ ),
358
+ stopApp: () => adb.stopApp(adbId, config.bundleId),
359
+ getAppPid: () => adb.getAppPid(adbId, config.bundleId),
360
+ getLogcatTimestamp: () => adb.getLogcatTimestamp(adbId),
361
+ startLogcat: (args) => adb.startLogcat(adbId, args),
362
+ getDropboxOutput: () => adb.getDropboxPrint(adbId),
363
+ getExitInfo: () => adb.getActivityExitInfo(adbId, config.bundleId),
364
+ crashArtifactWriter: init?.crashArtifactWriter,
365
+ });
386
366
  },
387
367
  dispose: async () => {
388
368
  await adb.stopApp(adbId, config.bundleId);
389
369
  await clearHarnessDebugHttpHost(adbId, config.bundleId);
390
370
  await adb.setHideErrorDialogs(adbId, false);
391
371
  },
392
- isAppRunning: async () => {
393
- return await adb.isAppRunning(adbId, config.bundleId);
394
- },
395
- createAppMonitor: (options?: CreateAppMonitorOptions) => {
396
- if (!detectNativeCrashes) {
397
- return createNoopAppMonitor();
398
- }
399
-
400
- return createAndroidAppMonitor({
401
- adbId,
402
- bundleId: config.bundleId,
403
- appUid,
404
- crashArtifactWriter: options?.crashArtifactWriter,
405
- });
406
- },
407
372
  };
408
373
  };
package/src/runner.ts CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  const getAndroidRunner = async (
21
21
  config: AndroidPlatformConfig,
22
22
  harnessConfig: HarnessConfig,
23
- init: HarnessPlatformInitOptions,
23
+ init: HarnessPlatformInitOptions
24
24
  ): Promise<HarnessPlatformRunner> => {
25
25
  const parsedConfig = AndroidPlatformConfigSchema.parse(config);
26
26
 
@@ -32,11 +32,15 @@ const getAndroidRunner = async (
32
32
  return getAndroidEmulatorPlatformInstance(
33
33
  parsedConfig,
34
34
  harnessConfig,
35
- init,
35
+ init
36
36
  );
37
37
  }
38
38
 
39
- return getAndroidPhysicalDevicePlatformInstance(parsedConfig, harnessConfig);
39
+ return getAndroidPhysicalDevicePlatformInstance(
40
+ parsedConfig,
41
+ harnessConfig,
42
+ init
43
+ );
40
44
  };
41
45
 
42
46
  export default getAndroidRunner;
package/test/setup.ts CHANGED
@@ -57,6 +57,7 @@ vi.mock('../src/adb.js', async (importOriginal) => {
57
57
  waitForEmulatorDisconnect: vi.fn().mockResolvedValue(undefined),
58
58
  waitForBoot: vi.fn().mockResolvedValue('emulator-5554'),
59
59
  isAppRunning: vi.fn().mockResolvedValue(false),
60
+ getAppPid: vi.fn().mockResolvedValue(null),
60
61
  getAppUid: vi.fn().mockResolvedValue(0),
61
62
  setHideErrorDialogs: vi.fn().mockResolvedValue(undefined),
62
63
  getLogcatTimestamp: vi.fn().mockResolvedValue('01-01 00:00:00.000'),