Open sourced CatalystTouchBubblingTestCase test for RN Android
Reviewed By: bestander Differential Revision: D3411681 fbshipit-source-id: 7b511a0447c61d94cbd43b7983fb3f96c2fcbddf
This commit is contained in:
parent
a7e6eea919
commit
7a635b2cd2
|
@ -0,0 +1,159 @@
|
||||||
|
/**
|
||||||
|
* 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 android.view.View;
|
||||||
|
|
||||||
|
import com.facebook.react.testing.ReactInstanceSpecForTest;
|
||||||
|
import com.facebook.react.testing.ReactAppInstrumentationTestCase;
|
||||||
|
import com.facebook.react.testing.SingleTouchGestureGenerator;
|
||||||
|
import com.facebook.react.testing.StringRecordingModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test is to verify that touch events bubbles up to the right handler. We emulate couple
|
||||||
|
* of different gestures on top of the application reflecting following layout:
|
||||||
|
*
|
||||||
|
* +---------------------------------------------------------------------------------------+
|
||||||
|
* | |
|
||||||
|
* | +----------------------------------------------------------------------------------+ |
|
||||||
|
* | | +-------------+ +----------------+ | |
|
||||||
|
* | | | +---+ | | | | |
|
||||||
|
* | | | | A | | | | | |
|
||||||
|
* | | | +---+ | | C | | |
|
||||||
|
* | | | {B} | | | | |
|
||||||
|
* | | | | {D} | | | |
|
||||||
|
* | | +-------------+ +----------------+ | |
|
||||||
|
* | | | |
|
||||||
|
* | | | |
|
||||||
|
* | +----------------------------------------------------------------------------------+ |
|
||||||
|
* |
|
||||||
|
* | +----------------------------------------------------------------------------------+ |
|
||||||
|
* | | | |
|
||||||
|
* | | | |
|
||||||
|
* | | | |
|
||||||
|
* | | {E} | |
|
||||||
|
* | | | |
|
||||||
|
* | | | |
|
||||||
|
* | +----------------------------------------------------------------------------------+ |
|
||||||
|
* +---------------------------------------------------------------------------------------+
|
||||||
|
*
|
||||||
|
* Then in each test case we eiter tap the center of a particular view (from A to E) or we start
|
||||||
|
* a gesture in one view and end it with another.
|
||||||
|
* View with names in brackets (e.g. {D}) have touch handlers set whereas all other views are not
|
||||||
|
* declared to handler touch events.
|
||||||
|
*/
|
||||||
|
public class CatalystTouchBubblingTestCase extends ReactAppInstrumentationTestCase {
|
||||||
|
|
||||||
|
private final StringRecordingModule mRecordingModule = new StringRecordingModule();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getReactApplicationKeyUnderTest() {
|
||||||
|
return "TouchBubblingTestAppModule";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1) Simulate touch event at view A, expect {B} touch handler to fire
|
||||||
|
* 2) Simulate touch event at view C, expect {D} touch handler to fire
|
||||||
|
*/
|
||||||
|
public void testSimpleClickAtInnerElements() {
|
||||||
|
mRecordingModule.reset();
|
||||||
|
View innerButton = getViewByTestId("A");
|
||||||
|
assertNotNull(innerButton);
|
||||||
|
createGestureGenerator().startGesture(innerButton).endGesture();
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
assertEquals(1, mRecordingModule.getCalls().size());
|
||||||
|
assertEquals("inner", mRecordingModule.getCalls().get(0));
|
||||||
|
|
||||||
|
mRecordingModule.reset();
|
||||||
|
innerButton = getViewByTestId("C");
|
||||||
|
assertNotNull(innerButton);
|
||||||
|
createGestureGenerator().startGesture(innerButton).endGesture();
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
assertEquals(1, mRecordingModule.getCalls().size());
|
||||||
|
assertEquals("outer", mRecordingModule.getCalls().get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1) Start touch at view A, then drag and release on view {B} (but outside of A), expect {B}'s
|
||||||
|
* touch handler to fire
|
||||||
|
* 2) Do the same with view C and {D}
|
||||||
|
*/
|
||||||
|
public void testDownOnInnerUpOnTouchableParent() {
|
||||||
|
View innerButton = getViewByTestId("A");
|
||||||
|
View touchableParent = getViewByTestId("B");
|
||||||
|
|
||||||
|
SingleTouchGestureGenerator gestureGenerator = createGestureGenerator();
|
||||||
|
gestureGenerator.startGesture(innerButton);
|
||||||
|
// wait for tapped view measurements
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
|
||||||
|
gestureGenerator.dragTo(touchableParent, 15).endGesture();
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
assertEquals(1, mRecordingModule.getCalls().size());
|
||||||
|
assertEquals("inner", mRecordingModule.getCalls().get(0));
|
||||||
|
|
||||||
|
// Do same with second inner view
|
||||||
|
mRecordingModule.reset();
|
||||||
|
|
||||||
|
touchableParent = getViewByTestId("D");
|
||||||
|
innerButton = getViewByTestId("C");
|
||||||
|
|
||||||
|
gestureGenerator = createGestureGenerator();
|
||||||
|
gestureGenerator.startGesture(innerButton);
|
||||||
|
// wait for tapped view measurements
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
|
||||||
|
gestureGenerator.dragTo(touchableParent, 15).endGesture();
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
assertEquals(1, mRecordingModule.getCalls().size());
|
||||||
|
assertEquals("outer", mRecordingModule.getCalls().get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start gesture at view A, then drag and release on view {E}. Expect no touch handlers to fire
|
||||||
|
*/
|
||||||
|
public void testDragOutOfTouchable() {
|
||||||
|
View outsideView = getViewByTestId("E");
|
||||||
|
View innerButton = getViewByTestId("A");
|
||||||
|
|
||||||
|
SingleTouchGestureGenerator gestureGenerator = createGestureGenerator();
|
||||||
|
gestureGenerator.startGesture(innerButton);
|
||||||
|
// wait for tapped view measurements
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
|
||||||
|
gestureGenerator.dragTo(outsideView, 15).endGesture();
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
assertTrue(mRecordingModule.getCalls().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In this scenario we start gesture at view A (has two touchable parents {B} and {D}) then we
|
||||||
|
* drag and release gesture on view {D}, but outside of {B}. We expect no touch handler to fire
|
||||||
|
*/
|
||||||
|
public void testNoEventWhenDragOutOfFirstTouchableParentToItsTouchableParent() {
|
||||||
|
View topLevelTouchable = getViewByTestId("C");
|
||||||
|
View innerButton = getViewByTestId("A");
|
||||||
|
|
||||||
|
SingleTouchGestureGenerator gestureGenerator = createGestureGenerator();
|
||||||
|
gestureGenerator.startGesture(innerButton);
|
||||||
|
// wait for tapped view measurements
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
|
||||||
|
gestureGenerator.dragTo(topLevelTouchable, 15).endGesture();
|
||||||
|
waitForBridgeAndUIIdle();
|
||||||
|
assertTrue(mRecordingModule.getCalls().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
|
||||||
|
return new ReactInstanceSpecForTest()
|
||||||
|
.addNativeModule(mRecordingModule);
|
||||||
|
}
|
||||||
|
}
|
|
@ -80,6 +80,10 @@ var apps = [
|
||||||
appKey: 'TimePickerDialogTestApp',
|
appKey: 'TimePickerDialogTestApp',
|
||||||
component: () => require('TimePickerDialogTestModule').TimePickerDialogTestApp
|
component: () => require('TimePickerDialogTestModule').TimePickerDialogTestApp
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
appKey: 'TouchBubblingTestAppModule',
|
||||||
|
component: () => require('TouchBubblingTestAppModule')
|
||||||
|
},
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
/**
|
||||||
|
* 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 TouchBubblingTestAppModule
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Recording = require('NativeModules').Recording;
|
||||||
|
|
||||||
|
var React = require('React');
|
||||||
|
var StyleSheet = require('StyleSheet');
|
||||||
|
var View = require('View');
|
||||||
|
var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
|
||||||
|
|
||||||
|
var TouchBubblingTestApp = React.createClass({
|
||||||
|
handlePress: function(record) {
|
||||||
|
Recording.record(record);
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<TouchableWithoutFeedback onPress={this.handlePress.bind(this, 'outer')} testID="D">
|
||||||
|
<View style={styles.outer}>
|
||||||
|
<TouchableWithoutFeedback onPress={this.handlePress.bind(this, 'inner')} testID="B">
|
||||||
|
<View style={styles.inner}>
|
||||||
|
<View style={styles.superinner} testID="A" />
|
||||||
|
</View>
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
|
<View style={styles.inner} testID="C" />
|
||||||
|
</View>
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
|
<TouchableWithoutFeedback onPress={this.handlePress.bind(this, 'outsider')} testID="E">
|
||||||
|
<View style={styles.element} />
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
backgroundColor: '#ccdd44',
|
||||||
|
},
|
||||||
|
element: {
|
||||||
|
backgroundColor: '#ff0000',
|
||||||
|
height: 100,
|
||||||
|
margin: 30,
|
||||||
|
},
|
||||||
|
outer: {
|
||||||
|
backgroundColor: '#00ff00',
|
||||||
|
height: 100,
|
||||||
|
margin: 30,
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
},
|
||||||
|
inner: {
|
||||||
|
backgroundColor: '#0000ff',
|
||||||
|
height: 50,
|
||||||
|
width: 50,
|
||||||
|
margin: 10,
|
||||||
|
},
|
||||||
|
superinner: {
|
||||||
|
backgroundColor: '#eeeeee',
|
||||||
|
height: 20,
|
||||||
|
width: 20,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = TouchBubblingTestApp;
|
Loading…
Reference in New Issue