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