Skip to content

Commit

Permalink
Merge pull request #1 from webdriverio/feat/add-testproperties
Browse files Browse the repository at this point in the history
This PR makes the app more accessible and also beter to use for automation
  • Loading branch information
wswebcreation authored Sep 17, 2018
2 parents f231326 + f8f6fa4 commit bbd27d4
Show file tree
Hide file tree
Showing 11 changed files with 253 additions and 37 deletions.
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ import {AppRegistry} from 'react-native';
import App from './js/App';
import {name as appName} from './app.json';

// Disable the yellow box
console.disableYellowBox = true;

AppRegistry.registerComponent(appName, () => App);
139 changes: 139 additions & 0 deletions js/components/Button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import React, { Component } from 'react';
import {
ActivityIndicator,
StyleSheet,
Text,
TouchableOpacity,
View,
ViewPropTypes
} from 'react-native';
import PropTypes from 'prop-types';
import { testProperties } from '../config/TestProperties';

class Button extends Component {
static propTypes = {
backgroundColor: PropTypes.string,
containerStyle: ViewPropTypes.style,
disabled: PropTypes.bool,
loading: PropTypes.bool,
onPress: PropTypes.func.isRequired,
testID: PropTypes.string,
text: PropTypes.string,
textStyle: Text.propTypes.style,
};

static defaultProps = {
backgroundColor: 'transparent',
containerStyle: null,
disabled: false,
loading: false,
testID: null,
text: null,
textStyle: null,
onDisabledPress: () => {},
};

onButtonPress = () => {
const { disabled, onDisabledPress, onPress, loading } = this.props;

if (loading) return;

if (disabled) {
return onDisabledPress();
}

return onPress();
};

get textStyle() {
const { icon, loading, textStyle, disabled } = this.props;
const style = [styles.text];

if (icon || loading) {
style.push(styles.textOffset);
}

style.push(textStyle);

if (disabled) {
style.push(styles.disabledText);
}

return style;
}

renderText = () => {
const { text } = this.props;

if (this.props.loading) {
return null;
}

if (text) {
return <Text style={this.textStyle}>{text}</Text>;
}

return null;
};

renderIcon = () => {
if (this.props.loading) {
return <ActivityIndicator size="small"/>;
}

return this.props.icon;
};

render() {
const {
text,
disabled,
testID,
backgroundColor,
containerStyle,
} = this.props;

return (
<TouchableOpacity
style={[styles.container, containerStyle]}
onPress={this.onButtonPress}
activeOpacity={disabled ? 1 : undefined}
{...testProperties(`button-${testID || text}`, true)}
>
<View style={[styles.content, disabled ? styles.disabledContent : { backgroundColor }]}>
{this.renderIcon()}
{this.renderText()}
</View>
</TouchableOpacity>
);
}
}

const styles = StyleSheet.create({
container: {
minHeight: 40,
},
content: {
flex: 1,
flexDirection: 'row',
paddingHorizontal: 15,
justifyContent: 'center',
alignItems: 'center',
},
disabledContent: {
backgroundColor: '#E0E6E8',
},
text: {
textAlign: 'center',
color: '#000',
alignSelf: 'center',
},
textOffset: {
marginLeft: 5,
},
disabledText: {
color: '#252525',
},
});

export default Button;
69 changes: 48 additions & 21 deletions js/components/FormComponents.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React, { Component } from 'react';
import { Alert, StyleSheet, Text, View } from 'react-native';
import { Alert, CheckBox, StyleSheet, Switch, Text, View } from 'react-native';
import SelectInput from '@tele2/react-native-select-input/src/SelectInput';
import { Button, CheckBox, Input } from 'react-native-elements';
import { Input } from 'react-native-elements';
import { WINDOW_WIDTH } from '../config/Constants';
import { testProperties } from '../config/TestProperties';
import Button from './Button';
import TitleDivider from './TitleDivider';

const options = [
Expand All @@ -23,7 +25,7 @@ class FormComponents extends Component {
super();

this.state = {
isCheckBoxActive: true,
isSwitchActive: false,
inputText: '',
};
}
Expand All @@ -42,7 +44,7 @@ class FormComponents extends Component {
}

render() {
const { isCheckBoxActive } = this.state;
const { isSwitchActive } = this.state;

return (
<View style={styles.container}>
Expand All @@ -63,41 +65,52 @@ class FormComponents extends Component {
inputStyle={styles.inputStyle}
maxLength={30}
multiline={false}
{...testProperties('text-input')}
/>
<Text style={styles.inputTextLabel}>You have typed:</Text>
<Text style={styles.inputText}>{this.state.inputText}</Text>
<Text
style={styles.inputText}
{...testProperties('input-text-result')}
>{this.state.inputText}</Text>
</View>
<Text style={styles.labelText}>Switch</Text>
<View style={styles.switchContainer}>
<Switch
value={this.state.isSwitchActive}
onValueChange={() => this.setState({ isSwitchActive: !isSwitchActive })}
style={styles.switch}
tintColor={'#FF5C06'}
onTintColor={'#FF5C06'}
thumbTintColor={'#e3e3e3'}
{...testProperties('switch')}
/>
<Text {...testProperties('switch-text')}>
{`Click to turn the switch ${this.state.isSwitchActive ? 'OFF' : 'ON'}`}
</Text>
</View>
<Text style={styles.labelText}>Checkbox</Text>
<CheckBox
title={`Click here to ${isCheckBoxActive ? 'un' : ''}check me`}
checked={this.state.isCheckBoxActive}
onPress={() => this.setState({ isCheckBoxActive: !isCheckBoxActive })}
containerStyle={styles.checkBoxContainer}
textStyle={styles.checkBoxText}
checkedColor='#ea5906'
/>
<SelectInput
label='Dropdown'
placeholder='Select a value here'
options={options}
containerStyle={styles.selectInput}
labelStyle={styles.selectInputLabel}
innerContainerStyle={styles.selectInputInnerContainer}
testProperty='Dropdown'
/>
<View>
<Text style={styles.labelText}>Buttons</Text>
<View style={styles.buttonContainer}>
<Button
buttonStyle={styles.button}
title='Active'
containerStyle={styles.button}
text='Active'
onPress={this.showAlert}
titleStyle={styles.buttonText}
textStyle={styles.buttonText}
disabled={false}
/>
<Button
buttonStyle={[styles.button, { marginLeft: 10 }]}
title='Inactive'
titleStyle={styles.buttonText}
containerStyle={[styles.button, { marginLeft: 10 }]}
text='Inactive'
textStyle={styles.buttonText}
disabled={true}
/>
</View>
Expand All @@ -122,7 +135,7 @@ const styles = StyleSheet.create({
borderColor: '#ea5906',
borderWidth: 5,
},
labelText:{
labelText: {
fontSize: 16,
marginLeft: 20,
},
Expand Down Expand Up @@ -170,6 +183,20 @@ const styles = StyleSheet.create({
borderColor: '#e3e3e3',
margin: 20
},
switchContainer: {
flex: 1,
paddingLeft: 10,
borderBottomColor: '#ea5906',
borderBottomWidth: 1,
marginLeft: 10,
marginRight: 10,
paddingBottom: 10,
alignItems: 'flex-start',
},
switch: {
marginTop: 10,
marginBottom: 10,
},
selectInput: {
paddingLeft: 10,
paddingRight: 10,
Expand Down
28 changes: 17 additions & 11 deletions js/components/LoginForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import {
KeyboardAvoidingView,
Alert,
} from 'react-native';
import { Input, Button } from 'react-native-elements'
import { Input } from 'react-native-elements'
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { WINDOW_WIDTH } from '../config/Constants';
import { testProperties } from '../config/TestProperties';
import Button from './Button';
import TitleDivider from './TitleDivider';

// Enable LayoutAnimation on Android
Expand Down Expand Up @@ -134,18 +136,18 @@ class LoginForm extends Component {
<TitleDivider text='Login / Sign up Form'/>
<View style={styles.categoryContainer}>
<Button
clear
onPress={() => this.selectCategory(0)}
containerStyle={{ flex: 1 }}
titleStyle={[styles.categoryText, isLoginPage && styles.selectedCategoryText]}
title={'Login'}
textStyle={[styles.categoryText, isLoginPage && styles.selectedCategoryText]}
text={'Login'}
testID={'login-container'}
/>
<Button
clear
onPress={() => this.selectCategory(1)}
containerStyle={{ flex: 1 }}
titleStyle={[styles.categoryText, isSignUpPage && styles.selectedCategoryText]}
title={'Sign up'}
textStyle={[styles.categoryText, isSignUpPage && styles.selectedCategoryText]}
text={'Sign up'}
testID={'sign-up-container'}
/>
</View>
<View style={styles.rowSelector}>
Expand Down Expand Up @@ -176,6 +178,7 @@ class LoginForm extends Component {
onSubmitEditing={() => this.passwordInput.focus()}
onChangeText={email => this.setState({ email })}
errorMessage={isEmailValid ? null : 'Please enter a valid email address'}
{...testProperties('input-email')}
/>
<Input
leftIcon={
Expand All @@ -201,6 +204,7 @@ class LoginForm extends Component {
onSubmitEditing={() => isSignUpPage ? this.confirmationInput.focus() : this.login()}
onChangeText={(password) => this.setState({ password })}
errorMessage={isPasswordValid ? null : 'Please enter at least 8 characters'}
{...testProperties('input-password')}
/>
{isSignUpPage &&
<Input
Expand Down Expand Up @@ -228,13 +232,13 @@ class LoginForm extends Component {
onSubmitEditing={this.signUp}
onChangeText={passwordConfirmation => this.setState({ passwordConfirmation })}
errorMessage={isConfirmationValid ? null : 'Please enter the same password'}
{...testProperties('input-repeat-password')}
/>}
<Button
buttonStyle={styles.button}
containerStyle={{ marginTop: 32, flex: 0 }}
title={isLoginPage ? 'LOGIN' : 'SIGN UP'}
containerStyle={styles.button}
onPress={isLoginPage ? this.login : this.signUp}
titleStyle={styles.buttonText}
text={isLoginPage ? 'LOGIN' : 'SIGN UP'}
textStyle={styles.buttonText}
loading={isLoading}
disabled={isLoading}
/>
Expand Down Expand Up @@ -321,6 +325,8 @@ const styles = StyleSheet.create({
backgroundColor: '#000',
borderColor: '#ea5906',
borderWidth: 5,
marginTop: 32,
flex: 0
},
});

Expand Down
2 changes: 2 additions & 0 deletions js/components/SliderEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Linking, View, Text, StyleSheet, TouchableOpacity } from 'react-native'
import PropTypes from 'prop-types';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { IS_IOS, WINDOW_HEIGHT, WINDOW_WIDTH } from '../config/Constants';
import { testProperties } from '../config/TestProperties';

const itemHorizontalMargin = Math.round(WINDOW_WIDTH * 0.02);
export const SLIDE_WIDTH = Math.round(WINDOW_WIDTH * 0.75) + itemHorizontalMargin * 2;
Expand All @@ -26,6 +27,7 @@ class SliderEntry extends Component {
activeOpacity={1}
style={styles.slideInnerContainer}
onPress={() => Linking.openURL(link)}
{...testProperties('card', true)}
>
<View style={styles.slideIconContainer}>
<Icon name={icon} size={150} style={styles.slideIcon}/>
Expand Down
22 changes: 22 additions & 0 deletions js/config/TestProperties.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Add a unique test id for iOS and Android
*
* @param {string} id
* @param {boolean} disableAccessible All touchable elements are accessible, meaning that it
* groups its children into a single selectable component, sometimes this is not needed for testing
*
* @return {object}
*/
import { IS_IOS } from './Constants';

function testProperties(id, disableAccessible = false) {
const disableAccessibility = disableAccessible ? { accessible: false } : {};

if (IS_IOS) {
return { ...disableAccessibility, testID: id };
}

return { ...disableAccessibility, accessibilityLabel: id };
}

export { testProperties };
Loading

0 comments on commit bbd27d4

Please sign in to comment.