@react-native-harness/platform-android 1.4.0 → 1.4.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 (60) hide show
  1. package/package.json +4 -4
  2. package/dist/__tests__/adb-id.test.d.ts +0 -2
  3. package/dist/__tests__/adb-id.test.d.ts.map +0 -1
  4. package/dist/__tests__/adb-id.test.js +0 -41
  5. package/dist/__tests__/adb-wait.test.d.ts +0 -2
  6. package/dist/__tests__/adb-wait.test.d.ts.map +0 -1
  7. package/dist/__tests__/adb-wait.test.js +0 -69
  8. package/dist/__tests__/adb.test.d.ts +0 -2
  9. package/dist/__tests__/adb.test.d.ts.map +0 -1
  10. package/dist/__tests__/adb.test.js +0 -552
  11. package/dist/__tests__/app-monitor.test.d.ts +0 -2
  12. package/dist/__tests__/app-monitor.test.d.ts.map +0 -1
  13. package/dist/__tests__/app-monitor.test.js +0 -257
  14. package/dist/__tests__/app-session.test.d.ts +0 -2
  15. package/dist/__tests__/app-session.test.d.ts.map +0 -1
  16. package/dist/__tests__/app-session.test.js +0 -57
  17. package/dist/__tests__/avd-config.test.d.ts +0 -2
  18. package/dist/__tests__/avd-config.test.d.ts.map +0 -1
  19. package/dist/__tests__/avd-config.test.js +0 -232
  20. package/dist/__tests__/ci-action.test.d.ts +0 -2
  21. package/dist/__tests__/ci-action.test.d.ts.map +0 -1
  22. package/dist/__tests__/ci-action.test.js +0 -46
  23. package/dist/__tests__/crash-diagnostics.test.d.ts +0 -2
  24. package/dist/__tests__/crash-diagnostics.test.d.ts.map +0 -1
  25. package/dist/__tests__/crash-diagnostics.test.js +0 -119
  26. package/dist/__tests__/crash-parser.test.d.ts +0 -2
  27. package/dist/__tests__/crash-parser.test.d.ts.map +0 -1
  28. package/dist/__tests__/crash-parser.test.js +0 -45
  29. package/dist/__tests__/crash-reporter.test.d.ts +0 -2
  30. package/dist/__tests__/crash-reporter.test.d.ts.map +0 -1
  31. package/dist/__tests__/crash-reporter.test.js +0 -150
  32. package/dist/__tests__/emulator-startup.test.d.ts +0 -2
  33. package/dist/__tests__/emulator-startup.test.d.ts.map +0 -1
  34. package/dist/__tests__/emulator-startup.test.js +0 -47
  35. package/dist/__tests__/environment.test.d.ts +0 -2
  36. package/dist/__tests__/environment.test.d.ts.map +0 -1
  37. package/dist/__tests__/environment.test.js +0 -117
  38. package/dist/__tests__/instance.test.d.ts +0 -2
  39. package/dist/__tests__/instance.test.d.ts.map +0 -1
  40. package/dist/__tests__/instance.test.js +0 -599
  41. package/dist/__tests__/shared-prefs.test.d.ts +0 -2
  42. package/dist/__tests__/shared-prefs.test.d.ts.map +0 -1
  43. package/dist/__tests__/shared-prefs.test.js +0 -87
  44. package/dist/__tests__/targets.test.d.ts +0 -2
  45. package/dist/__tests__/targets.test.d.ts.map +0 -1
  46. package/dist/__tests__/targets.test.js +0 -49
  47. package/dist/tsconfig.lib.tsbuildinfo +0 -1
  48. package/src/__tests__/adb-id.test.ts +0 -51
  49. package/src/__tests__/adb-wait.test.ts +0 -95
  50. package/src/__tests__/app-session.test.ts +0 -76
  51. package/src/__tests__/avd-config.test.ts +0 -276
  52. package/src/__tests__/ci-action.test.ts +0 -81
  53. package/src/__tests__/crash-diagnostics.test.ts +0 -144
  54. package/src/__tests__/crash-parser.test.ts +0 -52
  55. package/src/__tests__/crash-reporter.test.ts +0 -167
  56. package/src/__tests__/emulator-startup.test.ts +0 -82
  57. package/src/__tests__/instance.test.ts +0 -844
  58. package/src/__tests__/shared-prefs.test.ts +0 -144
  59. package/src/__tests__/targets.test.ts +0 -53
  60. package/tsconfig.tsbuildinfo +0 -1
@@ -1,552 +0,0 @@
1
- import { EventEmitter } from 'node:events';
2
- import fs from 'node:fs';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
- import { PassThrough } from 'node:stream';
6
- import { beforeEach, describe, expect, it, vi } from 'vitest';
7
- import { SubprocessError } from '@react-native-harness/tools';
8
- vi.unmock('../adb.js');
9
- import { createAvd, deleteAvd, emulatorProcess, getAppUid, getLogcatTimestamp, getStartAppArgs, hasAvd, installApp, startLogcat, startEmulator, uninstallApp, waitForBoot, waitForEmulatorDisconnect, } from '../adb.js';
10
- import * as tools from '@react-native-harness/tools';
11
- import * as environment from '../environment.js';
12
- import * as avdConfig from '../avd-config.js';
13
- const createAbortError = () => new DOMException('The operation was aborted', 'AbortError');
14
- let sdkRoot;
15
- const createMockChildProcess = () => {
16
- const process = new EventEmitter();
17
- process.stdout = new PassThrough();
18
- process.stderr = new PassThrough();
19
- process.unref = vi.fn();
20
- return process;
21
- };
22
- beforeEach(() => {
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);
32
- });
33
- describe('getStartAppArgs', () => {
34
- it('maps supported extras to adb am start flags', () => {
35
- expect(getStartAppArgs('com.example.app', '.MainActivity', {
36
- extras: {
37
- feature_flag: true,
38
- user_id: 42,
39
- mode: 'debug',
40
- },
41
- })).toEqual([
42
- 'shell',
43
- 'am',
44
- 'start',
45
- '-a',
46
- 'android.intent.action.MAIN',
47
- '-c',
48
- 'android.intent.category.LAUNCHER',
49
- '-n',
50
- 'com.example.app/.MainActivity',
51
- '--ez',
52
- 'feature_flag',
53
- 'true',
54
- '--ei',
55
- 'user_id',
56
- '42',
57
- '--es',
58
- 'mode',
59
- 'debug',
60
- ]);
61
- });
62
- it('rejects unsafe integer extras', () => {
63
- expect(() => getStartAppArgs('com.example.app', '.MainActivity', {
64
- extras: {
65
- count: Number.MAX_SAFE_INTEGER + 1,
66
- },
67
- })).toThrow('must be a safe integer');
68
- });
69
- it('extracts app uid from pm list packages output', async () => {
70
- const spawnSpy = vi.spyOn(tools, 'spawn').mockResolvedValueOnce({
71
- stdout: 'package:com.other.app uid:10123\npackage:com.example.app uid:10234\n',
72
- });
73
- await expect(getAppUid('emulator-5554', 'com.example.app')).resolves.toBe(10234);
74
- expect(spawnSpy).toHaveBeenCalledWith(expect.stringMatching(/adb$/), [
75
- '-s',
76
- 'emulator-5554',
77
- 'shell',
78
- 'pm',
79
- 'list',
80
- 'packages',
81
- '-U',
82
- ]);
83
- });
84
- it('reads the device timestamp in logcat format', async () => {
85
- const spawnSpy = vi.spyOn(tools, 'spawn').mockResolvedValueOnce({
86
- stdout: "'03-12 11:35:08.000'\n",
87
- });
88
- await expect(getLogcatTimestamp('emulator-5554')).resolves.toBe('03-12 11:35:08.000');
89
- expect(spawnSpy).toHaveBeenCalledWith(expect.stringMatching(/adb$/), [
90
- '-s',
91
- 'emulator-5554',
92
- 'shell',
93
- 'date',
94
- "+'%m-%d %H:%M:%S.000'",
95
- ]);
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
- });
120
- it('checks whether an AVD exists', async () => {
121
- vi.spyOn(tools, 'spawn').mockResolvedValue({
122
- stdout: 'Pixel_6_API_33\nPixel_8_API_35\n',
123
- });
124
- await expect(hasAvd('Pixel_8_API_35')).resolves.toBe(true);
125
- await expect(hasAvd('Missing_AVD')).resolves.toBe(false);
126
- });
127
- it('installs the app via adb', async () => {
128
- const spawnSpy = vi
129
- .spyOn(tools, 'spawn')
130
- .mockResolvedValueOnce({});
131
- await installApp('emulator-5554', '/tmp/app.apk');
132
- expect(spawnSpy).toHaveBeenCalledWith(expect.stringMatching(/adb$/), [
133
- '-s',
134
- 'emulator-5554',
135
- 'install',
136
- '-r',
137
- '/tmp/app.apk',
138
- ]);
139
- });
140
- it('uninstalls the app via adb', async () => {
141
- const spawnSpy = vi
142
- .spyOn(tools, 'spawn')
143
- .mockResolvedValueOnce({});
144
- await uninstallApp('emulator-5554', 'com.example.app');
145
- expect(spawnSpy).toHaveBeenCalledWith(expect.stringMatching(/adb$/), [
146
- '-s',
147
- 'emulator-5554',
148
- 'uninstall',
149
- 'com.example.app',
150
- ]);
151
- });
152
- it('creates an AVD and appends config overrides', async () => {
153
- vi.spyOn(avdConfig, 'readAvdConfig').mockResolvedValue({});
154
- const spawnSpy = vi
155
- .spyOn(tools, 'spawn')
156
- .mockResolvedValue({})
157
- .mockResolvedValueOnce({
158
- stdout: 'id: 0 or "pixel_8"\n Name: Pixel 8\nid: 1 or "pixel_6"\n Name: Pixel 6\n',
159
- });
160
- const verifyAndroidEmulatorSdk = vi
161
- .spyOn(environment, 'ensureAndroidSdkPackages')
162
- .mockResolvedValue('/tmp/android-sdk');
163
- vi.spyOn(environment, 'getHostAndroidSystemImageArch').mockReturnValue('x86_64');
164
- await createAvd({
165
- name: 'Pixel_8_API_35',
166
- apiLevel: 35,
167
- profile: 'pixel_8',
168
- diskSize: '1G',
169
- heapSize: '1G',
170
- });
171
- expect(verifyAndroidEmulatorSdk).toHaveBeenCalledWith([
172
- 'platform-tools',
173
- 'emulator',
174
- 'platforms;android-35',
175
- 'system-images;android-35;default;x86_64',
176
- ]);
177
- expect(spawnSpy).toHaveBeenNthCalledWith(1, expect.stringMatching(/avdmanager$/), ['list', 'device']);
178
- expect(spawnSpy).toHaveBeenNthCalledWith(2, 'bash', [
179
- '-lc',
180
- expect.stringContaining('create avd --force --name "Pixel_8_API_35" --package "system-images;android-35;default;x86_64" --device "pixel_8" -p '),
181
- ]);
182
- expect(spawnSpy).toHaveBeenNthCalledWith(3, 'bash', [
183
- '-lc',
184
- expect.stringContaining(`'avd.ini.encoding=UTF-8' 'path=`),
185
- ]);
186
- expect(spawnSpy).toHaveBeenNthCalledWith(4, 'bash', [
187
- '-lc',
188
- expect.stringContaining(`'disk.dataPartition.size=1G' 'vm.heapSize=1G' >> `),
189
- ]);
190
- });
191
- it('recreates the companion ini file when avdmanager leaves it missing', async () => {
192
- vi.spyOn(avdConfig, 'readAvdConfig').mockResolvedValue({});
193
- const spawnSpy = vi
194
- .spyOn(tools, 'spawn')
195
- .mockResolvedValue({})
196
- .mockResolvedValueOnce({
197
- stdout: 'id: 0 or "pixel_6"\n Name: Pixel 6\n',
198
- });
199
- vi.spyOn(environment, 'ensureAndroidSdkPackages').mockResolvedValue('/tmp/android-sdk');
200
- vi.spyOn(environment, 'getHostAndroidSystemImageArch').mockReturnValue('x86_64');
201
- await createAvd({
202
- name: 'Pixel_6_API_35',
203
- apiLevel: 35,
204
- profile: 'pixel_6',
205
- diskSize: '1G',
206
- heapSize: '1G',
207
- });
208
- expect(spawnSpy).toHaveBeenNthCalledWith(3, 'bash', [
209
- '-lc',
210
- expect.stringContaining(`'avd.ini.encoding=UTF-8' 'path=`),
211
- ]);
212
- expect(spawnSpy).toHaveBeenNthCalledWith(4, 'bash', [
213
- '-lc',
214
- expect.stringContaining(`'disk.dataPartition.size=1G' 'vm.heapSize=1G' >> `),
215
- ]);
216
- });
217
- it('throws an actionable error when the requested AVD profile is unavailable', async () => {
218
- vi.spyOn(tools, 'spawn').mockResolvedValueOnce({
219
- stdout: 'id: 0 or "pixel_8"\n Name: Pixel 8\nid: 1 or "pixel_6"\n Name: Pixel 6\n',
220
- });
221
- vi.spyOn(environment, 'ensureAndroidSdkPackages').mockResolvedValue('/tmp/android-sdk');
222
- vi.spyOn(environment, 'getHostAndroidSystemImageArch').mockReturnValue('x86_64');
223
- await expect(createAvd({
224
- name: 'Pixel_8_Pro_API_35',
225
- apiLevel: 35,
226
- profile: 'pixel_8_pro',
227
- diskSize: '1G',
228
- heapSize: '1G',
229
- })).rejects.toThrow('Android AVD profile "pixel_8_pro" is not available on this machine. Available profiles: pixel_8, pixel_6');
230
- });
231
- it('throws a clear error when avdmanager does not create config.ini', async () => {
232
- vi.spyOn(avdConfig, 'readAvdConfig').mockResolvedValue(null);
233
- vi.spyOn(tools, 'spawn')
234
- .mockResolvedValue({})
235
- .mockResolvedValueOnce({
236
- stdout: 'id: 0 or "pixel_6"\n Name: Pixel 6\n',
237
- });
238
- vi.spyOn(environment, 'ensureAndroidSdkPackages').mockResolvedValue('/tmp/android-sdk');
239
- vi.spyOn(environment, 'getHostAndroidSystemImageArch').mockReturnValue('x86_64');
240
- await expect(createAvd({
241
- name: 'Pixel_6_API_35',
242
- apiLevel: 35,
243
- profile: 'pixel_6',
244
- diskSize: '1G',
245
- heapSize: '1G',
246
- })).rejects.toThrow('Android AVD "Pixel_6_API_35" was created, but config.ini was not found at ');
247
- });
248
- it('creates an AVD with arm64 system image packages on arm64 hosts', async () => {
249
- vi.spyOn(avdConfig, 'readAvdConfig').mockResolvedValue({});
250
- vi.spyOn(tools, 'spawn')
251
- .mockResolvedValue({})
252
- .mockResolvedValueOnce({
253
- stdout: 'id: 0 or "pixel_8"\n Name: Pixel 8\n',
254
- });
255
- const ensureAndroidSdkPackages = vi
256
- .spyOn(environment, 'ensureAndroidSdkPackages')
257
- .mockResolvedValue('/tmp/android-sdk');
258
- vi.spyOn(environment, 'getHostAndroidSystemImageArch').mockReturnValue('arm64-v8a');
259
- await createAvd({
260
- name: 'Pixel_8_API_35',
261
- apiLevel: 35,
262
- profile: 'pixel_8',
263
- diskSize: '1G',
264
- heapSize: '1G',
265
- });
266
- expect(ensureAndroidSdkPackages).toHaveBeenCalledWith([
267
- 'platform-tools',
268
- 'emulator',
269
- 'platforms;android-35',
270
- 'system-images;android-35;default;arm64-v8a',
271
- ]);
272
- });
273
- it.skip('deletes both AVD directory and ini file', async () => {
274
- await deleteAvd('Pixel_8_API_35');
275
- });
276
- it('surfaces emulator stdout when startup fails immediately', async () => {
277
- const child = createMockChildProcess();
278
- let launcherReadyResolve;
279
- const launcherReady = new Promise((resolve) => {
280
- launcherReadyResolve = resolve;
281
- });
282
- vi.spyOn(tools, 'spawn').mockResolvedValue({
283
- stdout: 'List of devices attached\n\n',
284
- });
285
- vi.spyOn(emulatorProcess, 'startDetachedProcess').mockImplementation(() => {
286
- launcherReadyResolve?.();
287
- return child;
288
- });
289
- const startPromise = startEmulator('Pixel_8_API_35');
290
- await launcherReady;
291
- child.stdout.write('Unknown AVD name [Pixel_8_API_35]\n');
292
- child.stdout.end();
293
- child.stderr.end();
294
- child.emit('close', 1, null);
295
- await expect(startPromise).rejects.toThrow('Unknown AVD name [Pixel_8_API_35]');
296
- });
297
- it('surfaces emulator stderr when startup fails immediately', async () => {
298
- const child = createMockChildProcess();
299
- let launcherReadyResolve;
300
- const launcherReady = new Promise((resolve) => {
301
- launcherReadyResolve = resolve;
302
- });
303
- vi.spyOn(tools, 'spawn').mockResolvedValue({
304
- stdout: 'List of devices attached\n\n',
305
- });
306
- vi.spyOn(emulatorProcess, 'startDetachedProcess').mockImplementation(() => {
307
- launcherReadyResolve?.();
308
- return child;
309
- });
310
- const startPromise = startEmulator('Pixel_8_API_35');
311
- await launcherReady;
312
- child.stderr.write('emulator: panic: broken config\n');
313
- child.stdout.end();
314
- child.stderr.end();
315
- child.emit('close', 1, null);
316
- await expect(startPromise).rejects.toThrow('emulator: panic: broken config');
317
- });
318
- it('returns after the emulator appears without waiting for process exit', async () => {
319
- vi.useFakeTimers();
320
- const child = createMockChildProcess();
321
- const spawnSpy = vi.spyOn(tools, 'spawn');
322
- spawnSpy
323
- .mockResolvedValueOnce({
324
- stdout: 'List of devices attached\nemulator-5554\tdevice\n',
325
- })
326
- .mockResolvedValueOnce({
327
- stdout: 'Pixel_8_API_35\n',
328
- });
329
- vi.spyOn(emulatorProcess, 'startDetachedProcess').mockReturnValue(child);
330
- const startPromise = startEmulator('Pixel_8_API_35');
331
- await vi.runAllTimersAsync();
332
- await expect(startPromise).resolves.toBeUndefined();
333
- expect(child.unref).toHaveBeenCalled();
334
- });
335
- it('passes default boot args to the emulator process', async () => {
336
- vi.useFakeTimers();
337
- const child = createMockChildProcess();
338
- vi.spyOn(tools, 'spawn')
339
- .mockResolvedValueOnce({
340
- stdout: 'List of devices attached\nemulator-5554\tdevice\n',
341
- })
342
- .mockResolvedValueOnce({
343
- stdout: 'Pixel_8_API_35\n',
344
- });
345
- const startDetachedProcess = vi
346
- .spyOn(emulatorProcess, 'startDetachedProcess')
347
- .mockReturnValue(child);
348
- const startPromise = startEmulator('Pixel_8_API_35');
349
- await vi.runAllTimersAsync();
350
- await startPromise;
351
- expect(startDetachedProcess).toHaveBeenCalledWith(expect.stringMatching(/emulator$/), expect.arrayContaining(['-no-snapshot-load', '-no-snapshot-save']));
352
- });
353
- it('passes clean snapshot generation args to the emulator process', async () => {
354
- vi.useFakeTimers();
355
- const child = createMockChildProcess();
356
- vi.spyOn(tools, 'spawn')
357
- .mockResolvedValueOnce({
358
- stdout: 'List of devices attached\nemulator-5554\tdevice\n',
359
- })
360
- .mockResolvedValueOnce({
361
- stdout: 'Pixel_8_API_35\n',
362
- });
363
- const startDetachedProcess = vi
364
- .spyOn(emulatorProcess, 'startDetachedProcess')
365
- .mockReturnValue(child);
366
- const startPromise = startEmulator('Pixel_8_API_35', 'clean-snapshot-generation');
367
- await vi.runAllTimersAsync();
368
- await startPromise;
369
- expect(startDetachedProcess).toHaveBeenCalledWith(expect.stringMatching(/emulator$/), expect.arrayContaining(['-no-snapshot-load']));
370
- expect(startDetachedProcess.mock.calls[0]?.[1]).not.toContain('-no-snapshot-save');
371
- });
372
- it('passes snapshot reuse args to the emulator process', async () => {
373
- vi.useFakeTimers();
374
- const child = createMockChildProcess();
375
- vi.spyOn(tools, 'spawn')
376
- .mockResolvedValueOnce({
377
- stdout: 'List of devices attached\nemulator-5554\tdevice\n',
378
- })
379
- .mockResolvedValueOnce({
380
- stdout: 'Pixel_8_API_35\n',
381
- });
382
- const startDetachedProcess = vi
383
- .spyOn(emulatorProcess, 'startDetachedProcess')
384
- .mockReturnValue(child);
385
- const startPromise = startEmulator('Pixel_8_API_35', 'snapshot-reuse');
386
- await vi.runAllTimersAsync();
387
- await startPromise;
388
- expect(startDetachedProcess).toHaveBeenCalledWith(expect.stringMatching(/emulator$/), expect.arrayContaining(['-no-snapshot-save']));
389
- expect(startDetachedProcess.mock.calls[0]?.[1]).not.toContain('-no-snapshot-load');
390
- });
391
- it('aborts while waiting for an emulator to boot', async () => {
392
- vi.useFakeTimers();
393
- vi.spyOn(tools, 'spawn').mockResolvedValue({
394
- stdout: 'List of devices attached\n\n',
395
- });
396
- const controller = new AbortController();
397
- const waitPromise = waitForBoot('Pixel_8_API_35', controller.signal);
398
- await vi.advanceTimersByTimeAsync(1000);
399
- controller.abort(createAbortError());
400
- await expect(waitPromise).rejects.toBeInstanceOf(DOMException);
401
- });
402
- it('aborts while waiting for boot completion', async () => {
403
- vi.useFakeTimers();
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
- }));
422
- const controller = new AbortController();
423
- const waitPromise = waitForBoot('Pixel_8_API_35', controller.signal);
424
- await vi.advanceTimersByTimeAsync(1000);
425
- controller.abort(createAbortError());
426
- await expect(waitPromise).rejects.toBeInstanceOf(DOMException);
427
- });
428
- it('treats transient adb shell failures as not-yet-booted', async () => {
429
- vi.useFakeTimers();
430
- const spawnSpy = vi.spyOn(tools, 'spawn');
431
- const transientShellError = Object.assign(new Error('adb shell failed'), {
432
- exitCode: 1,
433
- });
434
- Object.setPrototypeOf(transientShellError, SubprocessError.prototype);
435
- spawnSpy
436
- .mockResolvedValueOnce({
437
- stdout: 'List of devices attached\nemulator-5554\tdevice\n',
438
- })
439
- .mockResolvedValueOnce({
440
- stdout: 'Pixel_8_API_35\n',
441
- })
442
- .mockRejectedValueOnce(transientShellError)
443
- .mockResolvedValueOnce({
444
- stdout: 'List of devices attached\nemulator-5554\tdevice\n',
445
- })
446
- .mockResolvedValueOnce({
447
- stdout: 'Pixel_8_API_35\n',
448
- })
449
- .mockResolvedValueOnce({
450
- stdout: '1\n',
451
- });
452
- const waitPromise = waitForBoot('Pixel_8_API_35', new AbortController().signal);
453
- await vi.advanceTimersByTimeAsync(1000);
454
- await expect(waitPromise).resolves.toBe('emulator-5554');
455
- expect(spawnSpy).toHaveBeenCalledTimes(6);
456
- });
457
- it('waits for an emulator to disconnect from adb', async () => {
458
- vi.useFakeTimers();
459
- const spawnSpy = vi.spyOn(tools, 'spawn');
460
- spawnSpy
461
- .mockResolvedValueOnce({
462
- stdout: 'List of devices attached\nemulator-5554\tdevice\n',
463
- })
464
- .mockResolvedValueOnce({
465
- stdout: 'List of devices attached\n\n',
466
- });
467
- const waitPromise = waitForEmulatorDisconnect('emulator-5554', new AbortController().signal);
468
- await vi.advanceTimersByTimeAsync(1000);
469
- await expect(waitPromise).resolves.toBeUndefined();
470
- expect(spawnSpy).toHaveBeenCalledTimes(2);
471
- });
472
- it('grants requested dangerous permissions to an app', async () => {
473
- const { grantPermissions } = await import('../adb.js');
474
- const spawnSpy = vi
475
- .spyOn(tools, 'spawn')
476
- .mockResolvedValueOnce({
477
- stdout: 'package:com.example.app\n',
478
- })
479
- .mockResolvedValueOnce({
480
- stdout: `requested permissions:\n android.permission.CAMERA\n android.permission.INTERNET\n android.permission.ACCESS_FINE_LOCATION\ninstall permissions:\n`,
481
- })
482
- .mockResolvedValueOnce({
483
- stdout: `Dangerous Permissions:\n permission:android.permission.CAMERA\n permission:android.permission.ACCESS_FINE_LOCATION\n`,
484
- })
485
- .mockResolvedValue({
486
- stdout: '',
487
- });
488
- await grantPermissions('emulator-5554', 'com.example.app');
489
- expect(spawnSpy).toHaveBeenCalledTimes(5);
490
- expect(spawnSpy).toHaveBeenNthCalledWith(1, expect.any(String), [
491
- '-s',
492
- 'emulator-5554',
493
- 'shell',
494
- 'pm',
495
- 'list',
496
- 'packages',
497
- 'com.example.app',
498
- ]);
499
- expect(spawnSpy).toHaveBeenNthCalledWith(2, expect.any(String), [
500
- '-s',
501
- 'emulator-5554',
502
- 'shell',
503
- 'dumpsys',
504
- 'package',
505
- 'com.example.app',
506
- ]);
507
- expect(spawnSpy).toHaveBeenNthCalledWith(3, expect.any(String), [
508
- '-s',
509
- 'emulator-5554',
510
- 'shell',
511
- 'pm',
512
- 'list',
513
- 'permissions',
514
- '-g',
515
- '-d',
516
- ]);
517
- expect(spawnSpy).toHaveBeenNthCalledWith(4, expect.any(String), [
518
- '-s',
519
- 'emulator-5554',
520
- 'shell',
521
- 'pm',
522
- 'grant',
523
- 'com.example.app',
524
- 'android.permission.CAMERA',
525
- ]);
526
- expect(spawnSpy).toHaveBeenNthCalledWith(5, expect.any(String), [
527
- '-s',
528
- 'emulator-5554',
529
- 'shell',
530
- 'pm',
531
- 'grant',
532
- 'com.example.app',
533
- 'android.permission.ACCESS_FINE_LOCATION',
534
- ]);
535
- });
536
- it('does nothing when the app has no grantable dangerous permissions', async () => {
537
- const { grantPermissions } = await import('../adb.js');
538
- const spawnSpy = vi
539
- .spyOn(tools, 'spawn')
540
- .mockResolvedValueOnce({
541
- stdout: 'package:com.example.app\n',
542
- })
543
- .mockResolvedValueOnce({
544
- stdout: `requested permissions:\n android.permission.INTERNET\ninstall permissions:\n`,
545
- })
546
- .mockResolvedValueOnce({
547
- stdout: `Dangerous Permissions:\n permission:android.permission.CAMERA\n`,
548
- });
549
- await grantPermissions('emulator-5554', 'com.example.app');
550
- expect(spawnSpy).toHaveBeenCalledTimes(3);
551
- });
552
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=app-monitor.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"app-monitor.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/app-monitor.test.ts"],"names":[],"mappings":""}