Skip to content

Commit a5570bf

Browse files
fix(platform-android): avoid probing physical devices as emulators (#112)
## Description When we specify an android emulator as the harness runner like below and connect a physical device, we get the following error. ```js const config = { runners: [ androidPlatform({ name: 'android', device: androidEmulator('Pixel_Tablet_Rootable'), bundleId: 'com.example', }), ] }; export default config; ``` ``` SubprocessError: Command failed with exit code 1: ~/Library/Android/sdk/platform-tools/adb -s <device-id> emu avd name at checkFailure (file:///path/to/node_modules/nano-spawn/source/result.js:40:9) at getResult (file:///path/to/node_modules/nano-spawn/source/result.js:17:3) at process.processTicksAndRejections (node:internal/process/task_queues:104:5) at async Module.getEmulatorName (file:///path/to/node_modules/@react-native-harness/platform-android/dist/adb.js:195:24) at async getAdbId (file:///path/to/node_modules/@react-native-harness/platform-android/dist/adb-id.js:10:34) at async getAndroidEmulatorPlatformInstance (file:///path/to/node_modules/@react-native-harness/platform-android/dist/instance.js:108:17) at async Object.work (file:///path/to/node_modules/@react-native-harness/jest/dist/harness.js:217:36) at async withPlatformReadyTimeout (file:///path/to/node_modules/@react-native-harness/jest/dist/harness.js:36:16) at async Promise.all (index 1) at async file:///path/to/node_modules/@react-native-harness/jest/dist/harness.js:202:24 ``` This is just because `getAdbId` tries to get an emulator name from a physical device. This patch fixes Android emulator device resolution to skip non-emulator ADB IDs before querying AVD name. Also adds a focused regression test suite. ## Testing I manually tested with that previously problematic situation. --------- Co-authored-by: Szymon Chmal <szymon@chmal.it>
1 parent 8d6a1bb commit a5570bf

3 files changed

Lines changed: 74 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
__default__: patch
3+
---
4+
5+
Harness will stop trying to treat connected physical Android devices as emulators. If you run against an Android emulator and also have a physical device plugged in, Harness will now pick the emulator cleanly instead of failing during device resolution.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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+
5+
describe('adb id resolution', () => {
6+
beforeEach(() => {
7+
vi.restoreAllMocks();
8+
});
9+
10+
it('identifies emulator adb ids', () => {
11+
expect(isAdbIdEmulator('emulator-5554')).toBe(true);
12+
expect(isAdbIdEmulator('device-serial-001')).toBe(false);
13+
});
14+
15+
it('skips non-emulator ids when resolving an emulator device', async () => {
16+
vi.spyOn(adb, 'getDeviceIds').mockResolvedValue([
17+
'device-serial-001',
18+
'emulator-5554',
19+
]);
20+
vi.spyOn(adb, 'getEmulatorName').mockResolvedValue('Test_AVD_API_35');
21+
22+
await expect(
23+
getAdbId({
24+
type: 'emulator',
25+
name: 'Test_AVD_API_35',
26+
}),
27+
).resolves.toBe('emulator-5554');
28+
});
29+
30+
it('resolves matching physical device by manufacturer and model', async () => {
31+
vi.spyOn(adb, 'getDeviceIds').mockResolvedValue([
32+
'device-serial-001',
33+
'emulator-5554',
34+
]);
35+
vi.spyOn(adb, 'getDeviceInfo').mockImplementation(async (adbId) => {
36+
const results: Record<string, { manufacturer: string; model: string }> = {
37+
'device-serial-001': { manufacturer: 'Acme', model: 'Model A1' },
38+
'emulator-5554': { manufacturer: 'Emulator', model: 'Emulator Model' },
39+
};
40+
return results[adbId] || null;
41+
});
42+
43+
await expect(
44+
getAdbId({
45+
type: 'physical',
46+
manufacturer: 'acme',
47+
model: 'model a1',
48+
}),
49+
).resolves.toBe('device-serial-001');
50+
});
51+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/// <reference types='vitest' />
2+
import { defineConfig } from 'vite';
3+
4+
export default defineConfig(() => ({
5+
root: __dirname,
6+
cacheDir: '../../node_modules/.vite/packages/platform-android',
7+
test: {
8+
watch: false,
9+
globals: true,
10+
environment: 'node',
11+
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
12+
reporters: ['default'],
13+
coverage: {
14+
reportsDirectory: './test-output/vitest/coverage',
15+
provider: 'v8' as const,
16+
},
17+
},
18+
}));

0 commit comments

Comments
 (0)