mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Move ReactNativeTestRule to OSS
Summary: And migrated ReactRootViewTestCase to use ReactNativeTestRule. Reviewed By: mdvacca Differential Revision: D9557362 fbshipit-source-id: 1469d0ad8c125b5ea729371d81956e61780c56cf
This commit is contained in:
committed by
Facebook Github Bot
parent
bf8e1b4ffa
commit
afe0843bee
@@ -0,0 +1,35 @@
|
||||
# BUILD FILE SYNTAX: SKYLARK
|
||||
load(
|
||||
"@xplat//ReactNative:DEFS.bzl",
|
||||
"react_native_dep",
|
||||
"react_native_integration_tests_target",
|
||||
"react_native_target",
|
||||
"rn_android_library",
|
||||
)
|
||||
|
||||
rn_android_library(
|
||||
name = "rule",
|
||||
srcs = glob(["*.java"]),
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
deps = [
|
||||
react_native_dep("java/com/facebook/testing/instrumentation:instrumentation"),
|
||||
react_native_dep("java/com/facebook/testing/instrumentation/base:base"),
|
||||
react_native_dep("third-party/java/espresso:espresso"),
|
||||
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
||||
react_native_dep("third-party/java/junit:junit"),
|
||||
react_native_dep("third-party/java/testing-support-lib:testing-support-lib"),
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
react_native_dep("third-party/android/support/v7/appcompat-orig:appcompat"),
|
||||
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
||||
react_native_integration_tests_target("java/com/facebook/react/testing:testing"),
|
||||
react_native_integration_tests_target("java/com/facebook/react/testing/idledetection:idledetection"),
|
||||
react_native_target("java/com/facebook/react:react"),
|
||||
react_native_target("java/com/facebook/react/bridge:bridge"),
|
||||
react_native_target("java/com/facebook/react/common:common"),
|
||||
react_native_target("java/com/facebook/react/modules/core:core"),
|
||||
react_native_target("java/com/facebook/react/shell:shell"),
|
||||
react_native_target("java/com/facebook/react/uimanager:uimanager"),
|
||||
],
|
||||
)
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
package com.facebook.react.testing.rule;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
import android.support.test.rule.ActivityTestRule;
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.ReactRootView;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.common.LifecycleState;
|
||||
import com.facebook.react.shell.MainReactPackage;
|
||||
import com.facebook.react.testing.ReactInstanceSpecForTest;
|
||||
import com.facebook.react.testing.ReactTestHelper;
|
||||
import com.facebook.react.testing.idledetection.ReactBridgeIdleSignaler;
|
||||
import com.facebook.react.testing.idledetection.ReactIdleDetectionUtil;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
import com.facebook.react.uimanager.UIImplementation;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
/** A test rule to simplify React Native rendering tests. */
|
||||
public class ReactNativeTestRule implements TestRule {
|
||||
|
||||
// we need a bigger timeout for CI builds because they run on a slow emulator
|
||||
private static final long IDLE_TIMEOUT_MS = 120000;
|
||||
|
||||
@Rule public ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(Activity.class);
|
||||
|
||||
private final String mBundleName;
|
||||
private ReactPackage mReactPackage;
|
||||
private ReactInstanceManager mReactInstanceManager;
|
||||
private ReactBridgeIdleSignaler mBridgeIdleSignaler;
|
||||
private ReactRootView mView;
|
||||
private CountDownLatch mLatch;
|
||||
|
||||
public ReactNativeTestRule(String bundleName) {
|
||||
this(bundleName, null);
|
||||
}
|
||||
|
||||
public ReactNativeTestRule(String bundleName, ReactPackage reactPackage) {
|
||||
mBundleName = bundleName;
|
||||
mReactPackage = reactPackage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement apply(final Statement base, final Description description) {
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
setUp();
|
||||
base.evaluate();
|
||||
tearDown();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void setUp() {
|
||||
final Activity activity = mActivityRule.launchActivity(null);
|
||||
mView = new ReactRootView(activity);
|
||||
|
||||
activity.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mBridgeIdleSignaler = new ReactBridgeIdleSignaler();
|
||||
mReactInstanceManager =
|
||||
ReactTestHelper.getReactTestFactory()
|
||||
.getReactInstanceManagerBuilder()
|
||||
.setApplication(activity.getApplication())
|
||||
.setBundleAssetName(mBundleName)
|
||||
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
|
||||
.setBridgeIdleDebugListener(mBridgeIdleSignaler)
|
||||
.addPackage(mReactPackage != null ? mReactPackage : new MainReactPackage())
|
||||
.build();
|
||||
mReactInstanceManager.onHostResume(activity);
|
||||
|
||||
// This threading garbage will be replaced by Surface
|
||||
final AtomicBoolean isLayoutUpdated = new AtomicBoolean(false);
|
||||
mReactInstanceManager.addReactInstanceEventListener(
|
||||
new ReactInstanceManager.ReactInstanceEventListener() {
|
||||
@Override
|
||||
public void onReactContextInitialized(ReactContext reactContext) {
|
||||
final UIManagerModule uiManagerModule =
|
||||
reactContext.getCatalystInstance().getNativeModule(UIManagerModule.class);
|
||||
uiManagerModule
|
||||
.getUIImplementation()
|
||||
.setLayoutUpdateListener(
|
||||
new UIImplementation.LayoutUpdateListener() {
|
||||
@Override
|
||||
public void onLayoutUpdated(ReactShadowNode reactShadowNode) {
|
||||
uiManagerModule.getUIImplementation().removeLayoutUpdateListener();
|
||||
isLayoutUpdated.set(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
mView
|
||||
.getViewTreeObserver()
|
||||
.addOnGlobalLayoutListener(
|
||||
new OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
if (isLayoutUpdated.get()) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
mView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
} else {
|
||||
mView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||
}
|
||||
mLatch.countDown();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void tearDown() {
|
||||
final ReactRootView view = mView;
|
||||
final ReactInstanceManager reactInstanceManager = mReactInstanceManager;
|
||||
mView = null;
|
||||
mReactInstanceManager = null;
|
||||
mActivityRule
|
||||
.getActivity()
|
||||
.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
view.unmountReactApplication();
|
||||
reactInstanceManager.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Renders the react component and waits until the layout has completed before returning */
|
||||
public void render(final String componentName) {
|
||||
mLatch = new CountDownLatch(1);
|
||||
final Activity activity = mActivityRule.getActivity();
|
||||
activity.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ReactRootView view = getView();
|
||||
view.startReactApplication(mReactInstanceManager, componentName);
|
||||
activity.setContentView(view);
|
||||
}
|
||||
});
|
||||
int timeoutSec = 10;
|
||||
try {
|
||||
mLatch.await(timeoutSec, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to render " + componentName + " after " + timeoutSec + " seconds");
|
||||
}
|
||||
}
|
||||
|
||||
public void waitForIdleSync() {
|
||||
ReactIdleDetectionUtil.waitForBridgeAndUIIdle(
|
||||
mBridgeIdleSignaler,
|
||||
mReactInstanceManager.getCurrentReactContext(),
|
||||
IDLE_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
/** Returns the react view */
|
||||
public ReactRootView getView() {
|
||||
return mView;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user