Skip to content

Commit

Permalink
Create a new instrumentation test that does not enforce rendering a s…
Browse files Browse the repository at this point in the history
…ingle RN component

Reviewed By: mdvacca

Differential Revision: D7293466

fbshipit-source-id: 8ddaf9a52f4d6324e8b37f3c6fd4d3e0db6f3a12
  • Loading branch information
ayc1 authored and macdoum1 committed Jun 28, 2018
1 parent 3b471d2 commit cde45eb
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,36 @@ public void loadApp(
String bundleName,
boolean useDevSupport,
UIImplementationProvider uiImplementationProvider) {
loadBundle(spec, bundleName, useDevSupport, uiImplementationProvider);
renderComponent(appKey, initialProps);
}

public void renderComponent(String appKey, @Nullable Bundle initialProps) {
final CountDownLatch currentLayoutEvent = mLayoutEvent = new CountDownLatch(1);
Assertions.assertNotNull(mReactRootView).getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
currentLayoutEvent.countDown();
}
});
Assertions.assertNotNull(mReactRootView)
.startReactApplication(mReactInstanceManager, appKey, initialProps);
}

public void loadBundle(
ReactInstanceSpecForTest spec,
String bundleName,
boolean useDevSupport) {
loadBundle(spec, bundleName, useDevSupport, null);
}

public void loadBundle(
ReactInstanceSpecForTest spec,
String bundleName,
boolean useDevSupport,
UIImplementationProvider uiImplementationProvider) {

mBridgeIdleSignaler = new ReactBridgeIdleSignaler();

ReactInstanceManagerBuilder builder =
Expand All @@ -200,49 +228,39 @@ public void loadApp(
.setBridgeIdleDebugListener(mBridgeIdleSignaler)
.setInitialLifecycleState(mLifecycleState)
.setJSIModulesProvider(
new JSIModulesProvider() {
@Override
public List<JSIModuleHolder> getJSIModules(
final ReactApplicationContext reactApplicationContext,
final JavaScriptContextHolder jsContext) {

List<JSIModuleHolder> modules = new ArrayList<>();
modules.add(
new JSIModuleHolder() {

@Override
public Class<? extends JSIModule> getJSIModuleClass() {
return UIManager.class;
}

@Override
public FabricUIManager getJSIModule() {
List<ViewManager> viewManagers =
getReactInstanceManager().getOrCreateViewManagers(reactApplicationContext);
FabricUIManager fabricUIManager =
new FabricUIManager(
reactApplicationContext, new ViewManagerRegistry(viewManagers));
new FabricJSCBinding().installFabric(jsContext, fabricUIManager);
return fabricUIManager;
}
});

return modules;
}})
new JSIModulesProvider() {
@Override
public List<JSIModuleHolder> getJSIModules(
final ReactApplicationContext reactApplicationContext,
final JavaScriptContextHolder jsContext) {

List<JSIModuleHolder> modules = new ArrayList<>();
modules.add(
new JSIModuleHolder() {

@Override
public Class<? extends JSIModule> getJSIModuleClass() {
return UIManager.class;
}

@Override
public FabricUIManager getJSIModule() {
List<ViewManager> viewManagers =
getReactInstanceManager().getOrCreateViewManagers(reactApplicationContext);
FabricUIManager fabricUIManager =
new FabricUIManager(
reactApplicationContext, new ViewManagerRegistry(viewManagers));
new FabricJSCBinding().installFabric(jsContext, fabricUIManager);
return fabricUIManager;
}
});

return modules;
}})
.setUIImplementationProvider(uiImplementationProvider);

mReactInstanceManager = builder.build();
mReactInstanceManager.onHostResume(this, this);

Assertions.assertNotNull(mReactRootView).getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
currentLayoutEvent.countDown();
}
});
Assertions.assertNotNull(mReactRootView)
.startReactApplication(mReactInstanceManager, appKey, initialProps);
}

private ReactInstanceManager getReactInstanceManager() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react.testing;

import android.content.Intent;
import android.test.ActivityInstrumentationTestCase2;
import android.view.View;
import android.view.ViewGroup;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.testing.idledetection.IdleWaiter;

/**
* Base class for instrumentation tests that runs React based application.
*
* This is similar to ReactAppInstrumentationTestCase except ReactInstrumentationTest allows
* optional rendering of components. A test case can render no components or render multiple
* components.
*/
public abstract class ReactInstrumentationTest extends
ActivityInstrumentationTestCase2<ReactAppTestActivity> implements IdleWaiter {

public ReactInstrumentationTest() {
super(ReactAppTestActivity.class);
}

@Override
protected void setUp() throws Exception {
super.setUp();

Intent intent = new Intent();
intent.putExtra(ReactAppTestActivity.EXTRA_IS_FABRIC_TEST, isFabricTest());
setActivityIntent(intent);
final ReactAppTestActivity activity = getActivity();
try {
runTestOnUiThread(new Runnable() {
@Override
public void run() {
activity.loadBundle(
createReactInstanceSpecForTest(),
getBundleName(),
getEnableDevSupport());
}
});
} catch (Throwable t) {
throw new Exception("Unable to load react bundle " + getBundleName(), t);
}
}

/**
* Renders this component within this test's activity
*/
public void renderComponent(final String componentName) throws Exception {
final ReactAppTestActivity activity = getActivity();
try {
runTestOnUiThread(new Runnable() {
@Override
public void run() {
activity.renderComponent(componentName, null);
}
});
} catch (Throwable t) {
throw new Exception("Unable to render component " + componentName, t);
}
assertTrue("Layout never occurred!", activity.waitForLayout(5000));
waitForBridgeAndUIIdle();
}

@Override
protected void tearDown() throws Exception {
ReactAppTestActivity activity = getActivity();
super.tearDown();
activity.waitForDestroy(5000);
}

public ViewGroup getRootView() {
return (ViewGroup) getActivity().getRootView();
}

public <T extends View> T getViewByTestId(String testID) {
return (T) ReactTestHelper
.getViewWithReactTestId((ViewGroup) getRootView().getParent(), testID);
}

public SingleTouchGestureGenerator createGestureGenerator() {
return new SingleTouchGestureGenerator(getRootView(), this);
}

public void waitForBridgeAndUIIdle() {
getActivity().waitForBridgeAndUIIdle();
}

public void waitForBridgeAndUIIdle(long timeoutMs) {
getActivity().waitForBridgeAndUIIdle(timeoutMs);
}

protected boolean getEnableDevSupport() {
return false;
}

protected boolean isFabricTest() {
return false;
}

/**
* Override this method to provide extra native modules to be loaded before the app starts
*/
protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
return new ReactInstanceSpecForTest();
}

/**
* Implement this method to provide the bundle for this test
*/
protected abstract String getBundleName();

protected ReactContext getReactContext() {
return getActivity().getReactContext();
}
}

0 comments on commit cde45eb

Please sign in to comment.