Detox: detox test hangs when starting the Android emulator (Apple Silicon)

Describe the bug

We upgraded our Detox machine to the new M1 Mac mini and ran into this issue. detox build -c android.emu.debug succeeds without problems. detox test -c android.emu.debug starts but then hangs when the emulator window opens. The app does not launch. Here is the printout.

detox test -c android.emu.debug --loglevel trace --record-logs all

detox[21491] INFO:  [test.js] DETOX_CONFIGURATION="android.emu.debug" DETOX_FORCE_ADB_INSTALL=false DETOX_LOGLEVEL="trace" DETOX_READ_ONLY_EMU=false DETOX_RECORD_LOGS="all" DETOX_REPORT_SPECS=true DETOX_START_TIMESTAMP=1620319503548 DETOX_USE_CUSTOM_LOGGER=true jest --config e2e/config.json --testNamePattern '^((?!:ios:).)*$' --maxWorkers 1 e2e
detox[21492] TRACE: [DETOX_CREATE] created a Detox instance with config:
{"artifactsConfig":{"rootDir":"artifacts/android.emu.debug.2021-05-06 16-45-03Z","plugins":{"log":{"enabled":true,"keepOnlyFailedTestsArtifacts":false},"screenshot":{"enabled":true,"shouldTakeAutomaticSnapshots":false,"keepOnlyFailedTestsArtifacts":false},"video":{"enabled":false,"keepOnlyFailedTestsArtifacts":false},"instruments":{"enabled":false,"keepOnlyFailedTestsArtifacts":false},"timeline":{"enabled":false},"uiHierarchy":{"enabled":false,"keepOnlyFailedTestsArtifacts":false}},"pathBuilder":{"_rootDir":"artifacts/android.emu.debug.2021-05-06 16-45-03Z"}},"appsConfig":{"default":{"type":"android.apk","binaryPath":"android/app/build/outputs/apk/dev/debug/app-dev-debug.apk","build":"cd android && ./gradlew assembleDevDebug assembleDevDebugAndroidTest -DtestBuildType=debug && cd .."}},"behaviorConfig":{"init":{"reinstallApp":true,"exposeGlobals":true},"cleanup":{"shutdownDevice":false},"launchApp":"auto"},"cliConfig":{"recordLogs":"all","configuration":"android.emu.debug","forceAdbInstall":"false","loglevel":"trace","useCustomLogger":"true"},"deviceConfig":{"type":"android.emulator","device":{"avdName":"Pixel_4_API_S"}},"runnerConfig":{"testRunner":"jest","runnerConfig":"e2e/config.json","specs":"e2e"},"sessionConfig":{"autoStart":true,"server":"ws://localhost:53897","sessionId":"739c184a-52ba-ed62-53c8-459377c997f9","debugSynchronization":10000},"errorComposer":{"configurationName":"android.emu.debug","filepath":"/Users/fleetback-ci/builds/9J-UT-y5/0/arhs-fleetback/fleetback-app-react/.detoxrc.json","contents":{"testRunner":"jest","runnerConfig":"e2e/config.json","configurations":{"ios.sim.debug":{"binaryPath":"ios/build/Build/Products/Debug-iphonesimulator/Fleetback DEV.app","build":"xcodebuild -workspace ios/FleetbackApp.xcworkspace -scheme FleetbackApp-DEV -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build","type":"ios.simulator","device":{"type":"iPhone 11"}},"ios.sim.release":{"binaryPath":"ios/build/Build/Products/Release-iphonesimulator/Fleetback DEV.app","build":"xcodebuild -workspace ios/FleetbackApp.xcworkspace -scheme FleetbackApp-DEV-release -configuration Release -sdk iphonesimulator -derivedDataPath ios/build","type":"ios.simulator","device":{"type":"iPhone 11"}},"android.emu.debug":{"binaryPath":"android/app/build/outputs/apk/dev/debug/app-dev-debug.apk","build":"cd android && ./gradlew assembleDevDebug assembleDevDebugAndroidTest -DtestBuildType=debug && cd ..","type":"android.emulator","device":{"avdName":"Pixel_4_API_S"}},"android.emu.release":{"binaryPath":"android/app/build/outputs/apk/dev/release/app-dev-release.apk","build":"cd android && ./gradlew assembleDevRelease assembleDevReleaseAndroidTest -DtestBuildType=release && cd ..","type":"android.emulator","device":{"avdName":"Pixel_4_API_S"}}}},"_extends":false}}
detox[21492] DEBUG: [WSS_CREATE] Detox server listening on localhost:53897...
detox[21492] DEBUG: [WSS_CONNECTION, #53898] registered a new connection.
detox[21492] TRACE: [WS_OPEN] opened web socket to: ws://localhost:53897
detox[21492] TRACE: [WS_SEND] {"type":"login","params":{"sessionId":"739c184a-52ba-ed62-53c8-459377c997f9","role":"tester"},"messageId":0}
detox[21492] TRACE: [WSS_GET_FROM, #53898] {"type":"login","params":{"sessionId":"739c184a-52ba-ed62-53c8-459377c997f9","role":"tester"},"messageId":0}
detox[21492] TRACE: [SESSION_CREATED] created session 739c184a-52ba-ed62-53c8-459377c997f9
detox[21492] TRACE: [WSS_SEND_TO, #tester] {"type":"loginSuccess","params":{"testerConnected":true,"appConnected":false},"messageId":0}
detox[21492] TRACE: [SESSION_JOINED] tester joined session 739c184a-52ba-ed62-53c8-459377c997f9
detox[21492] TRACE: [WS_MESSAGE] {"type":"loginSuccess","params":{"testerConnected":true,"appConnected":false},"messageId":0}
 
detox[21492] DEBUG: [EXEC_CMD, #0] "/Users/fleetback-ci/Library/Android/sdk/emulator/emulator" -list-avds --verbose
detox[21492] TRACE: [EXEC_SUCCESS, #0] Pixel_4_API_25
Pixel_4_API_S

detox[21492] DEBUG: [EXEC_CMD, #1] "/Users/fleetback-ci/Library/Android/sdk/emulator/emulator" -version 
detox[21492] ERROR: [EXEC_FAIL, #1] ""/Users/fleetback-ci/Library/Android/sdk/emulator/emulator" -version " failed with error = ChildProcessError: Command failed: "/Users/fleetback-ci/Library/Android/sdk/emulator/emulator" -version 
 `"/Users/fleetback-ci/Library/Android/sdk/emulator/emulator" -version ` (exited with error code 255) (code=255), stdout and stderr:

detox[21492] ERROR: [EXEC_FAIL, #1] emulator: Android emulator version 30.3.5.0 (build_id 7036990) (CL:N/A)
emulator: ERROR: can't find the emulator executable.


detox[21492] ERROR: [EXEC_FAIL, #1] 
detox[21492] DEBUG: [EMU_BIN_VERSION_DETECT] Detected emulator binary version { major: 30, minor: 3, patch: 5, toString: [Function: toString] }
detox[21492] DEBUG: [ALLOCATE_DEVICE] Trying to allocate a device based on "Pixel_4_API_S"
detox[21492] DEBUG: [EXEC_CMD, #2] "/Users/fleetback-ci/Library/Android/sdk/platform-tools/adb"  devices
detox[21492] DEBUG: [EXEC_SUCCESS, #2] List of devices attached


detox[21492] DEBUG: [ALLOCATE_DEVICE] Settled on emulator-17342
detox[21492] DEBUG: [SPAWN_CMD] /Users/fleetback-ci/Library/Android/sdk/emulator/emulator -verbose -no-audio -no-boot-anim -port 17342 @Pixel_4_API_S

 RUNS  e2e/firstTest.e2e.js

Building and running the iOS tests works. Both iOS and Android tests build, run and pass on our Intel MacBooks. I had to patch line 22 of EmulatorVersionResolver.js because the command seems broken but still prints the version so it’s easy to workaround.

If you Cmd+Q the emulator, more logs appear. The whole logs are attached to the post.

If you don’t have a M1 Mac to reproduce the problem, can you give us some pointers as to why the process can get stuck on the adb command? We can help debug and fix the problem.

Steps To Reproduce

  • I have tested this issue on the latest Detox release and it still reproduces
  1. create a basic react native project
  2. setup detox
  3. patch EmulatorVersionResolver.js with rawOutput = await (this._emulatorExec.exec(new QueryVersionCommand()).catch(e => e.stdout || e.stderr)) || '';
  4. run detox build -c android.emu.debug && detox test -c android.emu.debug
  5. it hangs

Expected behavior

It should launch the app and run the tests.

Detox Trace-Logs

See attached file detox_bug.txt

Device logs (adb logcat)

It says - waiting for device - and nothing happens. If you need them I can try with Android Studio.

Environment (please complete the following information):

  • Detox: 18.12.2
  • React Native: 0.64.1
  • Node: v14.16.1
  • Device: Emulated Pixel 4 API 31 arm64
  • OS: macOS 11.3 on the M1 Mac mini
  • Test-runner jest-circus

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 7
  • Comments: 36 (10 by maintainers)

Most upvoted comments

Indeed, here is my environment.js for reference.

const {
    DetoxCircusEnvironment,
    SpecReporter,
    WorkerAssignReporter,
} = require('detox/runners/jest-circus');

const TWENTY_MINUTES = 20 * 60 * 1000;

class CustomDetoxEnvironment extends DetoxCircusEnvironment {
    constructor(config, context) {
        super(config, context);
        this.initTimeout = TWENTY_MINUTES;
        this.registerListeners({ SpecReporter, WorkerAssignReporter });
    }

    async initDetox() {
        const instance = await this.detox.init(undefined, { launchApp: false });
        await instance.device.reverseTcpPort(8081); // added this line
        await instance.device.launchApp({ permissions: { notifications: 'YES', camera: 'YES', microphone: 'YES', photos: 'YES' } });
        return instance;
    }
}

@sorodrigo not sure what parts of Detox you’re using but I’ve updated to Detox v18 now and it works fine on M1, just not on iOS15 (a known issue #2895). I also tested Detox v18 with Android 12 and it appears fine (#2899). As far as I can tell, the only thing not working at the moment is ios15 (noted) and maybe a need for a manual adb reverse for bundler port 8081 - cheers

Not sure if this will be useful for others or not, but as of today (July 15, 2021) a procedure that worked for me to get Detox tests working for react-native on an Apple M1 device were:

  • Get the current Arctic Fox Preview Apple Silicon build (https://developer.android.com/studio/archive - it is 2020.1.3 beta5 for me right now / https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2020.3.1.20/android-studio-2020.3.1.20-mac_arm.zip) - you can now run it as ‘Android Studio Preview’
  • Use SDK Manager to install the emulator package
  • From Terminal go to $ANDROID_SDK_ROOT/emulator and run ./emulator make sure it updates itself with the emulator preview release etc (https://github.com/google/android-emulator-m1-preview/releases - 0.2 engine-only is what will be downloaded and unpacked). If you run ./emulator -version you should see 30.3.5.0 because the arm64 emulator is a custom build and overwrites the SDK Manager package. It will also show the exit code 255 could not find emulator binary executable error as well, which looks dire but may be ignored
  • Use AVD Manager to make a new AVD - I found if I used Android S / API31 preview networking was broken. API30 works though, both Play and Google APIs flavors. Boot it and test it, you should have a working emulator now
  • When you run Detox, it will give you a dire message about the exit code 255 mentioned above, but it will carry on 😃. Then it hangs and times out because the adb reverse does need to be done manually for some reason. Either as above using Detox config or in Terminal with adb reverse tcp:8081 tcp:8081

I believe most of this is simply confirming the above info, but an important point for me was total emulator network failure on API31 while API30 worked in general but did need the manual reverse port mapping.

Cheers

For me as @mikehardy mentioned above, a adb reverse tcp:8081 tcp:8081 made the detox detect the react-native packager & run the tests. So the process is:

  • Run detox build command
  • Run react-native packager (npx react-native start)
  • Open the emulator & run adb reverse tcp:8081 tcp:8081
  • Run detox test command

You can invoke port reversing through Detox as well.

As for Android Studio versions, I recommend to try to look up a Google archive.

Yes it works! Here are my steps if someone gets the same problem:

The google_apis image was not working for me, from the idea.logs it complained about a missing user.img file when creating the virtual device

  • Unzip and place the folder arm64-v8a in ~/Library/Android/sdk/system-images/android-S/google_apis_playstore/
  • You can create a API 30 or API 31 AVD

On the detox side, maybe it’s a regression but I had to run adb reverse. I’ll make another ticket if I can reproduce.