1 package com.testrunner; 2 3 import static androidx.test.espresso.Espresso.onView; 4 import static androidx.test.espresso.matcher.ViewMatchers.isRoot; 5 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 6 7 import android.app.Activity; 8 import android.content.Context; 9 import android.content.ContextWrapper; 10 import android.view.View; 11 import android.view.ViewGroup; 12 13 import androidx.test.ext.junit.runners.AndroidJUnit4; 14 import androidx.test.filters.LargeTest; 15 import androidx.test.rule.ActivityTestRule; 16 17 import com.facebook.react.ReactApplication; 18 import com.facebook.react.ReactNativeHost; 19 import com.wix.detox.Detox; 20 import com.wix.detox.config.DetoxConfig; 21 22 import org.junit.Rule; 23 import org.junit.Test; 24 import org.junit.runner.RunWith; 25 26 import expo.modules.devlauncher.DevLauncherController; 27 import expo.modules.devlauncher.launcher.DevLauncherActivity; 28 import expo.modules.devmenu.DevMenuManager; 29 30 // We need this class to pass dev launcher host to detox. 31 // Otherwise it won't detect that the app has been started. 32 class ReactNativeHolder extends ContextWrapper implements ReactApplication { ReactNativeHolder(Context base)33 public ReactNativeHolder(Context base) { 34 super(base); 35 } 36 37 @Override getReactNativeHost()38 public ReactNativeHost getReactNativeHost() { 39 return DevLauncherController.getInstance().getDevClientHost(); 40 } 41 } 42 43 class DevClientDetoxHelper { getCurrentActivity()44 public static Activity getCurrentActivity() { 45 final Activity[] activity = new Activity[1]; 46 47 onView(isRoot()).check((view, noViewFoundException) -> { 48 49 View checkedView = view; 50 51 while (checkedView instanceof ViewGroup && ((ViewGroup) checkedView).getChildCount() > 0) { 52 53 checkedView = ((ViewGroup) checkedView).getChildAt(0); 54 55 if (checkedView.getContext() instanceof Activity) { 56 activity[0] = (Activity) checkedView.getContext(); 57 return; 58 } 59 } 60 }); 61 return activity[0]; 62 } 63 openMenu()64 public static void openMenu() throws InterruptedException { 65 getInstrumentation().waitForIdleSync(); 66 Activity activity = getCurrentActivity(); 67 int counter = 10; 68 while (counter-- > 0 && activity == null) { 69 Thread.sleep(100); 70 activity = getCurrentActivity(); 71 } 72 73 DevMenuManager.INSTANCE.openMenu(activity, null); 74 } 75 } 76 77 @RunWith(AndroidJUnit4.class) 78 @LargeTest 79 public class DetoxTest { 80 @Rule 81 public ActivityTestRule<DevLauncherActivity> mActivityRule = new ActivityTestRule<>(DevLauncherActivity.class, false, false); 82 83 @Test runDetoxTests()84 public void runDetoxTests() { 85 DetoxConfig detoxConfig = new DetoxConfig(); 86 detoxConfig.idlePolicyConfig.masterTimeoutSec = 90; 87 detoxConfig.rnContextLoadTimeoutSec = 180; 88 89 ReactNativeHolder reactNativeHolder = new ReactNativeHolder(getInstrumentation().getTargetContext().getApplicationContext()); 90 Detox.runTests(mActivityRule, reactNativeHolder, detoxConfig); 91 } 92 } 93