Open sourced view tests

Reviewed By: mkonicek

Differential Revision: D2881830

fb-gh-sync-id: fef9176964892c5aa40633c177f1d5d8e3aed499
This commit is contained in:
Konstantin Raev 2016-02-01 05:32:31 -08:00 committed by facebook-github-bot-7
parent ee30433b76
commit 33e8a03ada
15 changed files with 2093 additions and 3 deletions

View File

@ -22,8 +22,18 @@ remote_file(
sha1 = 'a944015ddf50fdad79302e42a85a351633c24472',
)
android_library(
name = 'imagepipeline',
exported_deps = [
':imagepipeline-core',
':bolts',
],
visibility = ['//ReactAndroid/...',],
)
android_prebuilt_aar(
name = 'imagepipeline',
name = 'imagepipeline-core',
aar = ':imagepipeline-aar',
visibility = ['//ReactAndroid/...',],
)
@ -34,6 +44,18 @@ remote_file(
sha1 = '93fe3e629c03aea8f63dabd80a0e616b0caef65b',
)
prebuilt_jar(
name = 'bolts',
binary_jar = ':download-bolts',
visibility = ['//ReactAndroid/...',],
)
remote_file(
name = 'download-bolts',
url = 'mvn:com.parse.bolts:bolts-tasks:jar:1.4.0',
sha1 = 'd85884acf6810a3bbbecb587f239005cbc846dc4',
)
android_prebuilt_aar(
name = 'fbcore',
aar = ':fbcore-aar',

View File

@ -1,3 +1,14 @@
include_defs('//ReactAndroid/DEFS')
android_library(
name = 'jackson',
exported_deps = [
':databind',
':annotations',
],
visibility = ['//ReactAndroid/...',],
)
prebuilt_jar(
name = 'core',
binary_jar = ':jackson-core-binary-jar',
@ -9,3 +20,27 @@ remote_file(
url = 'mvn:com.fasterxml.jackson.core:jackson-core:jar:2.2.3',
sha1 = '1a0113da2cab5f4c216b4e5e7c1dbfaa67087e14',
)
prebuilt_jar(
name = 'databind',
binary_jar = ':jackson-databind-jar',
visibility = ['//ReactAndroid/...',],
)
remote_file(
name = 'jackson-databind-jar',
url = 'mvn:com.fasterxml.jackson.core:jackson-databind:jar:2.2.3',
sha1 = '03ae380888029daefb91d3ecdca3a37d8cb92bc9',
)
prebuilt_jar(
name = 'annotations',
binary_jar = ':jackson-annotations-jar',
visibility = ['//ReactAndroid/...',],
)
remote_file(
name = 'jackson-annotations-jar',
url = 'mvn:com.fasterxml.jackson.core:jackson-annotations:jar:2.2.3',
sha1 = '0527fece4f23a457070a36c371a26d6c0208e1c3',
)

View File

@ -0,0 +1,34 @@
include_defs('//ReactAndroid/DEFS')
robolectric3_test(
name = 'react',
# 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/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('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'),
react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'),
],
)
project_config(
test_target = ':react',
)

View File

@ -0,0 +1,218 @@
/**
* 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;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.Rule;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.RobolectricTestRunner;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class CompositeReactPackageTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
@Mock ReactPackage packageNo1;
@Mock ReactPackage packageNo2;
@Mock ReactPackage packageNo3;
@Mock ReactApplicationContext reactContext;
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testThatCreateNativeModulesIsCalledOnAllPackages() {
// Given
CompositeReactPackage composite = new CompositeReactPackage(packageNo1, packageNo2, packageNo3);
// When
composite.createNativeModules(reactContext);
// Then
verify(packageNo1).createNativeModules(reactContext);
verify(packageNo2).createNativeModules(reactContext);
verify(packageNo3).createNativeModules(reactContext);
}
@Test
public void testThatCreateJSModulesIsCalledOnAllPackages() {
// Given
CompositeReactPackage composite = new CompositeReactPackage(packageNo1, packageNo2, packageNo3);
// When
composite.createJSModules();
// Then
verify(packageNo1).createJSModules();
verify(packageNo2).createJSModules();
verify(packageNo3).createJSModules();
}
@Test
public void testThatCreateViewManagersIsCalledOnAllPackages() {
// Given
CompositeReactPackage composite = new CompositeReactPackage(packageNo1, packageNo2, packageNo3);
// When
composite.createViewManagers(reactContext);
// Then
verify(packageNo1).createViewManagers(reactContext);
verify(packageNo2).createViewManagers(reactContext);
verify(packageNo3).createViewManagers(reactContext);
}
@Test
public void testThatCompositeReturnsASumOfNativeModules() {
// Given
CompositeReactPackage composite = new CompositeReactPackage(packageNo1, packageNo2);
NativeModule moduleNo1 = mock(NativeModule.class);
when(moduleNo1.getName()).thenReturn("ModuleNo1");
// module2 and module3 will share same name, composite should return only the latter one
final String sameModuleName = "SameModuleName";
NativeModule moduleNo2 = mock(NativeModule.class);
when(moduleNo2.getName()).thenReturn(sameModuleName);
NativeModule moduleNo3 = mock(NativeModule.class);
when(moduleNo3.getName()).thenReturn(sameModuleName);
NativeModule moduleNo4 = mock(NativeModule.class);
when(moduleNo4.getName()).thenReturn("ModuleNo4");
when(packageNo1.createNativeModules(reactContext)).thenReturn(
Arrays.asList(new NativeModule[]{moduleNo1, moduleNo2}));
when(packageNo2.createNativeModules(reactContext)).thenReturn(
Arrays.asList(new NativeModule[]{moduleNo3, moduleNo4}));
// When
List<NativeModule> compositeModules = composite.createNativeModules(reactContext);
// Then
// Wrapping lists into sets to be order-independent.
// Note that there should be no module2 returned.
Set<NativeModule> expected = new HashSet<>(
Arrays.asList(new NativeModule[]{moduleNo1, moduleNo3, moduleNo4}));
Set<NativeModule> actual = new HashSet<>(compositeModules);
assertEquals(expected, actual);
}
@Test
public void testThatCompositeReturnsASumOfViewManagers() {
// Given
CompositeReactPackage composite = new CompositeReactPackage(packageNo1, packageNo2);
ViewManager managerNo1 = mock(ViewManager.class);
when(managerNo1.getName()).thenReturn("ManagerNo1");
// managerNo2 and managerNo3 will share same name, composite should return only the latter one
final String sameModuleName = "SameModuleName";
ViewManager managerNo2 = mock(ViewManager.class);
when(managerNo2.getName()).thenReturn(sameModuleName);
ViewManager managerNo3 = mock(ViewManager.class);
when(managerNo3.getName()).thenReturn(sameModuleName);
ViewManager managerNo4 = mock(ViewManager.class);
when(managerNo4.getName()).thenReturn("ManagerNo4");
when(packageNo1.createViewManagers(reactContext)).thenReturn(
Arrays.asList(new ViewManager[]{managerNo1, managerNo2}));
when(packageNo2.createViewManagers(reactContext)).thenReturn(
Arrays.asList(new ViewManager[]{managerNo3, managerNo4}));
// When
List<ViewManager> compositeModules = composite.createViewManagers(reactContext);
// Then
// Wrapping lists into sets to be order-independent.
// Note that there should be no managerNo2 returned.
Set<ViewManager> expected = new HashSet<>(
Arrays.asList(new ViewManager[]{managerNo1, managerNo3, managerNo4})
);
Set<ViewManager> actual = new HashSet<>(compositeModules);
assertEquals(expected, actual);
}
// public access level is required by Mockito
public static class JavaScriptModuleNo1 implements JavaScriptModule {};
public static class JavaScriptModuleNo2 implements JavaScriptModule {};
public static class JavaScriptModuleNo3 implements JavaScriptModule {};
@Test
public void testThatCompositeReturnsASumOfJSModules() {
// Given
CompositeReactPackage composite = new CompositeReactPackage(packageNo1, packageNo2);
Class<? extends JavaScriptModule> moduleNo1 = mock(JavaScriptModuleNo1.class).getClass();
Class<? extends JavaScriptModule> moduleNo2 = mock(JavaScriptModuleNo2.class).getClass();
Class<? extends JavaScriptModule> moduleNo3 = mock(JavaScriptModuleNo3.class).getClass();
List<Class<? extends JavaScriptModule>> l1 = new ArrayList<>();
l1.add(moduleNo1);
when(packageNo1.createJSModules()).thenReturn(l1);
List<Class<? extends JavaScriptModule>> l2 = new ArrayList<>();
l2.add(moduleNo2);
l2.add(moduleNo3);
when(packageNo2.createJSModules()).thenReturn(l2);
// When
List<Class<? extends JavaScriptModule>> compositeModules = composite.createJSModules();
// Then
// wrapping lists into sets to be order-independent
List<Class<? extends JavaScriptModule>> l3 = new ArrayList<>();
l3.add(moduleNo1);
l3.add(moduleNo2);
l3.add(moduleNo3);
Set<Class<? extends JavaScriptModule>> expected = new HashSet<>(l3);
Set<Class<? extends JavaScriptModule>> actual = new HashSet<>(compositeModules);
assertEquals(expected, actual);
}
}

View File

@ -0,0 +1,192 @@
/**
* 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;
import java.util.Date;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.ReactTestHelper;
import com.facebook.react.bridge.SimpleArray;
import com.facebook.react.bridge.SimpleMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.Rule;
import org.mockito.ArgumentCaptor;
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.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@PrepareForTest(Arguments.class)
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class RootViewTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
private ReactContext mReactContext;
private CatalystInstance mCatalystInstanceMock;
@Before
public void setUp() {
PowerMockito.mockStatic(Arguments.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();
}
});
mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance();
mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
mReactContext.initializeWithInstance(mCatalystInstanceMock);
DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics();
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class);
when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
.thenReturn(uiManagerModuleMock);
}
@Test
public void testTouchEmitter() {
ReactInstanceManager instanceManager = mock(ReactInstanceManager.class);
when(instanceManager.getCurrentReactContext()).thenReturn(mReactContext);
UIManagerModule uiManager = mock(UIManagerModule.class);
EventDispatcher eventDispatcher = mock(EventDispatcher.class);
RCTEventEmitter eventEmitterModuleMock = mock(RCTEventEmitter.class);
when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
.thenReturn(uiManager);
when(uiManager.getEventDispatcher()).thenReturn(eventDispatcher);
int rootViewId = 7;
ReactRootView rootView = new ReactRootView(mReactContext);
rootView.setId(rootViewId);
rootView.startReactApplication(instanceManager, "");
rootView.simulateAttachForTesting();
long ts = new Date().getTime();
// Test ACTION_DOWN event
rootView.onTouchEvent(
MotionEvent.obtain(100, ts, MotionEvent.ACTION_DOWN, 0, 0, 0));
ArgumentCaptor<Event> downEventCaptor = ArgumentCaptor.forClass(Event.class);
verify(eventDispatcher).dispatchEvent(downEventCaptor.capture());
verifyNoMoreInteractions(eventDispatcher);
downEventCaptor.getValue().dispatch(eventEmitterModuleMock);
ArgumentCaptor<SimpleArray> downActionTouchesArgCaptor =
ArgumentCaptor.forClass(SimpleArray.class);
verify(eventEmitterModuleMock).receiveTouches(
eq("topTouchStart"),
downActionTouchesArgCaptor.capture(),
any(SimpleArray.class));
verifyNoMoreInteractions(eventEmitterModuleMock);
assertThat(downActionTouchesArgCaptor.getValue().size()).isEqualTo(1);
assertThat(downActionTouchesArgCaptor.getValue().getMap(0)).isEqualTo(
SimpleMap.of(
"pageX",
0.,
"pageY",
0.,
"locationX",
0.,
"locationY",
0.,
"target",
rootViewId,
"timeStamp",
(double) ts,
"identifier",
0.));
// Test ACTION_UP event
reset(eventEmitterModuleMock, eventDispatcher);
ArgumentCaptor<Event> upEventCaptor = ArgumentCaptor.forClass(Event.class);
ArgumentCaptor<SimpleArray> upActionTouchesArgCaptor =
ArgumentCaptor.forClass(SimpleArray.class);
rootView.onTouchEvent(
MotionEvent.obtain(50, ts, MotionEvent.ACTION_UP, 0, 0, 0));
verify(eventDispatcher).dispatchEvent(upEventCaptor.capture());
verifyNoMoreInteractions(eventDispatcher);
upEventCaptor.getValue().dispatch(eventEmitterModuleMock);
verify(eventEmitterModuleMock).receiveTouches(
eq("topTouchEnd"),
upActionTouchesArgCaptor.capture(),
any(WritableArray.class));
verifyNoMoreInteractions(eventEmitterModuleMock);
assertThat(upActionTouchesArgCaptor.getValue().size()).isEqualTo(1);
assertThat(upActionTouchesArgCaptor.getValue().getMap(0)).isEqualTo(
SimpleMap.of(
"pageX",
0.,
"pageY",
0.,
"locationX",
0.,
"locationY",
0.,
"target",
rootViewId,
"timeStamp",
(double) ts,
"identifier",
0.));
// Test other action
reset(eventDispatcher);
rootView.onTouchEvent(
MotionEvent.obtain(50, new Date().getTime(), MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0));
verifyNoMoreInteractions(eventDispatcher);
}
}

View File

@ -1,12 +1,12 @@
include_defs('//ReactAndroid/DEFS')
STANDARD_TEST_SRCS = [
'**/*Test.java',
'*Test.java',
]
android_library(
name = 'testhelpers',
srcs = glob(['**/*.java'], excludes = STANDARD_TEST_SRCS),
srcs = glob(['*.java'], excludes = STANDARD_TEST_SRCS),
deps = [
react_native_target('java/com/facebook/react/bridge:bridge'),
react_native_target('java/com/facebook/react/uimanager:uimanager'),
@ -18,3 +18,32 @@ android_library(
'PUBLIC'
],
)
robolectric3_test(
name = 'bridge',
# Please change the contact to the oncall of your team
contacts = ['oncall+fbandroid_sheriff@xmail.facebook.com'],
srcs = glob(STANDARD_TEST_SRCS),
deps = [
':testhelpers',
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/uimanager:uimanager'),
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/mockito:mockito'),
react_native_dep('third-party/java/jackson:core'),
react_native_dep('third-party/java/jackson:jackson'),
react_native_dep('third-party/java/jsr-305:jsr-305'),
react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'),
],
visibility = [
'PUBLIC'
],
)
project_config(
test_target = ':bridge',
)

View File

@ -0,0 +1,98 @@
/**
* 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.bridge;
import java.io.IOException;
import java.io.StringWriter;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import static org.fest.assertions.api.Assertions.assertThat;
public class JavaScriptModuleConfigTest {
private static interface SomeModule extends JavaScriptModule {
public void stringMethod(String arg);
public void intMethod(int arg);
}
private static interface OtherModule extends JavaScriptModule {
public void method(String arg1, int arg2);
}
@Test
public void testModuleWithMethods() throws Exception {
JavaScriptModulesConfig jsModulesConfig = new JavaScriptModulesConfig.Builder()
.add(SomeModule.class)
.build();
String json = getModuleDescriptions(jsModulesConfig);
JsonNode node = parse(json);
assertThat(node).hasSize(1);
JsonNode module = node.fields().next().getValue();
assertThat(module).isNotNull();
JsonNode methods = module.get("methods");
assertThat(methods)
.isNotNull()
.hasSize(2);
JsonNode intMethodNode = methods.get("intMethod");
assertThat(intMethodNode).isNotNull();
assertThat(intMethodNode.get("methodID").asInt()).isEqualTo(0);
JsonNode stringMethod = methods.get("stringMethod");
assertThat(stringMethod).isNotNull();
assertThat(stringMethod.get("methodID").asInt()).isEqualTo(1);
}
@Test
public void testMultipleModules() throws Exception {
JavaScriptModulesConfig jsModulesConfig = new JavaScriptModulesConfig.Builder()
.add(OtherModule.class)
.add(SomeModule.class)
.build();
String json = getModuleDescriptions(jsModulesConfig);
JsonNode node = parse(json);
assertThat(node).hasSize(2);
JsonNode someModuleNode = node.get("SomeModule");
assertThat(someModuleNode).isNotNull();
int someModuleID = someModuleNode.get("moduleID").asInt();
JsonNode otherModuleNode = node.get("OtherModule");
assertThat(otherModuleNode).isNotNull();
int otherModuleID = otherModuleNode.get("moduleID").asInt();
assertThat(otherModuleID)
.isNotEqualTo(someModuleID);
}
private static String getModuleDescriptions(JavaScriptModulesConfig jsModulesConfig)
throws IOException {
JsonFactory jsonFactory = new JsonFactory();
StringWriter writer = new StringWriter();
JsonGenerator jg = jsonFactory.createGenerator(writer);
jsModulesConfig.writeModuleDescriptions(jg);
jg.close();
return writer.getBuffer().toString();
}
private JsonNode parse(String json) throws Exception {
ObjectMapper mapper = new ObjectMapper();
return mapper.readTree(json);
}
}

View File

@ -0,0 +1,296 @@
/**
* 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.bridge;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.facebook.react.common.MapBuilder;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.TextNode;
import org.junit.Test;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.robolectric.RobolectricTestRunner;
import static org.fest.assertions.api.Assertions.assertThat;
/**
* Tests for {@link NativeModuleRegistry}.
*/
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class NativeModuleRegistryTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
@Test
public void testModuleWithMethods() throws Exception {
NativeModuleRegistry registry = new NativeModuleRegistry.Builder()
.add(new MethodsModule())
.build();
String json = getModuleDescriptions(registry);
JsonNode node = parse(json);
JsonNode module = node.fields().next().getValue();
assertThat(module).isNotNull();
JsonNode methods = module.get("methods");
assertThat(methods).isNotNull();
ArrayList<String> expected = new ArrayList<String>();
expected.add("doSomething");
expected.add("saveData");
assertMethodsContainExactly(methods, expected);
}
@Test
public void testAsyncMethod() throws Exception {
NativeModuleRegistry registry = new NativeModuleRegistry.Builder()
.add(new MethodsModule())
.build();
String json = getModuleDescriptions(registry);
JsonNode node = parse(json);
JsonNode asyncMethodData = node.get("TestModule").get("methods").get("saveData");
assertThat(asyncMethodData.get("type")).isEqualTo(new TextNode("remoteAsync"));
JsonNode regularMethodData = node.get("TestModule").get("methods").get("doSomething");
assertThat(regularMethodData.get("type")).isNotEqualTo(new TextNode("remoteAsync"));
}
@Test
public void testModuleWithConstants() throws Exception {
ConstantsModule constantsModule = new ConstantsModule();
NativeModuleRegistry registry = new NativeModuleRegistry.Builder()
.add(constantsModule)
.build();
String json = getModuleDescriptions(registry);
JsonNode node = parse(json);
JsonNode module = node.fields().next().getValue();
assertThat(module).isNotNull();
JsonNode methods = module.get("methods");
assertThat(methods).isNotNull();
ArrayList<String> expected = new ArrayList<String>();
expected.add("runDMC");
assertMethodsContainExactly(methods, expected);
JsonNode constants = module.get("constants");
assertThat(constants.get("testInt").asInt()).isEqualTo(3);
assertThat(constants.get("testDouble").asDouble()).isEqualTo(3.14);
assertThat(constants.get("testString").asText()).isEqualTo("red panda");
JsonNode stringMap = constants.get("testStringMap");
assertThat(stringMap.get("war_room").asText()).isEqualTo("17.1");
assertThat(stringMap.get("android_corex").asText()).isEqualTo("16.1");
JsonNode intMap = constants.get("testIntMap");
assertThat(intMap.get("42").asInt()).isEqualTo(1);
assertThat(intMap.get("84").asInt()).isEqualTo(2);
JsonNode stringList = constants.get("testStringList");
assertThat(stringList.get(0).asText()).isEqualTo("vulpes vulpes");
assertThat(stringList.get(4).asText()).isEqualTo("vulpes velox");
JsonNode intList = constants.get("testIntList");
assertThat(intList.get(0).asInt()).isEqualTo(3);
assertThat(intList.get(4).asInt()).isEqualTo(5);
}
@Test
public void testModuleWithOnlyConstants() throws Exception {
OnlyConstantsModule onlyConstantsModule = new OnlyConstantsModule();
NativeModuleRegistry registry = new NativeModuleRegistry.Builder()
.add(onlyConstantsModule)
.build();
String json = getModuleDescriptions(registry);
JsonNode node = parse(json);
JsonNode module = node.fields().next().getValue();
assertThat(module).isNotNull();
JsonNode constants = module.get("constants");
assertThat(constants.get("testInt").asInt()).isEqualTo(4);
}
@Test
public void testModuleWithNestedMapConstants() throws Exception {
NestedMapConstantsModule nestedMapConstantsModule = new NestedMapConstantsModule();
NativeModuleRegistry registry = new NativeModuleRegistry.Builder()
.add(nestedMapConstantsModule)
.build();
String json = getModuleDescriptions(registry);
JsonNode node = parse(json);
JsonNode module = node.fields().next().getValue();
assertThat(module).isNotNull();
JsonNode constants = module.get("constants");
assertThat(constants).isNotNull();
JsonNode nestedMapConstant = constants.get("nestedMap");
assertThat(nestedMapConstant).isNotNull();
JsonNode firstLevel = nestedMapConstant.get("weNeedToGoDeeper");
assertThat(firstLevel).isNotNull();
JsonNode secondLevel = firstLevel.get("evenDeeper");
assertThat(secondLevel).isNotNull();
assertThat(secondLevel.get("inception").asBoolean()).isTrue();
}
private JsonNode parse(String json) throws Exception {
ObjectMapper mapper = new ObjectMapper();
return mapper.readTree(json);
}
private void assertMethodsContainExactly(JsonNode methodsObject, List<String> methodNames) {
ArrayList<String> actual = new ArrayList();
Iterator<Map.Entry<String,JsonNode>> fields = methodsObject.fields();
while (fields.hasNext()) {
String name = fields.next().getKey();
actual.add(name);
}
assertThat(actual)
.hasSize(methodNames.size())
.containsAll(methodNames);
}
private static String getModuleDescriptions(NativeModuleRegistry registry)
throws IOException {
JsonFactory jsonFactory = new JsonFactory();
StringWriter writer = new StringWriter();
JsonGenerator jg = jsonFactory.createGenerator(writer);
registry.writeModuleDescriptions(jg);
jg.close();
return writer.getBuffer().toString();
}
private static class MethodsModule extends BaseJavaModule {
@Override
public String getName() {
return "TestModule";
}
public void notACatalystMethod() {
}
@ReactMethod
public void doSomething() {
}
@ReactMethod
public void saveData(Promise promise) {
}
}
private static class ConstantsModule extends BaseJavaModule {
@Override
public String getName() {
return "ConstantsModule";
}
@Override
public Map<String, Object> getConstants() {
HashMap<String, Object> constants = new HashMap<String, Object>();
constants.put("testInt", 3);
constants.put("testDouble", 3.14);
constants.put("testString", "red panda");
constants.put(
"testStringMap",
MapBuilder.of(
"war_room",
"17.1",
"android_corex",
"16.1"));
constants.put(
"testIntMap",
MapBuilder.of(
42,
1,
84,
2));
constants.put(
"testStringList",
Arrays.asList(
new String[]{
"vulpes vulpes",
"vulpes cana",
"vulpes chama",
"vulpes fulfa",
"vulpes velox"}));
constants.put("testIntList", Arrays.asList(3, 1, 4, 1, 5));
return constants;
}
@ReactMethod
public void runDMC() {
}
}
private static class OnlyConstantsModule extends BaseJavaModule {
@Override
public String getName() {
return "OnlyConstantsModule";
}
@Override
public Map<String, Object> getConstants() {
return MapBuilder.<String, Object>of("testInt", 4);
}
}
private static class NestedMapConstantsModule extends BaseJavaModule {
@Override
public String getName() {
return "NestedMapConstantsModule";
}
@Override
public Map<String, Object> getConstants() {
return MapBuilder.<String, Object>of(
"nestedMap",
MapBuilder.of(
"weNeedToGoDeeper",
MapBuilder.of(
"evenDeeper",
MapBuilder.of("inception", true))));
}
}
}

View File

@ -0,0 +1,39 @@
include_defs('//ReactAndroid/DEFS')
robolectric3_test(
name = 'views',
# 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/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/image:image'),
react_native_target('java/com/facebook/react/views/text:text'),
react_native_target('java/com/facebook/react/views/textinput:textinput'),
react_native_target('java/com/facebook/react/views/view:view'),
react_native_tests_target('java/com/facebook/react/bridge:testhelpers'),
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'),
react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'),
react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'),
react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
],
)
project_config(
test_target = ':views',
)

View File

@ -0,0 +1,49 @@
/**
* 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.views.image;
import com.facebook.drawee.drawable.ScalingUtils;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.junit.Test;
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;
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class ImageResizeModeTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
@Test
public void testImageResizeMode() {
assertThat(ImageResizeMode.toScaleType(null))
.isEqualTo(ScalingUtils.ScaleType.CENTER_CROP);
assertThat(ImageResizeMode.toScaleType("contain"))
.isEqualTo(ScalingUtils.ScaleType.CENTER_INSIDE);
assertThat(ImageResizeMode.toScaleType("cover"))
.isEqualTo(ScalingUtils.ScaleType.CENTER_CROP);
assertThat(ImageResizeMode.toScaleType("stretch"))
.isEqualTo(ScalingUtils.ScaleType.FIT_XY);
// No resizeMode set
assertThat(ImageResizeMode.defaultValue())
.isEqualTo(ScalingUtils.ScaleType.CENTER_CROP);
}
}

View File

@ -0,0 +1,134 @@
/**
* 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.views.image;
import android.graphics.Color;
import android.util.DisplayMetrics;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.ReactTestHelper;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.SimpleMap;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.uimanager.ThemedReactContext;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Robolectric;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
/**
* Verify that {@link ScalingUtils} properties are being applied correctly
* by {@link ReactImageManager}.
*/
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class ReactImagePropertyTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
private ReactApplicationContext mContext;
private CatalystInstance mCatalystInstanceMock;
private ThemedReactContext mThemeContext;
@Before
public void setup() {
mContext = new ReactApplicationContext(RuntimeEnvironment.application);
mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance();
mContext.initializeWithInstance(mCatalystInstanceMock);
mThemeContext = new ThemedReactContext(mContext, mContext);
Fresco.initialize(mContext);
DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
}
@After
public void teardown() {
DisplayMetricsHolder.setDisplayMetrics(null);
}
public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
}
@Test(expected=JSApplicationIllegalArgumentException.class)
public void testImageInvalidResizeMode() {
ReactImageManager viewManager = new ReactImageManager();
ReactImageView view = viewManager.createViewInstance(mThemeContext);
viewManager.updateProperties(view, buildStyles("resizeMode", "pancakes"));
}
@Test
public void testBorderColor() {
ReactImageManager viewManager = new ReactImageManager();
ReactImageView view = viewManager.createViewInstance(mThemeContext);
viewManager.updateProperties(view, buildStyles("src", "http://mysite.com/mypic.jpg"));
viewManager.updateProperties(view, buildStyles("borderColor", Color.argb(0, 0, 255, 255)));
int borderColor = view.getHierarchy().getRoundingParams().getBorderColor();
assertEquals(0, Color.alpha(borderColor));
assertEquals(0, Color.red(borderColor));
assertEquals(255, Color.green(borderColor));
assertEquals(255, Color.blue(borderColor));
viewManager.updateProperties(view, buildStyles("borderColor", Color.argb(0, 255, 50, 128)));
borderColor = view.getHierarchy().getRoundingParams().getBorderColor();
assertEquals(0, Color.alpha(borderColor));
assertEquals(255, Color.red(borderColor));
assertEquals(50, Color.green(borderColor));
assertEquals(128, Color.blue(borderColor));
viewManager.updateProperties(view, buildStyles("borderColor", null));
borderColor = view.getHierarchy().getRoundingParams().getBorderColor();
assertEquals(0, Color.alpha(borderColor));
assertEquals(0, Color.red(borderColor));
assertEquals(0, Color.green(borderColor));
assertEquals(0, Color.blue(borderColor));
}
@Test
public void testRoundedCorners() {
ReactImageManager viewManager = new ReactImageManager();
ReactImageView view = viewManager.createViewInstance(mThemeContext);
viewManager.updateProperties(view, buildStyles("src", "http://mysite.com/mypic.jpg"));
// We can't easily verify if rounded corner was honored or not, this tests simply verifies
// we're not crashing..
viewManager.updateProperties(view, buildStyles("borderRadius", (double) 10));
viewManager.updateProperties(view, buildStyles("borderRadius", (double) 0));
viewManager.updateProperties(view, buildStyles("borderRadius", null));
}
@Test
public void testTintColor() {
ReactImageManager viewManager = new ReactImageManager();
ReactImageView view = viewManager.createViewInstance(mThemeContext);
assertNull(view.getColorFilter());
viewManager.updateProperties(view, buildStyles("tintColor", Color.argb(50, 0, 0, 255)));
// Can't actually assert the specific color so this is the next best thing.
// Does the color filter now exist?
assertNotNull(view.getColorFilter());
viewManager.updateProperties(view, buildStyles("tintColor", null));
assertNull(view.getColorFilter());
}
}

View File

@ -0,0 +1,386 @@
/**
* 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.views.text;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.annotation.TargetApi;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
import android.view.Choreographer;
import android.widget.TextView;
import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactTestHelper;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.SimpleArray;
import com.facebook.react.bridge.SimpleMap;
import com.facebook.react.uimanager.ReactChoreographer;
import com.facebook.react.uimanager.UIImplementation;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.uimanager.ViewProps;
import org.junit.Before;
import org.junit.Test;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.Robolectric;
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;
/**
* Tests for {@link UIManagerModule} specifically for React Text/RawText.
*/
@PrepareForTest({Arguments.class, ReactChoreographer.class})
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class ReactTextTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
private ArrayList<Choreographer.FrameCallback> mPendingChoreographerCallbacks;
@Before
public void setUp() {
PowerMockito.mockStatic(Arguments.class, ReactChoreographer.class);
ReactChoreographer choreographerMock = mock(ReactChoreographer.class);
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));
}
@Test
public void testFontSizeApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.FONT_SIZE, 21.0),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
AbsoluteSizeSpan sizeSpan = getSingleSpan(
(TextView) rootView.getChildAt(0), AbsoluteSizeSpan.class);
assertThat(sizeSpan.getSize()).isEqualTo(21);
}
@Test
public void testBoldFontApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.FONT_WEIGHT, "bold"),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
CustomStyleSpan customStyleSpan =
getSingleSpan((TextView)rootView.getChildAt(0), CustomStyleSpan.class);
assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero();
assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isZero();
}
@Test
public void testNumericBoldFontApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.FONT_WEIGHT, "500"),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
CustomStyleSpan customStyleSpan =
getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero();
assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isZero();
}
@Test
public void testItalicFontApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.FONT_STYLE, "italic"),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
CustomStyleSpan customStyleSpan =
getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isNotZero();
assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isZero();
}
@Test
public void testBoldItalicFontApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.FONT_WEIGHT, "bold", ViewProps.FONT_STYLE, "italic"),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
CustomStyleSpan customStyleSpan =
getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isNotZero();
assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero();
}
@Test
public void testNormalFontWeightApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.FONT_WEIGHT, "normal"),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
CustomStyleSpan customStyleSpan =
getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isZero();
}
@Test
public void testNumericNormalFontWeightApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.FONT_WEIGHT, "200"),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
CustomStyleSpan customStyleSpan =
getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isZero();
}
@Test
public void testNormalFontStyleApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.FONT_STYLE, "normal"),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
CustomStyleSpan customStyleSpan =
getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isZero();
}
@Test
public void testFontFamilyStyleApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.FONT_FAMILY, "sans-serif"),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
CustomStyleSpan customStyleSpan =
getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
assertThat(customStyleSpan.getFontFamily()).isEqualTo("sans-serif");
assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isZero();
assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isZero();
}
@Test
public void testFontFamilyBoldStyleApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.FONT_FAMILY, "sans-serif", ViewProps.FONT_WEIGHT, "bold"),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
CustomStyleSpan customStyleSpan =
getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
assertThat(customStyleSpan.getFontFamily()).isEqualTo("sans-serif");
assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isZero();
assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero();
}
@Test
public void testFontFamilyItalicStyleApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.FONT_FAMILY, "sans-serif", ViewProps.FONT_STYLE, "italic"),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
CustomStyleSpan customStyleSpan =
getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
assertThat(customStyleSpan.getFontFamily()).isEqualTo("sans-serif");
assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isNotZero();
assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isZero();
}
@Test
public void testFontFamilyBoldItalicStyleApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(
ViewProps.FONT_FAMILY, "sans-serif",
ViewProps.FONT_WEIGHT, "500",
ViewProps.FONT_STYLE, "italic"),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
CustomStyleSpan customStyleSpan =
getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
assertThat(customStyleSpan.getFontFamily()).isEqualTo("sans-serif");
assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isNotZero();
assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero();
}
@Test
public void testBackgroundColorStyleApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.BACKGROUND_COLOR, Color.BLUE),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
Drawable backgroundDrawable = ((TextView) rootView.getChildAt(0)).getBackground();
assertThat(((ColorDrawable) backgroundDrawable).getColor()).isEqualTo(Color.BLUE);
}
// JELLY_BEAN is needed for TextView#getMaxLines(), which is OK, because in the actual code we
// only use TextView#setMaxLines() which exists since API Level 1.
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Test
public void testMaxLinesApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = createText(
uiManager,
SimpleMap.of(ViewProps.NUMBER_OF_LINES, 2),
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
TextView textView = (TextView) rootView.getChildAt(0);
assertThat(textView.getText().toString()).isEqualTo("test text");
assertThat(textView.getMaxLines()).isEqualTo(2);
assertThat(textView.getEllipsize()).isEqualTo(TextUtils.TruncateAt.END);
}
/**
* Make sure TextView has exactly one span and that span has given type.
*/
private static <TSPAN> TSPAN getSingleSpan(TextView textView, Class<TSPAN> spanClass) {
Spanned text = (Spanned) textView.getText();
TSPAN[] spans = text.getSpans(0, text.length(), spanClass);
assertThat(spans).hasSize(1);
return spans[0];
}
private ReactRootView createText(
UIManagerModule uiManager,
SimpleMap textProps,
SimpleMap rawTextProps) {
ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application);
int rootTag = uiManager.addMeasuredRootView(rootView);
int textTag = rootTag + 1;
int rawTextTag = textTag + 1;
uiManager.createView(
textTag,
ReactTextViewManager.REACT_CLASS,
rootTag,
textProps);
uiManager.createView(
rawTextTag,
ReactRawTextManager.REACT_CLASS,
rootTag,
rawTextProps);
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 void executePendingChoreographerCallbacks() {
ArrayList<Choreographer.FrameCallback> callbacks =
new ArrayList<>(mPendingChoreographerCallbacks);
mPendingChoreographerCallbacks.clear();
for (Choreographer.FrameCallback frameCallback : callbacks) {
frameCallback.doFrame(0);
}
}
public UIManagerModule getUIManagerModule() {
ReactApplicationContext reactContext = ReactTestHelper.createCatalystContextForTest();
List<ViewManager> viewManagers = Arrays.asList(
new ViewManager[] {
new ReactTextViewManager(),
new ReactRawTextManager(),
});
UIManagerModule uiManagerModule = new UIManagerModule(
reactContext,
viewManagers,
new UIImplementation(reactContext, viewManagers));
uiManagerModule.onHostResume();
return uiManagerModule;
}
}

View File

@ -0,0 +1,314 @@
/**
* 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.views.textinput;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.text.InputType;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.widget.EditText;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.ReactTestHelper;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.JSApplicationCausedNativeException;
import com.facebook.react.bridge.SimpleMap;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.views.text.DefaultStyleValuesUtil;
import com.facebook.react.uimanager.ThemedReactContext;
import org.junit.Before;
import org.junit.Test;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import static org.fest.assertions.api.Assertions.assertThat;
/**
* Verify {@link EditText} view property being applied properly by {@link ReactTextInputManager}
*/
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class ReactTextInputPropertyTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
private ReactApplicationContext mContext;
private CatalystInstance mCatalystInstanceMock;
private ThemedReactContext mThemedContext;
private ReactTextInputManager mManager;
@Before
public void setup() {
mContext = new ReactApplicationContext(RuntimeEnvironment.application);
mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance();
mContext.initializeWithInstance(mCatalystInstanceMock);
mThemedContext = new ThemedReactContext(mContext, mContext);
mManager = new ReactTextInputManager();
DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
}
public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
}
@Test
public void testAutoCorrect() {
ReactEditText view = mManager.createViewInstance(mThemedContext);
mManager.updateProperties(view, buildStyles());
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isZero();
mManager.updateProperties(view, buildStyles("autoCorrect", true));
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isNotZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isZero();
mManager.updateProperties(view, buildStyles("autoCorrect", false));
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isNotZero();
mManager.updateProperties(view, buildStyles("autoCorrect", null));
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isZero();
}
@Test
public void testAutoCapitalize() {
ReactEditText view = mManager.createViewInstance(mThemedContext);
mManager.updateProperties(view, buildStyles());
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_WORDS).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS).isZero();
mManager.updateProperties(
view,
buildStyles("autoCapitalize", InputType.TYPE_TEXT_FLAG_CAP_SENTENCES));
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isNotZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_WORDS).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS).isZero();
mManager.updateProperties(
view,
buildStyles("autoCapitalize", InputType.TYPE_TEXT_FLAG_CAP_WORDS));
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_WORDS).isNotZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS).isZero();
mManager.updateProperties(
view,
buildStyles("autoCapitalize", InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS));
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_WORDS).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS).isNotZero();
mManager.updateProperties(
view,
buildStyles("autoCapitalize", InputType.TYPE_CLASS_TEXT));
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_WORDS).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS).isZero();
}
@Test
public void testPlaceholder() {
ReactEditText view = mManager.createViewInstance(mThemedContext);
mManager.updateProperties(view, buildStyles());
assertThat(view.getHint()).isNull();
mManager.updateProperties(view, buildStyles("placeholder", "sometext"));
assertThat(view.getHint()).isEqualTo("sometext");
mManager.updateProperties(view, buildStyles("placeholder", null));
assertThat(view.getHint()).isNull();
}
@Test
public void testEditable() {
ReactEditText view = mManager.createViewInstance(mThemedContext);
mManager.updateProperties(view, buildStyles());
assertThat(view.isEnabled()).isTrue();
mManager.updateProperties(view, buildStyles("editable", false));
assertThat(view.isEnabled()).isFalse();
mManager.updateProperties(view, buildStyles("editable", null));
assertThat(view.isEnabled()).isTrue();
mManager.updateProperties(view, buildStyles("editable", false));
assertThat(view.isEnabled()).isFalse();
mManager.updateProperties(view, buildStyles("editable", true));
assertThat(view.isEnabled()).isTrue();
}
@Test
public void testPlaceholderTextColor() {
ReactEditText view = mManager.createViewInstance(mThemedContext);
final ColorStateList defaultPlaceholderColorStateList =
DefaultStyleValuesUtil.getDefaultTextColorHint(
view.getContext());
ColorStateList colors = view.getHintTextColors();
assertThat(colors).isEqualTo(defaultPlaceholderColorStateList);
mManager.updateProperties(view, buildStyles("placeholderTextColor", null));
colors = view.getHintTextColors();
assertThat(colors).isEqualTo(defaultPlaceholderColorStateList);
mManager.updateProperties(view, buildStyles("placeholderTextColor", Color.RED));
colors = view.getHintTextColors();
assertThat(colors.getDefaultColor()).isEqualTo(Color.RED);
mManager.updateProperties(view, buildStyles("placeholderTextColor", null));
colors = view.getHintTextColors();
assertThat(colors).isEqualTo(defaultPlaceholderColorStateList);
}
@Test
public void testMultiline() {
ReactEditText view = mManager.createViewInstance(mThemedContext);
mManager.updateProperties(view, buildStyles());
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isZero();
mManager.updateProperties(view, buildStyles("multiline", false));
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isZero();
mManager.updateProperties(view, buildStyles("multiline", true));
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isNotZero();
mManager.updateProperties(view, buildStyles("multiline", null));
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isZero();
}
@Test
public void testNumLines() {
ReactEditText view = mManager.createViewInstance(mThemedContext);
mManager.updateProperties(view, buildStyles());
assertThat(view.getMinLines()).isEqualTo(1);
mManager.updateProperties(view, buildStyles("numberOfLines", 5));
assertThat(view.getMinLines()).isEqualTo(5);
mManager.updateProperties(view, buildStyles("numberOfLines", 4));
assertThat(view.getMinLines()).isEqualTo(4);
}
@Test
public void testKeyboardType() {
ReactEditText view = mManager.createViewInstance(mThemedContext);
mManager.updateProperties(view, buildStyles());
assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isZero();
mManager.updateProperties(view, buildStyles("keyboardType", "text"));
assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isZero();
mManager.updateProperties(view, buildStyles("keyboardType", "numeric"));
assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isNotZero();
mManager.updateProperties(view, buildStyles("keyboardType", "email-address"));
assertThat(view.getInputType() & InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS).isNotZero();
mManager.updateProperties(view, buildStyles("keyboardType", null));
assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isZero();
}
@Test
public void testPasswordInput() {
ReactEditText view = mManager.createViewInstance(mThemedContext);
mManager.updateProperties(view, buildStyles());
assertThat(view.getInputType() & InputType.TYPE_TEXT_VARIATION_PASSWORD).isZero();
mManager.updateProperties(view, buildStyles("password", false));
assertThat(view.getInputType() & InputType.TYPE_TEXT_VARIATION_PASSWORD).isZero();
mManager.updateProperties(view, buildStyles("password", true));
assertThat(view.getInputType() & InputType.TYPE_TEXT_VARIATION_PASSWORD).isNotZero();
mManager.updateProperties(view, buildStyles("password", null));
assertThat(view.getInputType() & InputType.TYPE_TEXT_VARIATION_PASSWORD).isZero();
}
@Test
public void testIncrementalInputTypeUpdates() {
ReactEditText view = mManager.createViewInstance(mThemedContext);
mManager.updateProperties(view, buildStyles());
assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isZero();
mManager.updateProperties(view, buildStyles("multiline", true));
assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isNotZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isZero();
mManager.updateProperties(view, buildStyles("autoCorrect", false));
assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isNotZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isNotZero();
mManager.updateProperties(view, buildStyles("keyboardType", "NUMERIC"));
assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isNotZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isNotZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isNotZero();
mManager.updateProperties(view, buildStyles("multiline", null));
assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isNotZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isNotZero();
}
@Test
public void testTextAlign() {
ReactEditText view = mManager.createViewInstance(mThemedContext);
int gravity = view.getGravity();
assertThat(view.getGravity() & Gravity.BOTTOM).isNotEqualTo(Gravity.BOTTOM);
mManager.updateProperties(view, buildStyles("textAlignVertical", "bottom"));
assertThat(view.getGravity() & Gravity.BOTTOM).isEqualTo(Gravity.BOTTOM);
mManager.updateProperties(
view,
buildStyles("textAlign", "right", "textAlignVertical", "top"));
assertThat(view.getGravity() & Gravity.BOTTOM).isNotEqualTo(Gravity.BOTTOM);
assertThat(view.getGravity() & (Gravity.RIGHT | Gravity.TOP))
.isEqualTo(Gravity.RIGHT | Gravity.TOP);
mManager.updateProperties(
view,
buildStyles("textAlignVertical", null));
assertThat(view.getGravity() & Gravity.RIGHT).isEqualTo(Gravity.RIGHT);
assertThat(view.getGravity() & Gravity.TOP).isNotEqualTo(Gravity.TOP);
mManager.updateProperties(view, buildStyles("textAlign", null));
assertThat(view.getGravity()).isEqualTo(gravity);
}
}

View File

@ -0,0 +1,191 @@
/**
* 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.views.textinput;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.view.Choreographer;
import android.widget.EditText;
import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactTestHelper;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.SimpleArray;
import com.facebook.react.bridge.SimpleMap;
import com.facebook.react.uimanager.ReactChoreographer;
import com.facebook.react.uimanager.UIImplementation;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.uimanager.ViewProps;
import org.junit.Before;
import org.junit.Test;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.Robolectric;
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;
/**
* Tests for TextInput.
*/
@PrepareForTest({Arguments.class, ReactChoreographer.class})
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class TextInputTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
private ArrayList<Choreographer.FrameCallback> mPendingChoreographerCallbacks;
@Before
public void setUp() {
PowerMockito.mockStatic(Arguments.class, ReactChoreographer.class);
ReactChoreographer choreographerMock = mock(ReactChoreographer.class);
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));
}
@Test
public void testPropsApplied() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application);
int rootTag = uiManager.addMeasuredRootView(rootView);
int textInputTag = rootTag + 1;
final String hintStr = "placeholder text";
uiManager.createView(
textInputTag,
ReactTextInputManager.REACT_CLASS,
rootTag,
SimpleMap.of(
ViewProps.FONT_SIZE, 13.37, ViewProps.HEIGHT, 20.0, "placeholder", hintStr));
uiManager.manageChildren(
rootTag,
null,
null,
SimpleArray.of(textInputTag),
SimpleArray.of(0),
null);
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
EditText editText = (EditText) rootView.getChildAt(0);
assertThat(editText.getHint()).isEqualTo(hintStr);
assertThat(editText.getTextSize()).isEqualTo((float) Math.ceil(13.37));
assertThat(editText.getHeight()).isEqualTo(20);
}
@Test
public void testPropsUpdate() {
UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application);
int rootTag = uiManager.addMeasuredRootView(rootView);
int textInputTag = rootTag + 1;
final String hintStr = "placeholder text";
uiManager.createView(
textInputTag,
ReactTextInputManager.REACT_CLASS,
rootTag,
SimpleMap.of(
ViewProps.FONT_SIZE, 13.37, ViewProps.HEIGHT, 20.0, "placeholder", hintStr));
uiManager.manageChildren(
rootTag,
null,
null,
SimpleArray.of(textInputTag),
SimpleArray.of(0),
null);
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
EditText editText = (EditText) rootView.getChildAt(0);
assertThat(editText.getHint()).isEqualTo(hintStr);
assertThat(editText.getTextSize()).isEqualTo((float) Math.ceil(13.37));
assertThat(editText.getHeight()).isEqualTo(20);
final String hintStr2 = "such hint";
uiManager.updateView(
textInputTag,
ReactTextInputManager.REACT_CLASS,
SimpleMap.of(
ViewProps.FONT_SIZE, 26.74, ViewProps.HEIGHT, 40.0, "placeholder", hintStr2));
uiManager.onBatchComplete();
executePendingChoreographerCallbacks();
EditText updatedEditText = (EditText) rootView.getChildAt(0);
assertThat(updatedEditText.getHint()).isEqualTo(hintStr2);
assertThat(updatedEditText.getTextSize()).isEqualTo((float) Math.ceil(26.74f));
assertThat(updatedEditText.getHeight()).isEqualTo(40);
}
private void executePendingChoreographerCallbacks() {
ArrayList<Choreographer.FrameCallback> callbacks =
new ArrayList<>(mPendingChoreographerCallbacks);
mPendingChoreographerCallbacks.clear();
for (Choreographer.FrameCallback frameCallback : callbacks) {
frameCallback.doFrame(0);
}
}
public UIManagerModule getUIManagerModule() {
ReactApplicationContext reactContext = ReactTestHelper.createCatalystContextForTest();
List<ViewManager> viewManagers = Arrays.asList(
new ViewManager[] {
new ReactTextInputManager(),
});
UIManagerModule uiManagerModule = new UIManagerModule(
reactContext,
viewManagers,
new UIImplementation(reactContext, viewManagers));
uiManagerModule.onHostResume();
return uiManagerModule;
}
}

View File

@ -0,0 +1,53 @@
/**
* 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.views.view;
import android.graphics.PixelFormat;
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 static org.junit.Assert.*;
/**
* Based on Fresco's DrawableUtilsTest (https://github.com/facebook/fresco).
*/
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class ColorUtilTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
@Test
public void testMultiplyColorAlpha() {
assertEquals(0x00123456, ColorUtil.multiplyColorAlpha(0xC0123456, 0));
assertEquals(0x07123456, ColorUtil.multiplyColorAlpha(0xC0123456, 10));
assertEquals(0x96123456, ColorUtil.multiplyColorAlpha(0xC0123456, 200));
assertEquals(0xC0123456, ColorUtil.multiplyColorAlpha(0xC0123456, 255));
}
@Test
public void testGetOpacityFromColor() {
assertEquals(PixelFormat.TRANSPARENT, ColorUtil.getOpacityFromColor(0x00000000));
assertEquals(PixelFormat.TRANSPARENT, ColorUtil.getOpacityFromColor(0x00123456));
assertEquals(PixelFormat.TRANSPARENT, ColorUtil.getOpacityFromColor(0x00FFFFFF));
assertEquals(PixelFormat.TRANSLUCENT, ColorUtil.getOpacityFromColor(0xC0000000));
assertEquals(PixelFormat.TRANSLUCENT, ColorUtil.getOpacityFromColor(0xC0123456));
assertEquals(PixelFormat.TRANSLUCENT, ColorUtil.getOpacityFromColor(0xC0FFFFFF));
assertEquals(PixelFormat.OPAQUE, ColorUtil.getOpacityFromColor(0xFF000000));
assertEquals(PixelFormat.OPAQUE, ColorUtil.getOpacityFromColor(0xFF123456));
assertEquals(PixelFormat.OPAQUE, ColorUtil.getOpacityFromColor(0xFFFFFFFF));
}
}