Repository: wix/Detox
Pull request #1751 (2019-11-11 11:16:21)

Adds device.setStatusBar and device.resetStatusBar
<!---
Thank you for contributing!
Before submitting a pull request that implements a new functionality or fixing a major bug,
please open an issue first and propose your solution. This way we can discuss before time is spent on a solution that may not work for us.

Please check the correct option in the below list and delete the irrelevant ones.
For the second option, please fill the issue where the solution has been discussed.
-->

- [x] This is a small change 
- [x] This change has been discussed in issue #1748 
  - [ ] and the solution has been agreed upon with maintainers.

---

**Description:**

This change adds `device.setStatusBar` and `device.resetStatusBar` allowing override status bar information, specially for screenshot tests


Patch:
diff --git a/.github/support.yml b/.github/support.yml
index 47b59fd94..cec3b74d8 100644
--- a/.github/support.yml
+++ b/.github/support.yml
@@ -11,7 +11,7 @@ supportComment: >
   
   
   
-  Feel free to post your Stack Overflow question here for more visility. We'll take a look at it.
+  Feel free to post your Stack Overflow question here for more visibility. We'll take a look at it.
   
   
   
@@ -19,7 +19,7 @@ supportComment: >
 
   
   
-  For more information on bots in this reporsitory, read [this discussion](https://github.com/wix/Detox/issues/1305).
+  For more information on bots in this repository, read [this discussion](https://github.com/wix/Detox/issues/1305).
 # Whether to close issues marked as support requests
 close: true
 # Whether to lock issues marked as support requests
diff --git a/detox/android/detox/src/main/java/com/wix/detox/DetoxActionHandlers.kt b/detox/android/detox/src/main/java/com/wix/detox/DetoxActionHandlers.kt
index ee7257087..9690b75d3 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/DetoxActionHandlers.kt
+++ b/detox/android/detox/src/main/java/com/wix/detox/DetoxActionHandlers.kt
@@ -7,7 +7,6 @@ import com.wix.invoke.MethodInvocation
 import org.json.JSONArray
 import org.json.JSONException
 import org.json.JSONObject
-import java.lang.Exception
 import java.lang.reflect.InvocationTargetException
 
 private const val LOG_TAG = "DetoxManager"
@@ -28,14 +27,14 @@ class ReadyActionHandler(
 }
 
 class ReactNativeReloadActionHandler(
-        private val rnContext: Context,
+        private val appContext: Context,
         private val wsClient: WebSocketClient,
         private val testEngineFacade: TestEngineFacade)
     : DetoxActionHandler {
 
     override fun handle(params: String, messageId: Long) {
         testEngineFacade.syncIdle()
-        testEngineFacade.reloadReactNative(rnContext)
+        testEngineFacade.reloadReactNative(appContext)
         wsClient.sendAction("ready", emptyMap<Any, Any>(), messageId)
     }
 }
@@ -45,7 +44,6 @@ class InvokeActionHandler(
         private val wsClient: WebSocketClient)
     : DetoxActionHandler {
 
-
     override fun handle(params: String, messageId: Long) {
         try {
             val invocationResult = methodInvocation.invoke(params)
@@ -61,7 +59,6 @@ class InvokeActionHandler(
 }
 
 class CleanupActionHandler(
-        private val rnContext: Context,
         private val wsClient: WebSocketClient,
         private val testEngineFacade: TestEngineFacade,
         private val doStopDetox: () -> Unit)
@@ -69,10 +66,9 @@ class CleanupActionHandler(
     override fun handle(params: String, messageId: Long) {
         val stopRunner = JSONObject(params).optBoolean("stopRunner", false)
         if (stopRunner) {
-            testEngineFacade.softResetReactNative()
             doStopDetox()
         } else {
-            testEngineFacade.hardResetReactNative(rnContext)
+            testEngineFacade.resetReactNative()
         }
         wsClient.sendAction("cleanupDone", emptyMap<Any, Any>(), messageId)
     }
diff --git a/detox/android/detox/src/main/java/com/wix/detox/DetoxManager.java b/detox/android/detox/src/main/java/com/wix/detox/DetoxManager.java
index 0596c4b98..2ff129231 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/DetoxManager.java
+++ b/detox/android/detox/src/main/java/com/wix/detox/DetoxManager.java
@@ -7,6 +7,7 @@ import android.os.Looper;
 import androidx.annotation.NonNull;
 import android.util.Log;
 
+import com.wix.detox.reactnative.ReactNativeExtension;
 import com.wix.detox.systeminfo.Environment;
 import com.wix.invoke.MethodInvocation;
 
@@ -80,7 +81,7 @@ class DetoxManager implements WebSocketClient.ActionHandler {
                 if (stopping) return;
                 stopping = true;
 
-                testEngineFacade.hardResetReactNative(reactNativeHostHolder);
+                testEngineFacade.resetReactNative();
 
                 actionHandlers.clear();
                 readyActionHandler = null;
@@ -118,9 +119,7 @@ class DetoxManager implements WebSocketClient.ActionHandler {
     }
 
     private void initReactNativeIfNeeded() {
-        if (ReactNativeSupport.isReactNativeApp()) {
-            ReactNativeSupport.waitForReactNativeLoad(reactNativeHostHolder, null);
-        }
+        ReactNativeExtension.waitForRNBootstrap(reactNativeHostHolder);
     }
 
     private void initWSClient() {
@@ -139,7 +138,7 @@ class DetoxManager implements WebSocketClient.ActionHandler {
         actionHandlers.put("reactNativeReload", new ReactNativeReloadActionHandler(reactNativeHostHolder, wsClient, testEngineFacade));
         actionHandlers.put("invoke", new InvokeActionHandler(new MethodInvocation(), wsClient));
         actionHandlers.put("currentStatus", new QueryStatusActionHandler(wsClient, testEngineFacade));
-        actionHandlers.put("cleanup", new CleanupActionHandler(reactNativeHostHolder, wsClient, testEngineFacade, new Function0<Unit>() {
+        actionHandlers.put("cleanup", new CleanupActionHandler(wsClient, testEngineFacade, new Function0<Unit>() {
             @Override
             public Unit invoke() {
                 stop();
diff --git a/detox/android/detox/src/main/java/com/wix/detox/ReactInstanceEventListenerProxy.java b/detox/android/detox/src/main/java/com/wix/detox/ReactInstanceEventListenerProxy.java
deleted file mode 100644
index a9314a75f..000000000
--- a/detox/android/detox/src/main/java/com/wix/detox/ReactInstanceEventListenerProxy.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.wix.detox;
-
-/**
- * Created by simonracz on 29/05/2017.
- */
-
-public interface ReactInstanceEventListenerProxy {
-    void onReactContextInitialized(Object reactContext);
-}
diff --git a/detox/android/detox/src/main/java/com/wix/detox/ReactNativeCompat.java b/detox/android/detox/src/main/java/com/wix/detox/ReactNativeCompat.java
deleted file mode 100644
index 17a71c347..000000000
--- a/detox/android/detox/src/main/java/com/wix/detox/ReactNativeCompat.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.wix.detox;
-
-import org.joor.Reflect;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class ReactNativeCompat {
-    private static Map<String, Object> VERSION;
-
-    static {
-        try {
-            Class reactNativeVersion = Class.forName("com.facebook.react.modules.systeminfo.ReactNativeVersion");
-            VERSION = Reflect.on(reactNativeVersion).field("VERSION").get();
-        } catch (ClassNotFoundException e) {
-            //ReactNativeVersion was introduced in RN50, default to latest previous version.
-            VERSION = new HashMap<>();
-            VERSION.put("major", 0);
-            VERSION.put("minor", 49);
-            VERSION.put("patch", 0);
-        }
-
-    }
-
-    public static int getMinor() {
-        return (Integer) VERSION.get("minor");
-    }
-}
diff --git a/detox/android/detox/src/main/java/com/wix/detox/ReactNativeSupport.java b/detox/android/detox/src/main/java/com/wix/detox/ReactNativeSupport.java
deleted file mode 100644
index 9ae4a1f59..000000000
--- a/detox/android/detox/src/main/java/com/wix/detox/ReactNativeSupport.java
+++ /dev/null
@@ -1,333 +0,0 @@
-package com.wix.detox;
-
-import android.content.Context;
-import android.os.Looper;
-import android.util.Log;
-
-import com.facebook.react.ReactApplication;
-import com.facebook.react.ReactInstanceManager;
-import com.facebook.react.bridge.ReactContext;
-import com.wix.detox.espresso.AnimatedModuleIdlingResource;
-import com.wix.detox.espresso.ReactBridgeIdlingResource;
-import com.wix.detox.espresso.ReactNativeNetworkIdlingResource;
-import com.wix.detox.espresso.ReactNativeTimersIdlingResource;
-import com.wix.detox.espresso.ReactNativeUIModuleIdlingResource;
-
-import org.joor.Reflect;
-import org.joor.ReflectException;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.test.espresso.IdlingRegistry;
-import androidx.test.espresso.base.IdlingResourceRegistry;
-import androidx.test.platform.app.InstrumentationRegistry;
-import okhttp3.OkHttpClient;
-
-
-/**
- * Created by simonracz on 15/05/2017.
- */
-
-//TODO Dear reader, if you get this far and find this class messy you are not alone. :) It needs a refactor.
-
-public class ReactNativeSupport {
-    private static final String LOG_TAG = "DetoxRNSupport";
-
-    private static final String FIELD_UI_BG_MSG_QUEUE = "mUiBackgroundMessageQueueThread";
-    private static final String FIELD_NATIVE_MODULES_MSG_QUEUE = "mNativeModulesMessageQueueThread";
-    private static final String FIELD_JS_MSG_QUEUE = "mJSMessageQueueThread";
-    private static final String METHOD_GET_LOOPER = "getLooper";
-
-    private ReactNativeSupport() {
-        // static class
-    }
-
-    static boolean isReactNativeApp() {
-        Class<?> found = null;
-        try {
-            found = Class.forName("com.facebook.react.ReactApplication");
-        } catch (ClassNotFoundException e) {
-            return false;
-        }
-        return (found != null);
-    }
-
-    /**
-     * Returns the instanceManager using reflection.
-     *
-     * @param context the object that has a getReactNativeHost() method
-     * @return Returns the instanceManager as an Object or null
-     */
-    public static ReactInstanceManager getInstanceManager(@NonNull Context context) {
-        return ((ReactApplication) context).getReactNativeHost().getReactInstanceManager();
-    }
-
-    /**
-     * <p>
-     * Reloads the React Native application.
-     * </p>
-     *
-     * <p>
-     * It is a lot faster to reload a React Native application this way,
-     * than to reload the whole Activity or Application.
-     * </p>
-     *
-     * @param reactNativeHostHolder the object that has a getReactNativeHost() method
-     */
-    static void reloadApp(@NonNull Context reactNativeHostHolder) {
-        if (!isReactNativeApp()) {
-            return;
-        }
-        Log.i(LOG_TAG, "Reloading React Native");
-        currentReactContext = null;
-
-        removeEspressoIdlingResources(reactNativeHostHolder);
-
-        final ReactInstanceManager instanceManager = getInstanceManager(reactNativeHostHolder);
-        if (instanceManager == null) {
-            return;
-        }
-
-        final Context prereloadReactContext = instanceManager.getCurrentReactContext();
-
-        // Must be called on the UI thread!
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                instanceManager.recreateReactContextInBackground();
-            }
-        });
-
-        waitForReactNativeLoad(reactNativeHostHolder, prereloadReactContext);
-    }
-
-    // Ideally we would not store this at all.
-    public static ReactContext currentReactContext = null;
-
-    /**
-     * <p>
-     * Waits for a ReactContext to be created. Can be called any time.
-     * </p>
-     * @param reactNativeHostHolder the object that has a getReactNativeHost() method
-     * @param previousReactContext The previous context that we had before *re*-loading. Can be null.
-     */
-    static void waitForReactNativeLoad(@NonNull Context reactNativeHostHolder, final @Nullable Context previousReactContext) {
-        if (!isReactNativeApp()) {
-            return;
-        }
-
-        final ReactInstanceManager instanceManager = getInstanceManager(reactNativeHostHolder);
-        if (instanceManager == null) {
-            throw new RuntimeException("ReactInstanceManager is null!");
-        }
-
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        ReactContext reactContext = instanceManager.getCurrentReactContext();
-                        if (reactContext != null && reactContext != previousReactContext) {
-                            Log.d(LOG_TAG, "Got new RN-context directly and immediately");
-                            countDownLatch.countDown();
-                            return;
-                        }
-
-                        instanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() {
-                            @Override
-                            public void onReactContextInitialized(ReactContext context) {
-                                Log.i(LOG_TAG, "Got new RN-context async'ly through listener");
-                                instanceManager.removeReactInstanceEventListener(this);
-                                countDownLatch.countDown();
-                            }
-                        });
-                    }
-                });
-
-
-        for (int i = 0; ; ) {
-            try {
-                if (!countDownLatch.await(1, TimeUnit.SECONDS)) {
-                    i++;
-                    if (i >= 60) {
-                        // First load can take a lot of time. (packager)
-                        // Loads afterwards should take less than a second.
-                        throw new RuntimeException("waited a whole minute for the new RN-context");
-                    }
-                } else {
-                    break;
-                }
-                // Due to an ugly timing issue in RN
-                // it is possible that our listener won't be ever called
-                // That's why we have to check the reactContext regularly.
-                ReactContext reactContext = instanceManager.getCurrentReactContext();
-                if (reactContext != null && reactContext != previousReactContext) {
-                    Log.d(LOG_TAG, "Got new RN-context explicitly while polling (#iteration="+i+")");
-                    break;
-                }
-            } catch (InterruptedException e) {
-                throw new RuntimeException("waiting for new RN-context got interrupted", e);
-            }
-        }
-
-        currentReactContext = instanceManager.getCurrentReactContext();
-        setupEspressoIdlingResources(currentReactContext);
-
-        hackRN50OrHigherWaitForReload();
-    }
-
-    private static void hackRN50OrHigherWaitForReload() {
-        if (ReactNativeCompat.getMinor() >= 50) {
-            try {
-                //TODO- Temp hack to make Detox usable for RN>=50 till we find a better sync solution.
-                Thread.sleep(1000);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    private static ReactNativeTimersIdlingResource rnTimerIdlingResource = null;
-    private static ReactBridgeIdlingResource rnBridgeIdlingResource = null;
-    private static ReactNativeUIModuleIdlingResource rnUIModuleIdlingResource = null;
-    private static AnimatedModuleIdlingResource animIdlingResource = null;
-
-    private static void setupEspressoIdlingResources(@NonNull ReactContext reactContext) {
-        removeEspressoIdlingResources(reactContext);
-        Log.i(LOG_TAG, "Setting up Espresso Idling Resources for React Native.");
-
-        setupReactNativeQueueInterrogators(reactContext);
-
-        rnBridgeIdlingResource = new ReactBridgeIdlingResource(reactContext);
-        rnTimerIdlingResource = new ReactNativeTimersIdlingResource(reactContext);
-        rnUIModuleIdlingResource = new ReactNativeUIModuleIdlingResource(reactContext);
-        animIdlingResource = new AnimatedModuleIdlingResource(reactContext);
-
-        IdlingRegistry.getInstance().register(rnTimerIdlingResource);
-        IdlingRegistry.getInstance().register(rnBridgeIdlingResource);
-        IdlingRegistry.getInstance().register(rnUIModuleIdlingResource);
-        IdlingRegistry.getInstance().register(animIdlingResource);
-
-        if (networkSyncEnabled) {
-            setupNetworkIdlingResource();
-        }
-    }
-
-    private static void setupReactNativeQueueInterrogators(@NonNull Object reactContext) {
-        Looper UIBackgroundMessageQueue = getLooperFromQueue(reactContext, FIELD_UI_BG_MSG_QUEUE);
-        Looper JSMessageQueue = getLooperFromQueue(reactContext, FIELD_JS_MSG_QUEUE);
-        Looper JMativeModulesMessageQueue = getLooperFromQueue(reactContext, FIELD_NATIVE_MODULES_MSG_QUEUE);
-
-//        IdlingRegistry.getInstance().registerLooperAsIdlingResource(UIBackgroundMessageQueue);
-        IdlingRegistry.getInstance().registerLooperAsIdlingResource(JSMessageQueue);
-        IdlingRegistry.getInstance().registerLooperAsIdlingResource(JMativeModulesMessageQueue);
-
-        IdlingResourceRegistry irr = Reflect.on(androidx.test.espresso.Espresso.class).field("baseRegistry").get();
-        irr.sync(IdlingRegistry.getInstance().getResources(), IdlingRegistry.getInstance().getLoopers());
-    }
-
-    private static Looper getLooperFromQueue(@NonNull Object reactContext, String queueName) {
-        Object queue;
-        Looper looper = null;
-
-        try {
-            queue = Reflect.on(reactContext).field(queueName).get();
-            if (queue != null) {
-                looper = Reflect.on(queue).call(METHOD_GET_LOOPER).get();
-            }
-        } catch (ReflectException e) {
-            Log.e(LOG_TAG, "Could not find looper queue: " + queueName, e.getCause());
-            return null;
-        }
-        return looper;
-    }
-
-    static void removeEspressoIdlingResources(@NonNull Context reactNativeHostHolder) {
-        final ReactInstanceManager instanceManager = getInstanceManager(reactNativeHostHolder);
-        removeNetworkIdlingResource();
-        removeEspressoIdlingResources(instanceManager.getCurrentReactContext());
-    }
-
-    private static void removeEspressoIdlingResources(ReactContext reactContext) {
-
-        Log.i(LOG_TAG, "Removing Espresso IdlingResources for React Native.");
-
-        IdlingRegistry.getInstance().unregister(rnTimerIdlingResource);
-        IdlingRegistry.getInstance().unregister(rnBridgeIdlingResource);
-        IdlingRegistry.getInstance().unregister(rnUIModuleIdlingResource);
-        IdlingRegistry.getInstance().unregister(animIdlingResource);
-
-        reactContext.getCatalystInstance().removeBridgeIdleDebugListener(rnBridgeIdlingResource);
-    }
-
-    private static boolean networkSyncEnabled = true;
-    public static void enableNetworkSynchronization(boolean enable) {
-        if (!isReactNativeApp()) return;
-        if (networkSyncEnabled == enable) return;
-
-        if (enable) {
-            setupNetworkIdlingResource();
-        } else {
-            removeNetworkIdlingResource();
-        }
-        networkSyncEnabled = enable;
-    }
-
-    private static ReactNativeNetworkIdlingResource networkIR = null;
-    private final static String CLASS_NETWORK_MODULE = "com.facebook.react.modules.network.NetworkingModule";
-    private final static String METHOD_GET_NATIVE_MODULE = "getNativeModule";
-    private final static String METHOD_HAS_NATIVE_MODULE = "hasNativeModule";
-    private final static String FIELD_OKHTTP_CLIENT = "mClient";
-
-    private static void setupNetworkIdlingResource() {
-        Class<?> networkModuleClass;
-        try {
-            networkModuleClass = Class.forName(CLASS_NETWORK_MODULE);
-        } catch (ClassNotFoundException e) {
-            Log.e(LOG_TAG, "NetworkingModule is not on classpath.");
-            return;
-        }
-
-        if (currentReactContext == null) {
-            return;
-        }
-
-        try {
-            if (!(boolean) Reflect.on(currentReactContext).call(METHOD_HAS_NATIVE_MODULE, networkModuleClass).get()) {
-                Log.e(LOG_TAG, "Can't find Networking Module.");
-                return;
-            }
-
-            OkHttpClient client = Reflect.on(currentReactContext)
-                    .call(METHOD_GET_NATIVE_MODULE, networkModuleClass)
-                    .field(FIELD_OKHTTP_CLIENT)
-                    .get();
-            networkIR = new ReactNativeNetworkIdlingResource(client.dispatcher());
-            IdlingRegistry.getInstance().register(networkIR);
-
-        } catch (ReflectException e) {
-            Log.e(LOG_TAG, "Can't set up Networking Module listener", e.getCause());
-        }
-    }
-
-    private static void removeNetworkIdlingResource() {
-        if (networkIR != null) {
-            networkIR.stop();
-            IdlingRegistry.getInstance().unregister(networkIR);
-            networkIR = null;
-        }
-    }
-
-    public static void pauseRNTimersIdlingResource() {
-        if (rnTimerIdlingResource != null) {
-            rnTimerIdlingResource.pause();
-        }
-    }
-
-    public static void resumeRNTimersIdlingResource() {
-        rnTimerIdlingResource.resume();
-    }
-}
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/DetoxAction.java b/detox/android/detox/src/main/java/com/wix/detox/espresso/DetoxAction.java
index bfcb76952..cb5336e81 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/DetoxAction.java
+++ b/detox/android/detox/src/main/java/com/wix/detox/espresso/DetoxAction.java
@@ -29,10 +29,10 @@ import static androidx.test.espresso.action.ViewActions.swipeRight;
 import static androidx.test.espresso.action.ViewActions.swipeUp;
 import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static com.wix.detox.espresso.common.annot.MotionDefsKt.MOTION_DIR_DOWN;
-import static com.wix.detox.espresso.common.annot.MotionDefsKt.MOTION_DIR_LEFT;
-import static com.wix.detox.espresso.common.annot.MotionDefsKt.MOTION_DIR_RIGHT;
-import static com.wix.detox.espresso.common.annot.MotionDefsKt.MOTION_DIR_UP;
+import static com.wix.detox.espresso.common.annot.MotionDefs.MOTION_DIR_DOWN;
+import static com.wix.detox.espresso.common.annot.MotionDefs.MOTION_DIR_LEFT;
+import static com.wix.detox.espresso.common.annot.MotionDefs.MOTION_DIR_RIGHT;
+import static com.wix.detox.espresso.common.annot.MotionDefs.MOTION_DIR_UP;
 import static org.hamcrest.Matchers.allOf;
 
 
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/DetoxMatcher.java b/detox/android/detox/src/main/java/com/wix/detox/espresso/DetoxMatcher.java
index 2d6cbddcf..63d9fdf7d 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/DetoxMatcher.java
+++ b/detox/android/detox/src/main/java/com/wix/detox/espresso/DetoxMatcher.java
@@ -15,8 +15,8 @@ import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription
 import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
 import static androidx.test.espresso.matcher.ViewMatchers.withTagValue;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
-import static com.wix.detox.espresso.matcher.ViewMatchersKt.isMatchingAtIndex;
-import static com.wix.detox.espresso.matcher.ViewMatchersKt.isOfClassName;
+import static com.wix.detox.espresso.matcher.ViewMatchers.isMatchingAtIndex;
+import static com.wix.detox.espresso.matcher.ViewMatchers.isOfClassName;
 import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.anyOf;
 import static org.hamcrest.Matchers.is;
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/EspressoDetox.java b/detox/android/detox/src/main/java/com/wix/detox/espresso/EspressoDetox.java
index 3971d7edc..de14174a3 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/EspressoDetox.java
+++ b/detox/android/detox/src/main/java/com/wix/detox/espresso/EspressoDetox.java
@@ -9,7 +9,8 @@ import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 
-import com.wix.detox.ReactNativeSupport;
+import com.wix.detox.reactnative.ReactNativeExtension;
+import com.wix.detox.reactnative.idlingresources.NetworkIdlingResource;
 
 import org.hamcrest.Matcher;
 import org.joor.Reflect;
@@ -66,10 +67,9 @@ public class EspressoDetox {
 
             @Override
             public void perform(UiController uiController, View view) {
-                Activity activity;
-                if (ReactNativeSupport.currentReactContext != null) {
-                    activity = Reflect.on(ReactNativeSupport.currentReactContext).call(METHOD_GET_ACTIVITY).get();
-                } else {
+                Activity activity = ReactNativeExtension.getRNActivity(view.getContext().getApplicationContext());
+
+                if (activity == null) {
                     activity = getActivity(view.getContext());
                     if (activity == null && view instanceof ViewGroup) {
                         ViewGroup v = (ViewGroup)view;
@@ -79,9 +79,11 @@ public class EspressoDetox {
                         }
                     }
                 }
+
                 if (activity == null) {
                     throw new RuntimeException("Couldn't get a hold of the Activity");
                 }
+
                 switch (orientation) {
                     case 0:
                         activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
@@ -104,14 +106,14 @@ public class EspressoDetox {
     }
 
     public static void setSynchronization(boolean enabled) {
-        ReactNativeSupport.enableNetworkSynchronization(enabled);
+        ReactNativeExtension.toggleNetworkSynchronization(enabled);
     }
 
     public static void setURLBlacklist(final ArrayList<String> urls) {
         InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                ReactNativeNetworkIdlingResource.setURLBlacklist(urls);
+                NetworkIdlingResource.setURLBlacklist(urls);
             }
         });
     }
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/action/RNClickAction.java b/detox/android/detox/src/main/java/com/wix/detox/espresso/action/RNClickAction.java
index 565c051df..b4c13bacf 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/action/RNClickAction.java
+++ b/detox/android/detox/src/main/java/com/wix/detox/espresso/action/RNClickAction.java
@@ -4,7 +4,7 @@ import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.View;
 
-import com.wix.detox.ReactNativeSupport;
+import com.wix.detox.reactnative.ReactNativeExtension;
 
 import org.hamcrest.Matcher;
 
@@ -38,11 +38,11 @@ public class RNClickAction implements ViewAction {
 
     @Override
     public void perform(UiController uiController, View view) {
-        ReactNativeSupport.pauseRNTimersIdlingResource();
+        ReactNativeExtension.toggleTimersSynchronization(false);
         try {
             clickAction.perform(uiController, view);
         } finally {
-            ReactNativeSupport.resumeRNTimersIdlingResource();
+            ReactNativeExtension.toggleTimersSynchronization(true);
         }
         uiController.loopMainThreadUntilIdle();
     }
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/common/annot/MotionDefs.kt b/detox/android/detox/src/main/java/com/wix/detox/espresso/common/annot/MotionDefs.kt
index db5eab8b1..d2ed8a006 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/common/annot/MotionDefs.kt
+++ b/detox/android/detox/src/main/java/com/wix/detox/espresso/common/annot/MotionDefs.kt
@@ -1,3 +1,5 @@
+@file:JvmName("MotionDefs")
+
 package com.wix.detox.espresso.common.annot
 
 import androidx.annotation.IntDef
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/matcher/ViewMatchers.kt b/detox/android/detox/src/main/java/com/wix/detox/espresso/matcher/ViewMatchers.kt
index 168b5f7a6..81bfd005c 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/matcher/ViewMatchers.kt
+++ b/detox/android/detox/src/main/java/com/wix/detox/espresso/matcher/ViewMatchers.kt
@@ -1,3 +1,5 @@
+@file:JvmName("ViewMatchers")
+
 package com.wix.detox.espresso.matcher
 
 import android.view.View
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/ScrollHelper.java b/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/ScrollHelper.java
index 4c6bf8a1c..01dd3fccc 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/ScrollHelper.java
+++ b/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/ScrollHelper.java
@@ -12,11 +12,11 @@ import com.wix.detox.espresso.common.annot.MotionDir;
 import androidx.test.espresso.UiController;
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import static com.wix.detox.espresso.common.annot.MotionDefsKt.MOTION_DIR_DOWN;
-import static com.wix.detox.espresso.common.annot.MotionDefsKt.MOTION_DIR_LEFT;
-import static com.wix.detox.espresso.common.annot.MotionDefsKt.MOTION_DIR_RIGHT;
-import static com.wix.detox.espresso.common.annot.MotionDefsKt.MOTION_DIR_UP;
-import static com.wix.detox.espresso.scroll.ScrollProbesKt.getScrollableProbe;
+import static com.wix.detox.espresso.common.annot.MotionDefs.MOTION_DIR_DOWN;
+import static com.wix.detox.espresso.common.annot.MotionDefs.MOTION_DIR_LEFT;
+import static com.wix.detox.espresso.common.annot.MotionDefs.MOTION_DIR_RIGHT;
+import static com.wix.detox.espresso.common.annot.MotionDefs.MOTION_DIR_UP;
+import static com.wix.detox.espresso.scroll.ScrollProbes.getScrollableProbe;
 
 /**
  * Created by simonracz on 09/08/2017.
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/ScrollProbes.kt b/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/ScrollProbes.kt
index 64bb49700..f9fe0448b 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/ScrollProbes.kt
+++ b/detox/android/detox/src/main/java/com/wix/detox/espresso/scroll/ScrollProbes.kt
@@ -1,3 +1,5 @@
+@file:JvmName("ScrollProbes")
+
 package com.wix.detox.espresso.scroll
 
 import android.annotation.SuppressLint
diff --git a/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeExtension.kt b/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeExtension.kt
new file mode 100644
index 000000000..8885bd1d8
--- /dev/null
+++ b/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeExtension.kt
@@ -0,0 +1,133 @@
+package com.wix.detox.reactnative
+
+import android.app.Activity
+import android.content.Context
+import android.util.Log
+import androidx.test.platform.app.InstrumentationRegistry
+import com.facebook.react.ReactApplication
+import com.facebook.react.ReactInstanceManager
+import com.facebook.react.bridge.ReactContext
+
+private const val LOG_TAG = "DetoxRNExt"
+
+object ReactNativeExtension {
+    private var rnIdlingResources: ReactNativeIdlingResources? = null
+
+    /**
+     * Reloads the React Native context and thus all javascript code.
+     *
+     * It is a lot faster to reload a React Native application this way,
+     * than to reload the whole Activity or Application.
+     *
+     * @param applicationContext The app context, implicitly assumed to be a [ReactApplication] instance.
+     */
+    @JvmStatic
+    fun reloadReactNative(applicationContext: Context) {
+        if (!ReactNativeInfo.isReactNativeApp()) {
+            return
+        }
+
+        Log.i(LOG_TAG, "Reloading React Native")
+
+        (applicationContext as ReactApplication).let {
+            val networkSyncEnabled = rnIdlingResources?.networkSyncEnabled ?: true
+            clearIdlingResources()
+
+            val previousReactContext = getCurrentReactContextSafe(it)
+
+            reloadReactNativeInBackground(it)
+            val reactContext = awaitNewReactNativeContext(it, previousReactContext)
+
+            setupIdlingResources(reactContext, networkSyncEnabled)
+            hackRN50OrHigherWaitForReady()
+        }
+    }
+
+    /**
+     * Wait for React-Native to finish loading (i.e. make RN context available).
+     *
+     * @param applicationContext The app context, implicitly assumed to be a [ReactApplication] instance.
+     */
+    @JvmStatic
+    fun waitForRNBootstrap(applicationContext: Context) {
+        if (!ReactNativeInfo.isReactNativeApp()) {
+            return
+        }
+
+        (applicationContext as ReactApplication).let {
+            val reactContext = awaitNewReactNativeContext(it, null)
+
+            setupIdlingResources(reactContext)
+            hackRN50OrHigherWaitForReady()
+        }
+    }
+
+    @JvmStatic
+    fun clearAllSynchronization() = clearIdlingResources()
+
+    @JvmStatic
+    fun getRNActivity(applicationContext: Context): Activity? {
+        if (ReactNativeInfo.isReactNativeApp()) {
+            return getCurrentReactContextSafe(applicationContext as ReactApplication)?.currentActivity
+        }
+        return null
+    }
+
+    @JvmStatic
+    fun toggleNetworkSynchronization(enable: Boolean) {
+        if (!ReactNativeInfo.isReactNativeApp()) {
+            return
+        }
+
+        rnIdlingResources?.setNetworkSynchronization(enable)
+    }
+
+    @JvmStatic
+    fun toggleTimersSynchronization(enable: Boolean) {
+        rnIdlingResources?.let {
+            if (enable) it.resumeRNTimersIdlingResource() else it.pauseRNTimersIdlingResource()
+        }
+    }
+
+    private fun reloadReactNativeInBackground(reactApplication: ReactApplication) {
+        val rnReloader = ReactNativeReLoader(InstrumentationRegistry.getInstrumentation(), reactApplication)
+        rnReloader.reloadInBackground()
+    }
+
+    private fun awaitNewReactNativeContext(reactApplication: ReactApplication, previousReactContext: ReactContext?): ReactContext {
+        val rnLoadingMonitor = ReactNativeLoadingMonitor(InstrumentationRegistry.getInstrumentation(), reactApplication, previousReactContext)
+        return rnLoadingMonitor.getNewContext()!!
+    }
+
+    private fun setupIdlingResources(reactContext: ReactContext, networkSyncEnabled: Boolean = true) {
+        rnIdlingResources = ReactNativeIdlingResources(reactContext, networkSyncEnabled).apply {
+            registerAll()
+        }
+    }
+
+    private fun hackRN50OrHigherWaitForReady() {
+        if (ReactNativeInfo.rnVersion().minor >= 50) {
+            try {
+                //TODO- Temp hack to make Detox usable for RN>=50 till we find a better sync solution.
+                Thread.sleep(1000)
+            } catch (e: InterruptedException) {
+                e.printStackTrace()
+            }
+
+        }
+    }
+
+    private fun clearIdlingResources() {
+        rnIdlingResources?.unregisterAll()
+        rnIdlingResources = null
+    }
+
+    private fun getInstanceManagerSafe(reactApplication: ReactApplication): ReactInstanceManager {
+        return reactApplication.reactNativeHost.reactInstanceManager
+                ?: throw RuntimeException("ReactInstanceManager is null!")
+    }
+
+    private fun getCurrentReactContextSafe(reactApplication: ReactApplication): ReactContext? {
+        return getInstanceManagerSafe(reactApplication).currentReactContext
+    }
+}
diff --git a/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt b/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt
new file mode 100644
index 000000000..4e59c274e
--- /dev/null
+++ b/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt
@@ -0,0 +1,169 @@
+package com.wix.detox.reactnative
+
+import android.os.Looper
+import android.util.Log
+import androidx.test.espresso.IdlingRegistry
+import androidx.test.espresso.base.IdlingResourceRegistry
+import com.facebook.react.bridge.ReactContext
+import com.facebook.react.modules.network.NetworkingModule
+import com.wix.detox.reactnative.idlingresources.*
+import okhttp3.OkHttpClient
+import org.joor.Reflect
+import org.joor.ReflectException
+
+private const val LOG_TAG = "DetoxRNIdleRes"
+
+class MQThreadsReflector(private val reactContext: ReactContext) {
+    fun getQueue(queueName: String): MQThreadReflected? {
+        try {
+            val queue = Reflect.on(reactContext).field(queueName).get() as Any?
+            return MQThreadReflected(queue, queueName)
+        } catch (e: ReflectException) {
+            Log.e(LOG_TAG, "Could not find queue: $queueName", e)
+        }
+        return null
+    }
+}
+
+class MQThreadReflected(private val queue: Any?, private val queueName: String) {
+    fun getLooper(): Looper? {
+        try {
+            if (queue != null) {
+                return Reflect.on(queue).call(METHOD_GET_LOOPER).get()
+            }
+        } catch (e: ReflectException) {
+            Log.e(LOG_TAG, "Could not find looper for queue: $queueName", e)
+        }
+        return null
+    }
+
+    companion object {
+        const val METHOD_GET_LOOPER = "getLooper"
+    }
+}
+
+class NetworkingModuleReflected(private val reactContext: ReactContext) {
+    fun getHttpClient(): OkHttpClient? {
+        if (reactContext.hasNativeModule(NetworkingModule::class.java)) {
+            val networkNativeModule = reactContext.getNativeModule(NetworkingModule::class.java)
+            try {
+                return Reflect.on(networkNativeModule).field(FIELD_OKHTTP_CLIENT).get()
+            } catch (e: ReflectException) {
+                Log.e(LOG_TAG, "Can't set up Networking Module listener", e)
+            }
+        }
+        return null
+    }
+
+    companion object {
+        private const val FIELD_OKHTTP_CLIENT = "mClient"
+    }
+}
+
+class ReactNativeIdlingResources
+    constructor(
+        private val reactContext: ReactContext,
+        internal var networkSyncEnabled: Boolean = true) {
+
+    companion object {
+        private const val FIELD_UI_BG_MSG_QUEUE = "mUiBackgroundMessageQueueThread"
+        private const val FIELD_NATIVE_MODULES_MSG_QUEUE = "mNativeModulesMessageQueueThread"
+        private const val FIELD_JS_MSG_QUEUE = "mJSMessageQueueThread"
+    }
+
+    private var timersIdlingResource: TimersIdlingResource? = null
+    private var rnBridgeIdlingResource: BridgeIdlingResource? = null
+    private var uiModuleIdlingResource: UIModuleIdlingResource? = null
+    private var animIdlingResource: AnimatedModuleIdlingResource? = null
+    private var networkIdlingResource: NetworkIdlingResource? = null
+
+    fun registerAll() {
+        Log.i(LOG_TAG, "Setting up Espresso Idling Resources for React Native.")
+        unregisterAll()
+        setupMQThreadsInterrogators()
+        setupCustomRNIdlingResources()
+        if (networkSyncEnabled) {
+            setupNetworkIdlingResource()
+        }
+    }
+
+    fun unregisterAll() {
+        removeNetworkIdlingResource()
+        unregisterAllIdlingResources(reactContext)
+    }
+
+    fun setNetworkSynchronization(enable: Boolean) {
+        if (networkSyncEnabled == enable) {
+            return
+        }
+
+        if (enable) {
+            setupNetworkIdlingResource()
+        } else {
+            removeNetworkIdlingResource()
+        }
+        networkSyncEnabled = enable
+    }
+
+    fun pauseRNTimersIdlingResource() = timersIdlingResource?.pause()
+    fun resumeRNTimersIdlingResource() = timersIdlingResource?.resume()
+
+    private fun setupMQThreadsInterrogators() {
+        val mqThreadsReflector = MQThreadsReflector(reactContext)
+        val mqUIBackground = mqThreadsReflector.getQueue(FIELD_UI_BG_MSG_QUEUE)?.getLooper()
+        val mqJS = mqThreadsReflector.getQueue(FIELD_JS_MSG_QUEUE)?.getLooper()
+        val mqNativeModules = mqThreadsReflector.getQueue(FIELD_NATIVE_MODULES_MSG_QUEUE)?.getLooper()
+
+        IdlingRegistry.getInstance().apply {
+//            registerLooperAsIdlingResource(mqUIBackground)
+            registerLooperAsIdlingResource(mqJS)
+            registerLooperAsIdlingResource(mqNativeModules)
+
+            val irr: IdlingResourceRegistry = Reflect.on(androidx.test.espresso.Espresso::class.java).field("baseRegistry").get()
+            irr.sync(this.resources, this.loopers)
+        }
+    }
+
+    private fun setupCustomRNIdlingResources() {
+        rnBridgeIdlingResource = BridgeIdlingResource(reactContext)
+        timersIdlingResource = TimersIdlingResource(reactContext)
+        uiModuleIdlingResource = UIModuleIdlingResource(reactContext)
+        animIdlingResource = AnimatedModuleIdlingResource(reactContext)
+
+        IdlingRegistry.getInstance().apply {
+            register(timersIdlingResource)
+            register(rnBridgeIdlingResource)
+            register(uiModuleIdlingResource)
+            register(animIdlingResource)
+        }
+    }
+
+    private fun unregisterAllIdlingResources(reactContext: ReactContext) {
+        IdlingRegistry.getInstance().apply {
+            unregister(timersIdlingResource)
+            unregister(rnBridgeIdlingResource)
+            unregister(uiModuleIdlingResource)
+            unregister(animIdlingResource)
+        }
+
+        reactContext.catalystInstance.removeBridgeIdleDebugListener(rnBridgeIdlingResource)
+    }
+
+    private fun setupNetworkIdlingResource() {
+        try {
+            val client = NetworkingModuleReflected(reactContext).getHttpClient()!!
+            networkIdlingResource = NetworkIdlingResource(client.dispatcher())
+            IdlingRegistry.getInstance().register(networkIdlingResource)
+        } catch (e: ReflectException) {
+            Log.e(LOG_TAG, "Can't set up Networking Module listener", e.cause)
+        }
+    }
+
+    private fun removeNetworkIdlingResource() {
+        networkIdlingResource?.let {
+            it.stop()
+            IdlingRegistry.getInstance().unregister(networkIdlingResource)
+            networkIdlingResource = null
+        }
+    }
+}
diff --git a/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeInfo.kt b/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeInfo.kt
new file mode 100644
index 000000000..151172d9d
--- /dev/null
+++ b/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeInfo.kt
@@ -0,0 +1,27 @@
+package com.wix.detox.reactnative
+
+import org.joor.Reflect
+
+data class RNVersion(val major: Int, val minor: Int, val patch: Int)
+
+object ReactNativeInfo {
+    private var rnVersion: RNVersion =
+            try {
+                val versionClass = Class.forName("com.facebook.react.modules.systeminfo.ReactNativeVersion")
+                val versionMap: Map<String, Int> = Reflect.on(versionClass).field("VERSION").get()
+                RNVersion(versionMap.getValue("major"), versionMap.getValue("minor"), versionMap.getValue("patch"))
+            } catch (e: ClassNotFoundException) {
+                // ReactNativeVersion was introduced in RN50, default to latest previous version.
+                RNVersion(0, 49, 0)
+            }
+
+    @JvmStatic
+    fun rnVersion() = rnVersion
+
+    fun isReactNativeApp(): Boolean = try {
+        Class.forName("com.facebook.react.ReactApplication")
+        true
+    } catch (e: ClassNotFoundException) {
+        false
+    }
+}
diff --git a/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeLoadingMonitor.kt b/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeLoadingMonitor.kt
new file mode 100644
index 000000000..cd62ba782
--- /dev/null
+++ b/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeLoadingMonitor.kt
@@ -0,0 +1,77 @@
+package com.wix.detox.reactnative
+
+import android.app.Instrumentation
+import android.util.Log
+import com.facebook.react.ReactApplication
+import com.facebook.react.ReactInstanceManager
+import com.facebook.react.bridge.ReactContext
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+
+private const val LOG_TAG = "DetoxRNLoading"
+
+open class ReactNativeLoadingMonitor(
+        private val instrumentation: Instrumentation,
+        private val rnApplication: ReactApplication,
+        private val previousReactContext: ReactContext?) {
+    val countDownLatch = CountDownLatch(1)
+
+    fun getNewContext(): ReactContext? {
+        subscribeToNewRNContextUpdates()
+        return awaitNewRNContext()
+    }
+
+    private fun subscribeToNewRNContextUpdates() {
+        instrumentation.runOnMainSync(
+                Runnable {
+                    val rnInstanceManager = rnApplication.reactNativeHost.reactInstanceManager
+                    val reactContext = rnInstanceManager.currentReactContext
+                    if (reactContext != null && reactContext !== previousReactContext) {
+                        Log.d(LOG_TAG, "Got new RN-context directly and immediately")
+                        countDownLatch.countDown()
+                        return@Runnable
+                    }
+
+                    rnInstanceManager.addReactInstanceEventListener(object : ReactInstanceManager.ReactInstanceEventListener {
+                        override fun onReactContextInitialized(context: ReactContext) {
+                            Log.i(LOG_TAG, "Got new RN-context async'ly through listener")
+                            rnInstanceManager.removeReactInstanceEventListener(this)
+                            countDownLatch.countDown()
+                        }
+                    })
+                })
+    }
+
+    private fun awaitNewRNContext(): ReactContext? {
+        val rnInstanceManager = rnApplication.reactNativeHost.reactInstanceManager
+
+        var i = 0
+        while (true) {
+            try {
+                if (!countDownLatch.await(1, TimeUnit.SECONDS)) {
+                    i++
+                    if (i >= 60) {
+                        // First load can take a lot of time. (packager)
+                        // Loads afterwards should take less than a second.
+                        throw RuntimeException("waited a whole minute for the new RN-context")
+                    }
+                } else {
+                    break
+                }
+
+                // Due to an ugly timing issue in RN
+                // it is possible that our listener won't be ever called
+                // That's why we have to check the reactContext regularly.
+                val reactContext = rnInstanceManager.currentReactContext
+                if (reactContext != null && reactContext !== previousReactContext) {
+                    Log.d(LOG_TAG, "Got new RN-context explicitly while polling (#iteration=$i)")
+                    break
+                }
+            } catch (e: InterruptedException) {
+                throw RuntimeException("waiting for new RN-context got interrupted", e)
+            }
+        }
+
+        return rnInstanceManager.currentReactContext
+    }
+}
diff --git a/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeReloader.kt b/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeReloader.kt
new file mode 100644
index 000000000..493ee959f
--- /dev/null
+++ b/detox/android/detox/src/main/java/com/wix/detox/reactnative/ReactNativeReloader.kt
@@ -0,0 +1,16 @@
+package com.wix.detox.reactnative
+
+import android.app.Instrumentation
+import com.facebook.react.ReactApplication
+
+open class ReactNativeReLoader(
+        private val instrumentation: Instrumentation,
+        private val rnApplication: ReactApplication) {
+
+    fun reloadInBackground() {
+        val rnInstanceManager = rnApplication.reactNativeHost.reactInstanceManager
+        instrumentation.runOnMainSync {
+            rnInstanceManager.recreateReactContextInBackground()
+        }
+    }
+}
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/AnimatedModuleIdlingResource.java b/detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/AnimatedModuleIdlingResource.java
similarity index 97%
rename from detox/android/detox/src/main/java/com/wix/detox/espresso/AnimatedModuleIdlingResource.java
rename to detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/AnimatedModuleIdlingResource.java
index 962b7e12c..bceb31fe5 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/AnimatedModuleIdlingResource.java
+++ b/detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/AnimatedModuleIdlingResource.java
@@ -1,14 +1,14 @@
-package com.wix.detox.espresso;
+package com.wix.detox.reactnative.idlingresources;
 
-import androidx.annotation.NonNull;
 import android.util.Log;
 import android.view.Choreographer;
 
-import com.wix.detox.ReactNativeCompat;
+import com.wix.detox.reactnative.ReactNativeInfo;
 
 import org.joor.Reflect;
 import org.joor.ReflectException;
 
+import androidx.annotation.NonNull;
 import androidx.test.espresso.IdlingResource;
 
 /**
@@ -92,7 +92,7 @@ public class AnimatedModuleIdlingResource implements IdlingResource, Choreograph
                 return true;
             }
 
-            if (ReactNativeCompat.getMinor() >= 51) {
+            if (ReactNativeInfo.rnVersion().getMinor() >= 51) {
                 if(isIdleRN51(animModuleClass)) {
                     return true;
                 }
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/ReactBridgeIdlingResource.java b/detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/BridgeIdlingResource.java
similarity index 81%
rename from detox/android/detox/src/main/java/com/wix/detox/espresso/ReactBridgeIdlingResource.java
rename to detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/BridgeIdlingResource.java
index 51d4f1b3a..04b9702e0 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/ReactBridgeIdlingResource.java
+++ b/detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/BridgeIdlingResource.java
@@ -1,4 +1,4 @@
-package com.wix.detox.espresso;
+package com.wix.detox.reactnative.idlingresources;
 
 import android.util.Log;
 
@@ -9,8 +9,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import androidx.test.espresso.IdlingResource;
 
-import static androidx.test.espresso.IdlingResource.ResourceCallback;
-
 /**
  * Created by simonracz on 01/06/2017.
  */
@@ -21,19 +19,19 @@ import static androidx.test.espresso.IdlingResource.ResourceCallback;
  * React Native's JS bridge.
  * </p>
  */
-public class ReactBridgeIdlingResource implements IdlingResource, NotThreadSafeBridgeIdleDebugListener {
+public class BridgeIdlingResource implements IdlingResource, NotThreadSafeBridgeIdleDebugListener {
     private static final String LOG_TAG = "Detox";
 
     private AtomicBoolean idleNow = new AtomicBoolean(true);
     private ResourceCallback callback = null;
 
-    public ReactBridgeIdlingResource(ReactContext reactContext) {
+    public BridgeIdlingResource(ReactContext reactContext) {
         reactContext.getCatalystInstance().addBridgeIdleDebugListener(this);
     }
 
     @Override
     public String getName() {
-        return ReactBridgeIdlingResource.class.getName();
+        return BridgeIdlingResource.class.getName();
     }
 
     @Override
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/ReactNativeNetworkIdlingResource.java b/detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java
similarity index 88%
rename from detox/android/detox/src/main/java/com/wix/detox/espresso/ReactNativeNetworkIdlingResource.java
rename to detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java
index 596765ec4..e376138ec 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/ReactNativeNetworkIdlingResource.java
+++ b/detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java
@@ -1,4 +1,4 @@
-package com.wix.detox.espresso;
+package com.wix.detox.reactnative.idlingresources;
 
 import androidx.annotation.NonNull;
 import android.util.Log;
@@ -11,7 +11,6 @@ import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
 
 import androidx.test.espresso.IdlingResource;
-import static androidx.test.espresso.IdlingResource.ResourceCallback;
 
 import okhttp3.Call;
 import okhttp3.Dispatcher;
@@ -26,7 +25,7 @@ import okhttp3.Dispatcher;
  * <p>
  * Must call stop() on it, before removing it from Espresso.
  */
-public class ReactNativeNetworkIdlingResource implements IdlingResource, Choreographer.FrameCallback {
+public class NetworkIdlingResource implements IdlingResource, Choreographer.FrameCallback {
 
     private static final String LOG_TAG = "Detox";
 
@@ -56,13 +55,13 @@ public class ReactNativeNetworkIdlingResource implements IdlingResource, Choreog
     }
 
 
-    public ReactNativeNetworkIdlingResource(@NonNull Dispatcher dispatcher) {
+    public NetworkIdlingResource(@NonNull Dispatcher dispatcher) {
         this.dispatcher = dispatcher;
     }
 
     @Override
     public String getName() {
-        return ReactNativeNetworkIdlingResource.class.getName();
+        return NetworkIdlingResource.class.getName();
     }
 
     @Override
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/ReactNativeTimersIdlingResource.kt b/detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/TimersIdlingResource.kt
similarity index 92%
rename from detox/android/detox/src/main/java/com/wix/detox/espresso/ReactNativeTimersIdlingResource.kt
rename to detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/TimersIdlingResource.kt
index e5585a141..1dd1ea4ec 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/ReactNativeTimersIdlingResource.kt
+++ b/detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/TimersIdlingResource.kt
@@ -1,4 +1,4 @@
-package com.wix.detox.espresso
+package com.wix.detox.reactnative.idlingresources
 
 import android.view.Choreographer
 import androidx.test.espresso.IdlingResource
@@ -36,7 +36,7 @@ class TimingModuleReflected(reactContext: ReactContext) {
     operator fun component2() = timersLock
 }
 
-class ReactNativeTimersIdlingResource @JvmOverloads constructor(
+class TimersIdlingResource @JvmOverloads constructor(
         private val reactContext: ReactContext,
         private val getChoreographer: () -> Choreographer = { Choreographer.getInstance() }
     ) : IdlingResource, Choreographer.FrameCallback {
@@ -61,7 +61,7 @@ class ReactNativeTimersIdlingResource @JvmOverloads constructor(
             if (result) {
                 callback?.onTransitionToIdle()
             } else {
-                getChoreographer().postFrameCallback(this@ReactNativeTimersIdlingResource)
+                getChoreographer().postFrameCallback(this@TimersIdlingResource)
             }
         }
     }
@@ -72,12 +72,12 @@ class ReactNativeTimersIdlingResource @JvmOverloads constructor(
         }
     }
 
-    public fun pause() {
+    fun pause() {
         paused.set(true)
         callback?.onTransitionToIdle()
     }
 
-    public fun resume() {
+    fun resume() {
         paused.set(false)
     }
 
diff --git a/detox/android/detox/src/main/java/com/wix/detox/espresso/ReactNativeUIModuleIdlingResource.java b/detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/UIModuleIdlingResource.java
similarity index 93%
rename from detox/android/detox/src/main/java/com/wix/detox/espresso/ReactNativeUIModuleIdlingResource.java
rename to detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/UIModuleIdlingResource.java
index 1153d15e9..181233a88 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/espresso/ReactNativeUIModuleIdlingResource.java
+++ b/detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/UIModuleIdlingResource.java
@@ -1,4 +1,4 @@
-package com.wix.detox.espresso;
+package com.wix.detox.reactnative.idlingresources;
 
 import androidx.annotation.NonNull;
 import android.util.Log;
@@ -9,8 +9,6 @@ import org.joor.ReflectException;
 
 import androidx.test.espresso.IdlingResource;
 
-import static androidx.test.espresso.IdlingResource.ResourceCallback;
-
 /**
  * Created by simonracz on 26/07/2017.
  */
@@ -24,7 +22,7 @@ import static androidx.test.espresso.IdlingResource.ResourceCallback;
  * Hooks up to React Native internals to grab the pending ui operations from it.
  * </p>
  */
-public class ReactNativeUIModuleIdlingResource implements IdlingResource, Choreographer.FrameCallback {
+public class UIModuleIdlingResource implements IdlingResource, Choreographer.FrameCallback {
     private static final String LOG_TAG = "Detox";
 
     private final static String CLASS_UI_MANAGER_MODULE = "com.facebook.react.uimanager.UIManagerModule";
@@ -42,13 +40,13 @@ public class ReactNativeUIModuleIdlingResource implements IdlingResource, Choreo
     private ResourceCallback callback = null;
     private Object reactContext = null;
 
-    public ReactNativeUIModuleIdlingResource(@NonNull Object reactContext) {
+    public UIModuleIdlingResource(@NonNull Object reactContext) {
         this.reactContext = reactContext;
     }
 
     @Override
     public String getName() {
-        return ReactNativeUIModuleIdlingResource.class.getName();
+        return UIModuleIdlingResource.class.getName();
     }
 
     @Override
diff --git a/detox/src/devices/Device.js b/detox/src/devices/Device.js
index 368803c39..cbfbfa4f9 100644
--- a/detox/src/devices/Device.js
+++ b/detox/src/devices/Device.js
@@ -262,6 +262,14 @@ class Device {
     return this.deviceDriver.getUiDevice();
   }
 
+  async setStatusBar(params) {
+    await this.deviceDriver.setStatusBar(this._deviceId, params);
+  }
+
+  async resetStatusBar() {
+    await this.deviceDriver.resetStatusBar(this._deviceId);
+  }
+
   _defaultLaunchArgs() {
     return {
       'detoxServer': this._sessionConfig.server,
diff --git a/detox/src/devices/drivers/DeviceDriverBase.js b/detox/src/devices/drivers/DeviceDriverBase.js
index 13a1bbbd4..89f69fe01 100644
--- a/detox/src/devices/drivers/DeviceDriverBase.js
+++ b/detox/src/devices/drivers/DeviceDriverBase.js
@@ -208,6 +208,13 @@ class DeviceDriverBase {
       error
     );
   }
+
+  async setStatusBar(deviceId, flags) {
+  }
+
+  async resetStatusBar(deviceId) {
+  }
+
 }
 
 module.exports = DeviceDriverBase;
diff --git a/detox/src/devices/drivers/SimulatorDriver.js b/detox/src/devices/drivers/SimulatorDriver.js
index 3d5fc709c..0c705e6f2 100644
--- a/detox/src/devices/drivers/SimulatorDriver.js
+++ b/detox/src/devices/drivers/SimulatorDriver.js
@@ -269,6 +269,14 @@ class SimulatorDriver extends IosDriver {
       ? JSON.stringify(rawDeviceQuery)
       : `(${rawDeviceQuery})`;
   }
+
+  async setStatusBar(deviceId, flags) {
+    await this.applesimutils.statusBarOverride(deviceId, flags);
+  }
+
+  async resetStatusBar(deviceId) {
+    await this.applesimutils.statusBarReset(deviceId);
+  }
 }
 
 module.exports = SimulatorDriver;
diff --git a/detox/src/devices/ios/AppleSimUtils.js b/detox/src/devices/ios/AppleSimUtils.js
index 6f96ddc5d..5df2488e5 100644
--- a/detox/src/devices/ios/AppleSimUtils.js
+++ b/detox/src/devices/ios/AppleSimUtils.js
@@ -308,6 +308,34 @@ class AppleSimUtils {
   _parseLaunchId(result) {
     return parseInt(_.get(result, 'stdout', ':').trim().split(':')[1]);
   }
+
+  async statusBarOverride(udid, flags) {
+    if (udid && flags) {
+      let overrides = [];
+      if (flags.time)
+        overrides.push(`--time "${flags.time}"`)
+      if (flags.dataNetwork)
+        overrides.push(`--dataNetwork "${flags.dataNetwork}"`)
+      if (flags.wifiMode)
+        overrides.push(`--wifiMode "${flags.wifiMode}"`)
+      if (flags.wifiBars)
+        overrides.push(`--wifiBars "${flags.wifiBars}"`)
+      if (flags.cellularMode)
+        overrides.push(`--cellularMode "${flags.cellularMode}"`)
+      if (flags.cellularBars)
+        overrides.push(`--cellularBars "${flags.cellularBars}"`)
+      if (flags.batteryState)
+        overrides.push(`--batteryState "${flags.batteryState}"`)
+      if (flags.batteryLevel)
+        overrides.push(`--batteryLevel "${flags.batteryLevel}"`)
+
+      await this._execSimctl({ cmd: `status_bar ${udid} override ${overrides.join(' ')}` });
+    }
+  }
+
+  async statusBarReset(udid) {
+    await this._execSimctl({ cmd: `status_bar ${udid} clear` });
+  }
 }
 
 module.exports = AppleSimUtils;
diff --git a/docs/APIRef.DeviceObjectAPI.md b/docs/APIRef.DeviceObjectAPI.md
index 541101cd2..f7656339e 100644
--- a/docs/APIRef.DeviceObjectAPI.md
+++ b/docs/APIRef.DeviceObjectAPI.md
@@ -29,6 +29,8 @@
 - [`device.matchFinger()` **iOS Only**](#devicematchfinger-ios-only)
 - [`device.unmatchFinger()` **iOS Only**](#deviceunmatchfinger-ios-only)
 - [`device.clearKeychain()` **iOS Only**](#deviceclearkeychain-ios-only)
+- [`device.setStatusBar()` **iOS Only**](#devicesetstatusbar-ios-only)
+- [`device.resetStatusBar()` **iOS Only**](#deviceresetstatusbar-ios-only)
 - [`device.pressBack()` **Android Only**](#devicepressback-android-only)
 - [`device.getUIDevice()` **Android Only**](#devicegetuidevice-android-only)
 
@@ -381,6 +383,34 @@ Simulates the failure of a finger match via TouchID
 ### `device.clearKeychain()` **iOS Only**
 Clears the device keychain
 
+### `device.setStatusBar()` **iOS Only**
+Override simulator's status bar. Available options:
+
+```
+{
+  time: "12:34"
+  // Set the date or time to a fixed value.
+  // If the string is a valid ISO date string it will also set the date on relevant devices.
+  dataNetwork: "wifi"
+  // If specified must be one of 'wifi', '3g', '4g', 'lte', 'lte-a', or 'lte+'.
+  wifiMode: "failed"
+  // If specified must be one of 'searching', 'failed', or 'active'.
+  wifiBars: "2"
+  // If specified must be 0-3.
+  cellularMode: "searching"
+  // If specified must be one of 'notSupported', 'searching', 'failed', or 'active'.
+  cellularBars: "3"
+  // If specified must be 0-4.
+  batteryState: "charging"
+  // If specified must be one of 'charging', 'charged', or 'discharging'.
+  batteryLevel: "50"
+  // If specified must be 0-100.
+}
+```
+
+### `device.resetStatusBar()` **iOS Only**
+Resets any override in simulator's status bar.
+
 ### `device.pressBack()` **Android Only**
 Simulate press back button.
 


Test patch:
diff --git a/detox/android/detox/src/main/java/com/wix/detox/TestEngineFacade.kt b/detox/android/detox/src/main/java/com/wix/detox/TestEngineFacade.kt
index c14c34679..02ad4dedb 100644
--- a/detox/android/detox/src/main/java/com/wix/detox/TestEngineFacade.kt
+++ b/detox/android/detox/src/main/java/com/wix/detox/TestEngineFacade.kt
@@ -5,17 +5,12 @@ import androidx.test.espresso.Espresso
 import androidx.test.espresso.IdlingResource
 import com.wix.detox.espresso.EspressoDetox
 import com.wix.detox.espresso.UiAutomatorHelper
+import com.wix.detox.reactnative.ReactNativeExtension
 
 class TestEngineFacade {
     fun awaitIdle() = Espresso.onIdle()
     fun syncIdle() = UiAutomatorHelper.espressoSync() // TODO Check whether this can be replaced with #awaitIdle()
     fun getBusyIdlingResources() = EspressoDetox.getBusyEspressoResources() as List<IdlingResource>
-    fun reloadReactNative(rnContext: Context) = ReactNativeSupport.reloadApp(rnContext)
-    fun softResetReactNative() {
-        ReactNativeSupport.currentReactContext = null
-    }
-    fun hardResetReactNative(context: Context) {
-        softResetReactNative()
-        ReactNativeSupport.removeEspressoIdlingResources(context)
-    }
+    fun reloadReactNative(appContext: Context) = ReactNativeExtension.reloadReactNative(appContext)
+    fun resetReactNative() = ReactNativeExtension.clearAllSynchronization()
 }
diff --git a/detox/android/detox/src/test/java/com/wix/detox/DetoxActionHandlersSpec.kt b/detox/android/detox/src/test/java/com/wix/detox/DetoxActionHandlersSpec.kt
index f20998533..a96d190ec 100644
--- a/detox/android/detox/src/test/java/com/wix/detox/DetoxActionHandlersSpec.kt
+++ b/detox/android/detox/src/test/java/com/wix/detox/DetoxActionHandlersSpec.kt
@@ -1,6 +1,6 @@
 package com.wix.detox
 
-import com.facebook.react.bridge.ReactContext
+import android.content.Context
 import com.nhaarman.mockitokotlin2.*
 import com.wix.detox.UTHelpers.yieldToOtherThreads
 import com.wix.invoke.MethodInvocation
@@ -15,12 +15,12 @@ object DetoxActionHandlersSpec: Spek({
         val params = "{\"mock\": \"params\"}"
         val messageId = 666L
 
-        lateinit var rnContext: ReactContext
+        lateinit var appContext: Context
         lateinit var wsClient: WebSocketClient
         lateinit var testEngineFacade: TestEngineFacade
 
         beforeEachTest {
-            rnContext = mock()
+            appContext = mock()
             wsClient = mock()
 
             testEngineFacade = mock()
@@ -57,11 +57,11 @@ object DetoxActionHandlersSpec: Spek({
         }
 
         describe("React-native reload action") {
-            fun uut() = ReactNativeReloadActionHandler(rnContext, wsClient, testEngineFacade)
+            fun uut() = ReactNativeReloadActionHandler(appContext, wsClient, testEngineFacade)
 
             it("should reload the app") {
                 uut().handle(params, messageId)
-                verify(testEngineFacade).reloadReactNative(rnContext)
+                verify(testEngineFacade).reloadReactNative(appContext)
             }
 
             it("should reply with a 'ready' ACK when ready") {
@@ -82,7 +82,7 @@ object DetoxActionHandlersSpec: Spek({
                     verify(wsClient, never()).sendAction(any(), any(), any())
                 }
                 yieldToOtherThreads(executor)
-                verify(testEngineFacade, times(1)).reloadReactNative(any())
+                verify(testEngineFacade, times(1)).reloadReactNative(eq(appContext))
                 verify(wsClient, times(1)).sendAction(any(), any(), any())
             }
         }
diff --git a/detox/android/detox/src/test/java/com/wix/detox/espresso/ReactNativeTimersIdlingResourceSpec.kt b/detox/android/detox/src/test/java/com/wix/detox/reactnative/idlingresources/ReactNativeTimersIdlingResourceSpec.kt
similarity index 98%
rename from detox/android/detox/src/test/java/com/wix/detox/espresso/ReactNativeTimersIdlingResourceSpec.kt
rename to detox/android/detox/src/test/java/com/wix/detox/reactnative/idlingresources/ReactNativeTimersIdlingResourceSpec.kt
index 6c689a28e..1e6749e0f 100644
--- a/detox/android/detox/src/test/java/com/wix/detox/espresso/ReactNativeTimersIdlingResourceSpec.kt
+++ b/detox/android/detox/src/test/java/com/wix/detox/reactnative/idlingresources/ReactNativeTimersIdlingResourceSpec.kt
@@ -1,4 +1,4 @@
-package com.wix.detox.espresso
+package com.wix.detox.reactnative.idlingresources
 
 import android.view.Choreographer
 import androidx.test.espresso.IdlingResource
@@ -40,7 +40,7 @@ object ReactNativeTimersIdlingResourceSpec : Spek({
         lateinit var choreographer: Choreographer
         lateinit var pendingTimers: PriorityQueue<Any>
 
-        fun uut() = ReactNativeTimersIdlingResource(reactAppContext) { choreographer }
+        fun uut() = TimersIdlingResource(reactAppContext) { choreographer }
 
         fun givenTimer(timer: Any) {
             pendingTimers.add(timer)
diff --git a/detox/src/devices/Device.test.js b/detox/src/devices/Device.test.js
index 97fb943b9..dc9a3e990 100644
--- a/detox/src/devices/Device.test.js
+++ b/detox/src/devices/Device.test.js
@@ -526,6 +526,21 @@ describe('Device', () => {
     expect(driverMock.driver.unmatchFinger).toHaveBeenCalledTimes(1);
   });
 
+  it(`setStatusBar() should pass to device driver`, async () => {
+    const device = validDevice();
+    const params = {};
+    await device.setStatusBar(params);
+
+    expect(driverMock.driver.setStatusBar).toHaveBeenCalledWith(device._deviceId, params);
+  });
+  
+  it(`resetStatusBar() should pass to device driver`, async () => {
+    const device = validDevice();
+    await device.resetStatusBar();
+
+    expect(driverMock.driver.resetStatusBar).toHaveBeenCalledWith(device._deviceId);
+  });
+
   it(`shake() should pass to device driver`, async () => {
     const device = validDevice();
     await device.shake();
diff --git a/detox/test/e2e/25.statusbar.test.js b/detox/test/e2e/25.statusbar.test.js
new file mode 100644
index 000000000..f24e452bc
--- /dev/null
+++ b/detox/test/e2e/25.statusbar.test.js
@@ -0,0 +1,47 @@
+
+
+describe(':ios: StatusBar Override', () => {
+  afterEach(async () => {
+    await device.resetStatusBar();
+  });
+  it.each(['11:11', '22:22', '33:33'])(`setStatusBar({ time: "%s" })`, async (time) => {
+    await device.setStatusBar({ time });
+    await device.takeScreenshot(`setStatusBar({ time: "${time}" })`);
+  })
+
+  it.each(['wifi', '3g', '4g', 'lte', 'lte-a', 'lte+'])(`setStatusBar({ dataNetwork: "%s" })`, async (dataNetwork) => {
+    await device.setStatusBar({ dataNetwork });
+    await device.takeScreenshot(`setStatusBar({ dataNetwork: "${dataNetwork}" })`);
+  })
+
+  it.each(['searching', 'failed', 'active'])(`setStatusBar({ wifiMode: "%s" })`, async (wifiMode) => {
+    await device.setStatusBar({ wifiMode, dataNetwork: 'wifi' });
+    await device.takeScreenshot(`setStatusBar({ wifiMode: "${wifiMode}" })`);
+  })
+
+  it.each(['0', '1', '2', '3'])(`setStatusBar({ wifiBars: "%s" })`, async (wifiBars) => {
+    await device.setStatusBar({ wifiBars, dataNetwork: 'wifi' });
+    await device.takeScreenshot(`setStatusBar({ wifiBars: "${wifiBars}" })`);
+  })
+
+  it.each(['searching', 'failed', 'active'])(`setStatusBar({ cellularMode: "%s" })`, async (cellularMode) => {
+    await device.setStatusBar({ cellularMode, dataNetwork: '3g' });
+    await device.takeScreenshot(`setStatusBar({ cellularMode: "${cellularMode}" })`);
+  })
+
+  it.each(['0', '1', '2', '3', '4'])(`setStatusBar({ cellularBars: "%s" })`, async (cellularBars) => {
+    await device.setStatusBar({ cellularBars, dataNetwork: '3g' });
+    await device.takeScreenshot(`setStatusBar({ cellularBars: "${cellularBars}" })`);
+  })
+
+  it.each(['charging', 'discharging', 'charged'])(`setStatusBar({ batteryState: "%s" })`, async (batteryState) => {
+    await device.setStatusBar({ batteryState });
+    await device.takeScreenshot(`setStatusBar({ batteryState: "${batteryState}" })`);
+  })
+
+  it.each(['30', '60', '90', '100'])(`setStatusBar({ batteryLevel: "%s" })`, async (batteryLevel) => {
+    await device.setStatusBar({ batteryLevel });
+    await device.takeScreenshot(`setStatusBar({ batteryLevel: "${batteryLevel}" })`);
+  })
+
+});