diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/InitialPropsTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/InitialPropsTestCase.java new file mode 100644 index 000000000..6f532e15c --- /dev/null +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/InitialPropsTestCase.java @@ -0,0 +1,127 @@ +/** + * Copyright (c) 2014-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 android.os.Bundle; +import android.test.ActivityInstrumentationTestCase2; + +import com.facebook.react.bridge.BaseJavaModule; +import com.facebook.react.testing.ReactInstanceSpecForTest; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.testing.ReactAppTestActivity; + +/** + * Simple test case for passing initial props to the root React application. + */ +public class InitialPropsTestCase extends + ActivityInstrumentationTestCase2 { + + public static final String DEFAULT_JS_BUNDLE = "AndroidTestBundle.js"; + + private static class RecordingModule extends BaseJavaModule { + private int mCount = 0; + private ReadableMap mProps; + + @Override + public String getName() { + return "InitialPropsRecordingModule"; + } + + @ReactMethod + public void recordProps(ReadableMap props) { + mProps = props; + mCount++; + } + + public int getCount() { + return mCount; + } + + public ReadableMap getProps() { + return mProps; + } + } + + private RecordingModule mRecordingModule; + + public InitialPropsTestCase() { + super(ReactAppTestActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mRecordingModule = new RecordingModule(); + } + + public void testInitialProps() throws Throwable { + final ReactAppTestActivity activity = getActivity(); + runTestOnUiThread( + new Runnable() { + @Override + public void run() { + ReactInstanceSpecForTest catalystInstanceSpec = new ReactInstanceSpecForTest(); + catalystInstanceSpec.addNativeModule(mRecordingModule); + Bundle props = new Bundle(); + props.putString("key1", "string"); + props.putInt("key2", 5); + props.putDouble("key3", 5.5); + props.putFloat("key4", 5.6f); + props.putBoolean("key5", true); + props.putStringArray("key6", new String[]{"one", "two", "three"}); + props.putIntArray("key7", new int[]{1, 2, 3}); + props.putDoubleArray("key8", new double[]{1.5, 2.5, 3.5}); + props.putFloatArray("key9", new float[]{1.6f, 2.6f, 3.6f}); + props.putBooleanArray("key10", new boolean[]{true, false}); + activity.loadApp( + "InitialPropsTestApp", + catalystInstanceSpec, + props, + DEFAULT_JS_BUNDLE, + false); + } + }); + activity.waitForBridgeAndUIIdle(); + + assertEquals(1, mRecordingModule.getCount()); + ReadableMap props = mRecordingModule.getProps(); + assertEquals("string", props.getString("key1")); + assertEquals(5, props.getInt("key2")); + assertEquals(5.5, props.getDouble("key3")); + assertEquals(5.6f, (float) props.getDouble("key4")); + assertEquals(true, props.getBoolean("key5")); + + ReadableArray stringArray = props.getArray("key6"); + assertEquals("one", stringArray.getString(0)); + assertEquals("two", stringArray.getString(1)); + assertEquals("three", stringArray.getString(2)); + + ReadableArray intArray = props.getArray("key7"); + assertEquals(1, intArray.getInt(0)); + assertEquals(2, intArray.getInt(1)); + assertEquals(3, intArray.getInt(2)); + + ReadableArray doubleArray = props.getArray("key8"); + assertEquals(1.5, doubleArray.getDouble(0)); + assertEquals(2.5, doubleArray.getDouble(1)); + assertEquals(3.5, doubleArray.getDouble(2)); + + ReadableArray floatArray = props.getArray("key9"); + assertEquals(1.6f, (float) floatArray.getDouble(0)); + assertEquals(2.6f, (float) floatArray.getDouble(1)); + assertEquals(3.6f, (float) floatArray.getDouble(2)); + + ReadableArray booleanArray = props.getArray("key10"); + assertEquals(true, booleanArray.getBoolean(0)); + assertEquals(false, booleanArray.getBoolean(1)); + } +} diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/JSLocaleTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/JSLocaleTest.java new file mode 100644 index 000000000..370f353c3 --- /dev/null +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/JSLocaleTest.java @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2014-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 com.facebook.react.testing.ReactIntegrationTestCase; +import com.facebook.react.testing.ReactTestHelper; +import com.facebook.react.testing.StringRecordingModule; +import com.facebook.react.bridge.CatalystInstance; +import com.facebook.react.bridge.JavaScriptModule; +import com.facebook.react.bridge.UiThreadUtil; +import com.facebook.react.uimanager.UIImplementation; +import com.facebook.react.uimanager.UIManagerModule; +import com.facebook.react.uimanager.ViewManager; +import com.facebook.react.views.view.ReactViewManager; + +/** + * Test locale-based functionality of JS VM + */ +public class JSLocaleTest extends ReactIntegrationTestCase { + + private interface TestJSLocaleModule extends JavaScriptModule { + void toUpper(String string); + void toLower(String string); + } + + StringRecordingModule mStringRecordingModule; + + private CatalystInstance mInstance; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + List viewManagers = Arrays.asList( + new ReactViewManager()); + final UIManagerModule mUIManager = new UIManagerModule( + getContext(), + viewManagers, + new UIImplementation(getContext(), viewManagers)); + UiThreadUtil.runOnUiThread( + new Runnable() { + @Override + public void run() { + mUIManager.onHostResume(); + } + }); + waitForIdleSync(); + + mStringRecordingModule = new StringRecordingModule(); + mInstance = ReactTestHelper.catalystInstanceBuilder(this) + .addNativeModule(mStringRecordingModule) + .addNativeModule(mUIManager) + .addJSModule(TestJSLocaleModule.class) + .build(); + + } + + public void testToUpper() { + TestJSLocaleModule testModule = mInstance.getJSModule(TestJSLocaleModule.class); + waitForBridgeAndUIIdle(); + + testModule.toUpper("test"); + testModule.toUpper("W niżach mógł zjeść truflę koń bądź psy"); + testModule.toUpper("Шеф взъярён тчк щипцы с эхом гудбай Жюль"); + testModule.toUpper("Γαζίες καὶ μυρτιὲς δὲν θὰ βρῶ πιὰ στὸ χρυσαφὶ ξέφωτο"); + testModule.toUpper("chinese: 幓 厏吪吙 鈊釿閍 碞碠粻 曮禷"); + waitForBridgeAndUIIdle(); + + String[] answers = mStringRecordingModule.getCalls().toArray(new String[0]); + assertEquals("TEST", answers[0]); + assertEquals("W NIŻACH MÓGŁ ZJEŚĆ TRUFLĘ KOŃ BĄDŹ PSY", answers[1]); + assertEquals("ШЕФ ВЗЪЯРЁН ТЧК ЩИПЦЫ С ЭХОМ ГУДБАЙ ЖЮЛЬ", answers[2]); + assertEquals("ΓΑΖΊΕΣ ΚΑῚ ΜΥΡΤΙῈΣ ΔῈΝ ΘᾺ ΒΡΩ͂ ΠΙᾺ ΣΤῸ ΧΡΥΣΑΦῚ ΞΈΦΩΤΟ", answers[3]); + assertEquals("CHINESE: 幓 厏吪吙 鈊釿閍 碞碠粻 曮禷", answers[4]); + } + + public void testToLower() { + TestJSLocaleModule testModule = mInstance.getJSModule(TestJSLocaleModule.class); + + testModule.toLower("TEST"); + testModule.toLower("W NIŻACH MÓGŁ ZJEŚĆ TRUFLĘ KOŃ BĄDŹ psy"); + testModule.toLower("ШЕФ ВЗЪЯРЁН ТЧК ЩИПЦЫ С ЭХОМ ГУДБАЙ ЖЮЛЬ"); + testModule.toLower("ΓΑΖΊΕΣ ΚΑῚ ΜΥΡΤΙῈΣ ΔῈΝ ΘᾺ ΒΡΩ͂ ΠΙᾺ ΣΤῸ ΧΡΥΣΑΦῚ ΞΈΦΩΤΟ"); + testModule.toLower("CHINESE: 幓 厏吪吙 鈊釿閍 碞碠粻 曮禷"); + waitForBridgeAndUIIdle(); + + String[] answers = mStringRecordingModule.getCalls().toArray(new String[0]); + assertEquals("test", answers[0]); + assertEquals("w niżach mógł zjeść truflę koń bądź psy", answers[1]); + assertEquals("шеф взъярён тчк щипцы с эхом гудбай жюль", answers[2]); + assertEquals("γαζίες καὶ μυρτιὲς δὲν θὰ βρῶ πιὰ στὸ χρυσαφὶ ξέφωτο", answers[3]); + assertEquals("chinese: 幓 厏吪吙 鈊釿閍 碞碠粻 曮禷", answers[4]); + } + + +} diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/JSResponderTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/JSResponderTestCase.java new file mode 100644 index 000000000..39947db0f --- /dev/null +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/JSResponderTestCase.java @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2014-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 android.widget.ScrollView; + +import com.facebook.react.uimanager.PixelUtil; +import com.facebook.react.testing.ReactAppInstrumentationTestCase; +import com.facebook.react.testing.SingleTouchGestureGenerator; + +/** + * Test case to verify that JSResponder flow work correctly. + * + * In a single test case scenario we have a view with pan gesture recognizer containing a scrollview + * We werify that by vertical drags affects a scrollview while horizontal drags are suppose to + * be recognized by pan responder and setJSResponder should be triggered resulting in scrollview + * events being intercepted. + */ +public class JSResponderTestCase extends ReactAppInstrumentationTestCase { + + @Override + protected String getReactApplicationKeyUnderTest() { + return "JSResponderTestApp"; + } + + public void testResponderLocksScrollView() { + ScrollView scrollView = getViewByTestId("scroll_view"); + assertNotNull(scrollView); + assertEquals(0, scrollView.getScrollY()); + + float inpx40dp = PixelUtil.toPixelFromDIP(40f); + float inpx100dp = PixelUtil.toPixelFromDIP(100f); + + SingleTouchGestureGenerator gestureGenerator = createGestureGenerator(); + + gestureGenerator + .startGesture(30, 30 + inpx100dp) + .dragTo(30 + inpx40dp, 30, 10, 1200) + .endGesture(180, 100); + + waitForBridgeAndUIIdle(); + + assertTrue("Expected to scroll by at least 80 dp", scrollView.getScrollY() >= inpx100dp * .8f); + + int previousScroll = scrollView.getScrollY(); + + gestureGenerator + .startGesture(30, 30 + inpx100dp) + .dragTo(30 + inpx40dp, 30 + inpx100dp, 10, 1200); + + waitForBridgeAndUIIdle(); + + gestureGenerator + .dragTo(30 + inpx40dp, 30, 10, 1200) + .endGesture(); + + waitForBridgeAndUIIdle(); + assertEquals("Expected not to scroll", scrollView.getScrollY(), previousScroll); + + } + +} diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/LayoutEventsTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/LayoutEventsTestCase.java new file mode 100644 index 000000000..6e201641e --- /dev/null +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/LayoutEventsTestCase.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2014-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 com.facebook.react.testing.ReactAppInstrumentationTestCase; +import com.facebook.react.testing.ReactInstanceSpecForTest; +import com.facebook.react.testing.StringRecordingModule; + +/** + * Simple test to verify that layout events (onLayout) propagate to JS from native. + */ +public class LayoutEventsTestCase extends ReactAppInstrumentationTestCase { + + private StringRecordingModule mStringRecordingModule; + + @Override + protected String getReactApplicationKeyUnderTest() { + return "LayoutEventsTestApp"; + } + + /** + * Creates a UI in JS and verifies the onLayout handler is called. + */ + public void testOnLayoutCalled() { + assertEquals(1, mStringRecordingModule.getCalls().size()); + assertEquals("10,10-100x100", mStringRecordingModule.getCalls().get(0)); + } + + @Override + protected ReactInstanceSpecForTest createReactInstanceSpecForTest() { + mStringRecordingModule = new StringRecordingModule(); + return super.createReactInstanceSpecForTest() + .addNativeModule(mStringRecordingModule); + } +} diff --git a/ReactAndroid/src/androidTest/js/InitialPropsTestApp.js b/ReactAndroid/src/androidTest/js/InitialPropsTestApp.js new file mode 100644 index 000000000..9b5142c24 --- /dev/null +++ b/ReactAndroid/src/androidTest/js/InitialPropsTestApp.js @@ -0,0 +1,27 @@ +/** + * 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 InitialPropsTestApp + */ + +'use strict'; + +var React = require('React'); +var RecordingModule = require('NativeModules').InitialPropsRecordingModule; +var Text = require('Text'); + +var InitialPropsTestApp = React.createClass({ + componentDidMount: function() { + RecordingModule.recordProps(this.props); + }, + render: function() { + return dummy; + } +}); + +module.exports = InitialPropsTestApp; diff --git a/ReactAndroid/src/androidTest/js/JSResponderTestApp.js b/ReactAndroid/src/androidTest/js/JSResponderTestApp.js new file mode 100644 index 000000000..314f7f39d --- /dev/null +++ b/ReactAndroid/src/androidTest/js/JSResponderTestApp.js @@ -0,0 +1,63 @@ +/** + * 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 JSResponderTestApp + */ +'use strict'; + +var React = require('React'); +var StyleSheet = require('StyleSheet'); +var View = require('View'); +var Text = require('Text'); +var PanResponder = require('PanResponder'); +var ScrollView = require('ScrollView'); + +var JSResponderTestApp = React.createClass({ + _handleMoveShouldSetPanResponder: function(e, gestureState) { + return Math.abs(gestureState.dx) > 30; + }, + componentWillMount: function() { + this.panGesture = PanResponder.create({ + onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder, + }); + }, + render: function() { + var views = []; + for (var i = 0; i < 100; i++) { + views[i] = ( + + I am row {i} + + ); + } + return ( + + + {views} + + + ); + }, +}); + +var styles = StyleSheet.create({ + container: { + flex: 1, + }, + scrollview: { + flex: 1, + }, + row: { + height: 30, + } +}); + +module.exports = JSResponderTestApp; diff --git a/ReactAndroid/src/androidTest/js/LayoutEventsTestApp.js b/ReactAndroid/src/androidTest/js/LayoutEventsTestApp.js new file mode 100644 index 000000000..d9a0dcfa2 --- /dev/null +++ b/ReactAndroid/src/androidTest/js/LayoutEventsTestApp.js @@ -0,0 +1,35 @@ +/** + * 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 LayoutEventsTestApp + */ + +'use strict'; + +var React = require('React'); +var View = require('View'); + +var RecordingModule = require('NativeModules').Recording; + +var LayoutEventsTestApp = React.createClass({ + handleOnLayout: function(e) { + var layout = e.nativeEvent.layout; + RecordingModule.record(layout.x + ',' + layout.y + '-' + layout.width + 'x' + layout.height); + }, + + render: function() { + return ( + + ); + }, +}); + +module.exports = LayoutEventsTestApp; diff --git a/ReactAndroid/src/androidTest/js/TestBundle.js b/ReactAndroid/src/androidTest/js/TestBundle.js index 1e027fbca..b506f40ad 100644 --- a/ReactAndroid/src/androidTest/js/TestBundle.js +++ b/ReactAndroid/src/androidTest/js/TestBundle.js @@ -16,6 +16,7 @@ console.disableYellowBox = true; require('ProgressBarTestModule'); require('ViewRenderingTestModule'); require('TestJavaToJSArgumentsModule'); +require('TestJSLocaleModule'); require('TestJSToJavaParametersModule'); require('CatalystRootViewTestModule'); @@ -40,10 +41,22 @@ var apps = [ appKey: 'DatePickerDialogTestApp', component: () => require('DatePickerDialogTestModule').DatePickerDialogTestApp }, +{ + appKey: 'JSResponderTestApp', + component: () => require('JSResponderTestApp'), +}, { appKey: 'HorizontalScrollViewTestApp', component: () => require('ScrollViewTestModule').HorizontalScrollViewTestApp, }, +{ + appKey: 'InitialPropsTestApp', + component: () => require('InitialPropsTestApp'), +}, +{ + appKey: 'LayoutEventsTestApp', + component: () => require('LayoutEventsTestApp'), +}, { appKey: 'MeasureLayoutTestApp', component: () => require('MeasureLayoutTestModule').MeasureLayoutTestApp diff --git a/ReactAndroid/src/androidTest/js/TestJSLocaleModule.js b/ReactAndroid/src/androidTest/js/TestJSLocaleModule.js new file mode 100644 index 000000000..eff35902c --- /dev/null +++ b/ReactAndroid/src/androidTest/js/TestJSLocaleModule.js @@ -0,0 +1,31 @@ +/** + * 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 TestJSLocaleModule + */ + +'use strict'; + +var BatchedBridge = require('BatchedBridge'); +var Recording = require('NativeModules').Recording; + +var TestJSLocaleModule = { + toUpper: function(s) { + Recording.record(s.toUpperCase()); + }, + toLower: function(s) { + Recording.record(s.toLowerCase()); + }, +}; + +BatchedBridge.registerCallableModule( + 'TestJSLocaleModule', + TestJSLocaleModule +); + +module.exports = TestJSLocaleModule; diff --git a/scripts/run-android-local-integration-tests.sh b/scripts/run-android-local-integration-tests.sh index ca60756a6..88c40dd8a 100755 --- a/scripts/run-android-local-integration-tests.sh +++ b/scripts/run-android-local-integration-tests.sh @@ -5,7 +5,7 @@ set -e -which buck > /dev/null || { +which buck > /dev/null || { echo "React Native uses the Buck build tool to run tests. Please install Buck: https://buckbuild.com/setup/install.html"; exit 1; }