Moving more unit tests to open source

Reviewed By: foghina, mkonicek

Differential Revision: D2865561

fb-gh-sync-id: 7aab67d205b94d657a6ec7bf81a4ecee644eabc2
This commit is contained in:
Konstantin Raev 2016-01-27 07:26:55 -08:00 committed by facebook-github-bot-2
parent fff5dc3943
commit 83fd314e37
12 changed files with 2702 additions and 9 deletions

View File

@ -17,9 +17,6 @@ android_library(
react_native_dep('third-party/java/asm:asm'),
react_native_dep('third-party/java/sqlite:sqlite'),
],
deps = [
# ':locate_android-all',
],
visibility = ['//ReactAndroid/...',],
)

View File

@ -0,0 +1,37 @@
include_defs('//ReactAndroid/DEFS')
robolectric3_test(
name = 'uimanager',
# Please change the contact to the oncall of your team
contacts = ['oncall+fbandroid_sheriff@xmail.facebook.com'],
srcs = glob(['**/*.java']),
deps = [
react_native_target('java/com/facebook/csslayout:csslayout'),
react_native_target('java/com/facebook/react:react'),
react_native_target('java/com/facebook/react/animation:animation'),
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/touch:touch'),
react_native_target('java/com/facebook/react/uimanager:uimanager'),
react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
react_native_target('java/com/facebook/react/views/text:text'),
react_native_target('java/com/facebook/react/views/view:view'),
react_native_tests_target('java/com/facebook/react/bridge:testhelpers'),
react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'),
react_native_dep('third-party/java/robolectric3/robolectric:robolectric'),
react_native_dep('third-party/java/fest:fest'),
react_native_dep('third-party/java/junit:junit'),
react_native_dep('third-party/java/okio:okio'),
react_native_dep('third-party/java/mockito:mockito'),
react_native_dep('third-party/java/okhttp:okhttp'),
react_native_dep('third-party/java/jsr-305:jsr-305'),
],
visibility = [
'PUBLIC'
],
)
project_config(
test_target = ':uimanager',
)

View File

@ -0,0 +1,449 @@
/**
* Copyright (c) 2015-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.uimanager;
import android.util.DisplayMetrics;
import com.facebook.csslayout.CSSAlign;
import com.facebook.csslayout.CSSConstants;
import com.facebook.csslayout.CSSFlexDirection;
import com.facebook.csslayout.CSSJustify;
import com.facebook.csslayout.CSSPositionType;
import com.facebook.csslayout.Spacing;
import com.facebook.react.bridge.SimpleMap;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.RobolectricTestRunner;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyFloat;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
@PrepareForTest({PixelUtil.class})
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class LayoutPropertyApplicatorTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
@Before
public void setup() {
DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
}
@After
public void teardown() {
DisplayMetricsHolder.setDisplayMetrics(null);
}
public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
}
@Test
public void testDimensions() {
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
ReactStylesDiffMap map = spy(
buildStyles(
"width", 10.0,
"height", 10.0,
"left", 10.0,
"top", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setStyleWidth(anyFloat());
verify(map).getFloat(eq("width"), anyFloat());
verify(reactShadowNode).setStyleHeight(anyFloat());
verify(map).getFloat(eq("height"), anyFloat());
verify(reactShadowNode).setPositionLeft(anyFloat());
verify(map).getFloat(eq("left"), anyFloat());
verify(reactShadowNode).setPositionTop(anyFloat());
verify(map).getFloat(eq("top"), anyFloat());
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles());
reactShadowNode.updateProperties(map);
verify(reactShadowNode, never()).setStyleWidth(anyFloat());
verify(map, never()).getFloat(eq("width"), anyFloat());
verify(reactShadowNode, never()).setStyleHeight(anyFloat());
verify(map, never()).getFloat(eq("height"), anyFloat());
verify(reactShadowNode, never()).setPositionLeft(anyFloat());
verify(map, never()).getFloat(eq("left"), anyFloat());
verify(reactShadowNode, never()).setPositionTop(anyFloat());
verify(map, never()).getFloat(eq("top"), anyFloat());
}
@Test
public void testFlex() {
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
ReactStylesDiffMap map = spy(buildStyles("flex", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setFlex(anyFloat());
verify(map).getFloat("flex", 0.f);
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles());
reactShadowNode.updateProperties(map);
verify(reactShadowNode, never()).setFlex(anyFloat());
verify(map, never()).getFloat("flex", 0.f);
}
@Test
public void testPosition() {
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
ReactStylesDiffMap map = spy(buildStyles(
"position", "absolute",
"bottom", 10.0,
"right", 5.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setPositionBottom(anyFloat());
verify(reactShadowNode).setPositionRight(anyFloat());
verify(reactShadowNode).setPositionType(any(CSSPositionType.class));
verify(map).getFloat("bottom", Float.NaN);
verify(map).getFloat("right", Float.NaN);
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles());
reactShadowNode.updateProperties(map);
verify(reactShadowNode, never()).setPositionBottom(anyFloat());
verify(reactShadowNode, never()).setPositionRight(anyFloat());
verify(reactShadowNode, never()).setPositionType(any(CSSPositionType.class));
verify(map, never()).getFloat("bottom", Float.NaN);
verify(map, never()).getFloat("right", Float.NaN);
}
@Test
public void testMargin() {
// margin
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
ReactStylesDiffMap map = spy(buildStyles("margin", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setMargin(eq(Spacing.ALL), anyFloat());
verify(map).getFloat("margin", CSSConstants.UNDEFINED);
// marginVertical
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles("marginVertical", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setMargin(eq(Spacing.VERTICAL), anyFloat());
verify(map).getFloat("marginVertical", CSSConstants.UNDEFINED);
// marginHorizontal
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles("marginHorizontal", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setMargin(eq(Spacing.HORIZONTAL), anyFloat());
verify(map).getFloat("marginHorizontal", CSSConstants.UNDEFINED);
// marginTop
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles("marginTop", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setMargin(eq(Spacing.TOP), anyFloat());
verify(map).getFloat("marginTop", CSSConstants.UNDEFINED);
// marginBottom
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles("marginBottom", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setMargin(eq(Spacing.BOTTOM), anyFloat());
verify(map).getFloat("marginBottom", CSSConstants.UNDEFINED);
// marginLeft
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles("marginLeft", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setMargin(eq(Spacing.LEFT), anyFloat());
verify(map).getFloat("marginLeft", CSSConstants.UNDEFINED);
// marginRight
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles("marginRight", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setMargin(eq(Spacing.RIGHT), anyFloat());
verify(map).getFloat("marginRight", CSSConstants.UNDEFINED);
// no margin
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles());
reactShadowNode.updateProperties(map);
verify(reactShadowNode, never()).setMargin(anyInt(), anyFloat());
verify(map, never()).getFloat("margin", CSSConstants.UNDEFINED);
}
@Test
public void testPadding() {
// padding
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
ReactStylesDiffMap map = spy(buildStyles("padding", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setPadding(eq(Spacing.ALL), anyFloat());
verify(map).getFloat("padding", CSSConstants.UNDEFINED);
// paddingVertical
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles("paddingVertical", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setPadding(eq(Spacing.VERTICAL), anyFloat());
verify(map).getFloat("paddingVertical", CSSConstants.UNDEFINED);
// paddingHorizontal
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles("paddingHorizontal", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setPadding(eq(Spacing.HORIZONTAL), anyFloat());
verify(map).getFloat("paddingHorizontal", CSSConstants.UNDEFINED);
// paddingTop
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles("paddingTop", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setPadding(eq(Spacing.TOP), anyFloat());
verify(map).getFloat("paddingTop", CSSConstants.UNDEFINED);
// paddingBottom
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles("paddingBottom", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setPadding(eq(Spacing.BOTTOM), anyFloat());
verify(map).getFloat("paddingBottom", CSSConstants.UNDEFINED);
// paddingLeft
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles("paddingLeft", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setPadding(eq(Spacing.LEFT), anyFloat());
verify(map).getFloat("paddingLeft", CSSConstants.UNDEFINED);
// paddingRight
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles("paddingRight", 10.0));
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setPadding(eq(Spacing.RIGHT), anyFloat());
verify(map).getFloat("paddingRight", CSSConstants.UNDEFINED);
// no padding
reactShadowNode = spy(new LayoutShadowNode());
map = spy(buildStyles());
reactShadowNode.updateProperties(map);
verify(reactShadowNode, never()).setPadding(anyInt(), anyFloat());
verify(map, never()).getFloat("padding", CSSConstants.UNDEFINED);
}
@Test
public void testEnumerations() {
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
ReactStylesDiffMap map = buildStyles(
"flexDirection", "column",
"alignSelf", "stretch",
"alignItems", "center",
"justifyContent", "space_between",
"position", "relative");
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setFlexDirection(CSSFlexDirection.COLUMN);
verify(reactShadowNode).setAlignSelf(CSSAlign.STRETCH);
verify(reactShadowNode).setAlignItems(CSSAlign.CENTER);
verify(reactShadowNode).setJustifyContent(CSSJustify.SPACE_BETWEEN);
verify(reactShadowNode).setPositionType(CSSPositionType.RELATIVE);
reactShadowNode = spy(new LayoutShadowNode());
map = buildStyles();
reactShadowNode.updateProperties(map);
verify(reactShadowNode, never()).setFlexDirection(any(CSSFlexDirection.class));
verify(reactShadowNode, never()).setAlignSelf(any(CSSAlign.class));
verify(reactShadowNode, never()).setAlignItems(any(CSSAlign.class));
verify(reactShadowNode, never()).setJustifyContent(any(CSSJustify.class));
verify(reactShadowNode, never()).setPositionType(any(CSSPositionType.class));
}
@Test
public void testPropertiesResetToDefault() {
DisplayMetrics displayMetrics = new DisplayMetrics();
displayMetrics.density = 1.0f;
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
ReactStylesDiffMap map = buildStyles(
"width", 10.0,
"height", 10.0,
"left", 10.0,
"top", 10.0,
"flex", 1.0,
"padding", 10.0,
"marginLeft", 10.0,
"borderTopWidth", 10.0,
"flexDirection", "row",
"alignSelf", "stretch",
"alignItems", "center",
"justifyContent", "space_between",
"position", "absolute");
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setStyleWidth(10.f);
verify(reactShadowNode).setStyleHeight(10.f);
verify(reactShadowNode).setPositionLeft(10.f);
verify(reactShadowNode).setPositionTop(10.f);
verify(reactShadowNode).setFlex(1.0f);
verify(reactShadowNode).setPadding(Spacing.ALL, 10.f);
verify(reactShadowNode).setMargin(Spacing.LEFT, 10.f);
verify(reactShadowNode).setBorder(Spacing.TOP, 10.f);
verify(reactShadowNode).setFlexDirection(CSSFlexDirection.ROW);
verify(reactShadowNode).setAlignSelf(CSSAlign.STRETCH);
verify(reactShadowNode).setAlignItems(CSSAlign.CENTER);
verify(reactShadowNode).setJustifyContent(CSSJustify.SPACE_BETWEEN);
verify(reactShadowNode).setPositionType(CSSPositionType.ABSOLUTE);
map = buildStyles(
"width", null,
"height", null,
"left", null,
"top", null,
"flex", null,
"padding", null,
"marginLeft", null,
"borderTopWidth", null,
"flexDirection", null,
"alignSelf", null,
"alignItems", null,
"justifyContent", null,
"position", null);
reset(reactShadowNode);
reactShadowNode.updateProperties(map);
verify(reactShadowNode).setStyleWidth(CSSConstants.UNDEFINED);
verify(reactShadowNode).setStyleHeight(CSSConstants.UNDEFINED);
verify(reactShadowNode).setPositionLeft(CSSConstants.UNDEFINED);
verify(reactShadowNode).setPositionTop(CSSConstants.UNDEFINED);
verify(reactShadowNode).setFlex(0.f);
verify(reactShadowNode).setPadding(Spacing.ALL, CSSConstants.UNDEFINED);
verify(reactShadowNode).setMargin(Spacing.LEFT, CSSConstants.UNDEFINED);
verify(reactShadowNode).setBorder(Spacing.TOP, CSSConstants.UNDEFINED);
verify(reactShadowNode).setFlexDirection(CSSFlexDirection.COLUMN);
verify(reactShadowNode).setAlignSelf(CSSAlign.AUTO);
verify(reactShadowNode).setAlignItems(CSSAlign.STRETCH);
verify(reactShadowNode).setJustifyContent(CSSJustify.FLEX_START);
verify(reactShadowNode).setPositionType(CSSPositionType.RELATIVE);
}
@Test
public void testSettingDefaultStyleValues() {
mockStatic(PixelUtil.class);
when(PixelUtil.toPixelFromDIP(anyFloat())).thenAnswer(
new Answer() {
@Override
public Float answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
return (Float) args[0];
}
});
LayoutShadowNode[] nodes = new LayoutShadowNode[7];
for (int idx = 0; idx < nodes.length; idx++) {
nodes[idx] = new LayoutShadowNode();
nodes[idx].setDefaultPadding(Spacing.LEFT, 15);
nodes[idx].setDefaultPadding(Spacing.TOP, 25);
nodes[idx].setDefaultPadding(Spacing.RIGHT, 35);
nodes[idx].setDefaultPadding(Spacing.BOTTOM, 45);
}
ReactStylesDiffMap[] mapNodes = new ReactStylesDiffMap[7];
mapNodes[0] = buildStyles("paddingLeft", 10.0, "paddingHorizontal", 5.0);
mapNodes[1] = buildStyles("padding", 10.0, "paddingTop", 5.0);
mapNodes[2] = buildStyles("paddingLeft", 10.0, "paddingVertical", 5.0);
mapNodes[3] = buildStyles("paddingBottom", 10.0, "paddingHorizontal", 5.0);
mapNodes[4] = buildStyles("padding", null, "paddingTop", 5.0);
mapNodes[5] = buildStyles(
"paddingRight", 10.0,
"paddingHorizontal", null,
"paddingVertical", 7.0);
mapNodes[6] = buildStyles("margin", 5.0);
for (int idx = 0; idx < nodes.length; idx++) {
nodes[idx].updateProperties(mapNodes[idx]);
}
assertEquals(10.0, nodes[0].getPadding().get(Spacing.LEFT), .0001);
assertEquals(25.0, nodes[0].getPadding().get(Spacing.TOP), .0001);
assertEquals(5.0, nodes[0].getPadding().get(Spacing.RIGHT), .0001);
assertEquals(45.0, nodes[0].getPadding().get(Spacing.BOTTOM), .0001);
assertEquals(10.0, nodes[1].getPadding().get(Spacing.LEFT), .0001);
assertEquals(5.0, nodes[1].getPadding().get(Spacing.TOP), .0001);
assertEquals(10.0, nodes[1].getPadding().get(Spacing.RIGHT), .0001);
assertEquals(10.0, nodes[1].getPadding().get(Spacing.BOTTOM), .0001);
assertEquals(10.0, nodes[2].getPadding().get(Spacing.LEFT), .0001);
assertEquals(5.0, nodes[2].getPadding().get(Spacing.TOP), .0001);
assertEquals(35.0, nodes[2].getPadding().get(Spacing.RIGHT), .0001);
assertEquals(5.0, nodes[2].getPadding().get(Spacing.BOTTOM), .0001);
assertEquals(5.0, nodes[3].getPadding().get(Spacing.LEFT), .0001);
assertEquals(25.0, nodes[3].getPadding().get(Spacing.TOP), .0001);
assertEquals(5.0, nodes[3].getPadding().get(Spacing.RIGHT), .0001);
assertEquals(10.0, nodes[3].getPadding().get(Spacing.BOTTOM), .0001);
assertEquals(15.0, nodes[4].getPadding().get(Spacing.LEFT), .0001);
assertEquals(5.0, nodes[4].getPadding().get(Spacing.TOP), .0001);
assertEquals(35.0, nodes[4].getPadding().get(Spacing.RIGHT), .0001);
assertEquals(45.0, nodes[4].getPadding().get(Spacing.BOTTOM), .0001);
assertEquals(15.0, nodes[5].getPadding().get(Spacing.LEFT), .0001);
assertEquals(7.0, nodes[5].getPadding().get(Spacing.TOP), .0001);
assertEquals(10.0, nodes[5].getPadding().get(Spacing.RIGHT), .0001);
assertEquals(7.0, nodes[5].getPadding().get(Spacing.BOTTOM), .0001);
assertEquals(15.0, nodes[6].getPadding().get(Spacing.LEFT), .0001);
assertEquals(25.0, nodes[6].getPadding().get(Spacing.TOP), .0001);
assertEquals(35.0, nodes[6].getPadding().get(Spacing.RIGHT), .0001);
assertEquals(45.0, nodes[6].getPadding().get(Spacing.BOTTOM), .0001);
}
}

View File

@ -0,0 +1,143 @@
/**
* Copyright (c) 2015-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.uimanager;
import java.util.Date;
import android.view.View;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.annotations.ReactPropGroup;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/**
* Test that verifies that spec of methods annotated with @ReactProp is correct
*/
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class ReactPropAnnotationSetterSpecTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
private abstract class BaseViewManager extends ViewManager<View, ReactShadowNode> {
@Override
public String getName() {
return "IgnoredName";
}
@Override
public ReactShadowNode createShadowNodeInstance() {
return null;
}
@Override
public Class<? extends ReactShadowNode> getShadowNodeClass() {
return ReactShadowNode.class;
}
@Override
protected View createViewInstance(ThemedReactContext reactContext) {
return null;
}
@Override
public void updateExtraData(View root, Object extraData) {
}
}
@Test(expected = RuntimeException.class)
public void testMethodWithWongNumberOfParams() {
new BaseViewManager() {
@ReactProp(name = "prop")
public void setterWithIncorrectNumberOfArgs(View v, boolean value, boolean otherValue) {
}
}.getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testMethodWithTooFewParams() {
new BaseViewManager() {
@ReactProp(name = "prop")
public void setterWithTooFewParams(View v) {
}
}.getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testUnsupportedPropValueType() {
new BaseViewManager() {
@ReactProp(name = "prop")
public void setterWithUnsupportedValueType(View v, Date value) {
}
}.getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testSetterWIthNonViewParam() {
new BaseViewManager() {
@ReactProp(name = "prop")
public void setterWithNonViewParam(Object v, boolean value) {
}
}.getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testGroupInvalidNumberOfParams() {
new BaseViewManager() {
@ReactPropGroup(names = {"prop1", "prop2"})
public void setterWIthInvalidNumberOfParams(View v, int index, float value, float other) {
}
}.getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testGroupTooFewParams() {
new BaseViewManager() {
@ReactPropGroup(names = {"prop1", "prop2"})
public void setterWIthTooFewParams(View v, int index) {
}
}.getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testGroupNoIndexParam() {
new BaseViewManager() {
@ReactPropGroup(names = {"prop1", "prop2"})
public void setterWithoutIndexParam(View v, float value, float sth) {
}
}.getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testGroupNoViewParam() {
new BaseViewManager() {
@ReactPropGroup(names = {"prop1", "prop2"})
public void setterWithoutViewParam(Object v, int index, float value) {
}
}.getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testGroupUnsupportedPropType() {
new BaseViewManager() {
@ReactPropGroup(names = {"prop1", "prop2"})
public void setterWithUnsupportedPropType(View v, int index, long value) {
}
}.getNativeProps();
}
}

View File

@ -0,0 +1,493 @@
/**
* Copyright (c) 2015-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.uimanager;
import android.view.View;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.SimpleArray;
import com.facebook.react.bridge.SimpleMap;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.annotations.ReactPropGroup;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Rule;
import org.junit.Test;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.RobolectricTestRunner;
import static org.fest.assertions.api.Assertions.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* Test updating view through {@link ViewManager} with {@link ReactProp} and {@link ReactPropGroup}
* annotations.
*/
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class ReactPropAnnotationSetterTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
public interface ViewManagerUpdatesReceiver {
void onBooleanSetterCalled(boolean value);
void onIntSetterCalled(int value);
void onDoubleSetterCalled(double value);
void onFloatSetterCalled(float value);
void onStringSetterCalled(String value);
void onBoxedBooleanSetterCalled(Boolean value);
void onBoxedIntSetterCalled(Integer value);
void onArraySetterCalled(ReadableArray value);
void onMapSetterCalled(ReadableMap value);
void onFloatGroupPropSetterCalled(int index, float value);
void onIntGroupPropSetterCalled(int index, int value);
void onBoxedIntGroupPropSetterCalled(int index, Integer value);
}
private class ViewManagerUnderTest extends ViewManager<View, ReactShadowNode> {
final ViewManagerUpdatesReceiver mViewManagerUpdatesReceiver;
private ViewManagerUnderTest(ViewManagerUpdatesReceiver viewManagerUpdatesReceiver) {
mViewManagerUpdatesReceiver = viewManagerUpdatesReceiver;
}
@Override
public String getName() {
return "RedpandasLivestreamVideoView";
}
@Override
public ReactShadowNode createShadowNodeInstance() {
fail("This method should not be executed as a part of this test");
return null;
}
@Override
public Class<? extends ReactShadowNode> getShadowNodeClass() {
return ReactShadowNode.class;
}
@Override
protected View createViewInstance(ThemedReactContext reactContext) {
fail("This method should not be executed as a part of this test");
return null;
}
@Override
public void updateExtraData(View root, Object extraData) {
fail("This method should not be executed as a part of this test");
}
@ReactProp(name = "boolProp")
public void setBoolProp(View v, boolean value) {
mViewManagerUpdatesReceiver.onBooleanSetterCalled(value);
}
@ReactProp(name = "boolPropWithDefault", defaultBoolean = true)
public void setBoolPropWithDefault(View v, boolean value) {
mViewManagerUpdatesReceiver.onBooleanSetterCalled(value);
}
@ReactProp(name = "intProp")
public void setIntProp(View v, int value) {
mViewManagerUpdatesReceiver.onIntSetterCalled(value);
}
@ReactProp(name = "intPropWithDefault", defaultInt = 7168)
public void setIntPropWithDefault(View v, int value) {
mViewManagerUpdatesReceiver.onIntSetterCalled(value);
}
@ReactProp(name = "floatProp")
public void setFloatProp(View v, float value) {
mViewManagerUpdatesReceiver.onFloatSetterCalled(value);
}
@ReactProp(name = "floatPropWithDefault", defaultFloat = 14.0f)
public void setFloatPropWithDefault(View v, float value) {
mViewManagerUpdatesReceiver.onFloatSetterCalled(value);
}
@ReactProp(name = "doubleProp")
public void setDoubleProp(View v, double value) {
mViewManagerUpdatesReceiver.onDoubleSetterCalled(value);
}
@ReactProp(name = "doublePropWithDefault", defaultDouble = -88.0)
public void setDoublePropWithDefault(View v, double value) {
mViewManagerUpdatesReceiver.onDoubleSetterCalled(value);
}
@ReactProp(name = "stringProp")
public void setStringProp(View v, String value) {
mViewManagerUpdatesReceiver.onStringSetterCalled(value);
}
@ReactProp(name = "boxedBoolProp")
public void setBoxedBoolProp(View v, Boolean value) {
mViewManagerUpdatesReceiver.onBoxedBooleanSetterCalled(value);
}
@ReactProp(name = "boxedIntProp")
public void setBoxedIntProp(View v, Integer value) {
mViewManagerUpdatesReceiver.onBoxedIntSetterCalled(value);
}
@ReactProp(name = "arrayProp")
public void setArrayProp(View v, ReadableArray value) {
mViewManagerUpdatesReceiver.onArraySetterCalled(value);
}
@ReactProp(name = "mapProp")
public void setMapProp(View v, ReadableMap value) {
mViewManagerUpdatesReceiver.onMapSetterCalled(value);
}
@ReactPropGroup(names = {
"floatGroupPropFirst",
"floatGroupPropSecond",
})
public void setFloatGroupProp(View v, int index, float value) {
mViewManagerUpdatesReceiver.onFloatGroupPropSetterCalled(index, value);
}
@ReactPropGroup(names = {
"floatGroupPropWithDefaultFirst",
"floatGroupPropWithDefaultSecond",
}, defaultFloat = -100.0f)
public void setFloatGroupPropWithDefault(View v, int index, float value) {
mViewManagerUpdatesReceiver.onFloatGroupPropSetterCalled(index, value);
}
@ReactPropGroup(names = {
"intGroupPropFirst",
"intGroupPropSecond"
})
public void setIntGroupProp(View v, int index, int value) {
mViewManagerUpdatesReceiver.onIntGroupPropSetterCalled(index, value);
}
@ReactPropGroup(names = {
"intGroupPropWithDefaultFirst",
"intGroupPropWithDefaultSecond"
}, defaultInt = 555)
public void setIntGroupPropWithDefault(View v, int index, int value) {
mViewManagerUpdatesReceiver.onIntGroupPropSetterCalled(index, value);
}
@ReactPropGroup(names = {
"boxedIntGroupPropFirst",
"boxedIntGroupPropSecond",
})
public void setBoxedIntGroupProp(View v, int index, Integer value) {
mViewManagerUpdatesReceiver.onBoxedIntGroupPropSetterCalled(index, value);
}
}
public static ReactStylesDiffMap buildStyles(Object... keysAndValues) {
return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
}
private ViewManagerUnderTest mViewManager;
private ViewManagerUpdatesReceiver mUpdatesReceiverMock;
@Before
public void setup() {
mUpdatesReceiverMock = mock(ViewManagerUpdatesReceiver.class);
mViewManager = new ViewManagerUnderTest(mUpdatesReceiverMock);
}
@Test
public void testBooleanSetter() {
mViewManager.updateProperties(null, buildStyles("boolProp", true));
verify(mUpdatesReceiverMock).onBooleanSetterCalled(true);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("boolProp", false));
verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("boolProp", null));
verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("boolPropWithDefault", false));
verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("boolPropWithDefault", null));
verify(mUpdatesReceiverMock).onBooleanSetterCalled(true);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testIntSetter() {
mViewManager.updateProperties(null, buildStyles("intProp", 13));
verify(mUpdatesReceiverMock).onIntSetterCalled(13);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("intProp", null));
verify(mUpdatesReceiverMock).onIntSetterCalled(0);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("intPropWithDefault", -1));
verify(mUpdatesReceiverMock).onIntSetterCalled(-1);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("intPropWithDefault", null));
verify(mUpdatesReceiverMock).onIntSetterCalled(7168);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testDoubleSetter() {
mViewManager.updateProperties(null, buildStyles("doubleProp", 13.0));
verify(mUpdatesReceiverMock).onDoubleSetterCalled(13.0);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("doubleProp", null));
verify(mUpdatesReceiverMock).onDoubleSetterCalled(0.0);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("doublePropWithDefault", -1.0));
verify(mUpdatesReceiverMock).onDoubleSetterCalled(-1.0);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("doublePropWithDefault", null));
verify(mUpdatesReceiverMock).onDoubleSetterCalled(-88.0);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testFloatSetter() {
mViewManager.updateProperties(null, buildStyles("floatProp", 13.0));
verify(mUpdatesReceiverMock).onFloatSetterCalled(13.0f);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("floatProp", null));
verify(mUpdatesReceiverMock).onFloatSetterCalled(0.0f);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("floatPropWithDefault", -1.0));
verify(mUpdatesReceiverMock).onFloatSetterCalled(-1.0f);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("floatPropWithDefault", null));
verify(mUpdatesReceiverMock).onFloatSetterCalled(14.0f);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testStringSetter() {
mViewManager.updateProperties(null, buildStyles("stringProp", "someRandomString"));
verify(mUpdatesReceiverMock).onStringSetterCalled("someRandomString");
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("stringProp", null));
verify(mUpdatesReceiverMock).onStringSetterCalled(null);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testBoxedBooleanSetter() {
mViewManager.updateProperties(null, buildStyles("boxedBoolProp", true));
verify(mUpdatesReceiverMock).onBoxedBooleanSetterCalled(Boolean.TRUE);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("boxedBoolProp", false));
verify(mUpdatesReceiverMock).onBoxedBooleanSetterCalled(Boolean.FALSE);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("boxedBoolProp", null));
verify(mUpdatesReceiverMock).onBoxedBooleanSetterCalled(null);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testBoxedIntSetter() {
mViewManager.updateProperties(null, buildStyles("boxedIntProp", 55));
verify(mUpdatesReceiverMock).onBoxedIntSetterCalled(Integer.valueOf(55));
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("boxedIntProp", null));
verify(mUpdatesReceiverMock).onBoxedIntSetterCalled(null);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testArraySetter() {
ReadableArray array = new SimpleArray();
mViewManager.updateProperties(null, buildStyles("arrayProp", array));
verify(mUpdatesReceiverMock).onArraySetterCalled(array);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("arrayProp", null));
verify(mUpdatesReceiverMock).onArraySetterCalled(null);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testMapSetter() {
ReadableMap map = new SimpleMap();
mViewManager.updateProperties(null, buildStyles("mapProp", map));
verify(mUpdatesReceiverMock).onMapSetterCalled(map);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("mapProp", null));
verify(mUpdatesReceiverMock).onMapSetterCalled(null);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testFloatGroupSetter() {
mViewManager.updateProperties(null, buildStyles("floatGroupPropFirst", 11.0));
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(0, 11.0f);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("floatGroupPropSecond", -111.0));
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(1, -111.0f);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("floatGroupPropSecond", null));
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(1, 0.0f);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("floatGroupPropWithDefaultFirst", null));
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(0, -100.0f);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testIntGroupSetter() {
mViewManager.updateProperties(null, buildStyles("intGroupPropFirst", -7));
verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(0, -7);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("intGroupPropSecond", -77));
verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(1, -77);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("intGroupPropSecond", null));
verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(1, 0);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("intGroupPropWithDefaultFirst", 5));
verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(0, 5);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("intGroupPropWithDefaultFirst", null));
verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(0, 555);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("intGroupPropWithDefaultSecond", null));
verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(1, 555);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testStringGroupSetter() {
mViewManager.updateProperties(null, buildStyles("boxedIntGroupPropFirst", -7));
verify(mUpdatesReceiverMock).onBoxedIntGroupPropSetterCalled(0, -7);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("boxedIntGroupPropSecond", 12345));
verify(mUpdatesReceiverMock).onBoxedIntGroupPropSetterCalled(1, 12345);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mViewManager.updateProperties(null, buildStyles("boxedIntGroupPropSecond", null));
verify(mUpdatesReceiverMock).onBoxedIntGroupPropSetterCalled(1, null);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test(expected = JSApplicationIllegalArgumentException.class)
public void testFailToUpdateBoolPropWithMap() {
mViewManager.updateProperties(null, buildStyles("boolProp", new SimpleMap()));
}
@Test(expected = JSApplicationIllegalArgumentException.class)
public void testFailToUpdateStringPropWithDouble() {
mViewManager.updateProperties(null, buildStyles("stringProp", 14.5));
}
@Test(expected = JSApplicationIllegalArgumentException.class)
public void testFailToUpdateDoublePropWithString() {
mViewManager.updateProperties(null, buildStyles("doubleProp", "hello"));
}
@Test(expected = JSApplicationIllegalArgumentException.class)
public void testFailToUpdateIntPropWithDouble() {
mViewManager.updateProperties(null, buildStyles("intProp", -7.4));
}
@Test(expected = JSApplicationIllegalArgumentException.class)
public void testFailToUpdateArrayPropWithBool() {
mViewManager.updateProperties(null, buildStyles("arrayProp", false));
}
@Test(expected = JSApplicationIllegalArgumentException.class)
public void testFailToUpdateMapPropWithArray() {
mViewManager.updateProperties(null, buildStyles("mapProp", new SimpleArray()));
}
@Test(expected = JSApplicationIllegalArgumentException.class)
public void testFailToUpdateBoxedIntPropWithBoxedDouble() {
mViewManager.updateProperties(null, buildStyles("boxedIntProp", Double.valueOf(1)));
}
}

View File

@ -0,0 +1,188 @@
/**
* Copyright (c) 2015-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.uimanager;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import android.view.View;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.annotations.ReactPropGroup;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.fest.assertions.api.Assertions.fail;
/**
* Verifies that prop constants are generated properly based on {@code ReactProp} annotation.
*/
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class ReactPropConstantsTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
private class ViewManagerUnderTest extends ViewManager<View, ReactShadowNode> {
@Override
public String getName() {
return "SomeView";
}
@Override
public ReactShadowNode createShadowNodeInstance() {
fail("This method should not be executed as a part of this test");
return null;
}
@Override
protected View createViewInstance(ThemedReactContext reactContext) {
fail("This method should not be executed as a part of this test");
return null;
}
@Override
public Class<? extends ReactShadowNode> getShadowNodeClass() {
return ReactShadowNode.class;
}
@Override
public void updateExtraData(View root, Object extraData) {
fail("This method should not be executed as a part of this test");
}
@ReactProp(name = "boolProp")
public void setBoolProp(View v, boolean value) {
}
@ReactProp(name = "intProp")
public void setIntProp(View v, int value) {
}
@ReactProp(name = "floatProp")
public void setFloatProp(View v, float value) {
}
@ReactProp(name = "doubleProp")
public void setDoubleProp(View v, double value) {
}
@ReactProp(name = "stringProp")
public void setStringProp(View v, String value) {
}
@ReactProp(name = "boxedBoolProp")
public void setBoxedBoolProp(View v, Boolean value) {
}
@ReactProp(name = "boxedIntProp")
public void setBoxedIntProp(View v, Integer value) {
}
@ReactProp(name = "arrayProp")
public void setArrayProp(View v, ReadableArray value) {
}
@ReactProp(name = "mapProp")
public void setMapProp(View v, ReadableMap value) {
}
@ReactPropGroup(names = {
"floatGroupPropFirst",
"floatGroupPropSecond",
})
public void setFloatGroupProp(View v, int index, float value) {
}
@ReactPropGroup(names = {
"intGroupPropFirst",
"intGroupPropSecond"
})
public void setIntGroupProp(View v, int index, int value) {
}
@ReactPropGroup(names = {
"boxedIntGroupPropFirst",
"boxedIntGroupPropSecond",
})
public void setBoxedIntGroupProp(View v, int index, Integer value) {
}
@ReactProp(name = "customIntProp", customType = "date")
public void customIntProp(View v, int value) {
}
@ReactPropGroup(names = {
"customBoxedIntGroupPropFirst",
"customBoxedIntGroupPropSecond"
}, customType = "color")
public void customIntGroupProp(View v, int index, Integer value) {
}
}
@Test
public void testNativePropsIncludeCorrectTypes() {
List<ViewManager> viewManagers = Arrays.<ViewManager>asList(new ViewManagerUnderTest());
ReactApplicationContext reactContext = new ReactApplicationContext(RuntimeEnvironment.application);
UIManagerModule uiManagerModule = new UIManagerModule(
reactContext,
viewManagers,
new UIImplementation(reactContext, viewManagers));
Map<String, String> constants =
(Map) valueAtPath(uiManagerModule.getConstants(), "SomeView", "NativeProps");
assertThat(constants).isEqualTo(
MapBuilder.<String, String>builder()
.put("boolProp", "boolean")
.put("intProp", "number")
.put("doubleProp", "number")
.put("floatProp", "number")
.put("stringProp", "String")
.put("boxedBoolProp", "boolean")
.put("boxedIntProp", "number")
.put("arrayProp", "Array")
.put("mapProp", "Map")
.put("floatGroupPropFirst", "number")
.put("floatGroupPropSecond", "number")
.put("intGroupPropFirst", "number")
.put("intGroupPropSecond", "number")
.put("boxedIntGroupPropFirst", "number")
.put("boxedIntGroupPropSecond", "number")
.put("customIntProp", "date")
.put("customBoxedIntGroupPropFirst", "color")
.put("customBoxedIntGroupPropSecond", "color")
.build());
}
private static Object valueAtPath(Map nestedMap, String... keyPath) {
assertThat(keyPath).isNotEmpty();
Object value = nestedMap;
for (String key : keyPath) {
assertThat(value).isInstanceOf(Map.class);
nestedMap = (Map) value;
assertThat(nestedMap).containsKey(key);
value = nestedMap.get(key);
}
return value;
}
}

View File

@ -0,0 +1,133 @@
/**
* Copyright (c) 2015-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.uimanager;
import javax.annotation.Nullable;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.annotations.ReactPropGroup;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Rule;
import org.junit.Test;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.RobolectricTestRunner;
import static com.facebook.react.uimanager.ReactPropAnnotationSetterTest.ViewManagerUpdatesReceiver;
import static com.facebook.react.uimanager.ReactPropAnnotationSetterTest.buildStyles;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* Test {@link ReactProp} annotation for {@link ReactShadowNode}. More comprahensive test of this
* annotation can be found in {@link ReactPropAnnotationSetterTest} where we test all possible types
* of properties to be updated.
*/
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class ReactPropForShadowNodeSetterTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
private class ShadowViewUnderTest extends ReactShadowNode {
private ViewManagerUpdatesReceiver mViewManagerUpdatesReceiver;
private ShadowViewUnderTest(ViewManagerUpdatesReceiver viewManagerUpdatesReceiver) {
mViewManagerUpdatesReceiver = viewManagerUpdatesReceiver;
}
@ReactProp(name = "boolProp")
public void setBoolProp(boolean value) {
mViewManagerUpdatesReceiver.onBooleanSetterCalled(value);
}
@ReactProp(name = "stringProp")
public void setStringProp(@Nullable String value) {
mViewManagerUpdatesReceiver.onStringSetterCalled(value);
}
@ReactProp(name = "boxedIntProp")
public void setBoxedIntProp(@Nullable Integer value) {
mViewManagerUpdatesReceiver.onBoxedIntSetterCalled(value);
}
@ReactPropGroup(names = {
"floatGroupPropFirst",
"floatGroupPropSecond",
})
public void setFloatGroupProp(int index, float value) {
mViewManagerUpdatesReceiver.onFloatGroupPropSetterCalled(index, value);
}
}
private ViewManagerUpdatesReceiver mUpdatesReceiverMock;
private ShadowViewUnderTest mShadowView;
@Before
public void setup() {
mUpdatesReceiverMock = mock(ViewManagerUpdatesReceiver.class);
mShadowView = new ShadowViewUnderTest(mUpdatesReceiverMock);
}
@Test
public void testBooleanSetter() {
mShadowView.updateProperties(buildStyles("boolProp", true));
verify(mUpdatesReceiverMock).onBooleanSetterCalled(true);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mShadowView.updateProperties(buildStyles("boolProp", false));
verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mShadowView.updateProperties(buildStyles("boolProp", null));
verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testStringSetter() {
mShadowView.updateProperties(buildStyles("stringProp", "someRandomString"));
verify(mUpdatesReceiverMock).onStringSetterCalled("someRandomString");
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mShadowView.updateProperties(buildStyles("stringProp", null));
verify(mUpdatesReceiverMock).onStringSetterCalled(null);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
@Test
public void testFloatGroupSetter() {
mShadowView.updateProperties(buildStyles("floatGroupPropFirst", 11.0));
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(0, 11.0f);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mShadowView.updateProperties(buildStyles("floatGroupPropSecond", -111.0));
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(1, -111.0f);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
mShadowView.updateProperties(buildStyles("floatGroupPropSecond", null));
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(1, 0.0f);
verifyNoMoreInteractions(mUpdatesReceiverMock);
reset(mUpdatesReceiverMock);
}
}

View File

@ -0,0 +1,123 @@
/**
* Copyright (c) 2015-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.uimanager;
import java.util.Map;
import android.view.View;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.annotations.ReactPropGroup;
import org.junit.Test;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.RobolectricTestRunner;
/**
* Test that verifies that spec of methods annotated with @ReactProp in {@link ReactShadowNode} is
* correct
*/
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class ReactPropForShadowNodeSpecTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
private static class BaseViewManager extends ViewManager {
private final Class<? extends ReactShadowNode> mShadowNodeClass;
private BaseViewManager(Class<? extends ReactShadowNode> shadowNodeClass) {
mShadowNodeClass = shadowNodeClass;
}
@Override
public String getName() {
return "IgnoredName";
}
@Override
public ReactShadowNode createShadowNodeInstance() {
return null;
}
@Override
public Class getShadowNodeClass() {
return mShadowNodeClass;
}
@Override
protected View createViewInstance(ThemedReactContext reactContext) {
return null;
}
@Override
public void updateExtraData(View root, Object extraData) {
}
}
@Test(expected = RuntimeException.class)
public void testMethodWithWrongNumberOfParams() {
new BaseViewManager(new ReactShadowNode() {
@ReactProp(name = "prop")
public void setterWithIncorrectNumberOfArgs(boolean value, int anotherValue) {
}
}.getClass()).getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testMethodWithTooFewParams() {
new BaseViewManager(new ReactShadowNode() {
@ReactProp(name = "prop")
public void setterWithNoArgs() {
}
}.getClass()).getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testUnsupportedValueType() {
new BaseViewManager(new ReactShadowNode() {
@ReactProp(name = "prop")
public void setterWithMap(Map value) {
}
}.getClass()).getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testGroupInvalidNumberOfParams() {
new BaseViewManager(new ReactShadowNode() {
@ReactPropGroup(names = {"prop1", "prop2"})
public void setterWithTooManyParams(int index, float value, boolean bool) {
}
}.getClass()).getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testGroupTooFewParams() {
new BaseViewManager(new ReactShadowNode() {
@ReactPropGroup(names = {"prop1", "prop2"})
public void setterWithTooManyParams(int index) {
}
}.getClass()).getNativeProps();
}
@Test(expected = RuntimeException.class)
public void testGroupNoIndexParam() {
new BaseViewManager(new ReactShadowNode() {
@ReactPropGroup(names = {"prop1", "prop2"})
public void setterWithTooManyParams(float value, boolean bool) {
}
}.getClass()).getNativeProps();
}
}

View File

@ -0,0 +1,105 @@
/**
* Copyright (c) 2015-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.uimanager;
import java.util.Map;
import android.view.View;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.touch.JSResponderHandler;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactTestHelper;
import com.facebook.react.bridge.SimpleMap;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.uimanager.annotations.ReactProp;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.RobolectricTestRunner;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.fest.assertions.api.Assertions.offset;
/**
* Verify {@link View} view property being applied properly by {@link SimpleViewManager}
*/
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class SimpleViewPropertyTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
private static class ConcreteViewManager extends SimpleViewManager<View> {
@ReactProp(name = "foo")
public void setFoo(View view, boolean foo) {
}
@ReactProp(name = "bar")
public void setBar(View view, ReadableMap bar) {
}
@Override
protected View createViewInstance(ThemedReactContext reactContext) {
return new View(reactContext);
}
@Override
public String getName() {
return "View";
}
}
private ReactApplicationContext mContext;
private CatalystInstance mCatalystInstanceMock;
private ThemedReactContext mThemedContext;
private ConcreteViewManager mManager;
@Before
public void setup() {
mContext = new ReactApplicationContext(RuntimeEnvironment.application);
mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance();
mContext.initializeWithInstance(mCatalystInstanceMock);
mThemedContext = new ThemedReactContext(mContext, mContext);
mManager = new ConcreteViewManager();
}
public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
}
@Test
public void testOpacity() {
View view = mManager.createView(mThemedContext, new JSResponderHandler());
mManager.updateProperties(view, buildStyles());
assertThat(view.getAlpha()).isEqualTo(1.0f);
mManager.updateProperties(view, buildStyles("opacity", 0.31));
assertThat(view.getAlpha()).isEqualTo(0.31f, offset(1e-5f));
mManager.updateProperties(view, buildStyles("opacity", null));
assertThat(view.getAlpha()).isEqualTo(1.0f);
}
@Test
public void testGetNativeProps() {
Map<String, String> nativeProps = mManager.getNativeProps();
assertThat(nativeProps.get("foo")).isEqualTo("boolean");
assertThat(nativeProps.get("bar")).isEqualTo("Map");
}
}

View File

@ -0,0 +1,198 @@
/**
* Copyright (c) 2015-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.uimanager;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.common.MapBuilder;
import org.fest.assertions.data.MapEntry;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class UIManagerModuleConstantsTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
private static final String CUSTOM_BUBBLING_EVENT_TYPES = "customBubblingEventTypes";
private static final String CUSTOM_DIRECT_EVENT_TYPES = "customDirectEventTypes";
private static final Map TWIRL_BUBBLING_EVENT_MAP = MapBuilder.of(
"phasedRegistrationNames",
MapBuilder.of(
"bubbled",
"onTwirl",
"captured",
"onTwirlCaptured"));
private static final Map TWIRL_DIRECT_EVENT_MAP = MapBuilder.of("registrationName", "onTwirl");
private ReactApplicationContext mReactContext;
private UIImplementation mUIImplementation;
@Before
public void setUp() {
mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
mUIImplementation = mock(UIImplementation.class);
}
@Test
public void testNoCustomConstants() {
List<ViewManager> viewManagers = Arrays.asList(mock(ViewManager.class));
UIManagerModule uiManagerModule = new UIManagerModule(
mReactContext,
viewManagers,
mUIImplementation);
Map<String, Object> constants = uiManagerModule.getConstants();
assertThat(constants)
.containsKey(CUSTOM_BUBBLING_EVENT_TYPES)
.containsKey(CUSTOM_DIRECT_EVENT_TYPES)
.containsKey("Dimensions");
}
@Test
public void testCustomBubblingEvents() {
ViewManager mockViewManager = mock(ViewManager.class);
List<ViewManager> viewManagers = Arrays.asList(mockViewManager);
when(mockViewManager.getExportedCustomBubblingEventTypeConstants())
.thenReturn(MapBuilder.of("onTwirl", TWIRL_BUBBLING_EVENT_MAP));
UIManagerModule uiManagerModule = new UIManagerModule(
mReactContext,
viewManagers,
mUIImplementation);
Map<String, Object> constants = uiManagerModule.getConstants();
assertThat((Map) constants.get(CUSTOM_BUBBLING_EVENT_TYPES))
.contains(MapEntry.entry("onTwirl", TWIRL_BUBBLING_EVENT_MAP))
.containsKey("topChange");
}
@Test
public void testCustomDirectEvents() {
ViewManager mockViewManager = mock(ViewManager.class);
List<ViewManager> viewManagers = Arrays.asList(mockViewManager);
when(mockViewManager.getExportedCustomDirectEventTypeConstants())
.thenReturn(MapBuilder.of("onTwirl", TWIRL_DIRECT_EVENT_MAP));
UIManagerModule uiManagerModule = new UIManagerModule(
mReactContext,
viewManagers,
mUIImplementation);
Map<String, Object> constants = uiManagerModule.getConstants();
assertThat((Map) constants.get(CUSTOM_DIRECT_EVENT_TYPES))
.contains(MapEntry.entry("onTwirl", TWIRL_DIRECT_EVENT_MAP))
.containsKey("topLoadingStart");
}
@Test
public void testCustomViewConstants() {
ViewManager mockViewManager = mock(ViewManager.class);
List<ViewManager> viewManagers = Arrays.asList(mockViewManager);
when(mockViewManager.getName()).thenReturn("RedPandaPhotoOfTheDayView");
when(mockViewManager.getExportedViewConstants())
.thenReturn(MapBuilder.of("PhotoSizeType", MapBuilder.of("Small", 1, "Large", 2)));
UIManagerModule uiManagerModule = new UIManagerModule(
mReactContext,
viewManagers,
mUIImplementation);
Map<String, Object> constants = uiManagerModule.getConstants();
assertThat(constants).containsKey("RedPandaPhotoOfTheDayView");
assertThat((Map) constants.get("RedPandaPhotoOfTheDayView")).containsKey("Constants");
assertThat((Map) valueAtPath(constants, "RedPandaPhotoOfTheDayView", "Constants"))
.containsKey("PhotoSizeType");
}
@Test
public void testNativeProps() {
ViewManager mockViewManager = mock(ViewManager.class);
List<ViewManager> viewManagers = Arrays.asList(mockViewManager);
when(mockViewManager.getName()).thenReturn("SomeView");
when(mockViewManager.getNativeProps())
.thenReturn(MapBuilder.of("fooProp", "number"));
UIManagerModule uiManagerModule = new UIManagerModule(
mReactContext,
viewManagers,
mUIImplementation);
Map<String, Object> constants = uiManagerModule.getConstants();
assertThat((String) valueAtPath(constants, "SomeView", "NativeProps", "fooProp"))
.isEqualTo("number");
}
@Test
public void testMergeConstants() {
ViewManager managerX = mock(ViewManager.class);
when(managerX.getExportedCustomDirectEventTypeConstants()).thenReturn(MapBuilder.of(
"onTwirl",
MapBuilder.of(
"registrationName",
"onTwirl",
"keyToOverride",
"valueX",
"mapToMerge",
MapBuilder.of("keyToOverride", "innerValueX", "anotherKey", "valueX"))));
ViewManager managerY = mock(ViewManager.class);
when(managerY.getExportedCustomDirectEventTypeConstants()).thenReturn(MapBuilder.of(
"onTwirl",
MapBuilder.of(
"extraKey",
"extraValue",
"keyToOverride",
"valueY",
"mapToMerge",
MapBuilder.of("keyToOverride", "innerValueY", "extraKey", "valueY"))));
List<ViewManager> viewManagers = Arrays.asList(managerX, managerY);
UIManagerModule uiManagerModule = new UIManagerModule(
mReactContext,
viewManagers,
mUIImplementation);
Map<String, Object> constants = uiManagerModule.getConstants();
assertThat((Map) constants.get(CUSTOM_DIRECT_EVENT_TYPES)).containsKey("onTwirl");
Map twirlMap = (Map) valueAtPath(constants, CUSTOM_DIRECT_EVENT_TYPES, "onTwirl");
assertThat(twirlMap)
.contains(MapEntry.entry("registrationName", "onTwirl"))
.contains(MapEntry.entry("keyToOverride", "valueY"))
.contains(MapEntry.entry("extraKey", "extraValue"))
.containsKey("mapToMerge");
Map mapToMerge = (Map) valueAtPath(twirlMap, "mapToMerge");
assertThat(mapToMerge)
.contains(MapEntry.entry("keyToOverride", "innerValueY"))
.contains(MapEntry.entry("anotherKey", "valueX"))
.contains(MapEntry.entry("extraKey", "valueY"));
}
private static Object valueAtPath(Map nestedMap, String... keyPath) {
assertThat(keyPath).isNotEmpty();
Object value = nestedMap;
for (String key : keyPath) {
assertThat(value).isInstanceOf(Map.class);
nestedMap = (Map) value;
assertThat(nestedMap).containsKey(key);
value = nestedMap.get(key);
}
return value;
}
}

View File

@ -0,0 +1,827 @@
/**
* Copyright (c) 2015-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.uimanager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.graphics.Color;
import android.view.Choreographer;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.facebook.react.ReactRootView;
import com.facebook.react.animation.Animation;
import com.facebook.react.animation.AnimationPropertyUpdater;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.SimpleArray;
import com.facebook.react.bridge.SimpleMap;
import com.facebook.react.views.text.ReactRawTextManager;
import com.facebook.react.views.text.ReactTextShadowNode;
import com.facebook.react.views.text.ReactTextViewManager;
import com.facebook.react.views.view.ReactViewGroup;
import com.facebook.react.views.view.ReactViewManager;
import com.facebook.react.bridge.ReactTestHelper;
import org.junit.Before;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Tests for {@link UIManagerModule}.
*/
@PrepareForTest({Arguments.class, ReactChoreographer.class})
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class UIManagerModuleTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
private ReactApplicationContext mReactContext;
private CatalystInstance mCatalystInstanceMock;
private ArrayList<Choreographer.FrameCallback> mPendingChoreographerCallbacks;
@Before
public void setUp() {
PowerMockito.mockStatic(Arguments.class, ReactChoreographer.class);
ReactChoreographer choreographerMock = mock(ReactChoreographer.class);
PowerMockito.when(Arguments.createArray()).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return new SimpleArray();
}
});
PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return new SimpleMap();
}
});
PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(choreographerMock);
mPendingChoreographerCallbacks = new ArrayList<>();
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
mPendingChoreographerCallbacks
.add((Choreographer.FrameCallback) invocation.getArguments()[1]);
return null;
}
}).when(choreographerMock).postFrameCallback(
any(ReactChoreographer.CallbackType.class),
any(Choreographer.FrameCallback.class));
mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance();
mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
mReactContext.initializeWithInstance(mCatalystInstanceMock);
UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class);
when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
.thenReturn(uiManagerModuleMock);
}
@Test
public void testCreateSimpleHierarchy() {
UIManagerModule uiManager = getUIManagerModule();
ViewGroup rootView = createSimpleTextHierarchy(uiManager, "Some text");
assertThat(rootView.getChildCount()).isEqualTo(1);
View firstChild = rootView.getChildAt(0);
assertThat(firstChild).isInstanceOf(TextView.class);
assertThat(((TextView) firstChild).getText().toString()).isEqualTo("Some text");
}
@Test
public void testUpdateSimpleHierarchy() {
UIManagerModule uiManager = getUIManagerModule();
ViewGroup rootView = createSimpleTextHierarchy(uiManager, "Some text");
TextView textView = (TextView) rootView.getChildAt(0);
int rawTextTag = 3;
uiManager.updateView(
rawTextTag,
ReactRawTextManager.REACT_CLASS,
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "New text"));
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertThat(textView.getText().toString()).isEqualTo("New text");
}
@Test
public void testHierarchyWithView() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView =
new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
int rootTag = uiManager.addMeasuredRootView(rootView);
int viewTag = rootTag + 1;
int subViewTag = viewTag + 1;
uiManager.createView(
viewTag,
ReactViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
uiManager.createView(
subViewTag,
ReactViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
uiManager.manageChildren(
viewTag,
null,
null,
SimpleArray.of(subViewTag),
SimpleArray.of(0),
null);
uiManager.manageChildren(
rootTag,
null,
null,
SimpleArray.of(viewTag),
SimpleArray.of(0),
null);
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertThat(rootView.getChildCount()).isEqualTo(1);
ViewGroup child = (ViewGroup) rootView.getChildAt(0);
assertThat(child.getChildCount()).isEqualTo(1);
ViewGroup grandchild = (ViewGroup) child.getChildAt(0);
assertThat(grandchild).isInstanceOf(ViewGroup.class);
assertThat(grandchild.getChildCount()).isEqualTo(0);
}
@Test
public void testMoveViews() {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(1);
View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2);
View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(0);
View expectedViewAt3 = hierarchy.nativeRootView.getChildAt(3);
uiManager.manageChildren(
hierarchy.rootView,
SimpleArray.of(1, 0, 2),
SimpleArray.of(0, 2, 1),
null,
null,
null);
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertChildrenAreExactly(
hierarchy.nativeRootView,
expectedViewAt0,
expectedViewAt1,
expectedViewAt2,
expectedViewAt3);
}
@Test
public void testDeleteViews() {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(1);
View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2);
uiManager.manageChildren(
hierarchy.rootView,
null,
null,
null,
null,
SimpleArray.of(0, 3));
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertChildrenAreExactly(
hierarchy.nativeRootView,
expectedViewAt0,
expectedViewAt1);
}
@Test
public void testMoveAndDeleteViews() {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(3);
View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(2);
uiManager.manageChildren(
hierarchy.rootView,
SimpleArray.of(3),
SimpleArray.of(1),
null,
null,
SimpleArray.of(1));
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertChildrenAreExactly(
hierarchy.nativeRootView,
expectedViewAt0,
expectedViewAt1,
expectedViewAt2);
}
@Test(expected = IllegalViewOperationException.class)
public void testMoveAndDeleteRemoveViewsDuplicateRemove() {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
uiManager.manageChildren(
hierarchy.rootView,
SimpleArray.of(3),
SimpleArray.of(1),
null,
null,
SimpleArray.of(3));
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
}
@Test(expected = IllegalViewOperationException.class)
public void testDuplicateRemove() {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
uiManager.manageChildren(
hierarchy.rootView,
null,
null,
null,
null,
SimpleArray.of(3, 3));
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
}
@Test
public void testMoveAndAddViews() {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
int textViewTag = 1000;
uiManager.createView(
textViewTag,
ReactTextViewManager.REACT_CLASS,
hierarchy.rootView,
SimpleMap.of("collapsable", false));
View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(3);
View expectedViewAt3 = hierarchy.nativeRootView.getChildAt(1);
View expectedViewAt4 = hierarchy.nativeRootView.getChildAt(2);
uiManager.manageChildren(
hierarchy.rootView,
SimpleArray.of(1, 2, 3),
SimpleArray.of(3, 4, 1),
SimpleArray.of(textViewTag),
SimpleArray.of(2),
null);
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(5);
assertThat(hierarchy.nativeRootView.getChildAt(0)).isEqualTo(expectedViewAt0);
assertThat(hierarchy.nativeRootView.getChildAt(1)).isEqualTo(expectedViewAt1);
assertThat(hierarchy.nativeRootView.getChildAt(3)).isEqualTo(expectedViewAt3);
assertThat(hierarchy.nativeRootView.getChildAt(4)).isEqualTo(expectedViewAt4);
}
@Test
public void testMoveViewsWithChildren() {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2);
View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(1);
View expectedViewAt3 = hierarchy.nativeRootView.getChildAt(3);
uiManager.manageChildren(
hierarchy.rootView,
SimpleArray.of(1, 2),
SimpleArray.of(2, 1),
null,
null,
null);
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertChildrenAreExactly(
hierarchy.nativeRootView,
expectedViewAt0,
expectedViewAt1,
expectedViewAt2,
expectedViewAt3);
assertThat(((ViewGroup) hierarchy.nativeRootView.getChildAt(2)).getChildCount()).isEqualTo(2);
}
@Test
public void testDeleteViewsWithChildren() {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2);
View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(3);
uiManager.manageChildren(
hierarchy.rootView,
null,
null,
null,
null,
SimpleArray.of(1));
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertChildrenAreExactly(
hierarchy.nativeRootView,
expectedViewAt0,
expectedViewAt1,
expectedViewAt2);
}
@Test
public void testLayoutAppliedToNodes() throws Exception {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
int newViewTag = 10000;
uiManager.createView(
newViewTag,
ReactViewManager.REACT_CLASS,
hierarchy.rootView,
SimpleMap
.of("left", 10.0, "top", 20.0, "width", 30.0, "height", 40.0, "collapsable", false));
uiManager.manageChildren(
hierarchy.rootView,
null,
null,
SimpleArray.of(newViewTag),
SimpleArray.of(4),
null);
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
View newView = hierarchy.nativeRootView.getChildAt(4);
assertThat(newView.getLeft()).isEqualTo(10);
assertThat(newView.getTop()).isEqualTo(20);
assertThat(newView.getWidth()).isEqualTo(30);
assertThat(newView.getHeight()).isEqualTo(40);
}
/**
* This is to make sure we execute enqueued operations in the order given by JS.
*/
@Test
public void testAddUpdateRemoveInSingleBatch() {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
int newViewTag = 10000;
uiManager.createView(
newViewTag,
ReactViewManager.REACT_CLASS,
hierarchy.rootView,
SimpleMap.of("collapsable", false));
uiManager.manageChildren(
hierarchy.rootView,
null,
null,
SimpleArray.of(newViewTag),
SimpleArray.of(4),
null);
uiManager.updateView(
newViewTag,
ReactViewManager.REACT_CLASS,
SimpleMap.of("backgroundColor", Color.RED));
uiManager.manageChildren(
hierarchy.rootView,
null,
null,
null,
null,
SimpleArray.of(4));
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(4);
}
@Test
public void testTagsAssignment() {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
View view0 = hierarchy.nativeRootView.getChildAt(0);
assertThat(view0.getId()).isEqualTo(hierarchy.view0);
View viewWithChildren1 = hierarchy.nativeRootView.getChildAt(1);
assertThat(viewWithChildren1.getId()).isEqualTo(hierarchy.viewWithChildren1);
View childView0 = ((ViewGroup) viewWithChildren1).getChildAt(0);
assertThat(childView0.getId()).isEqualTo(hierarchy.childView0);
View childView1 = ((ViewGroup) viewWithChildren1).getChildAt(1);
assertThat(childView1.getId()).isEqualTo(hierarchy.childView1);
View view2 = hierarchy.nativeRootView.getChildAt(2);
assertThat(view2.getId()).isEqualTo(hierarchy.view2);
View view3 = hierarchy.nativeRootView.getChildAt(3);
assertThat(view3.getId()).isEqualTo(hierarchy.view3);
}
@Test
public void testLayoutPropertyUpdatingOnlyOnLayoutChange() {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
// Update layout to some values, this way we can verify it hasn't been updated, because the
// update process would normally reset it back to some non-negative value
View view0 = hierarchy.nativeRootView.getChildAt(0);
view0.layout(1, 2, 3, 4);
// verify that X get updated when we update layout properties
uiManager.updateView(
hierarchy.view0,
ReactViewManager.REACT_CLASS,
SimpleMap.of("left", 10.0, "top", 20.0, "width", 30.0, "height", 40.0));
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertThat(view0.getLeft()).isGreaterThan(2);
// verify that the layout doesn't get updated when we update style property not affecting the
// position (e.g., background-color)
view0.layout(1, 2, 3, 4);
uiManager.updateView(
hierarchy.view0,
ReactViewManager.REACT_CLASS,
SimpleMap.of("backgroundColor", Color.RED));
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertThat(view0.getLeft()).isEqualTo(1);
}
private static class AnimationStub extends Animation {
public AnimationStub(int animationID, AnimationPropertyUpdater propertyUpdater) {
super(animationID, propertyUpdater);
}
@Override
public void run() {
}
}
@Test
public void testAddAndRemoveAnimation() {
UIManagerModule uiManagerModule = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManagerModule);
AnimationPropertyUpdater mockPropertyUpdater = mock(AnimationPropertyUpdater.class);
Animation mockAnimation = spy(new AnimationStub(1000, mockPropertyUpdater));
Callback callbackMock = mock(Callback.class);
int rootTag = hierarchy.rootView;
uiManagerModule.createView(
hierarchy.rootView,
ReactViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
uiManagerModule.registerAnimation(mockAnimation);
uiManagerModule.addAnimation(hierarchy.rootView, 1000, callbackMock);
uiManagerModule.removeAnimation(hierarchy.rootView, 1000);
uiManagerModule.onBatchComplete();
executePendingChoreographerCallbacks();
verify(callbackMock, times(1)).invoke(false);
verify(mockAnimation).run();
verify(mockAnimation).cancel();
}
/**
* Makes sure replaceExistingNonRootView by replacing a view with a new view that has a background
* color set.
*/
@Test
public void testReplaceExistingNonRootView() {
UIManagerModule uiManager = getUIManagerModule();
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
int newViewTag = 1234;
uiManager.createView(
newViewTag,
ReactViewManager.REACT_CLASS,
hierarchy.rootView,
SimpleMap.of("backgroundColor", Color.RED));
uiManager.replaceExistingNonRootView(hierarchy.view2, newViewTag);
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(4);
assertThat(hierarchy.nativeRootView.getChildAt(2)).isInstanceOf(ReactViewGroup.class);
ReactViewGroup view = (ReactViewGroup) hierarchy.nativeRootView.getChildAt(2);
assertThat(view.getBackgroundColor()).isEqualTo(Color.RED);
}
/**
* Verifies removeSubviewsFromContainerWithID works by adding subviews, removing them, and
* checking that the final number of children is correct.
*/
@Test
public void testRemoveSubviewsFromContainerWithID() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView =
new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
int rootTag = uiManager.addMeasuredRootView(rootView);
final int containerTag = rootTag + 1;
final int containerSiblingTag = containerTag + 1;
uiManager.createView(
containerTag,
ReactViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
uiManager.createView(
containerSiblingTag,
ReactViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
addChild(uiManager, rootTag, containerTag, 0);
addChild(uiManager, rootTag, containerSiblingTag, 1);
uiManager.createView(
containerTag + 2,
ReactTextViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
uiManager.createView(
containerTag + 3,
ReactTextViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
addChild(uiManager, containerTag, containerTag + 2, 0);
addChild(uiManager, containerTag, containerTag + 3, 1);
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertThat(rootView.getChildCount()).isEqualTo(2);
assertThat(((ViewGroup)rootView.getChildAt(0)).getChildCount()).isEqualTo(2);
uiManager.removeSubviewsFromContainerWithID(containerTag);
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
assertThat(rootView.getChildCount()).isEqualTo(2);
assertThat(((ViewGroup)rootView.getChildAt(0)).getChildCount()).isEqualTo(0);
}
/**
* Assuming no other views have been created, the root view will have tag 1, Text tag 2, and
* RawText tag 3.
*/
private ViewGroup createSimpleTextHierarchy(UIManagerModule uiManager, String text) {
ReactRootView rootView =
new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
int rootTag = uiManager.addMeasuredRootView(rootView);
int textTag = rootTag + 1;
int rawTextTag = textTag + 1;
uiManager.createView(
textTag,
ReactTextViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
uiManager.createView(
rawTextTag,
ReactRawTextManager.REACT_CLASS,
rootTag,
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, text, "collapsable", false));
uiManager.manageChildren(
textTag,
null,
null,
SimpleArray.of(rawTextTag),
SimpleArray.of(0),
null);
uiManager.manageChildren(
rootTag,
null,
null,
SimpleArray.of(textTag),
SimpleArray.of(0),
null);
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
return rootView;
}
private TestMoveDeleteHierarchy createMoveDeleteHierarchy(UIManagerModule uiManager) {
ReactRootView rootView = new ReactRootView(mReactContext);
int rootTag = uiManager.addMeasuredRootView(rootView);
TestMoveDeleteHierarchy hierarchy = new TestMoveDeleteHierarchy(rootView, rootTag);
uiManager.createView(
hierarchy.view0,
ReactViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
uiManager.createView(
hierarchy.viewWithChildren1,
ReactViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
uiManager.createView(
hierarchy.view2,
ReactViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
uiManager.createView(
hierarchy.view3,
ReactViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
uiManager.createView(
hierarchy.childView0,
ReactViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
uiManager.createView(
hierarchy.childView1,
ReactViewManager.REACT_CLASS,
rootTag,
SimpleMap.of("collapsable", false));
addChild(uiManager, rootTag, hierarchy.view0, 0);
addChild(uiManager, rootTag, hierarchy.viewWithChildren1, 1);
addChild(uiManager, rootTag, hierarchy.view2, 2);
addChild(uiManager, rootTag, hierarchy.view3, 3);
addChild(uiManager, hierarchy.viewWithChildren1, hierarchy.childView0, 0);
addChild(uiManager, hierarchy.viewWithChildren1, hierarchy.childView1, 1);
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
return hierarchy;
}
private void addChild(UIManagerModule uiManager, int parentTag, int childTag, int index) {
uiManager.manageChildren(
parentTag,
null,
null,
SimpleArray.of(childTag),
SimpleArray.of(index),
null);
}
private void assertChildrenAreExactly(ViewGroup parent, View... views) {
assertThat(parent.getChildCount()).isEqualTo(views.length);
for (int i = 0; i < views.length; i++) {
assertThat(parent.getChildAt(i))
.describedAs("View at " + i)
.isEqualTo(views[i]);
}
}
/**
* Holder for the tags that represent that represent views in the following hierarchy:
* - View rootView
* - View view0
* - View viewWithChildren1
* - View childView0
* - View childView1
* - View view2
* - View view3
*
* This hierarchy is used to test move/delete functionality in manageChildren.
*/
private static class TestMoveDeleteHierarchy {
public ReactRootView nativeRootView;
public int rootView;
public int view0;
public int viewWithChildren1;
public int view2;
public int view3;
public int childView0;
public int childView1;
public TestMoveDeleteHierarchy(ReactRootView nativeRootView, int rootViewTag) {
this.nativeRootView = nativeRootView;
rootView = rootViewTag;
view0 = rootView + 1;
viewWithChildren1 = rootView + 2;
view2 = rootView + 3;
view3 = rootView + 4;
childView0 = rootView + 5;
childView1 = rootView + 6;
}
}
private void executePendingChoreographerCallbacks() {
ArrayList<Choreographer.FrameCallback> callbacks =
new ArrayList<>(mPendingChoreographerCallbacks);
mPendingChoreographerCallbacks.clear();
for (Choreographer.FrameCallback frameCallback : callbacks) {
frameCallback.doFrame(0);
}
}
private UIManagerModule getUIManagerModule() {
List<ViewManager> viewManagers = Arrays.<ViewManager>asList(
new ReactViewManager(),
new ReactTextViewManager(),
new ReactRawTextManager());
UIManagerModule uiManagerModule = new UIManagerModule(
mReactContext,
viewManagers,
new UIImplementation(mReactContext, viewManagers));
uiManagerModule.onHostResume();
return uiManagerModule;
}
}

View File

@ -17,17 +17,17 @@ dependencies:
- if [[ ! -e buck ]]; then git clone https://github.com/facebook/buck.git; fi
- cd buck && ant
- buck/bin/buck --version
- buck/bin/buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
- buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react
- buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
- buck/bin/buck fetch ReactAndroid/src/androidTest/java/com/facebook/react/tests
- buck/bin/buck fetch ReactAndroid/src/main/...
- buck/bin/buck fetch ReactAndroid/src/test/...
- buck/bin/buck fetch ReactAndroid/src/androidTest/...
# using npm@3 because of problems with shrink-wrapped optional deps installs on linux
- npm install -g npm@3.2
- source scripts/circle-ci-android-setup.sh && getAndroidSDK
- ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
cache_directories:
- "ReactAndroid/build/downloads"
- "buck-out"
- "buck"
- "buck-out/bin"
test:
pre:
# starting emulator in advance because it takes very long to boot
@ -39,7 +39,7 @@ test:
- source scripts/circle-ci-android-setup.sh && waitForAVD
override:
# buck tests
- buck/bin/buck test ReactAndroid/src/test/java/com/facebook/react/modules
- buck/bin/buck test ReactAndroid/src/test/...
- buck/bin/buck build ReactAndroid/src/main/java/com/facebook/react
- buck/bin/buck build ReactAndroid/src/main/java/com/facebook/react/shell
# temp, we can't run instrumentation tests yet