Files
react-native/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
T
Andres Suarez 3b31e69e28 Tidy up license headers [2/n]
Summary: Changelog: [General] [Fixed] - License header cleanup

Reviewed By: yungsters

Differential Revision: D17952694

fbshipit-source-id: 17c87de7ebb271fa2ac8d00af72a4d1addef8bd0
2019-10-16 10:06:34 -07:00

210 lines
6.6 KiB
Java

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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 static org.mockito.Mockito.mock;
import android.test.AndroidTestCase;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.BaseJavaModule;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.SoftAssertions;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.futures.SimpleSettableFuture;
import com.facebook.react.devsupport.interfaces.DevSupportManager;
import com.facebook.react.modules.core.ReactChoreographer;
import com.facebook.react.modules.core.TimingModule;
import com.facebook.react.testing.idledetection.ReactBridgeIdleSignaler;
import com.facebook.react.testing.idledetection.ReactIdleDetectionUtil;
import com.facebook.soloader.SoLoader;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* Use this class for writing integration tests of catalyst. This class will run all JNI call within
* separate android looper, thus you don't need to care about starting your own looper.
*
* <p>Keep in mind that all JS remote method calls and script load calls are asynchronous and you
* should not expect them to return results immediately.
*
* <p>In order to write catalyst integration:
*
* <ol>
* <li>Make {@link ReactIntegrationTestCase} a base class of your test case
* <li>Use {@link ReactTestHelper#catalystInstanceBuilder()} instead of {@link
* com.facebook.react.bridge.CatalystInstanceImpl.Builder} to build catalyst instance for
* testing purposes
* </ol>
*/
public abstract class ReactIntegrationTestCase extends AndroidTestCase {
// we need a bigger timeout for CI builds because they run on a slow emulator
private static final long IDLE_TIMEOUT_MS = 60000;
private @Nullable CatalystInstance mInstance;
private @Nullable ReactBridgeIdleSignaler mBridgeIdleSignaler;
private @Nullable ReactApplicationContext mReactContext;
@Override
public ReactApplicationContext getContext() {
if (mReactContext == null) {
mReactContext = new ReactApplicationContext(super.getContext());
Assertions.assertNotNull(mReactContext);
}
return mReactContext;
}
public void shutDownContext() {
if (mInstance != null) {
final ReactContext contextToDestroy = mReactContext;
mReactContext = null;
mInstance = null;
final SimpleSettableFuture<Void> semaphore = new SimpleSettableFuture<>();
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (contextToDestroy != null) {
contextToDestroy.destroy();
}
semaphore.set(null);
}
});
semaphore.getOrThrow();
}
}
/**
* This method isn't safe since it doesn't factor in layout-only view removal. Use {@link
* #getViewByTestId} instead.
*/
@Deprecated
public <T extends View> T getViewAtPath(ViewGroup rootView, int... path) {
return ReactTestHelper.getViewAtPath(rootView, path);
}
public <T extends View> T getViewByTestId(ViewGroup rootView, String testID) {
return (T) ReactTestHelper.getViewWithReactTestId(rootView, testID);
}
public static class Event {
private final CountDownLatch mLatch;
public Event() {
this(1);
}
public Event(int counter) {
mLatch = new CountDownLatch(counter);
}
public void occur() {
mLatch.countDown();
}
public boolean didOccur() {
return mLatch.getCount() == 0;
}
public boolean await(long millis) {
try {
return mLatch.await(millis, TimeUnit.MILLISECONDS);
} catch (InterruptedException ignore) {
return false;
}
}
}
/**
* Timing module needs to be created on the main thread so that it gets the correct Choreographer.
*/
protected TimingModule createTimingModule() {
final SimpleSettableFuture<TimingModule> simpleSettableFuture =
new SimpleSettableFuture<TimingModule>();
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
ReactChoreographer.initialize();
TimingModule timingModule =
new TimingModule(getContext(), mock(DevSupportManager.class));
simpleSettableFuture.set(timingModule);
}
});
try {
return simpleSettableFuture.get(5000, TimeUnit.MILLISECONDS);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void initializeWithInstance(CatalystInstance instance) {
mInstance = instance;
mBridgeIdleSignaler = new ReactBridgeIdleSignaler();
mInstance.addBridgeIdleDebugListener(mBridgeIdleSignaler);
getContext().initializeWithInstance(mInstance);
}
public boolean waitForBridgeIdle(long millis) {
return Assertions.assertNotNull(mBridgeIdleSignaler).waitForIdle(millis);
}
public void waitForIdleSync() {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
public void waitForBridgeAndUIIdle() {
ReactIdleDetectionUtil.waitForBridgeAndUIIdle(
Assertions.assertNotNull(mBridgeIdleSignaler), getContext(), IDLE_TIMEOUT_MS);
}
@Override
protected void setUp() throws Exception {
super.setUp();
SoLoader.init(getContext(), /* native exopackage */ false);
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
shutDownContext();
}
protected static void initializeJavaModule(final BaseJavaModule javaModule) {
final Semaphore semaphore = new Semaphore(0);
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
javaModule.initialize();
if (javaModule instanceof LifecycleEventListener) {
((LifecycleEventListener) javaModule).onHostResume();
}
semaphore.release();
}
});
try {
SoftAssertions.assertCondition(
semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS),
"Timed out initializing timing module");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}