From 030a58d9058ddf0507670d0b5a348afa794f9775 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 8 May 2026 16:14:32 +0100 Subject: [PATCH 1/2] fix(platform-android): avoid probing physical devices as emulators ## Description Fix Android emulator device resolution to skip non-emulator ADB IDs before querying AVD name, preventing harness runs from failing when both physical devices and emulators are connected. Also adds a focused regression test suite for mixed-device scenarios and introduces package-local Vite test config so nx test works for platform-android. ## Related Issue No upstream issue link available in this branch context. The bug was reproduced from downstream integration usage where a connected physical device caused adb -s emu avd name to fail during emulator resolution. ## Context getAdbId iterated all IDs from adb devices and called getEmulatorName for emulator-configured runs regardless of ID type. On physical devices this command is invalid and throws. The fix filters IDs to emulator-* before calling getEmulatorName, preserving existing matching behavior while avoiding false failures. The regression tests intentionally use generic device serials and model names to avoid personal/local identifiers in upstream tests. ## Testing - pnpm nx lint @react-native-harness/platform-android (pass) - pnpm nx typecheck @react-native-harness/platform-android (pass) - pnpm nx test @react-native-harness/platform-android -- --run src/__tests__/adb-id.test.ts (pass) - Full target run currently has unrelated pre-existing failures in app-monitor.test.ts in this repo state --- .../src/__tests__/adb-id.test.ts | 51 +++++++++++++++++++ packages/platform-android/src/adb-id.ts | 4 ++ packages/platform-android/vite.config.ts | 18 +++++++ 3 files changed, 73 insertions(+) create mode 100644 packages/platform-android/src/__tests__/adb-id.test.ts create mode 100644 packages/platform-android/vite.config.ts diff --git a/packages/platform-android/src/__tests__/adb-id.test.ts b/packages/platform-android/src/__tests__/adb-id.test.ts new file mode 100644 index 00000000..3d6078c7 --- /dev/null +++ b/packages/platform-android/src/__tests__/adb-id.test.ts @@ -0,0 +1,51 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { getAdbId, isAdbIdEmulator } from '../adb-id.js'; +import * as adb from '../adb.js'; + +describe('adb id resolution', () => { + beforeEach(() => { + vi.restoreAllMocks(); + }); + + it('identifies emulator adb ids', () => { + expect(isAdbIdEmulator('emulator-5554')).toBe(true); + expect(isAdbIdEmulator('device-serial-001')).toBe(false); + }); + + it('skips non-emulator ids when resolving an emulator device', async () => { + vi.spyOn(adb, 'getDeviceIds').mockResolvedValue([ + 'device-serial-001', + 'emulator-5554', + ]); + vi.spyOn(adb, 'getEmulatorName').mockResolvedValue('Test_AVD_API_35'); + + await expect( + getAdbId({ + type: 'emulator', + name: 'Test_AVD_API_35', + }), + ).resolves.toBe('emulator-5554'); + }); + + it('resolves matching physical device by manufacturer and model', async () => { + vi.spyOn(adb, 'getDeviceIds').mockResolvedValue([ + 'device-serial-001', + 'emulator-5554', + ]); + vi.spyOn(adb, 'getDeviceInfo').mockImplementation(async (adbId) => { + const results: Record = { + 'device-serial-001': { manufacturer: 'Acme', model: 'Model A1' }, + 'emulator-5554': { manufacturer: 'Emulator', model: 'Emulator Model' }, + }; + return results[adbId] || null; + }); + + await expect( + getAdbId({ + type: 'physical', + manufacturer: 'acme', + model: 'model a1', + }), + ).resolves.toBe('device-serial-001'); + }); +}); diff --git a/packages/platform-android/src/adb-id.ts b/packages/platform-android/src/adb-id.ts index a24b938b..2d714d0f 100644 --- a/packages/platform-android/src/adb-id.ts +++ b/packages/platform-android/src/adb-id.ts @@ -16,6 +16,10 @@ export const getAdbId = async ( for (const adbId of adbIds) { if (isAndroidDeviceEmulator(device)) { + if (!isAdbIdEmulator(adbId)) { + continue; + } + const emulatorName = await adb.getEmulatorName(adbId); if (emulatorName === device.name) { diff --git a/packages/platform-android/vite.config.ts b/packages/platform-android/vite.config.ts new file mode 100644 index 00000000..c1ee0570 --- /dev/null +++ b/packages/platform-android/vite.config.ts @@ -0,0 +1,18 @@ +/// +import { defineConfig } from 'vite'; + +export default defineConfig(() => ({ + root: __dirname, + cacheDir: '../../node_modules/.vite/packages/platform-android', + test: { + watch: false, + globals: true, + environment: 'node', + include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8' as const, + }, + }, +})); From 3f1a7ce42aa4773314cb72ed0a7f724e15711d81 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Mon, 11 May 2026 09:25:38 +0200 Subject: [PATCH 2/2] chore: add version plan --- .nx/version-plans/version-plan-1777795200000.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .nx/version-plans/version-plan-1777795200000.md diff --git a/.nx/version-plans/version-plan-1777795200000.md b/.nx/version-plans/version-plan-1777795200000.md new file mode 100644 index 00000000..f9b9aece --- /dev/null +++ b/.nx/version-plans/version-plan-1777795200000.md @@ -0,0 +1,5 @@ +--- +__default__: patch +--- + +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.