Open sourced CatalystUIManagerTestCase test for RN Android
Reviewed By: bestander Differential Revision: D3436688 fbshipit-source-id: bed53f8f4aa8346d6f808c2d79eb9c279c2cd078
This commit is contained in:
Родитель
2fc0f4041e
Коммит
e3b5948392
|
@ -0,0 +1,250 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2013-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.tests;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.facebook.react.ReactRootView;
|
||||||
|
import com.facebook.react.bridge.JavaScriptModule;
|
||||||
|
import com.facebook.react.bridge.UiThreadUtil;
|
||||||
|
import com.facebook.react.modules.systeminfo.AndroidInfoModule;
|
||||||
|
import com.facebook.react.uimanager.PixelUtil;
|
||||||
|
import com.facebook.react.uimanager.UIImplementation;
|
||||||
|
import com.facebook.react.uimanager.UIManagerModule;
|
||||||
|
import com.facebook.react.uimanager.ViewManager;
|
||||||
|
import com.facebook.react.views.text.ReactRawTextManager;
|
||||||
|
import com.facebook.react.views.text.ReactTextViewManager;
|
||||||
|
import com.facebook.react.views.view.ReactViewManager;
|
||||||
|
import com.facebook.react.testing.ReactIntegrationTestCase;
|
||||||
|
import com.facebook.react.testing.ReactTestHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test case for basic {@link UIManagerModule} functionality.
|
||||||
|
*/
|
||||||
|
public class CatalystUIManagerTestCase extends ReactIntegrationTestCase {
|
||||||
|
private interface UIManagerTestModule extends JavaScriptModule {
|
||||||
|
void renderFlexTestApplication(int rootTag);
|
||||||
|
void renderFlexWithTextApplication(int rootTag);
|
||||||
|
void renderAbsolutePositionTestApplication(int rootTag);
|
||||||
|
void renderAbsolutePositionBottomRightTestApplication(int rootTag);
|
||||||
|
void renderCenteredTextViewTestApplication(int rootTag, String text);
|
||||||
|
void renderUpdatePositionInListTestApplication(int rootTag);
|
||||||
|
void flushUpdatePositionInList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private UIManagerTestModule jsModule;
|
||||||
|
private UIManagerModule uiManager;
|
||||||
|
|
||||||
|
private int inPixelRounded(int val) {
|
||||||
|
return Math.round(PixelUtil.toPixelFromDIP(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isWithinRange(float value, float lower, float upper) {
|
||||||
|
return value >= lower && value <= upper;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReactRootView createRootView() {
|
||||||
|
ReactRootView rootView = new ReactRootView(getContext());
|
||||||
|
final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
|
||||||
|
rootView.setLayoutParams(
|
||||||
|
new FrameLayout.LayoutParams(metrics.widthPixels, metrics.heightPixels));
|
||||||
|
uiManager.addMeasuredRootView(rootView);
|
||||||
|
// We add the root view by posting to the main thread so wait for that to complete so that the
|
||||||
|
// root view tag is added to the view
|
||||||
|
waitForIdleSync();
|
||||||
|
return rootView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
List<ViewManager> viewManagers = Arrays.<ViewManager>asList(
|
||||||
|
new ReactViewManager(),
|
||||||
|
new ReactTextViewManager(),
|
||||||
|
new ReactRawTextManager());
|
||||||
|
uiManager = new UIManagerModule(
|
||||||
|
getContext(),
|
||||||
|
viewManagers,
|
||||||
|
new UIImplementation(getContext(), viewManagers));
|
||||||
|
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
uiManager.onHostResume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
waitForIdleSync();
|
||||||
|
|
||||||
|
jsModule = ReactTestHelper.catalystInstanceBuilder(this)
|
||||||
|
.addNativeModule(uiManager)
|
||||||
|
.addNativeModule(new AndroidInfoModule())
|
||||||
|
.addJSModule(UIManagerTestModule.class)
|
||||||
|
.build()
|
||||||
|
.getJSModule(UIManagerTestModule.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFlexUIRendered() {
|
||||||
|
FrameLayout rootView = createRootView();
|
||||||
|
jsModule.renderFlexTestApplication(rootView.getId());
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
|
||||||
|
assertEquals(1, rootView.getChildCount());
|
||||||
|
|
||||||
|
ViewGroup container = getViewByTestId(rootView, "container");
|
||||||
|
assertEquals(inPixelRounded(200), container.getWidth());
|
||||||
|
assertEquals(inPixelRounded(200), container.getHeight());
|
||||||
|
assertEquals(2, container.getChildCount());
|
||||||
|
|
||||||
|
View child0 = container.getChildAt(0);
|
||||||
|
assertEquals(inPixelRounded(100), child0.getWidth());
|
||||||
|
assertEquals(inPixelRounded(200), child0.getHeight());
|
||||||
|
|
||||||
|
View child1 = container.getChildAt(1);
|
||||||
|
assertEquals(inPixelRounded(100), child1.getWidth());
|
||||||
|
assertEquals(inPixelRounded(200), child1.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFlexWithTextViews() {
|
||||||
|
FrameLayout rootView = createRootView();
|
||||||
|
jsModule.renderFlexWithTextApplication(rootView.getId());
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
|
||||||
|
assertEquals(1, rootView.getChildCount());
|
||||||
|
|
||||||
|
ViewGroup container = getViewByTestId(rootView, "container");
|
||||||
|
assertEquals(inPixelRounded(300), container.getHeight());
|
||||||
|
assertEquals(1, container.getChildCount());
|
||||||
|
|
||||||
|
ViewGroup row = (ViewGroup) container.getChildAt(0);
|
||||||
|
assertEquals(inPixelRounded(300), row.getHeight());
|
||||||
|
assertEquals(2, row.getChildCount());
|
||||||
|
|
||||||
|
// Text measurement adds padding that isn't completely dependent on density so we can't easily
|
||||||
|
// get an exact value here
|
||||||
|
float approximateExpectedTextHeight = inPixelRounded(19);
|
||||||
|
View leftText = row.getChildAt(0);
|
||||||
|
assertTrue(
|
||||||
|
isWithinRange(
|
||||||
|
leftText.getHeight(),
|
||||||
|
approximateExpectedTextHeight - PixelUtil.toPixelFromDIP(1),
|
||||||
|
approximateExpectedTextHeight + PixelUtil.toPixelFromDIP(1)));
|
||||||
|
assertEquals(row.getWidth() / 2 - inPixelRounded(20), leftText.getWidth());
|
||||||
|
assertEquals(inPixelRounded(290), (leftText.getTop() + leftText.getHeight()));
|
||||||
|
|
||||||
|
View rightText = row.getChildAt(1);
|
||||||
|
assertTrue(
|
||||||
|
isWithinRange(
|
||||||
|
rightText.getHeight(),
|
||||||
|
approximateExpectedTextHeight - PixelUtil.toPixelFromDIP(1),
|
||||||
|
approximateExpectedTextHeight + PixelUtil.toPixelFromDIP(1)));
|
||||||
|
assertEquals(leftText.getWidth(), rightText.getWidth());
|
||||||
|
assertEquals(leftText.getTop(), rightText.getTop());
|
||||||
|
assertEquals(leftText.getWidth() + inPixelRounded(30), rightText.getLeft());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAbsolutePositionUIRendered() {
|
||||||
|
FrameLayout rootView = createRootView();
|
||||||
|
jsModule.renderAbsolutePositionTestApplication(rootView.getId());
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
|
||||||
|
assertEquals(1, rootView.getChildCount());
|
||||||
|
|
||||||
|
View absoluteView = getViewByTestId(rootView, "absolute");
|
||||||
|
assertEquals(inPixelRounded(50), absoluteView.getWidth());
|
||||||
|
assertEquals(inPixelRounded(60), absoluteView.getHeight());
|
||||||
|
assertEquals(inPixelRounded(10), absoluteView.getLeft());
|
||||||
|
assertEquals(inPixelRounded(15), absoluteView.getTop());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testUpdatePositionInList() {
|
||||||
|
FrameLayout rootView = createRootView();
|
||||||
|
jsModule.renderUpdatePositionInListTestApplication(rootView.getId());
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
|
||||||
|
ViewGroup containerView = getViewByTestId(rootView, "container");
|
||||||
|
View c0 = containerView.getChildAt(0);
|
||||||
|
View c1 = containerView.getChildAt(1);
|
||||||
|
View c2 = containerView.getChildAt(2);
|
||||||
|
|
||||||
|
assertEquals(inPixelRounded(10), c0.getHeight());
|
||||||
|
assertEquals(inPixelRounded(0), c0.getTop());
|
||||||
|
assertEquals(inPixelRounded(10), c1.getHeight());
|
||||||
|
assertEquals(inPixelRounded(10), c1.getTop());
|
||||||
|
assertEquals(inPixelRounded(10), c2.getHeight());
|
||||||
|
assertEquals(inPixelRounded(20), c2.getTop());
|
||||||
|
|
||||||
|
// Let's make the second elements 50px height instead of 10px
|
||||||
|
jsModule.flushUpdatePositionInList();
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
|
||||||
|
assertEquals(inPixelRounded(10), c0.getHeight());
|
||||||
|
assertEquals(inPixelRounded(0), c0.getTop());
|
||||||
|
assertEquals(inPixelRounded(50), c1.getHeight());
|
||||||
|
assertEquals(inPixelRounded(10), c1.getTop());
|
||||||
|
assertEquals(inPixelRounded(10), c2.getHeight());
|
||||||
|
assertEquals(inPixelRounded(60), c2.getTop());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAbsolutePositionBottomRightUIRendered() {
|
||||||
|
FrameLayout rootView = createRootView();
|
||||||
|
jsModule.renderAbsolutePositionBottomRightTestApplication(rootView.getId());
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
|
||||||
|
assertEquals(1, rootView.getChildCount());
|
||||||
|
|
||||||
|
ViewGroup containerView = getViewByTestId(rootView, "container");
|
||||||
|
View absoluteView = containerView.getChildAt(0);
|
||||||
|
|
||||||
|
assertEquals(inPixelRounded(50), absoluteView.getWidth());
|
||||||
|
assertEquals(inPixelRounded(60), absoluteView.getHeight());
|
||||||
|
assertEquals(inPixelRounded(100 - 50 - 10), Math.round(absoluteView.getLeft()));
|
||||||
|
assertEquals(inPixelRounded(100 - 60 - 15), Math.round(absoluteView.getTop()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void _testCenteredText(String text) {
|
||||||
|
ReactRootView rootView = new ReactRootView(getContext());
|
||||||
|
int rootTag = uiManager.addMeasuredRootView(rootView);
|
||||||
|
|
||||||
|
jsModule.renderCenteredTextViewTestApplication(rootTag, text);
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
|
||||||
|
TextView textView = getViewByTestId(rootView, "text");
|
||||||
|
|
||||||
|
// text view should be centered
|
||||||
|
String msg = "text `" + text + "` is not centered";
|
||||||
|
assertTrue(msg, textView.getLeft() > 0.1);
|
||||||
|
assertTrue(msg, textView.getTop() > 0.1);
|
||||||
|
assertEquals(
|
||||||
|
msg,
|
||||||
|
(int) Math.ceil((inPixelRounded(200) - textView.getWidth()) * 0.5f),
|
||||||
|
textView.getLeft());
|
||||||
|
assertEquals(
|
||||||
|
msg,
|
||||||
|
(int) Math.ceil((inPixelRounded(100) - textView.getHeight()) * 0.5f),
|
||||||
|
textView.getTop());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCenteredTextCases() {
|
||||||
|
String[] cases = new String[] {
|
||||||
|
"test",
|
||||||
|
"with whitespace",
|
||||||
|
};
|
||||||
|
for (String text : cases) {
|
||||||
|
_testCenteredText(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ require('ViewRenderingTestModule');
|
||||||
require('TestJavaToJSArgumentsModule');
|
require('TestJavaToJSArgumentsModule');
|
||||||
require('TestJSLocaleModule');
|
require('TestJSLocaleModule');
|
||||||
require('TestJSToJavaParametersModule');
|
require('TestJSToJavaParametersModule');
|
||||||
|
require('UIManagerTestModule');
|
||||||
|
|
||||||
require('CatalystRootViewTestModule');
|
require('CatalystRootViewTestModule');
|
||||||
require('DatePickerDialogTestModule');
|
require('DatePickerDialogTestModule');
|
||||||
|
|
|
@ -0,0 +1,202 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2013-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.
|
||||||
|
*
|
||||||
|
* @providesModule UIManagerTestModule
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var BatchedBridge = require('BatchedBridge');
|
||||||
|
var React = require('React');
|
||||||
|
var StyleSheet = require('StyleSheet');
|
||||||
|
var View = require('View');
|
||||||
|
var Text = require('Text');
|
||||||
|
|
||||||
|
var renderApplication = require('renderApplication');
|
||||||
|
|
||||||
|
var FlexTestApp = React.createClass({
|
||||||
|
_styles: StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
width: 200,
|
||||||
|
height: 200,
|
||||||
|
flexDirection: 'row',
|
||||||
|
},
|
||||||
|
child: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
absolute: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 15,
|
||||||
|
left: 10,
|
||||||
|
width: 50,
|
||||||
|
height: 60,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<View style={this._styles.container} testID="container" collapsable={false}>
|
||||||
|
<View style={[this._styles.child, {backgroundColor: '#ff0000'}]} collapsable={false}/>
|
||||||
|
<View style={[this._styles.child, {backgroundColor: '#0000ff'}]} collapsable={false}/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var FlexWithText = React.createClass({
|
||||||
|
_styles: StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
margin: 20,
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'flex-end',
|
||||||
|
height: 300,
|
||||||
|
},
|
||||||
|
inner: {
|
||||||
|
flex: 1,
|
||||||
|
margin: 10,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<View style={this._styles.container} testID="container" collapsable={false}>
|
||||||
|
<View style={this._styles.row} collapsable={false}>
|
||||||
|
<Text style={this._styles.inner}>Hello</Text>
|
||||||
|
<Text style={this._styles.inner}>World</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var AbsolutePositionTestApp = React.createClass({
|
||||||
|
_styles: StyleSheet.create({
|
||||||
|
absolute: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 15,
|
||||||
|
left: 10,
|
||||||
|
width: 50,
|
||||||
|
height: 60,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
render: function() {
|
||||||
|
return <View style={this._styles.absolute} testID="absolute" collapsable={false}/>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var AbsolutePositionBottomRightTestApp = React.createClass({
|
||||||
|
_styles: StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
},
|
||||||
|
absolute: {
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 15,
|
||||||
|
right: 10,
|
||||||
|
width: 50,
|
||||||
|
height: 60,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<View style={this._styles.container} testID="container" collapsable={false}>
|
||||||
|
<View style={this._styles.absolute} collapsable={false}/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var CenteredTextView = React.createClass({
|
||||||
|
_styles: StyleSheet.create({
|
||||||
|
parent: {
|
||||||
|
width: 200,
|
||||||
|
height: 100,
|
||||||
|
backgroundColor: '#aa3311',
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontSize: 15,
|
||||||
|
color: '#672831',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<View collapsable={false}>
|
||||||
|
<View style={this._styles.parent} collapsable={false}>
|
||||||
|
<Text style={this._styles.text} testID="text">{this.props.text}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var flushUpdatePositionInList = null;
|
||||||
|
var UpdatePositionInListTestApp = React.createClass({
|
||||||
|
_styles: StyleSheet.create({
|
||||||
|
element: {
|
||||||
|
height: 10,
|
||||||
|
},
|
||||||
|
active: {
|
||||||
|
height: 50,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
getInitialState: function() {
|
||||||
|
flushUpdatePositionInList = () => this.setState({ active: true });
|
||||||
|
return { active: false };
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<View collapsable={false} testID="container">
|
||||||
|
<View style={this._styles.element} collapsable={false} />
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
this._styles.element,
|
||||||
|
this.state.active && this._styles.active,
|
||||||
|
]}
|
||||||
|
collapsable={false}
|
||||||
|
/>
|
||||||
|
<View style={this._styles.element} collapsable={false}/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var UIManagerTestModule = {
|
||||||
|
renderFlexTestApplication: function(rootTag) {
|
||||||
|
renderApplication(FlexTestApp, {}, rootTag);
|
||||||
|
},
|
||||||
|
renderFlexWithTextApplication: function(rootTag) {
|
||||||
|
renderApplication(FlexWithText, {}, rootTag);
|
||||||
|
},
|
||||||
|
renderAbsolutePositionBottomRightTestApplication: function(rootTag) {
|
||||||
|
renderApplication(AbsolutePositionBottomRightTestApp, {}, rootTag);
|
||||||
|
},
|
||||||
|
renderAbsolutePositionTestApplication: function(rootTag) {
|
||||||
|
renderApplication(AbsolutePositionTestApp, {}, rootTag);
|
||||||
|
},
|
||||||
|
renderCenteredTextViewTestApplication: function(rootTag, text) {
|
||||||
|
renderApplication(CenteredTextView, {text: text}, rootTag);
|
||||||
|
},
|
||||||
|
renderUpdatePositionInListTestApplication: function(rootTag) {
|
||||||
|
renderApplication(UpdatePositionInListTestApp, {}, rootTag);
|
||||||
|
},
|
||||||
|
flushUpdatePositionInList: function() {
|
||||||
|
flushUpdatePositionInList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BatchedBridge.registerCallableModule(
|
||||||
|
'UIManagerTestModule',
|
||||||
|
UIManagerTestModule
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = UIManagerTestModule;
|
Загрузка…
Ссылка в новой задаче