Move bridge dependencies into a single ReactTestFactory

Reviewed By: cjhopman

Differential Revision: D2816291

fb-gh-sync-id: 0eb654541cac7816922d948cc38a26fab44fad70
This commit is contained in:
Marc Horowitz
2016-01-29 00:56:51 -08:00
committed by facebook-github-bot-6
parent b9ceecb31f
commit 5e82094fcb
4 changed files with 129 additions and 60 deletions

View File

@@ -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

View File

@@ -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) {

View File

@@ -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();
}

View File

@@ -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;
}
/**