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

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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=adb-id.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adb-id.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/adb-id.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,41 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { getAdbId, isAdbIdEmulator } from '../adb-id.js';
3
+ import * as adb from '../adb.js';
4
+ describe('adb id resolution', () => {
5
+ beforeEach(() => {
6
+ vi.restoreAllMocks();
7
+ });
8
+ it('identifies emulator adb ids', () => {
9
+ expect(isAdbIdEmulator('emulator-5554')).toBe(true);
10
+ expect(isAdbIdEmulator('device-serial-001')).toBe(false);
11
+ });
12
+ it('skips non-emulator ids when resolving an emulator device', async () => {
13
+ vi.spyOn(adb, 'getDeviceIds').mockResolvedValue([
14
+ 'device-serial-001',
15
+ 'emulator-5554',
16
+ ]);
17
+ vi.spyOn(adb, 'getEmulatorName').mockResolvedValue('Test_AVD_API_35');
18
+ await expect(getAdbId({
19
+ type: 'emulator',
20
+ name: 'Test_AVD_API_35',
21
+ })).resolves.toBe('emulator-5554');
22
+ });
23
+ it('resolves matching physical device by manufacturer and model', async () => {
24
+ vi.spyOn(adb, 'getDeviceIds').mockResolvedValue([
25
+ 'device-serial-001',
26
+ 'emulator-5554',
27
+ ]);
28
+ vi.spyOn(adb, 'getDeviceInfo').mockImplementation(async (adbId) => {
29
+ const results = {
30
+ 'device-serial-001': { manufacturer: 'Acme', model: 'Model A1' },
31
+ 'emulator-5554': { manufacturer: 'Emulator', model: 'Emulator Model' },
32
+ };
33
+ return results[adbId] || null;
34
+ });
35
+ await expect(getAdbId({
36
+ type: 'physical',
37
+ manufacturer: 'acme',
38
+ model: 'model a1',
39
+ })).resolves.toBe('device-serial-001');
40
+ });
41
+ });
@@ -1,12 +1,17 @@
1
1
  import { EventEmitter } from 'node:events';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
2
5
  import { PassThrough } from 'node:stream';
3
6
  import { beforeEach, describe, expect, it, vi } from 'vitest';
4
7
  import { SubprocessError } from '@react-native-harness/tools';
5
- import { createAvd, deleteAvd, emulatorProcess, getAppUid, getLogcatTimestamp, getStartAppArgs, hasAvd, installApp, startEmulator, uninstallApp, waitForBoot, waitForEmulatorDisconnect, } from '../adb.js';
8
+ vi.unmock('../adb.js');
9
+ import { createAvd, deleteAvd, emulatorProcess, getAppUid, getLogcatTimestamp, getStartAppArgs, hasAvd, installApp, startLogcat, startEmulator, uninstallApp, waitForBoot, waitForEmulatorDisconnect, } from '../adb.js';
6
10
  import * as tools from '@react-native-harness/tools';
7
11
  import * as environment from '../environment.js';
8
12
  import * as avdConfig from '../avd-config.js';
9
13
  const createAbortError = () => new DOMException('The operation was aborted', 'AbortError');
14
+ let sdkRoot;
10
15
  const createMockChildProcess = () => {
11
16
  const process = new EventEmitter();
12
17
  process.stdout = new PassThrough();
@@ -16,6 +21,14 @@ const createMockChildProcess = () => {
16
21
  };
17
22
  beforeEach(() => {
18
23
  vi.restoreAllMocks();
24
+ vi.unstubAllEnvs();
25
+ sdkRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'android-sdk-'));
26
+ fs.mkdirSync(path.join(sdkRoot, 'emulator'), { recursive: true });
27
+ fs.writeFileSync(path.join(sdkRoot, 'emulator', 'emulator'), '');
28
+ fs.mkdirSync(path.join(sdkRoot, 'platform-tools'), { recursive: true });
29
+ fs.writeFileSync(path.join(sdkRoot, 'platform-tools', 'adb'), '');
30
+ vi.stubEnv('ANDROID_HOME', sdkRoot);
31
+ vi.spyOn(environment, 'ensureAndroidEmulatorAvailable').mockResolvedValue(sdkRoot);
19
32
  });
20
33
  describe('getStartAppArgs', () => {
21
34
  it('maps supported extras to adb am start flags', () => {
@@ -81,8 +94,31 @@ describe('getStartAppArgs', () => {
81
94
  "+'%m-%d %H:%M:%S.000'",
82
95
  ]);
83
96
  });
97
+ it('starts logcat using the resolved adb binary path', async () => {
98
+ const subprocess = {};
99
+ const spawnSpy = vi.spyOn(tools, 'spawn').mockReturnValue(subprocess);
100
+ expect(startLogcat('emulator-5554', [
101
+ 'logcat',
102
+ '-v',
103
+ 'threadtime',
104
+ '-b',
105
+ 'crash',
106
+ ])).toBe(subprocess);
107
+ expect(spawnSpy).toHaveBeenCalledWith(expect.stringMatching(/adb$/), [
108
+ '-s',
109
+ 'emulator-5554',
110
+ 'logcat',
111
+ '-v',
112
+ 'threadtime',
113
+ '-b',
114
+ 'crash',
115
+ ], {
116
+ stdout: 'pipe',
117
+ stderr: 'pipe',
118
+ });
119
+ });
84
120
  it('checks whether an AVD exists', async () => {
85
- vi.spyOn(tools, 'spawn').mockResolvedValueOnce({
121
+ vi.spyOn(tools, 'spawn').mockResolvedValue({
86
122
  stdout: 'Pixel_6_API_33\nPixel_8_API_35\n',
87
123
  });
88
124
  await expect(hasAvd('Pixel_8_API_35')).resolves.toBe(true);
@@ -365,17 +401,24 @@ describe('getStartAppArgs', () => {
365
401
  });
366
402
  it('aborts while waiting for boot completion', async () => {
367
403
  vi.useFakeTimers();
368
- const spawnSpy = vi.spyOn(tools, 'spawn');
369
- spawnSpy
370
- .mockResolvedValueOnce({
371
- stdout: 'List of devices attached\nemulator-5554\tdevice\n',
372
- })
373
- .mockResolvedValueOnce({
374
- stdout: 'Pixel_8_API_35\n',
375
- })
376
- .mockResolvedValueOnce({
377
- stdout: '0\n',
378
- });
404
+ vi.spyOn(tools, 'spawn').mockImplementation((async (_file, args) => {
405
+ if (args?.[0] === 'devices') {
406
+ return {
407
+ stdout: 'List of devices attached\nemulator-5554\tdevice\n',
408
+ };
409
+ }
410
+ if (args?.includes('emu') && args?.includes('avd') && args?.includes('name')) {
411
+ return {
412
+ stdout: 'Pixel_8_API_35\n',
413
+ };
414
+ }
415
+ if (args?.includes('getprop')) {
416
+ return {
417
+ stdout: '0\n',
418
+ };
419
+ }
420
+ throw new Error(`Unexpected adb call: ${args?.join(' ')}`);
421
+ }));
379
422
  const controller = new AbortController();
380
423
  const waitPromise = waitForBoot('Pixel_8_API_35', controller.signal);
381
424
  await vi.advanceTimersByTimeAsync(1000);
@@ -3,8 +3,8 @@ import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { createAndroidAppMonitor, createAndroidLogEvent } from '../app-monitor.js';
6
- import * as tools from '@react-native-harness/tools';
7
6
  import { createCrashArtifactWriter } from '@react-native-harness/tools';
7
+ import * as adb from '../adb.js';
8
8
  const createMockSubprocess = () => ({
9
9
  nodeChildProcess: Promise.resolve({
10
10
  kill: vi.fn(),
@@ -55,15 +55,12 @@ describe('createAndroidLogEvent', () => {
55
55
  });
56
56
  });
57
57
  it('starts logcat from the current device timestamp', async () => {
58
- const spawnSpy = vi.spyOn(tools, 'spawn');
59
- spawnSpy.mockImplementation(((file, args) => {
60
- if (file === 'adb' && args?.includes('date')) {
61
- return {
62
- stdout: '03-12 11:35:08.000\n',
63
- };
64
- }
65
- return createMockSubprocess();
66
- }));
58
+ const getLogcatTimestampSpy = vi
59
+ .spyOn(adb, 'getLogcatTimestamp')
60
+ .mockResolvedValue('03-12 11:35:08.000');
61
+ const startLogcatSpy = vi
62
+ .spyOn(adb, 'startLogcat')
63
+ .mockReturnValue(createMockSubprocess());
67
64
  const monitor = createAndroidAppMonitor({
68
65
  adbId: 'emulator-5554',
69
66
  bundleId: 'com.harnessplayground',
@@ -71,9 +68,8 @@ describe('createAndroidLogEvent', () => {
71
68
  });
72
69
  await monitor.start();
73
70
  await monitor.stop();
74
- expect(spawnSpy).toHaveBeenNthCalledWith(2, 'adb', [
75
- '-s',
76
- 'emulator-5554',
71
+ expect(getLogcatTimestampSpy).toHaveBeenCalledWith('emulator-5554');
72
+ expect(startLogcatSpy).toHaveBeenCalledWith('emulator-5554', [
77
73
  'logcat',
78
74
  '-v',
79
75
  'threadtime',
@@ -82,34 +78,24 @@ describe('createAndroidLogEvent', () => {
82
78
  '--uid=10234',
83
79
  '-T',
84
80
  '03-12 11:35:08.000',
85
- ], {
86
- stdout: 'pipe',
87
- stderr: 'pipe',
88
- });
81
+ ]);
89
82
  });
90
83
  it('hydrates crash details with stack lines that arrive after the first crash event', async () => {
91
- const spawnSpy = vi.spyOn(tools, 'spawn');
92
- spawnSpy.mockImplementation(((file, args) => {
93
- if (file === 'adb' && args?.includes('date')) {
94
- return {
95
- stdout: '03-12 10:44:40.000\n',
96
- };
97
- }
98
- return createStreamingSubprocess([
99
- { line: '--------- beginning of crash' },
100
- {
101
- line: '03-12 10:44:40.420 13861 13861 E AndroidRuntime: Process: com.harnessplayground, PID: 13861',
102
- },
103
- {
104
- line: '03-12 10:44:40.421 13861 13861 E AndroidRuntime: java.lang.RuntimeException: boom',
105
- delayMs: 25,
106
- },
107
- {
108
- line: '03-12 10:44:40.422 13861 13861 E AndroidRuntime: at com.harnessplayground.MainActivity.onCreate(MainActivity.kt:42)',
109
- delayMs: 25,
110
- },
111
- ]);
112
- }));
84
+ vi.spyOn(adb, 'getLogcatTimestamp').mockResolvedValue('03-12 10:44:40.000');
85
+ vi.spyOn(adb, 'startLogcat').mockReturnValue(createStreamingSubprocess([
86
+ { line: '--------- beginning of crash' },
87
+ {
88
+ line: '03-12 10:44:40.420 13861 13861 E AndroidRuntime: Process: com.harnessplayground, PID: 13861',
89
+ },
90
+ {
91
+ line: '03-12 10:44:40.421 13861 13861 E AndroidRuntime: java.lang.RuntimeException: boom',
92
+ delayMs: 25,
93
+ },
94
+ {
95
+ line: '03-12 10:44:40.422 13861 13861 E AndroidRuntime: at com.harnessplayground.MainActivity.onCreate(MainActivity.kt:42)',
96
+ delayMs: 25,
97
+ },
98
+ ]));
113
99
  const monitor = createAndroidAppMonitor({
114
100
  adbId: 'emulator-5554',
115
101
  bundleId: 'com.harnessplayground',
@@ -130,24 +116,17 @@ describe('createAndroidLogEvent', () => {
130
116
  ]);
131
117
  });
132
118
  it('persists resolved Android crash blocks into .harness', async () => {
133
- const spawnSpy = vi.spyOn(tools, 'spawn');
134
- spawnSpy.mockImplementation(((file, args) => {
135
- if (file === 'adb' && args?.includes('date')) {
136
- return {
137
- stdout: '03-12 10:44:40.000\n',
138
- };
139
- }
140
- return createStreamingSubprocess([
141
- { line: '--------- beginning of crash' },
142
- {
143
- line: '03-12 10:44:40.420 13861 13861 E AndroidRuntime: Process: com.harnessplayground, PID: 13861',
144
- },
145
- {
146
- line: '03-12 10:44:40.421 13861 13861 E AndroidRuntime: java.lang.RuntimeException: boom',
147
- delayMs: 20,
148
- },
149
- ]);
150
- }));
119
+ vi.spyOn(adb, 'getLogcatTimestamp').mockResolvedValue('03-12 10:44:40.000');
120
+ vi.spyOn(adb, 'startLogcat').mockReturnValue(createStreamingSubprocess([
121
+ { line: '--------- beginning of crash' },
122
+ {
123
+ line: '03-12 10:44:40.420 13861 13861 E AndroidRuntime: Process: com.harnessplayground, PID: 13861',
124
+ },
125
+ {
126
+ line: '03-12 10:44:40.421 13861 13861 E AndroidRuntime: java.lang.RuntimeException: boom',
127
+ delayMs: 20,
128
+ },
129
+ ]));
151
130
  const monitor = createAndroidAppMonitor({
152
131
  adbId: 'emulator-5554',
153
132
  bundleId: 'com.harnessplayground',
@@ -171,21 +150,13 @@ describe('createAndroidLogEvent', () => {
171
150
  expect(fs.readFileSync(details.artifactPath, 'utf8')).toContain('RuntimeException: boom');
172
151
  });
173
152
  it('can be started again after timestamp lookup fails', async () => {
174
- const spawnSpy = vi.spyOn(tools, 'spawn');
175
153
  const timestampError = new Error('date failed');
176
- spawnSpy.mockImplementation(((file, args) => {
177
- if (file === 'adb' && args?.includes('date')) {
178
- if (spawnSpy.mock.calls.filter(([calledFile, calledArgs]) => calledFile === 'adb' &&
179
- Array.isArray(calledArgs) &&
180
- calledArgs.includes('date')).length === 1) {
181
- throw timestampError;
182
- }
183
- return {
184
- stdout: '03-12 11:35:08.000\n',
185
- };
186
- }
187
- return createMockSubprocess();
188
- }));
154
+ vi.spyOn(adb, 'getLogcatTimestamp')
155
+ .mockRejectedValueOnce(timestampError)
156
+ .mockResolvedValueOnce('03-12 11:35:08.000');
157
+ const startLogcatSpy = vi
158
+ .spyOn(adb, 'startLogcat')
159
+ .mockReturnValue(createMockSubprocess());
189
160
  const monitor = createAndroidAppMonitor({
190
161
  adbId: 'emulator-5554',
191
162
  bundleId: 'com.harnessplayground',
@@ -194,9 +165,15 @@ describe('createAndroidLogEvent', () => {
194
165
  await expect(monitor.start()).rejects.toThrow(timestampError);
195
166
  await expect(monitor.start()).resolves.toBeUndefined();
196
167
  await monitor.stop();
197
- expect(spawnSpy.mock.calls.some(([file, args]) => file === 'adb' &&
198
- Array.isArray(args) &&
199
- args.includes('logcat') &&
200
- args.includes('--uid=10234'))).toBe(true);
168
+ expect(startLogcatSpy).toHaveBeenCalledWith('emulator-5554', [
169
+ 'logcat',
170
+ '-v',
171
+ 'threadtime',
172
+ '-b',
173
+ 'crash',
174
+ '--uid=10234',
175
+ '-T',
176
+ '03-12 11:35:08.000',
177
+ ]);
201
178
  });
202
179
  });
@@ -1,8 +1,5 @@
1
1
  import { beforeEach, describe, expect, it, vi } from 'vitest';
2
2
  import { DEFAULT_METRO_PORT, } from '@react-native-harness/config';
3
- import fs from 'node:fs';
4
- import os from 'node:os';
5
- import path from 'node:path';
6
3
  import { getAndroidEmulatorPlatformInstance, getAndroidPhysicalDevicePlatformInstance, } from '../instance.js';
7
4
  import * as adb from '../adb.js';
8
5
  import * as avdConfig from '../avd-config.js';
@@ -19,9 +16,10 @@ const init = {
19
16
  signal: new AbortController().signal,
20
17
  };
21
18
  describe('Android platform instance', () => {
22
- beforeEach(() => {
19
+ beforeEach(async () => {
23
20
  vi.restoreAllMocks();
24
21
  vi.unstubAllEnvs();
22
+ vi.spyOn(await import('../environment.js'), 'ensureAndroidEmulatorAvailable').mockResolvedValue('/tmp/android-sdk');
25
23
  });
26
24
  it('reuses a running emulator and does not shut it down on dispose', async () => {
27
25
  const ensureAndroidEmulatorEnvironment = vi
@@ -137,6 +135,7 @@ describe('Android platform instance', () => {
137
135
  });
138
136
  it('reuses a compatible cached AVD snapshot when caching is enabled', async () => {
139
137
  vi.stubEnv('HARNESS_AVD_CACHING', 'true');
138
+ vi.spyOn(await import('../environment.js'), 'getHostAndroidSystemImageArch').mockReturnValue('arm64-v8a');
140
139
  vi.spyOn(await import('../environment.js'), 'ensureAndroidEmulatorEnvironment').mockResolvedValue('/tmp/android-sdk');
141
140
  vi.spyOn(adb, 'getDeviceIds').mockResolvedValue([]);
142
141
  vi.spyOn(adb, 'hasAvd').mockResolvedValue(true);
@@ -261,74 +260,6 @@ describe('Android platform instance', () => {
261
260
  expect(waitForEmulatorDisconnect).toHaveBeenCalledWith('emulator-5554', init.signal);
262
261
  expect(startEmulator).toHaveBeenNthCalledWith(2, 'Pixel_8_API_35', 'snapshot-reuse');
263
262
  });
264
- it('installs the app from HARNESS_APP_PATH when missing', async () => {
265
- const appPath = path.join(os.tmpdir(), 'HarnessPlayground.apk');
266
- fs.writeFileSync(appPath, 'apk');
267
- vi.stubEnv('HARNESS_APP_PATH', appPath);
268
- vi.spyOn(await import('../environment.js'), 'ensureAndroidEmulatorEnvironment').mockResolvedValue('/tmp/android-sdk');
269
- vi.spyOn(adb, 'getDeviceIds').mockResolvedValue(['emulator-5554']);
270
- vi.spyOn(adb, 'getEmulatorName').mockResolvedValue('Pixel_8_API_35');
271
- vi.spyOn(adb, 'waitForBoot').mockResolvedValue('emulator-5554');
272
- vi.spyOn(adb, 'isAppInstalled').mockResolvedValue(false);
273
- const installApp = vi.spyOn(adb, 'installApp').mockResolvedValue(undefined);
274
- vi.spyOn(adb, 'reversePort').mockResolvedValue(undefined);
275
- vi.spyOn(adb, 'setHideErrorDialogs').mockResolvedValue(undefined);
276
- vi.spyOn(adb, 'getAppUid').mockResolvedValue(10234);
277
- vi.spyOn(sharedPrefs, 'applyHarnessDebugHttpHost').mockResolvedValue(undefined);
278
- await expect(getAndroidEmulatorPlatformInstance({
279
- name: 'android',
280
- device: {
281
- type: 'emulator',
282
- name: 'Pixel_8_API_35',
283
- avd: {
284
- apiLevel: 35,
285
- profile: 'pixel_8',
286
- diskSize: '1G',
287
- heapSize: '1G',
288
- },
289
- },
290
- bundleId: 'com.harnessplayground',
291
- activityName: '.MainActivity',
292
- }, harnessConfig, init)).resolves.toBeDefined();
293
- expect(installApp).toHaveBeenCalledWith('emulator-5554', appPath);
294
- fs.rmSync(appPath, { force: true });
295
- });
296
- it('reinstalls the app from HARNESS_APP_PATH when already installed', async () => {
297
- const appPath = path.join(os.tmpdir(), 'HarnessPlayground-installed.apk');
298
- fs.writeFileSync(appPath, 'apk');
299
- vi.stubEnv('HARNESS_APP_PATH', appPath);
300
- vi.spyOn(await import('../environment.js'), 'ensureAndroidEmulatorEnvironment').mockResolvedValue('/tmp/android-sdk');
301
- vi.spyOn(adb, 'getDeviceIds').mockResolvedValue(['emulator-5554']);
302
- vi.spyOn(adb, 'getEmulatorName').mockResolvedValue('Pixel_8_API_35');
303
- vi.spyOn(adb, 'waitForBoot').mockResolvedValue('emulator-5554');
304
- vi.spyOn(adb, 'isAppInstalled').mockResolvedValue(true);
305
- const uninstallApp = vi
306
- .spyOn(adb, 'uninstallApp')
307
- .mockResolvedValue(undefined);
308
- const installApp = vi.spyOn(adb, 'installApp').mockResolvedValue(undefined);
309
- vi.spyOn(adb, 'reversePort').mockResolvedValue(undefined);
310
- vi.spyOn(adb, 'setHideErrorDialogs').mockResolvedValue(undefined);
311
- vi.spyOn(adb, 'getAppUid').mockResolvedValue(10234);
312
- vi.spyOn(sharedPrefs, 'applyHarnessDebugHttpHost').mockResolvedValue(undefined);
313
- await expect(getAndroidEmulatorPlatformInstance({
314
- name: 'android',
315
- device: {
316
- type: 'emulator',
317
- name: 'Pixel_8_API_35',
318
- avd: {
319
- apiLevel: 35,
320
- profile: 'pixel_8',
321
- diskSize: '1G',
322
- heapSize: '1G',
323
- },
324
- },
325
- bundleId: 'com.harnessplayground',
326
- activityName: '.MainActivity',
327
- }, harnessConfig, init)).resolves.toBeDefined();
328
- expect(uninstallApp).toHaveBeenCalledWith('emulator-5554', 'com.harnessplayground');
329
- expect(installApp).toHaveBeenCalledWith('emulator-5554', appPath);
330
- fs.rmSync(appPath, { force: true });
331
- });
332
263
  it('throws a HarnessAppPathError when HARNESS_APP_PATH is missing', async () => {
333
264
  vi.spyOn(adb, 'getDeviceIds').mockResolvedValue(['emulator-5554']);
334
265
  vi.spyOn(adb, 'getEmulatorName').mockResolvedValue('Pixel_8_API_35');
package/dist/adb.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { type AndroidAppLaunchOptions } from '@react-native-harness/platforms';
2
+ import { type Subprocess } from '@react-native-harness/tools';
2
3
  import type { ChildProcessByStdio } from 'node:child_process';
3
4
  import type { Readable } from 'node:stream';
4
5
  import { type EmulatorBootMode } from './emulator-startup.js';
@@ -42,6 +43,7 @@ export declare const isAppRunning: (adbId: string, bundleId: string) => Promise<
42
43
  export declare const getAppUid: (adbId: string, bundleId: string) => Promise<number>;
43
44
  export declare const setHideErrorDialogs: (adbId: string, hide: boolean) => Promise<void>;
44
45
  export declare const getLogcatTimestamp: (adbId: string) => Promise<string>;
46
+ export declare const startLogcat: (adbId: string, args: readonly string[]) => Subprocess;
45
47
  export declare const getAvds: () => Promise<string[]>;
46
48
  export type AdbDevice = {
47
49
  id: string;
package/dist/adb.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"adb.d.ts","sourceRoot":"","sources":["../src/adb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAG/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAgB5C,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AA2C/B,eAAO,MAAM,eAAe;iCAElB,MAAM,QACN,SAAS,MAAM,EAAE,KACtB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC;CAKjD,CAAC;AAqEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,2BAA2B,GAAI,UAAU,MAAM,KAAG,MAAM,EAMpE,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAEd,CAAC;AAgEF,eAAO,MAAM,eAAe,GAC1B,UAAU,MAAM,EAChB,cAAc,MAAM,EACpB,UAAU,uBAAuB,KAChC,MAAM,EAoCR,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,OAAO,CAWjB,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,OAAO,MAAM,EACb,MAAM,MAAM,EACZ,WAAU,MAAa,KACtB,OAAO,CAAC,IAAI,CAQd,CAAC;AAEF,eAAO,MAAM,OAAO,GAClB,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CASd,CAAC;AAEF,eAAO,MAAM,QAAQ,GACnB,OAAO,MAAM,EACb,UAAU,MAAM,EAChB,cAAc,MAAM,EACpB,UAAU,uBAAuB,KAChC,OAAO,CAAC,IAAI,CAMd,CAAC;AAEF,eAAO,MAAM,YAAY,QAAa,OAAO,CAAC,MAAM,EAAE,CAOrD,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,OAAO,MAAM,KACZ,OAAO,CAAC,MAAM,GAAG,IAAI,CASvB,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,GAAG,IAAI,CASvB,CAAC;AAMF,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,OAAO,MAAM,KACZ,OAAO,CAAC,UAAU,GAAG,IAAI,CAI3B,CAAC;AA2EF,eAAO,MAAM,eAAe,GAAU,OAAO,MAAM,KAAG,OAAO,CAAC,OAAO,CAWpE,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,OAAO,MAAM,KAAG,OAAO,CAAC,IAAI,CAE9D,CAAC;AAEF,eAAO,MAAM,UAAU,GACrB,OAAO,MAAM,EACb,SAAS,MAAM,KACd,OAAO,CAAC,IAAI,CAEd,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAEd,CAAC;AAEF,eAAO,MAAM,MAAM,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,OAAO,CAG1D,CAAC;AAEF,eAAO,MAAM,SAAS,GAAU,kDAM7B,gBAAgB,KAAG,OAAO,CAAC,IAAI,CAkBjC,CAAC;AAEF,eAAO,MAAM,SAAS,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,IAAI,CAkB1D,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,MAAM,MAAM,EACZ,OAAM,gBAAiC,KACtC,OAAO,CAAC,IAAI,CAgFd,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,EACZ,QAAQ,WAAW,KAClB,OAAO,CAAC,MAAM,CAoBhB,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,OAAO,MAAM,EACb,QAAQ,WAAW,KAClB,OAAO,CAAC,IAAI,CAYd,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,MAAM,MAAM,EACZ,QAAQ,WAAW,KAClB,OAAO,CAAC,MAAM,CAwBhB,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,OAAO,CAiBjB,CAAC;AAEF,eAAO,MAAM,SAAS,GACpB,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,CAoBhB,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,OAAO,MAAM,EACb,MAAM,OAAO,KACZ,OAAO,CAAC,IAAI,CAWd,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAU,OAAO,MAAM,KAAG,OAAO,CAAC,MAAM,CAUtE,CAAC;AAEF,eAAO,MAAM,OAAO,QAAa,OAAO,CAAC,MAAM,EAAE,CAWhD,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAa,OAAO,CAAC,SAAS,EAAE,CA8B/D,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,EACb,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAqEd,CAAC"}
1
+ {"version":3,"file":"adb.d.ts","sourceRoot":"","sources":["../src/adb.ts"],"names":[],"mappings":"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"}
package/dist/adb.js CHANGED
@@ -1,4 +1,4 @@
1
- import { logger, spawn, SubprocessError } from '@react-native-harness/tools';
1
+ import { logger, spawn, SubprocessError, } from '@react-native-harness/tools';
2
2
  import { spawn as nodeSpawn } from 'node:child_process';
3
3
  import { access, rm } from 'node:fs/promises';
4
4
  import { getAvdConfigPath, getAvdDirectory, readAvdConfig, } from './avd-config.js';
@@ -490,6 +490,10 @@ export const getLogcatTimestamp = async (adbId) => {
490
490
  ]);
491
491
  return stdout.trim().replace(/^'+|'+$/g, '');
492
492
  };
493
+ export const startLogcat = (adbId, args) => spawn(getAdbBinaryPath(), ['-s', adbId, ...args], {
494
+ stdout: 'pipe',
495
+ stderr: 'pipe',
496
+ });
493
497
  export const getAvds = async () => {
494
498
  try {
495
499
  const emulatorBinaryPath = await ensureEmulatorInstalled();
@@ -1 +1 @@
1
- {"version":3,"file":"app-monitor.d.ts","sourceRoot":"","sources":["../src/app-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,eAAe,EAErB,MAAM,iCAAiC,CAAC;AAgTzC,QAAA,MAAM,qBAAqB,GACzB,MAAM,MAAM,EACZ,UAAU,MAAM,KACf,eAAe,GAAG,IAwEpB,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,mDAKrC;IACD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;CAC3C,KAAG,iBAgLH,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,CAAC;AACjC,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG;IAC3C,eAAe,EAAE,CACf,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;CACtC,CAAC"}
1
+ {"version":3,"file":"app-monitor.d.ts","sourceRoot":"","sources":["../src/app-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,eAAe,EAErB,MAAM,iCAAiC,CAAC;AA+SzC,QAAA,MAAM,qBAAqB,GACzB,MAAM,MAAM,EACZ,UAAU,MAAM,KACf,eAAe,GAAG,IAwEpB,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,mDAKrC;IACD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;CAC3C,KAAG,iBA4KH,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,CAAC;AACjC,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG;IAC3C,eAAe,EAAE,CACf,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;CACtC,CAAC"}
@@ -1,4 +1,4 @@
1
- import { escapeRegExp, getEmitter, logger, spawn, SubprocessError, } from '@react-native-harness/tools';
1
+ import { escapeRegExp, getEmitter, logger, SubprocessError, } from '@react-native-harness/tools';
2
2
  import * as adb from './adb.js';
3
3
  import { androidCrashParser } from './crash-parser.js';
4
4
  const androidAppMonitorLogger = logger.child('android-app-monitor');
@@ -281,10 +281,7 @@ export const createAndroidAppMonitor = ({ adbId, bundleId, appUid, crashArtifact
281
281
  };
282
282
  const startLogcat = async () => {
283
283
  const logcatTimestamp = await adb.getLogcatTimestamp(adbId);
284
- logcatProcess = spawn('adb', ['-s', adbId, ...getLogcatArgs(appUid, logcatTimestamp)], {
285
- stdout: 'pipe',
286
- stderr: 'pipe',
287
- });
284
+ logcatProcess = adb.startLogcat(adbId, getLogcatArgs(appUid, logcatTimestamp));
288
285
  const currentProcess = logcatProcess;
289
286
  if (!currentProcess) {
290
287
  return;