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:
parent
9db0050635
commit
34ee8250b5
|
@ -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!')),
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
|
@ -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>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
@ -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 />;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
@ -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}) =>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}) => (
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 />;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
Loading…
Reference in New Issue