diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java index d63110551..9297f59a2 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java @@ -132,7 +132,8 @@ public class ReactAppTestActivity extends FragmentActivity implements final CountDownLatch currentLayoutEvent = mLayoutEvent = new CountDownLatch(1); mBridgeIdleSignaler = new ReactBridgeIdleSignaler(); - ReactInstanceManager.Builder builder = ReactInstanceManager.builder() + ReactInstanceManager.Builder builder = + ReactTestHelper.getReactTestFactory().getReactInstanceManagerBuilder() .setApplication(getApplication()) .setBundleAssetName(bundleName) // By not setting a JS module name, we force the bundle to be always loaded from diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java index 58173647f..3b8f1aba6 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java @@ -24,7 +24,7 @@ import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.BaseJavaModule; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.CatalystInstanceImpl; +import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.SoftAssertions; import com.facebook.react.bridge.UiThreadUtil; @@ -41,17 +41,16 @@ import com.facebook.react.modules.core.Timing; * * In order to write catalyst integration: * 1) Make {@link ReactIntegrationTestCase} a base class of your test case - * 2) Use {@link ReactIntegrationTestCase.ReactTestInstanceBuilder} + * 2) Use {@link ReactTestHelper#catalystInstanceBuilder()} * instead of {@link com.facebook.react.bridge.CatalystInstanceImpl.Builder} to build catalyst * instance for testing purposes * */ public abstract class ReactIntegrationTestCase extends AndroidTestCase { - private static final long SETUP_TIMEOUT_MS = 5000; private static final long IDLE_TIMEOUT_MS = 15000; - private @Nullable CatalystInstanceImpl mInstance; + private @Nullable CatalystInstance mInstance; private @Nullable ReactBridgeIdleSignaler mBridgeIdleSignaler; private @Nullable ReactApplicationContext mReactContext; @@ -143,31 +142,12 @@ public abstract class ReactIntegrationTestCase extends AndroidTestCase { } } - public class ReactTestInstanceBuilder extends CatalystInstanceImpl.Builder { - - @Override - public CatalystInstanceImpl build() { - // Call build in separate looper and wait for it to finish before returning - final Event setupEvent = new Event(); - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - mInstance = ReactTestInstanceBuilder.super.build(); - mBridgeIdleSignaler = new ReactBridgeIdleSignaler(); - mInstance.addBridgeIdleDebugListener(mBridgeIdleSignaler); - getContext().initializeWithInstance(mInstance); - ApplicationHolder.setApplication((Application) getContext().getApplicationContext()); - setupEvent.occur(); - } - }); - - if (!setupEvent.await(SETUP_TIMEOUT_MS)) { - throw new RuntimeException( - "Instance setup should take less than " + SETUP_TIMEOUT_MS + "ms"); - } - return mInstance; - } + public void initializeWithInstance(CatalystInstance instance) { + mInstance = instance; + mBridgeIdleSignaler = new ReactBridgeIdleSignaler(); + mInstance.addBridgeIdleDebugListener(mBridgeIdleSignaler); + getContext().initializeWithInstance(mInstance); + ApplicationHolder.setApplication((Application) getContext().getApplicationContext()); } public boolean waitForBridgeIdle(long millis) { diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java new file mode 100644 index 000000000..42877cdd8 --- /dev/null +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package com.facebook.react.testing; + +import android.content.Context; + +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.bridge.CatalystInstance; +import com.facebook.react.bridge.NativeModule; + +public interface ReactTestFactory { + public static interface ReactInstanceEasyBuilder { + ReactInstanceEasyBuilder setContext(Context context); + ReactInstanceEasyBuilder addNativeModule(NativeModule module); + ReactInstanceEasyBuilder addJSModule(Class moduleInterfaceClass); + CatalystInstance build(); + } + + ReactInstanceEasyBuilder getCatalystInstanceBuilder(); + ReactInstanceManager.Builder getReactInstanceManagerBuilder(); +} diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java index ff23f1f23..fbe1c0db2 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java @@ -8,70 +8,131 @@ package com.facebook.react.testing; +import javax.annotation.Nullable; + +import android.app.Instrumentation; +import android.content.Context; import android.view.View; import android.view.ViewGroup; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.CatalystInstanceImpl; import com.facebook.react.bridge.JSBundleLoader; -import com.facebook.react.bridge.NativeModuleCallExceptionHandler; import com.facebook.react.bridge.JSCJavaScriptExecutor; -import com.facebook.react.bridge.NativeModule; -import com.facebook.react.bridge.NativeModuleRegistry; import com.facebook.react.bridge.JavaScriptModulesConfig; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.NativeModuleCallExceptionHandler; +import com.facebook.react.bridge.NativeModuleRegistry; import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec; +import android.support.test.InstrumentationRegistry; import com.android.internal.util.Predicate; public class ReactTestHelper { + private static class DefaultReactTestFactory implements ReactTestFactory { + private static class ReactInstanceEasyBuilderImpl implements ReactInstanceEasyBuilder { + private @Nullable Context mContext; + private final NativeModuleRegistry.Builder mNativeModuleRegistryBuilder = + new NativeModuleRegistry.Builder(); + private final JavaScriptModulesConfig.Builder mJSModulesConfigBuilder = + new JavaScriptModulesConfig.Builder(); - public static class ReactInstanceEasyBuilder { + @Override + public ReactInstanceEasyBuilder setContext(Context context) { + mContext = context; + return this; + } - private final ReactIntegrationTestCase mTestCase; - private final NativeModuleRegistry.Builder mNativeModuleRegistryBuilder; - private final JavaScriptModulesConfig.Builder mJSModulesConfigBuilder; + @Override + public ReactInstanceEasyBuilder addNativeModule(NativeModule module) { + mNativeModuleRegistryBuilder.add(module); + return this; + } - private ReactInstanceEasyBuilder(ReactIntegrationTestCase testCase) { - mTestCase = testCase; - mNativeModuleRegistryBuilder = new NativeModuleRegistry.Builder(); - mJSModulesConfigBuilder = new JavaScriptModulesConfig.Builder(); - } + @Override + public ReactInstanceEasyBuilder addJSModule(Class moduleInterfaceClass) { + mJSModulesConfigBuilder.add(moduleInterfaceClass); + return this; + } - public CatalystInstanceImpl build() { - CatalystInstanceImpl instance = mTestCase.new ReactTestInstanceBuilder() + @Override + public CatalystInstance build() { + return new CatalystInstanceImpl.Builder() .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()) .setJSExecutor(new JSCJavaScriptExecutor()) .setRegistry(mNativeModuleRegistryBuilder.build()) .setJSModulesConfig(mJSModulesConfigBuilder.build()) .setJSBundleLoader(JSBundleLoader.createFileLoader( - mTestCase.getContext(), - "assets://AndroidTestBundle.js")) + mContext, + "assets://AndroidTestBundle.js")) .setNativeModuleCallExceptionHandler( - new NativeModuleCallExceptionHandler() { + new NativeModuleCallExceptionHandler() { @Override public void handleException(Exception e) { throw new RuntimeException(e); } - }) + }) .build(); - instance.runJSBundle(); - mTestCase.waitForBridgeAndUIIdle(); - return instance; + } } - public ReactInstanceEasyBuilder addNativeModule(NativeModule module) { - mNativeModuleRegistryBuilder.add(module); - return this; + @Override + public ReactInstanceEasyBuilder getCatalystInstanceBuilder() { + return new ReactInstanceEasyBuilderImpl(); } - public ReactInstanceEasyBuilder addJSModule(Class moduleInterfaceClass) { - mJSModulesConfigBuilder.add(moduleInterfaceClass); - return this; + @Override + public ReactInstanceManager.Builder getReactInstanceManagerBuilder() { + return ReactInstanceManager.builder(); } } - public static ReactInstanceEasyBuilder catalystInstanceBuilder( - ReactIntegrationTestCase testCase) { - return new ReactInstanceEasyBuilder(testCase); + public static ReactTestFactory getReactTestFactory() { + Instrumentation inst = InstrumentationRegistry.getInstrumentation(); + if (!(inst instanceof ReactTestFactory)) { + return new DefaultReactTestFactory(); + } + + return (ReactTestFactory) inst; + } + + public static ReactTestFactory.ReactInstanceEasyBuilder catalystInstanceBuilder( + final ReactIntegrationTestCase testCase) { + final ReactTestFactory.ReactInstanceEasyBuilder builder = + getReactTestFactory().getCatalystInstanceBuilder(); + ReactTestFactory.ReactInstanceEasyBuilder postBuilder = + new ReactTestFactory.ReactInstanceEasyBuilder() { + @Override + public ReactTestFactory.ReactInstanceEasyBuilder setContext(Context context) { + builder.setContext(context); + return this; + } + + @Override + public ReactTestFactory.ReactInstanceEasyBuilder addNativeModule(NativeModule module) { + builder.addNativeModule(module); + return this; + } + + @Override + public ReactTestFactory.ReactInstanceEasyBuilder addJSModule(Class moduleInterfaceClass) { + builder.addJSModule(moduleInterfaceClass); + return this; + } + + @Override + public CatalystInstance build() { + CatalystInstance instance = builder.build(); + testCase.initializeWithInstance(instance); + instance.runJSBundle(); + testCase.waitForBridgeAndUIIdle(); + return instance; + } + }; + + postBuilder.setContext(testCase.getContext()); + return postBuilder; } /**