Add filtering to e2e tests (#22828)

Summary:
This PR adds filtering for e2e test examples using the new examples filter introduced in https://github.com/facebook/react-native/pull/22777

To do that we:
- Add a `testID` to `RNTesterExampleFilter` to select an example
- Refactor a few examples to export multiple examples for filtering
- Update all tests to filter by example title
Pull Request resolved: https://github.com/facebook/react-native/pull/22828

Reviewed By: TheSavior

Differential Revision: D13562664

Pulled By: rickhanlonii

fbshipit-source-id: efb0ca8050c1ca5c10d96bd77d35dd1143c3a3b3
This commit is contained in:
Rick Hanlon 2018-12-31 04:30:58 -08:00 committed by Facebook Github Bot
parent 9db0050635
commit 34ee8250b5
13 changed files with 483 additions and 363 deletions

View File

@ -9,34 +9,36 @@
*/
/* global device, element, by, expect */
const {
openComponentWithLabel,
openExampleWithTitle,
} = require('../e2e-helpers');
describe('Button', () => {
beforeAll(async () => {
await device.reloadReactNative();
await element(by.id('explorer_search')).replaceText('<Button>');
await element(
by.label('<Button> Simple React Native button component.'),
).tap();
});
afterAll(async () => {
//TODO - remove app state persistency, till then, we must go back to main screen,
await element(by.label('Back')).tap();
await openComponentWithLabel(
'<Button>',
'<Button> Simple React Native button component.',
);
});
it('Simple button should be tappable', async () => {
await openExampleWithTitle('Simple Button');
await element(by.id('simple_button')).tap();
await expect(element(by.text('Simple has been pressed!'))).toBeVisible();
await element(by.text('OK')).tap();
});
it('Adjusted color button should be tappable', async () => {
await openExampleWithTitle('Adjusted color');
await element(by.id('purple_button')).tap();
await expect(element(by.text('Purple has been pressed!'))).toBeVisible();
await element(by.text('OK')).tap();
});
it("Two buttons with JustifyContent:'space-between' should be tappable", async () => {
await openExampleWithTitle('Fit to text layout');
await element(by.id('left_button')).tap();
await expect(element(by.text('Left has been pressed!'))).toBeVisible();
await element(by.text('OK')).tap();
@ -47,6 +49,7 @@ describe('Button', () => {
});
it('Disabled button should not interact', async () => {
await openExampleWithTitle('Disabled Button');
await element(by.id('disabled_button')).tap();
await expect(
element(by.text('Disabled has been pressed!')),

View File

@ -8,23 +8,24 @@
* @format
*/
/* global element, by, expect */
/* global element, by, expect, device */
const {
openComponentWithLabel,
openExampleWithTitle,
} = require('../e2e-helpers');
describe('DatePickerIOS', () => {
beforeAll(async () => {
await element(by.id('explorer_search')).replaceText('<DatePickerIOS>');
await element(
by.label(
'<DatePickerIOS> Select dates and times using the native UIDatePicker.',
),
).tap();
});
afterAll(async () => {
await element(by.label('Back')).tap();
await device.reloadReactNative();
await openComponentWithLabel(
'<DatePickerIOS>',
'<DatePickerIOS> Select dates and times using the native UIDatePicker.',
);
});
it('Should change indicator with datetime picker', async () => {
await openExampleWithTitle('Date and time picker');
const testID = 'date-and-time';
const indicatorID = 'date-and-time-indicator';
@ -45,6 +46,7 @@ describe('DatePickerIOS', () => {
});
it('Should change indicator with date-only picker', async () => {
await openExampleWithTitle('Date only');
const testID = 'date-only';
const indicatorID = 'date-and-time-indicator';

View File

@ -8,23 +8,23 @@
* @format
*/
/* global element, by, expect */
/* global device, element, by, expect */
const {
openComponentWithLabel,
openExampleWithTitle,
} = require('../e2e-helpers');
describe('Picker', () => {
beforeAll(async () => {
await element(by.id('explorer_search')).replaceText('<Picker>');
await element(
by.label(
'<Picker> Provides multiple options to choose from, using either a dropdown menu or a dialog.',
),
).tap();
});
afterAll(async () => {
await element(by.label('Back')).tap();
await device.reloadReactNative();
await openComponentWithLabel(
'<Picker>',
'<Picker> Provides multiple options to choose from, using either a dropdown menu or a dialog.',
);
});
it('should be selectable by ID', async () => {
await openExampleWithTitle('Basic picker');
await expect(element(by.id('basic-picker'))).toBeVisible();
});
});

View File

@ -11,71 +11,86 @@
/* global device, element, by, expect */
const jestExpect = require('expect');
const {
openComponentWithLabel,
openExampleWithTitle,
} = require('../e2e-helpers');
describe('Switch', () => {
beforeEach(async () => {
beforeAll(async () => {
await device.reloadReactNative();
await element(by.id('explorer_search')).replaceText('<Switch>');
await element(by.label('<Switch> Native boolean input')).tap();
await openComponentWithLabel('<Switch>', '<Switch> Native boolean input');
});
it('Switch that starts off should switch', async () => {
const testID = 'on-off-initial-off';
const indicatorID = 'on-off-initial-off-indicator';
describe('Switches can be set to true or false', () => {
beforeAll(async () => {
await openExampleWithTitle('Switches can be set to true or false');
});
await expect(element(by.id(testID))).toHaveValue('0');
await expect(element(by.id(indicatorID))).toHaveText('Off');
await element(by.id(testID)).tap();
await expect(element(by.id(testID))).toHaveValue('1');
await expect(element(by.id(indicatorID))).toHaveText('On');
it('Switch that starts off should switch', async () => {
const testID = 'on-off-initial-off';
const indicatorID = 'on-off-initial-off-indicator';
await expect(element(by.id(testID))).toHaveValue('0');
await expect(element(by.id(indicatorID))).toHaveText('Off');
await element(by.id(testID)).tap();
await expect(element(by.id(testID))).toHaveValue('1');
await expect(element(by.id(indicatorID))).toHaveText('On');
});
it('Switch that starts on should switch', async () => {
const testID = 'on-off-initial-on';
const indicatorID = 'on-off-initial-on-indicator';
await expect(element(by.id(testID))).toHaveValue('1');
await expect(element(by.id(indicatorID))).toHaveText('On');
await element(by.id(testID)).tap();
await expect(element(by.id(testID))).toHaveValue('0');
await expect(element(by.id(indicatorID))).toHaveText('Off');
});
});
it('Switch that starts on should switch', async () => {
const testID = 'on-off-initial-on';
const indicatorID = 'on-off-initial-on-indicator';
describe('Switches can be disabled', () => {
beforeAll(async () => {
await openExampleWithTitle('Switches can be disabled');
});
await expect(element(by.id(testID))).toHaveValue('1');
await expect(element(by.id(indicatorID))).toHaveText('On');
await element(by.id(testID)).tap();
await expect(element(by.id(testID))).toHaveValue('0');
await expect(element(by.id(indicatorID))).toHaveText('Off');
});
it('disabled switch should not toggle', async () => {
const onTestID = 'disabled-initial-on';
const offTestID = 'disabled-initial-off';
const onIndicatorID = 'disabled-initial-on-indicator';
const offIndicatorID = 'disabled-initial-off-indicator';
it('disabled switch should not toggle', async () => {
const onTestID = 'disabled-initial-on';
const offTestID = 'disabled-initial-off';
const onIndicatorID = 'disabled-initial-on-indicator';
const offIndicatorID = 'disabled-initial-off-indicator';
await expect(element(by.id(onTestID))).toHaveValue('1');
await expect(element(by.id(onIndicatorID))).toHaveText('On');
await expect(element(by.id(onTestID))).toHaveValue('1');
await expect(element(by.id(onIndicatorID))).toHaveText('On');
try {
await element(by.id(onTestID)).tap();
throw new Error('Does not match');
} catch (err) {
jestExpect(err.message.message).toEqual(
jestExpect.stringContaining(
'Cannot perform action due to constraint(s) failure',
),
);
}
await expect(element(by.id(onTestID))).toHaveValue('1');
await expect(element(by.id(onIndicatorID))).toHaveText('On');
try {
await element(by.id(onTestID)).tap();
throw new Error('Does not match');
} catch (err) {
jestExpect(err.message.message).toEqual(
jestExpect.stringContaining(
'Cannot perform action due to constraint(s) failure',
),
);
}
await expect(element(by.id(onTestID))).toHaveValue('1');
await expect(element(by.id(onIndicatorID))).toHaveText('On');
await expect(element(by.id(offTestID))).toHaveValue('0');
await expect(element(by.id(offIndicatorID))).toHaveText('Off');
try {
await element(by.id(offTestID)).tap();
throw new Error('Does not match');
} catch (err) {
jestExpect(err.message.message).toEqual(
jestExpect.stringContaining(
'Cannot perform action due to constraint(s) failure',
),
);
}
await expect(element(by.id(offTestID))).toHaveValue('0');
await expect(element(by.id(offIndicatorID))).toHaveText('Off');
await expect(element(by.id(offTestID))).toHaveValue('0');
await expect(element(by.id(offIndicatorID))).toHaveText('Off');
try {
await element(by.id(offTestID)).tap();
throw new Error('Does not match');
} catch (err) {
jestExpect(err.message.message).toEqual(
jestExpect.stringContaining(
'Cannot perform action due to constraint(s) failure',
),
);
}
await expect(element(by.id(offTestID))).toHaveValue('0');
await expect(element(by.id(offIndicatorID))).toHaveText('Off');
});
});
});

View File

@ -8,22 +8,23 @@
* @format
*/
/* global element, by, expect */
/* global device, element, by, expect */
const {
openComponentWithLabel,
openExampleWithTitle,
} = require('../e2e-helpers');
describe('Touchable', () => {
beforeAll(async () => {
await element(by.id('explorer_search')).replaceText('<Touchable*');
await element(
by.label('<Touchable*> and onPress Touchable and onPress examples.'),
).tap();
});
afterAll(async () => {
//TODO - remove app state persistency, till then, we must go back to main screen,
await element(by.label('Back')).tap();
await device.reloadReactNative();
await openComponentWithLabel(
'<Touchable*',
'<Touchable*> and onPress Touchable and onPress examples.',
);
});
it('Touchable Highlight should be tappable', async () => {
await openExampleWithTitle('<TouchableHighlight>');
const buttonID = 'touchable_highlight_image_button';
const button2ID = 'touchable_highlight_text_button';
const consoleID = 'touchable_highlight_console';
@ -45,6 +46,8 @@ describe('Touchable', () => {
});
it('Touchable Without Feedback should be tappable', async () => {
await openExampleWithTitle('<TouchableWithoutFeedback>');
const buttonID = 'touchable_without_feedback_button';
const consoleID = 'touchable_without_feedback_console';
@ -60,6 +63,8 @@ describe('Touchable', () => {
});
it('Text should be tappable', async () => {
await openExampleWithTitle('<Text onPress={fn}> with highlight');
const buttonID = 'tappable_text';
const consoleID = 'tappable_text_console';

View File

@ -0,0 +1,24 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails oncall+react_native
* @format
*/
/* global element, by, expect */
// Will open a component example from the root list
// by filtering by component and then tapping on the label
exports.openComponentWithLabel = async (component, label) => {
await element(by.id('explorer_search')).replaceText(component);
await element(by.label(label)).tap();
};
// Will open an individual example for a component
// by filtering on the example title
exports.openExampleWithTitle = async title => {
await element(by.id('example_search')).replaceText(title);
};

View File

@ -14,20 +14,21 @@ const React = require('react');
const ReactNative = require('react-native');
const {DatePickerIOS, StyleSheet, Text, TextInput, View} = ReactNative;
class DatePickerExample extends React.Component<
$FlowFixMeProps,
$FlowFixMeState,
> {
static defaultProps = {
type State = {|
date: Date,
timeZoneOffsetInHours: number,
|};
type Props = {|
children: (State, (Date) => void) => React.Node,
|};
class WithDatePickerData extends React.Component<Props, State> {
state = {
date: new Date(),
timeZoneOffsetInHours: (-1 * new Date().getTimezoneOffset()) / 60,
};
state = {
date: this.props.date,
timeZoneOffsetInHours: this.props.timeZoneOffsetInHours,
};
onDateChange = date => {
this.setState({date: date});
};
@ -63,37 +64,18 @@ class DatePickerExample extends React.Component<
/>
<Text> hours from UTC</Text>
</WithLabel>
<Heading label="Date + time picker" />
<DatePickerIOS
testID="date-and-time"
date={this.state.date}
mode="datetime"
timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
onDateChange={this.onDateChange}
/>
<Heading label="Date picker" />
<DatePickerIOS
testID="date-only"
date={this.state.date}
mode="date"
timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
onDateChange={this.onDateChange}
/>
<Heading label="Time picker, 10-minute interval" />
<DatePickerIOS
testID="time-only"
date={this.state.date}
mode="time"
timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
onDateChange={this.onDateChange}
minuteInterval={10}
/>
{this.props.children(this.state, this.onDateChange)}
</View>
);
}
}
class WithLabel extends React.Component<$FlowFixMeProps> {
type LabelProps = {|
label: string,
children: React.Node,
|};
class WithLabel extends React.Component<LabelProps> {
render() {
return (
<View style={styles.labelContainer}>
@ -106,28 +88,6 @@ class WithLabel extends React.Component<$FlowFixMeProps> {
}
}
class Heading extends React.Component<$FlowFixMeProps> {
render() {
return (
<View style={styles.headingContainer}>
<Text style={styles.heading}>{this.props.label}</Text>
</View>
);
}
}
exports.displayName = (undefined: ?string);
exports.title = '<DatePickerIOS>';
exports.description = 'Select dates and times using the native UIDatePicker.';
exports.examples = [
{
title: '<DatePickerIOS>',
render: function(): React.Element<any> {
return <DatePickerExample />;
},
},
];
const styles = StyleSheet.create({
textinput: {
height: 26,
@ -149,12 +109,63 @@ const styles = StyleSheet.create({
label: {
fontWeight: '500',
},
headingContainer: {
padding: 4,
backgroundColor: '#f6f7f8',
},
heading: {
fontWeight: '500',
fontSize: 14,
},
});
exports.title = '<DatePickerIOS>';
exports.description = 'Select dates and times using the native UIDatePicker.';
exports.examples = [
{
title: 'Date and time picker',
render: function(): React.Element<any> {
return (
<WithDatePickerData>
{(state, onDateChange) => (
<DatePickerIOS
testID="date-and-time"
date={state.date}
mode="datetime"
timeZoneOffsetInMinutes={state.timeZoneOffsetInHours * 60}
onDateChange={onDateChange}
/>
)}
</WithDatePickerData>
);
},
},
{
title: 'Date only picker',
render: function(): React.Element<any> {
return (
<WithDatePickerData>
{(state, onDateChange) => (
<DatePickerIOS
testID="date-only"
date={state.date}
mode="date"
timeZoneOffsetInMinutes={state.timeZoneOffsetInHours * 60}
onDateChange={onDateChange}
/>
)}
</WithDatePickerData>
);
},
},
{
title: 'Time only picker, 10-minute interval',
render: function(): React.Element<any> {
return (
<WithDatePickerData>
{(state, onDateChange) => (
<DatePickerIOS
testID="time-only"
date={state.date}
mode="time"
timeZoneOffsetInMinutes={state.timeZoneOffsetInHours * 60}
onDateChange={onDateChange}
/>
)}
</WithDatePickerData>
);
},
},
];

View File

@ -13,115 +13,123 @@
const React = require('react');
const ReactNative = require('react-native');
const StyleSheet = require('StyleSheet');
const RNTesterBlock = require('RNTesterBlock');
const RNTesterPage = require('RNTesterPage');
const {Picker, Text} = ReactNative;
const Item = Picker.Item;
class PickerExample extends React.Component<{}, $FlowFixMeState> {
static title = '<Picker>';
static description =
'Provides multiple options to choose from, using either a dropdown menu or a dialog.';
type State = {
value: string | number,
};
class BasicPickerExample extends React.Component<{}, State> {
state = {
selected1: 'key1',
selected2: 'key1',
selected3: 'key1',
color: 'red',
mode: Picker.MODE_DIALOG,
value: 'key1',
};
render() {
return (
<RNTesterPage title="<Picker>">
<RNTesterBlock title="Basic Picker">
<Picker
testID="basic-picker"
style={styles.picker}
selectedValue={this.state.selected1}
onValueChange={this.onValueChange.bind(this, 'selected1')}>
<Item label="hello" value="key0" />
<Item label="world" value="key1" />
</Picker>
</RNTesterBlock>
<RNTesterBlock title="Disabled picker">
<Picker
style={styles.picker}
enabled={false}
selectedValue={this.state.selected1}>
<Item label="hello" value="key0" />
<Item label="world" value="key1" />
</Picker>
</RNTesterBlock>
<RNTesterBlock title="Dropdown Picker">
<Picker
style={styles.picker}
selectedValue={this.state.selected2}
onValueChange={this.onValueChange.bind(this, 'selected2')}
mode="dropdown">
<Item label="hello" value="key0" />
<Item label="world" value="key1" />
</Picker>
</RNTesterBlock>
<RNTesterBlock title="Picker with prompt message">
<Picker
style={styles.picker}
selectedValue={this.state.selected3}
onValueChange={this.onValueChange.bind(this, 'selected3')}
prompt="Pick one, just one">
<Item label="hello" value="key0" />
<Item label="world" value="key1" />
</Picker>
</RNTesterBlock>
<RNTesterBlock title="Picker with no listener">
<Picker style={styles.picker}>
<Item label="hello" value="key0" />
<Item label="world" value="key1" />
</Picker>
<Text>
Cannot change the value of this picker because it doesn't update
selectedValue.
</Text>
</RNTesterBlock>
<RNTesterBlock title="Colorful pickers">
<Picker
style={[styles.picker, {color: 'white', backgroundColor: '#333'}]}
selectedValue={this.state.color}
onValueChange={this.onValueChange.bind(this, 'color')}
mode="dropdown">
<Item label="red" color="red" value="red" />
<Item label="green" color="green" value="green" />
<Item label="blue" color="blue" value="blue" />
</Picker>
<Picker
style={styles.picker}
selectedValue={this.state.color}
onValueChange={this.onValueChange.bind(this, 'color')}
mode="dialog">
<Item label="red" color="red" value="red" />
<Item label="green" color="green" value="green" />
<Item label="blue" color="blue" value="blue" />
</Picker>
</RNTesterBlock>
</RNTesterPage>
<Picker
testID="basic-picker"
style={styles.picker}
selectedValue={this.state.value}
onValueChange={v => this.setState({value: v})}>
<Item label="hello" value="key0" />
<Item label="world" value="key1" />
</Picker>
);
}
}
changeMode = () => {
const newMode =
this.state.mode === Picker.MODE_DIALOG
? Picker.MODE_DROPDOWN
: Picker.MODE_DIALOG;
this.setState({mode: newMode});
class DisabledPickerExample extends React.Component<{}, State> {
state = {
value: 'key1',
};
onValueChange = (key: string, value: string | number) => {
const newState = {};
newState[key] = value;
this.setState(newState);
render() {
return (
<Picker
style={styles.picker}
enabled={false}
selectedValue={this.state.value}>
<Item label="hello" value="key0" />
<Item label="world" value="key1" />
</Picker>
);
}
}
class DropdownPickerExample extends React.Component<{}, State> {
state = {
value: 'key1',
};
render() {
return (
<Picker
style={styles.picker}
selectedValue={this.state.value}
onValueChange={v => this.setState({value: v})}
mode="dropdown">
<Item label="hello" value="key0" />
<Item label="world" value="key1" />
</Picker>
);
}
}
class PromptPickerExample extends React.Component<{}, State> {
state = {
value: 'key1',
};
render() {
return (
<Picker
style={styles.picker}
selectedValue={this.state.value}
onValueChange={v => this.setState({value: v})}
prompt="Pick one, just one">
<Item label="hello" value="key0" />
<Item label="world" value="key1" />
</Picker>
);
}
}
type ColorState = {
color: string | number,
};
class ColorPickerExample extends React.Component<{}, ColorState> {
state = {
color: 'red',
};
render() {
return (
<>
<Picker
style={[styles.picker, {color: 'white', backgroundColor: '#333'}]}
selectedValue={this.state.color}
onValueChange={v => this.setState({color: v})}
mode="dropdown">
<Item label="red" color="red" value="red" />
<Item label="green" color="green" value="green" />
<Item label="blue" color="blue" value="blue" />
</Picker>
<Picker
style={styles.picker}
selectedValue={this.state.color}
onValueChange={v => this.setState({color: v})}
mode="dialog">
<Item label="red" color="red" value="red" />
<Item label="green" color="green" value="green" />
<Item label="blue" color="blue" value="blue" />
</Picker>
</>
);
}
}
const styles = StyleSheet.create({
@ -130,4 +138,55 @@ const styles = StyleSheet.create({
},
});
module.exports = PickerExample;
exports.title = '<Picker>';
exports.description =
'Provides multiple options to choose from, using either a dropdown menu or a dialog.';
exports.examples = [
{
title: 'Basic Picker',
render: function(): React.Element<typeof BasicPickerExample> {
return <BasicPickerExample />;
},
},
{
title: 'Disabled Picker',
render: function(): React.Element<typeof DisabledPickerExample> {
return <DisabledPickerExample />;
},
},
{
title: 'Dropdown Picker',
render: function(): React.Element<typeof DropdownPickerExample> {
return <DropdownPickerExample />;
},
},
{
title: 'Picker with prompt message',
render: function(): React.Element<typeof PromptPickerExample> {
return <PromptPickerExample />;
},
},
{
title: 'Picker with no listener',
render: function(): React.Element<typeof PromptPickerExample> {
return (
<>
<Picker style={styles.picker}>
<Item label="hello" value="key0" />
<Item label="world" value="key1" />
</Picker>
<Text>
Cannot change the value of this picker because it doesn't update
selectedValue.
</Text>
</>
);
},
},
{
title: 'Colorful pickers',
render: function(): React.Element<typeof ColorPickerExample> {
return <ColorPickerExample />;
},
},
];

View File

@ -56,6 +56,7 @@ class RNTesterExampleContainer extends React.Component {
return (
<RNTesterPage title={this.props.title}>
<RNTesterExampleFilter
testID="example_search"
sections={sections}
filter={filter}
render={({filteredSections}) =>

View File

@ -20,6 +20,7 @@ type Props = {
render: Function,
sections: Object,
disableSearch?: boolean,
testID?: string,
};
type State = {
@ -75,7 +76,7 @@ class RNTesterExampleFilter extends React.Component<Props, State> {
placeholder="Search..."
underlineColorAndroid="transparent"
style={styles.searchTextInput}
testID="explorer_search"
testID={this.props.testID}
value={this.state.filter}
/>
</View>

View File

@ -94,6 +94,7 @@ class RNTesterExampleList extends React.Component<Props, $FlowFixMeState> {
<View style={[styles.listContainer, this.props.style]}>
{this._renderTitleRow()}
<RNTesterExampleFilter
testID="explorer_search"
sections={sections}
filter={filter}
render={({filteredSections}) => (

View File

@ -198,7 +198,10 @@ class EventSwitchExample extends React.Component<{}, $FlowFixMeState> {
}
}
const examples = [
exports.title = '<Switch>';
exports.displayName = 'SwitchExample';
exports.description = 'Native boolean input';
exports.examples = [
{
title: 'Switches can be set to true or false',
render(): React.Element<any> {
@ -230,8 +233,3 @@ const examples = [
},
},
];
exports.title = '<Switch>';
exports.displayName = 'SwitchExample';
exports.description = 'Native boolean input';
exports.examples = examples;

View File

@ -32,108 +32,6 @@ const forceTouchAvailable =
NativeModules.PlatformConstants.forceTouchAvailable) ||
false;
exports.displayName = (undefined: ?string);
exports.description = 'Touchable and onPress examples.';
exports.title = '<Touchable*> and onPress';
exports.examples = [
{
title: '<TouchableHighlight>',
description:
'TouchableHighlight works by adding an extra view with a ' +
'black background under the single child view. This works best when the ' +
'child view is fully opaque, although it can be made to work as a simple ' +
'background color change as well with the activeOpacity and ' +
'underlayColor props.',
render: function() {
return <TouchableHighlightBox />;
},
},
{
title: '<TouchableWithoutFeedback>',
render: function() {
return <TouchableWithoutFeedbackBox />;
},
},
{
title: 'TouchableNativeFeedback with Animated child',
description:
'TouchableNativeFeedback can have an AnimatedComponent as a' +
'direct child.',
platform: 'android',
render: function() {
const mScale = new Animated.Value(1);
Animated.timing(mScale, {toValue: 0.3, duration: 1000}).start();
const style = {
backgroundColor: 'rgb(180, 64, 119)',
width: 200,
height: 100,
transform: [{scale: mScale}],
};
return (
<View>
<View style={styles.row}>
<TouchableNativeFeedback>
<Animated.View style={style} />
</TouchableNativeFeedback>
</View>
</View>
);
},
},
{
title: '<Text onPress={fn}> with highlight',
render: function(): React.Element<any> {
return <TextOnPressBox />;
},
},
{
title: 'Touchable feedback events',
description:
'<Touchable*> components accept onPress, onPressIn, ' +
'onPressOut, and onLongPress as props.',
render: function(): React.Element<any> {
return <TouchableFeedbackEvents />;
},
},
{
title: 'Touchable delay for events',
description:
'<Touchable*> components also accept delayPressIn, ' +
'delayPressOut, and delayLongPress as props. These props impact the ' +
'timing of feedback events.',
render: function(): React.Element<any> {
return <TouchableDelayEvents />;
},
},
{
title: '3D Touch / Force Touch',
description:
'iPhone 6s and 6s plus support 3D touch, which adds a force property to touches',
render: function(): React.Element<any> {
return <ForceTouchExample />;
},
platform: 'ios',
},
{
title: 'Touchable Hit Slop',
description:
'<Touchable*> components accept hitSlop prop which extends the touch area ' +
'without changing the view bounds.',
render: function(): React.Element<any> {
return <TouchableHitSlop />;
},
},
{
title: 'Disabled Touchable*',
description:
'<Touchable*> components accept disabled prop which prevents ' +
'any interaction with component',
render: function(): React.Element<any> {
return <TouchableDisabled />;
},
},
];
class TouchableHighlightBox extends React.Component<{}, $FlowFixMeState> {
state = {
timesPressed: 0,
@ -566,3 +464,105 @@ const styles = StyleSheet.create({
color: 'blue',
},
});
exports.displayName = (undefined: ?string);
exports.description = 'Touchable and onPress examples.';
exports.title = '<Touchable*> and onPress';
exports.examples = [
{
title: '<TouchableHighlight>',
description:
'TouchableHighlight works by adding an extra view with a ' +
'black background under the single child view. This works best when the ' +
'child view is fully opaque, although it can be made to work as a simple ' +
'background color change as well with the activeOpacity and ' +
'underlayColor props.',
render: function() {
return <TouchableHighlightBox />;
},
},
{
title: '<TouchableWithoutFeedback>',
render: function() {
return <TouchableWithoutFeedbackBox />;
},
},
{
title: 'TouchableNativeFeedback with Animated child',
description:
'TouchableNativeFeedback can have an AnimatedComponent as a' +
'direct child.',
platform: 'android',
render: function() {
const mScale = new Animated.Value(1);
Animated.timing(mScale, {toValue: 0.3, duration: 1000}).start();
const style = {
backgroundColor: 'rgb(180, 64, 119)',
width: 200,
height: 100,
transform: [{scale: mScale}],
};
return (
<View>
<View style={styles.row}>
<TouchableNativeFeedback>
<Animated.View style={style} />
</TouchableNativeFeedback>
</View>
</View>
);
},
},
{
title: '<Text onPress={fn}> with highlight',
render: function(): React.Element<any> {
return <TextOnPressBox />;
},
},
{
title: 'Touchable feedback events',
description:
'<Touchable*> components accept onPress, onPressIn, ' +
'onPressOut, and onLongPress as props.',
render: function(): React.Element<any> {
return <TouchableFeedbackEvents />;
},
},
{
title: 'Touchable delay for events',
description:
'<Touchable*> components also accept delayPressIn, ' +
'delayPressOut, and delayLongPress as props. These props impact the ' +
'timing of feedback events.',
render: function(): React.Element<any> {
return <TouchableDelayEvents />;
},
},
{
title: '3D Touch / Force Touch',
description:
'iPhone 6s and 6s plus support 3D touch, which adds a force property to touches',
render: function(): React.Element<any> {
return <ForceTouchExample />;
},
platform: 'ios',
},
{
title: 'Touchable Hit Slop',
description:
'<Touchable*> components accept hitSlop prop which extends the touch area ' +
'without changing the view bounds.',
render: function(): React.Element<any> {
return <TouchableHitSlop />;
},
},
{
title: 'Disabled Touchable*',
description:
'<Touchable*> components accept disabled prop which prevents ' +
'any interaction with component',
render: function(): React.Element<any> {
return <TouchableDisabled />;
},
},
];