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