Detox tests E2E (#283)
This commit is contained in:
parent
a9acbec05c
commit
182ab69d6f
|
@ -35,6 +35,52 @@ jobs:
|
||||||
command: |
|
command: |
|
||||||
npx codecov
|
npx codecov
|
||||||
|
|
||||||
|
e2e-test:
|
||||||
|
macos:
|
||||||
|
xcode: "9.0"
|
||||||
|
|
||||||
|
environment:
|
||||||
|
BASH_ENV: "~/.nvm/nvm.sh"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Install Node 8
|
||||||
|
command: |
|
||||||
|
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash
|
||||||
|
source ~/.nvm/nvm.sh
|
||||||
|
# https://github.com/creationix/nvm/issues/1394
|
||||||
|
set +e
|
||||||
|
nvm install 8
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Install appleSimUtils
|
||||||
|
command: |
|
||||||
|
brew update
|
||||||
|
brew tap wix/brew
|
||||||
|
brew install applesimutils
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Install NPM modules
|
||||||
|
command: |
|
||||||
|
rm -rf node_modules
|
||||||
|
npm install
|
||||||
|
npm install -g detox-cli
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Build
|
||||||
|
command: |
|
||||||
|
detox build
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Test
|
||||||
|
command: |
|
||||||
|
detox test
|
||||||
|
|
||||||
|
- store_artifacts:
|
||||||
|
path: /tmp/screenshots
|
||||||
|
|
||||||
android-build:
|
android-build:
|
||||||
<<: *defaults
|
<<: *defaults
|
||||||
docker:
|
docker:
|
||||||
|
@ -215,10 +261,14 @@ workflows:
|
||||||
build-and-test:
|
build-and-test:
|
||||||
jobs:
|
jobs:
|
||||||
- lint-testunit
|
- lint-testunit
|
||||||
|
- e2e-test:
|
||||||
|
requires:
|
||||||
|
- lint-testunit
|
||||||
|
|
||||||
- ios-build:
|
- ios-build:
|
||||||
requires:
|
requires:
|
||||||
- lint-testunit
|
- lint-testunit
|
||||||
|
- e2e-test
|
||||||
- ios-testflight:
|
- ios-testflight:
|
||||||
requires:
|
requires:
|
||||||
- ios-build
|
- ios-build
|
||||||
|
@ -235,3 +285,4 @@ workflows:
|
||||||
- android-build:
|
- android-build:
|
||||||
requires:
|
requires:
|
||||||
- lint-testunit
|
- lint-testunit
|
||||||
|
- e2e-test
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
__tests__
|
__tests__
|
||||||
node_modules
|
node_modules
|
||||||
coverage
|
coverage
|
||||||
|
e2e
|
||||||
|
|
13
README.md
13
README.md
|
@ -38,6 +38,19 @@ Follow the [React Native Getting Started Guide](https://facebook.github.io/react
|
||||||
$ npm run android
|
$ npm run android
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Detox (end-to-end tests)
|
||||||
|
- Build your app
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ detox build
|
||||||
|
```
|
||||||
|
|
||||||
|
- Run tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ detox test
|
||||||
|
```
|
||||||
|
|
||||||
# Storybook
|
# Storybook
|
||||||
- General requirements
|
- General requirements
|
||||||
- Install storybook
|
- Install storybook
|
||||||
|
|
|
@ -12,5 +12,6 @@ if (__DEV__) {
|
||||||
.connect();
|
.connect();
|
||||||
// Running on android device
|
// Running on android device
|
||||||
// $ adb reverse tcp:9090 tcp:9090
|
// $ adb reverse tcp:9090 tcp:9090
|
||||||
console.warn = Reactotron.log;
|
// Reactotron.clear();
|
||||||
|
// console.warn = Reactotron.log;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ export default class Button extends React.PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
title, type, onPress, disabled
|
title, type, onPress, disabled, ...otherProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
<Touch
|
<Touch
|
||||||
|
@ -68,6 +68,7 @@ export default class Button extends React.PureComponent {
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
style={Platform.OS === 'ios' && styles.margin}
|
style={Platform.OS === 'ios' && styles.margin}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
{...otherProps}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
|
|
|
@ -24,7 +24,11 @@ export default class CloseModalButton extends React.PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity onPress={() => this.props.navigation.dispatch(NavigationActions.back())} style={styles.button}>
|
<TouchableOpacity
|
||||||
|
onPress={() => this.props.navigation.dispatch(NavigationActions.back())}
|
||||||
|
style={styles.button}
|
||||||
|
testID='close-modal-button'
|
||||||
|
>
|
||||||
<Icon
|
<Icon
|
||||||
style={styles.icon}
|
style={styles.icon}
|
||||||
name='close'
|
name='close'
|
||||||
|
|
|
@ -49,6 +49,7 @@ export default class EmojiCategory extends React.Component {
|
||||||
activeOpacity={0.7}
|
activeOpacity={0.7}
|
||||||
key={emoji.isCustom ? emoji.content : emoji}
|
key={emoji.isCustom ? emoji.content : emoji}
|
||||||
onPress={() => this.props.onEmojiSelected(emoji)}
|
onPress={() => this.props.onEmojiSelected(emoji)}
|
||||||
|
testID={`reaction-picker-${ emoji.isCustom ? emoji.content : emoji }`}
|
||||||
>
|
>
|
||||||
{renderEmoji(emoji, size)}
|
{renderEmoji(emoji, size)}
|
||||||
</TouchableOpacity>);
|
</TouchableOpacity>);
|
||||||
|
|
|
@ -20,6 +20,7 @@ export default class TabBar extends React.PureComponent {
|
||||||
key={tab}
|
key={tab}
|
||||||
onPress={() => this.props.goToPage(i)}
|
onPress={() => this.props.goToPage(i)}
|
||||||
style={styles.tab}
|
style={styles.tab}
|
||||||
|
testID={`reaction-picker-${ tab }`}
|
||||||
>
|
>
|
||||||
<Text style={[styles.tabEmoji, this.props.tabEmojiStyle]}>{tab}</Text>
|
<Text style={[styles.tabEmoji, this.props.tabEmojiStyle]}>{tab}</Text>
|
||||||
{this.props.activeTab === i ? <View style={styles.activeTabLine} /> : <View style={styles.tabLine} />}
|
{this.props.activeTab === i ? <View style={styles.activeTabLine} /> : <View style={styles.tabLine} />}
|
||||||
|
|
|
@ -337,6 +337,7 @@ export default class MessageActions extends React.Component {
|
||||||
<ActionSheet
|
<ActionSheet
|
||||||
ref={o => this.ActionSheet = o}
|
ref={o => this.ActionSheet = o}
|
||||||
title='Messages actions'
|
title='Messages actions'
|
||||||
|
testID='message-actions'
|
||||||
options={this.options}
|
options={this.options}
|
||||||
cancelButtonIndex={this.CANCEL_INDEX}
|
cancelButtonIndex={this.CANCEL_INDEX}
|
||||||
destructiveButtonIndex={this.DELETE_INDEX}
|
destructiveButtonIndex={this.DELETE_INDEX}
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default class EmojiKeyboard extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<View style={styles.emojiKeyboardContainer}>
|
<View style={styles.emojiKeyboardContainer} testID='messagebox-keyboard-emoji'>
|
||||||
<EmojiPicker onEmojiSelected={emoji => this.onEmojiSelected(emoji)} />
|
<EmojiPicker onEmojiSelected={emoji => this.onEmojiSelected(emoji)} />
|
||||||
</View>
|
</View>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
|
|
@ -100,7 +100,8 @@ export default class extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<SafeAreaView
|
<SafeAreaView
|
||||||
key='messagebox'
|
key='messagebox-recording'
|
||||||
|
testID='messagebox-recording'
|
||||||
style={styles.textBox}
|
style={styles.textBox}
|
||||||
>
|
>
|
||||||
<View style={[styles.textArea, { backgroundColor: '#F6F7F9' }]}>
|
<View style={[styles.textArea, { backgroundColor: '#F6F7F9' }]}>
|
||||||
|
|
|
@ -88,7 +88,6 @@ export default class MessageBox extends React.PureComponent {
|
||||||
const regexp = /(#|@|:)([a-z0-9._-]+)$/im;
|
const regexp = /(#|@|:)([a-z0-9._-]+)$/im;
|
||||||
|
|
||||||
const result = lastNativeText.substr(0, cursor).match(regexp);
|
const result = lastNativeText.substr(0, cursor).match(regexp);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return this.stopTrackingMention();
|
return this.stopTrackingMention();
|
||||||
}
|
}
|
||||||
|
@ -111,6 +110,7 @@ export default class MessageBox extends React.PureComponent {
|
||||||
accessibilityLabel='Cancel editing'
|
accessibilityLabel='Cancel editing'
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
onPress={() => this.editCancel()}
|
onPress={() => this.editCancel()}
|
||||||
|
testID='messagebox-cancel-editing'
|
||||||
/>);
|
/>);
|
||||||
}
|
}
|
||||||
return !this.state.showEmojiKeyboard ? (<Icon
|
return !this.state.showEmojiKeyboard ? (<Icon
|
||||||
|
@ -119,12 +119,14 @@ export default class MessageBox extends React.PureComponent {
|
||||||
accessibilityLabel='Open emoji selector'
|
accessibilityLabel='Open emoji selector'
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
name='mood'
|
name='mood'
|
||||||
|
testID='messagebox-open-emoji'
|
||||||
/>) : (<Icon
|
/>) : (<Icon
|
||||||
onPress={() => this.closeEmoji()}
|
onPress={() => this.closeEmoji()}
|
||||||
style={styles.actionButtons}
|
style={styles.actionButtons}
|
||||||
accessibilityLabel='Close emoji selector'
|
accessibilityLabel='Close emoji selector'
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
name='keyboard'
|
name='keyboard'
|
||||||
|
testID='messagebox-close-emoji'
|
||||||
/>);
|
/>);
|
||||||
}
|
}
|
||||||
get rightButtons() {
|
get rightButtons() {
|
||||||
|
@ -138,6 +140,7 @@ export default class MessageBox extends React.PureComponent {
|
||||||
accessibilityLabel='Send message'
|
accessibilityLabel='Send message'
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
onPress={() => this.submit(this.state.text)}
|
onPress={() => this.submit(this.state.text)}
|
||||||
|
testID='messagebox-send-message'
|
||||||
/>);
|
/>);
|
||||||
return icons;
|
return icons;
|
||||||
}
|
}
|
||||||
|
@ -148,6 +151,7 @@ export default class MessageBox extends React.PureComponent {
|
||||||
accessibilityLabel='Send audio message'
|
accessibilityLabel='Send audio message'
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
onPress={() => this.recordAudioMessage()}
|
onPress={() => this.recordAudioMessage()}
|
||||||
|
testID='messagebox-send-audio'
|
||||||
/>);
|
/>);
|
||||||
icons.push(<MyIcon
|
icons.push(<MyIcon
|
||||||
style={[styles.actionButtons, { color: '#2F343D', fontSize: 16 }]}
|
style={[styles.actionButtons, { color: '#2F343D', fontSize: 16 }]}
|
||||||
|
@ -156,6 +160,7 @@ export default class MessageBox extends React.PureComponent {
|
||||||
accessibilityLabel='Message actions'
|
accessibilityLabel='Message actions'
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
onPress={() => this.addFile()}
|
onPress={() => this.addFile()}
|
||||||
|
testID='messagebox-actions'
|
||||||
/>);
|
/>);
|
||||||
return icons;
|
return icons;
|
||||||
}
|
}
|
||||||
|
@ -438,6 +443,7 @@ export default class MessageBox extends React.PureComponent {
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.mentionItem}
|
style={styles.mentionItem}
|
||||||
onPress={() => this._onPressMention(item)}
|
onPress={() => this._onPressMention(item)}
|
||||||
|
testID={`mention-item-${ this.state.trackingType === MENTIONS_TRACKING_TYPE_EMOJIS ? item.name || item : item.username || item.name }`}
|
||||||
>
|
>
|
||||||
{this.state.trackingType === MENTIONS_TRACKING_TYPE_EMOJIS ?
|
{this.state.trackingType === MENTIONS_TRACKING_TYPE_EMOJIS ?
|
||||||
[
|
[
|
||||||
|
@ -463,14 +469,15 @@ export default class MessageBox extends React.PureComponent {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
<View key='messagebox-container' testID='messagebox-container'>
|
||||||
<FlatList
|
<FlatList
|
||||||
key='messagebox-container'
|
|
||||||
style={styles.mentionList}
|
style={styles.mentionList}
|
||||||
data={mentions}
|
data={mentions}
|
||||||
renderItem={({ item }) => this.renderMentionItem(item)}
|
renderItem={({ item }) => this.renderMentionItem(item)}
|
||||||
keyExtractor={item => item._id || item}
|
keyExtractor={item => item._id || item}
|
||||||
keyboardShouldPersistTaps='always'
|
keyboardShouldPersistTaps='always'
|
||||||
/>
|
/>
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -481,7 +488,11 @@ export default class MessageBox extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
[
|
[
|
||||||
this.renderMentions(),
|
this.renderMentions(),
|
||||||
<View key='messagebox' style={[styles.textArea, this.props.editing && styles.editing]}>
|
<View
|
||||||
|
key='messagebox'
|
||||||
|
style={[styles.textArea, this.props.editing && styles.editing]}
|
||||||
|
testID='messagebox'
|
||||||
|
>
|
||||||
{this.leftButtons}
|
{this.leftButtons}
|
||||||
<TextInput
|
<TextInput
|
||||||
ref={component => this.component = component}
|
ref={component => this.component = component}
|
||||||
|
@ -496,6 +507,7 @@ export default class MessageBox extends React.PureComponent {
|
||||||
defaultValue=''
|
defaultValue=''
|
||||||
multiline
|
multiline
|
||||||
placeholderTextColor='#9EA2A8'
|
placeholderTextColor='#9EA2A8'
|
||||||
|
testID='messagebox-input'
|
||||||
/>
|
/>
|
||||||
{this.rightButtons}
|
{this.rightButtons}
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -67,7 +67,7 @@ export default class Sidebar extends Component {
|
||||||
|
|
||||||
onPressItem = (item) => {
|
onPressItem = (item) => {
|
||||||
this.props.selectServer(item.id);
|
this.props.selectServer(item.id);
|
||||||
this.props.navigation.dispatch(DrawerActions.closeDrawer());
|
this.closeDrawer();
|
||||||
}
|
}
|
||||||
|
|
||||||
getState = () => ({
|
getState = () => ({
|
||||||
|
@ -78,12 +78,17 @@ export default class Sidebar extends Component {
|
||||||
this.setState(this.getState());
|
this.setState(this.getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
closeDrawer = () => {
|
||||||
|
this.props.navigation.dispatch(DrawerActions.closeDrawer());
|
||||||
|
}
|
||||||
|
|
||||||
renderItem = ({ item, separators }) => (
|
renderItem = ({ item, separators }) => (
|
||||||
|
|
||||||
<TouchableHighlight
|
<TouchableHighlight
|
||||||
onShowUnderlay={separators.highlight}
|
onShowUnderlay={separators.highlight}
|
||||||
onHideUnderlay={separators.unhighlight}
|
onHideUnderlay={separators.unhighlight}
|
||||||
onPress={() => { this.onPressItem(item); }}
|
onPress={() => { this.onPressItem(item); }}
|
||||||
|
testID={`sidebar-${ item.id }`}
|
||||||
>
|
>
|
||||||
<View style={[styles.serverItem, (item.id === this.props.server ? styles.selectedServer : null)]}>
|
<View style={[styles.serverItem, (item.id === this.props.server ? styles.selectedServer : null)]}>
|
||||||
<Text>
|
<Text>
|
||||||
|
@ -96,14 +101,18 @@ export default class Sidebar extends Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ScrollView style={styles.scrollView}>
|
<ScrollView style={styles.scrollView}>
|
||||||
<View style={{ paddingBottom: 20 }}>
|
<View style={{ paddingBottom: 20 }} testID='sidebar'>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={this.state.servers}
|
data={this.state.servers}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
keyExtractor={keyExtractor}
|
keyExtractor={keyExtractor}
|
||||||
/>
|
/>
|
||||||
<TouchableHighlight
|
<TouchableHighlight
|
||||||
onPress={() => { this.props.logout(); }}
|
onPress={() => {
|
||||||
|
this.closeDrawer();
|
||||||
|
this.props.logout();
|
||||||
|
}}
|
||||||
|
testID='sidebar-logout'
|
||||||
>
|
>
|
||||||
<View style={styles.serverItem}>
|
<View style={styles.serverItem}>
|
||||||
<Text>
|
<Text>
|
||||||
|
@ -112,7 +121,11 @@ export default class Sidebar extends Component {
|
||||||
</View>
|
</View>
|
||||||
</TouchableHighlight>
|
</TouchableHighlight>
|
||||||
<TouchableHighlight
|
<TouchableHighlight
|
||||||
onPress={() => { this.props.navigation.navigate({ key: 'AddServer', routeName: 'AddServer' }); }}
|
onPress={() => {
|
||||||
|
this.closeDrawer();
|
||||||
|
this.props.navigation.navigate({ key: 'AddServer', routeName: 'AddServer' });
|
||||||
|
}}
|
||||||
|
testID='sidebar-add-server'
|
||||||
>
|
>
|
||||||
<View style={styles.serverItem}>
|
<View style={styles.serverItem}>
|
||||||
<Text>
|
<Text>
|
||||||
|
|
|
@ -75,22 +75,37 @@ export default class RCTextInput extends React.PureComponent {
|
||||||
showPassword: false
|
showPassword: false
|
||||||
}
|
}
|
||||||
|
|
||||||
icon = ({ name, onPress, style }) => <Icon name={name} style={[styles.icon, style]} size={20} onPress={onPress} />
|
icon = ({
|
||||||
|
name,
|
||||||
|
onPress,
|
||||||
|
style,
|
||||||
|
testID
|
||||||
|
}) => <Icon name={name} style={[styles.icon, style]} size={20} onPress={onPress} testID={testID} />
|
||||||
|
|
||||||
iconLeft = name => this.icon({ name, onPress: null, style: { left: 0 } });
|
iconLeft = name => this.icon({
|
||||||
|
name,
|
||||||
|
onPress: null,
|
||||||
|
style: { left: 0 },
|
||||||
|
testID: this.props.testID ? `${ this.props.testID }-icon-left` : null
|
||||||
|
});
|
||||||
|
|
||||||
iconPassword = name => this.icon({ name, onPress: () => this.tooglePassword(), style: { right: 0 } });
|
iconPassword = name => this.icon({
|
||||||
|
name,
|
||||||
|
onPress: () => this.tooglePassword(),
|
||||||
|
style: { right: 0 },
|
||||||
|
testID: this.props.testID ? `${ this.props.testID }-icon-right` : null
|
||||||
|
});
|
||||||
|
|
||||||
tooglePassword = () => this.setState({ showPassword: !this.state.showPassword });
|
tooglePassword = () => this.setState({ showPassword: !this.state.showPassword });
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
label, error, secureTextEntry, containerStyle, inputRef, iconLeft, inputStyle, ...inputProps
|
label, error, secureTextEntry, containerStyle, inputRef, iconLeft, inputStyle, testID, placeholder, ...inputProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { showPassword } = this.state;
|
const { showPassword } = this.state;
|
||||||
return (
|
return (
|
||||||
<View style={[styles.inputContainer, containerStyle]}>
|
<View style={[styles.inputContainer, containerStyle]}>
|
||||||
{ label && <Text style={[styles.label, error.error && styles.labelError]}>{label}</Text> }
|
{label && <Text contentDescription={null} accessibilityLabel={null} style={[styles.label, error.error && styles.labelError]}>{label}</Text> }
|
||||||
<View style={styles.wrap}>
|
<View style={styles.wrap}>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={[
|
style={[
|
||||||
|
@ -105,6 +120,10 @@ export default class RCTextInput extends React.PureComponent {
|
||||||
autoCapitalize='none'
|
autoCapitalize='none'
|
||||||
underlineColorAndroid='transparent'
|
underlineColorAndroid='transparent'
|
||||||
secureTextEntry={secureTextEntry && !showPassword}
|
secureTextEntry={secureTextEntry && !showPassword}
|
||||||
|
testID={testID}
|
||||||
|
accessibilityLabel={placeholder}
|
||||||
|
placeholder={placeholder}
|
||||||
|
contentDescription={placeholder}
|
||||||
{...inputProps}
|
{...inputProps}
|
||||||
/>
|
/>
|
||||||
{iconLeft && this.iconLeft(iconLeft)}
|
{iconLeft && this.iconLeft(iconLeft)}
|
||||||
|
|
|
@ -270,6 +270,7 @@ export default class Message extends React.Component {
|
||||||
onPress={() => this.onReactionPress(reaction.emoji)}
|
onPress={() => this.onReactionPress(reaction.emoji)}
|
||||||
onLongPress={() => this.onReactionLongPress()}
|
onLongPress={() => this.onReactionLongPress()}
|
||||||
key={reaction.emoji}
|
key={reaction.emoji}
|
||||||
|
testID={`message-reaction-${ reaction.emoji }`}
|
||||||
>
|
>
|
||||||
<View style={[styles.reactionContainer, reactedContainerStyle]}>
|
<View style={[styles.reactionContainer, reactedContainerStyle]}>
|
||||||
<Emoji
|
<Emoji
|
||||||
|
@ -292,7 +293,8 @@ export default class Message extends React.Component {
|
||||||
{this.props.item.reactions.map(this.renderReaction)}
|
{this.props.item.reactions.map(this.renderReaction)}
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => this.props.toggleReactionPicker(this.parseMessage())}
|
onPress={() => this.props.toggleReactionPicker(this.parseMessage())}
|
||||||
key='add-reaction'
|
key='message-add-reaction'
|
||||||
|
testID='message-add-reaction'
|
||||||
style={styles.reactionContainer}
|
style={styles.reactionContainer}
|
||||||
>
|
>
|
||||||
<Icon name='insert-emoticon' color='#aaaaaa' size={15} />
|
<Icon name='insert-emoticon' color='#aaaaaa' size={15} />
|
||||||
|
|
|
@ -40,6 +40,7 @@ async function canOpenRoomDDP(...args) {
|
||||||
|
|
||||||
export default async function canOpenRoom({ rid, path }) {
|
export default async function canOpenRoom({ rid, path }) {
|
||||||
const { database: db } = database;
|
const { database: db } = database;
|
||||||
|
|
||||||
const room = db.objects('subscriptions').filtered('rid == $0', rid);
|
const room = db.objects('subscriptions').filtered('rid == $0', rid);
|
||||||
if (room.length) {
|
if (room.length) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -15,7 +15,7 @@ export const merge = (subscription, room) => {
|
||||||
subscription.joinCodeRequired = room.joinCodeRequired;
|
subscription.joinCodeRequired = room.joinCodeRequired;
|
||||||
|
|
||||||
if (room.muted && room.muted.length) {
|
if (room.muted && room.muted.length) {
|
||||||
subscription.muted = room.muted.filter(role => role).map(role => ({ value: role }));
|
subscription.muted = room.muted.filter(user => user).map(user => ({ value: user }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (subscription.roles && subscription.roles.length) {
|
if (subscription.roles && subscription.roles.length) {
|
||||||
|
|
|
@ -21,9 +21,13 @@ export const getMessage = (rid, msg = {}) => {
|
||||||
username: reduxStore.getState().login.user.username
|
username: reduxStore.getState().login.user.username
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
try {
|
||||||
database.write(() => {
|
database.write(() => {
|
||||||
database.create('messages', message, true);
|
database.create('messages', message, true);
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('getMessage', error);
|
||||||
|
}
|
||||||
return message;
|
return message;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
import Random from 'react-native-meteor/lib/Random';
|
||||||
import database from '../../realm';
|
import database from '../../realm';
|
||||||
import { merge } from '../helpers/mergeSubscriptionsRooms';
|
import { merge } from '../helpers/mergeSubscriptionsRooms';
|
||||||
import protectedFunction from '../helpers/protectedFunction';
|
import protectedFunction from '../helpers/protectedFunction';
|
||||||
|
import messagesStatus from '../../../constants/messagesStatus';
|
||||||
import log from '../../../utils/log';
|
import log from '../../../utils/log';
|
||||||
|
|
||||||
export default async function subscribeRooms(id) {
|
export default async function subscribeRooms(id) {
|
||||||
|
@ -26,7 +28,9 @@ export default async function subscribeRooms(id) {
|
||||||
}, 5000);
|
}, 5000);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.ddp) {
|
if (!this.ddp && this._login) {
|
||||||
|
loop();
|
||||||
|
} else {
|
||||||
this.ddp.on('logged', () => {
|
this.ddp.on('logged', () => {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
timer = false;
|
timer = false;
|
||||||
|
@ -48,7 +52,7 @@ export default async function subscribeRooms(id) {
|
||||||
const [, ev] = ddpMessage.fields.eventName.split('/');
|
const [, ev] = ddpMessage.fields.eventName.split('/');
|
||||||
if (/subscriptions/.test(ev)) {
|
if (/subscriptions/.test(ev)) {
|
||||||
const tpm = merge(data);
|
const tpm = merge(data);
|
||||||
return database.write(() => {
|
database.write(() => {
|
||||||
database.create('subscriptions', tpm, true);
|
database.create('subscriptions', tpm, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -58,6 +62,25 @@ export default async function subscribeRooms(id) {
|
||||||
merge(sub, data);
|
merge(sub, data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (/message/.test(ev)) {
|
||||||
|
const [args] = ddpMessage.fields.args;
|
||||||
|
const _id = Random.id();
|
||||||
|
const message = {
|
||||||
|
_id,
|
||||||
|
rid: args.rid,
|
||||||
|
msg: args.msg,
|
||||||
|
ts: new Date(),
|
||||||
|
_updatedAt: new Date(),
|
||||||
|
status: messagesStatus.SENT,
|
||||||
|
u: {
|
||||||
|
_id,
|
||||||
|
username: 'rocket.cat'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
requestAnimationFrame(() => database.write(() => {
|
||||||
|
database.create('messages', message, true);
|
||||||
|
}));
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { AsyncStorage, Platform } from 'react-native';
|
import { AsyncStorage, Platform } from 'react-native';
|
||||||
import { hashPassword } from 'react-native-meteor/lib/utils';
|
import { hashPassword } from 'react-native-meteor/lib/utils';
|
||||||
import foreach from 'lodash/forEach';
|
import foreach from 'lodash/forEach';
|
||||||
import Random from 'react-native-meteor/lib/Random';
|
|
||||||
import RNFetchBlob from 'react-native-fetch-blob';
|
import RNFetchBlob from 'react-native-fetch-blob';
|
||||||
|
|
||||||
import reduxStore from './createStore';
|
import reduxStore from './createStore';
|
||||||
|
@ -23,8 +22,6 @@ import { someoneTyping, roomMessageReceived } from '../actions/room';
|
||||||
import { setRoles } from '../actions/roles';
|
import { setRoles } from '../actions/roles';
|
||||||
import Ddp from './ddp';
|
import Ddp from './ddp';
|
||||||
|
|
||||||
import normalizeMessage from './methods/helpers/normalizeMessage';
|
|
||||||
|
|
||||||
import subscribeRooms from './methods/subscriptions/rooms';
|
import subscribeRooms from './methods/subscriptions/rooms';
|
||||||
import subscribeRoom from './methods/subscriptions/room';
|
import subscribeRoom from './methods/subscriptions/room';
|
||||||
|
|
||||||
|
@ -167,9 +164,11 @@ const RocketChat = {
|
||||||
|
|
||||||
this.ddp.on('disconnected', protectedFunction(() => {
|
this.ddp.on('disconnected', protectedFunction(() => {
|
||||||
reduxStore.dispatch(disconnect());
|
reduxStore.dispatch(disconnect());
|
||||||
|
console.warn(this.ddp);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.ddp.on('stream-room-messages', (ddpMessage) => {
|
this.ddp.on('stream-room-messages', (ddpMessage) => {
|
||||||
|
// TODO: debounce
|
||||||
const message = _buildMessage(ddpMessage.fields.args[0]);
|
const message = _buildMessage(ddpMessage.fields.args[0]);
|
||||||
requestAnimationFrame(() => reduxStore.dispatch(roomMessageReceived(message)));
|
requestAnimationFrame(() => reduxStore.dispatch(roomMessageReceived(message)));
|
||||||
});
|
});
|
||||||
|
@ -182,65 +181,66 @@ const RocketChat = {
|
||||||
return reduxStore.dispatch(someoneTyping({ _rid, username: ddpMessage.fields.args[0], typing: ddpMessage.fields.args[1] }));
|
return reduxStore.dispatch(someoneTyping({ _rid, username: ddpMessage.fields.args[0], typing: ddpMessage.fields.args[1] }));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.ddp.on('stream-notify-user', protectedFunction((ddpMessage) => {
|
// this.ddp.on('stream-notify-user', protectedFunction((ddpMessage) => {
|
||||||
const [type, data] = ddpMessage.fields.args;
|
// console.warn('rc.stream-notify-user')
|
||||||
const [, ev] = ddpMessage.fields.eventName.split('/');
|
// const [type, data] = ddpMessage.fields.args;
|
||||||
if (/subscriptions/.test(ev)) {
|
// const [, ev] = ddpMessage.fields.eventName.split('/');
|
||||||
if (data.roles) {
|
// if (/subscriptions/.test(ev)) {
|
||||||
data.roles = data.roles.map(role => ({ value: role }));
|
// if (data.roles) {
|
||||||
}
|
// data.roles = data.roles.map(role => ({ value: role }));
|
||||||
if (data.blocker) {
|
// }
|
||||||
data.blocked = true;
|
// if (data.blocker) {
|
||||||
} else {
|
// data.blocked = true;
|
||||||
data.blocked = false;
|
// } else {
|
||||||
}
|
// data.blocked = false;
|
||||||
if (data.mobilePushNotifications === 'nothing') {
|
// }
|
||||||
data.notifications = true;
|
// if (data.mobilePushNotifications === 'nothing') {
|
||||||
} else {
|
// data.notifications = true;
|
||||||
data.notifications = false;
|
// } else {
|
||||||
}
|
// data.notifications = false;
|
||||||
database.write(() => {
|
// }
|
||||||
database.create('subscriptions', data, true);
|
// database.write(() => {
|
||||||
});
|
// database.create('subscriptions', data, true);
|
||||||
}
|
// });
|
||||||
if (/rooms/.test(ev) && type === 'updated') {
|
// }
|
||||||
const sub = database.objects('subscriptions').filtered('rid == $0', data._id)[0];
|
// if (/rooms/.test(ev) && type === 'updated') {
|
||||||
|
// const sub = database.objects('subscriptions').filtered('rid == $0', data._id)[0];
|
||||||
|
|
||||||
database.write(() => {
|
// database.write(() => {
|
||||||
sub.roomUpdatedAt = data._updatedAt;
|
// sub.roomUpdatedAt = data._updatedAt;
|
||||||
sub.lastMessage = normalizeMessage(data.lastMessage);
|
// sub.lastMessage = normalizeMessage(data.lastMessage);
|
||||||
sub.ro = data.ro;
|
// sub.ro = data.ro;
|
||||||
sub.description = data.description;
|
// sub.description = data.description;
|
||||||
sub.topic = data.topic;
|
// sub.topic = data.topic;
|
||||||
sub.announcement = data.announcement;
|
// sub.announcement = data.announcement;
|
||||||
sub.reactWhenReadOnly = data.reactWhenReadOnly;
|
// sub.reactWhenReadOnly = data.reactWhenReadOnly;
|
||||||
sub.archived = data.archived;
|
// sub.archived = data.archived;
|
||||||
sub.joinCodeRequired = data.joinCodeRequired;
|
// sub.joinCodeRequired = data.joinCodeRequired;
|
||||||
if (data.muted) {
|
// if (data.muted) {
|
||||||
sub.muted = data.muted.map(m => ({ value: m }));
|
// sub.muted = data.muted.map(m => ({ value: m }));
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
if (/message/.test(ev)) {
|
// if (/message/.test(ev)) {
|
||||||
const [args] = ddpMessage.fields.args;
|
// const [args] = ddpMessage.fields.args;
|
||||||
const _id = Random.id();
|
// const _id = Random.id();
|
||||||
const message = {
|
// const message = {
|
||||||
_id,
|
// _id,
|
||||||
rid: args.rid,
|
// rid: args.rid,
|
||||||
msg: args.msg,
|
// msg: args.msg,
|
||||||
ts: new Date(),
|
// ts: new Date(),
|
||||||
_updatedAt: new Date(),
|
// _updatedAt: new Date(),
|
||||||
status: messagesStatus.SENT,
|
// status: messagesStatus.SENT,
|
||||||
u: {
|
// u: {
|
||||||
_id,
|
// _id,
|
||||||
username: 'rocket.cat'
|
// username: 'rocket.cat'
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
requestAnimationFrame(() => database.write(() => {
|
// requestAnimationFrame(() => database.write(() => {
|
||||||
database.create('messages', message, true);
|
// database.create('messages', message, true);
|
||||||
}));
|
// }));
|
||||||
}
|
// }
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
this.ddp.on('rocketchat_starred_message', protectedFunction((ddpMessage) => {
|
this.ddp.on('rocketchat_starred_message', protectedFunction((ddpMessage) => {
|
||||||
if (ddpMessage.msg === 'added') {
|
if (ddpMessage.msg === 'added') {
|
||||||
|
|
|
@ -171,7 +171,8 @@ export default class RoomItem extends React.Component {
|
||||||
onLongPress: PropTypes.func,
|
onLongPress: PropTypes.func,
|
||||||
user: PropTypes.object,
|
user: PropTypes.object,
|
||||||
avatarSize: PropTypes.number,
|
avatarSize: PropTypes.number,
|
||||||
statusStyle: ViewPropTypes.style
|
statusStyle: ViewPropTypes.style,
|
||||||
|
testID: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
@ -238,7 +239,7 @@ export default class RoomItem extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
favorite, unread, userMentions, name, _updatedAt, alert, type
|
favorite, unread, userMentions, name, _updatedAt, alert, type, testID
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const date = this.formatDate(_updatedAt);
|
const date = this.formatDate(_updatedAt);
|
||||||
|
@ -266,6 +267,7 @@ export default class RoomItem extends React.Component {
|
||||||
activeOpacity={0.5}
|
activeOpacity={0.5}
|
||||||
accessibilityLabel={accessibilityLabel}
|
accessibilityLabel={accessibilityLabel}
|
||||||
accessibilityTraits='selected'
|
accessibilityTraits='selected'
|
||||||
|
testID={testID}
|
||||||
>
|
>
|
||||||
<View style={[styles.container, favorite && styles.favorite]}>
|
<View style={[styles.container, favorite && styles.favorite]}>
|
||||||
{this.icon}
|
{this.icon}
|
||||||
|
|
|
@ -164,7 +164,7 @@ const watchLoginOpen = function* watchLoginOpen() {
|
||||||
}
|
}
|
||||||
const sub = yield RocketChat.subscribe('meteor.loginServiceConfiguration');
|
const sub = yield RocketChat.subscribe('meteor.loginServiceConfiguration');
|
||||||
yield take(types.LOGIN.CLOSE);
|
yield take(types.LOGIN.CLOSE);
|
||||||
sub.unsubscribe();
|
yield sub.unsubscribe().catch(err => console.warn(err));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('watchLoginOpen', e);
|
log('watchLoginOpen', e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,12 +140,16 @@ const updateLastOpen = function* updateLastOpen() {
|
||||||
const goRoomsListAndDelete = function* goRoomsListAndDelete(rid) {
|
const goRoomsListAndDelete = function* goRoomsListAndDelete(rid) {
|
||||||
NavigationService.goRoomsList();
|
NavigationService.goRoomsList();
|
||||||
yield delay(1000);
|
yield delay(1000);
|
||||||
|
try {
|
||||||
database.write(() => {
|
database.write(() => {
|
||||||
const messages = database.objects('messages').filtered('rid = $0', rid);
|
const messages = database.objects('messages').filtered('rid = $0', rid);
|
||||||
database.delete(messages);
|
database.delete(messages);
|
||||||
const subscription = database.objects('subscriptions').filtered('rid = $0', rid);
|
const subscription = database.objects('subscriptions').filtered('rid = $0', rid);
|
||||||
database.delete(subscription);
|
database.delete(subscription);
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('goRoomsListAndDelete', error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLeaveRoom = function* handleLeaveRoom({ rid }) {
|
const handleLeaveRoom = function* handleLeaveRoom({ rid }) {
|
||||||
|
|
|
@ -62,7 +62,7 @@ export default class CreateChannelView extends LoggedView {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text style={[styles.label_white, styles.label_error]}>
|
<Text style={[styles.label_white, styles.label_error]} testID='create-channel-error'>
|
||||||
{this.props.createChannel.error.reason}
|
{this.props.createChannel.error.reason}
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
|
@ -75,6 +75,7 @@ export default class CreateChannelView extends LoggedView {
|
||||||
style={[{ flexGrow: 0, flexShrink: 1 }]}
|
style={[{ flexGrow: 0, flexShrink: 1 }]}
|
||||||
value={this.state.type}
|
value={this.state.type}
|
||||||
onValueChange={type => this.setState({ type })}
|
onValueChange={type => this.setState({ type })}
|
||||||
|
testID='create-channel-type'
|
||||||
/>
|
/>
|
||||||
<Text style={[styles.label_white, styles.switchLabel]}>
|
<Text style={[styles.label_white, styles.switchLabel]}>
|
||||||
{this.state.type ? 'Public' : 'Private'}
|
{this.state.type ? 'Public' : 'Private'}
|
||||||
|
@ -90,7 +91,7 @@ export default class CreateChannelView extends LoggedView {
|
||||||
keyboardVerticalOffset={128}
|
keyboardVerticalOffset={128}
|
||||||
>
|
>
|
||||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
|
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
|
||||||
<SafeAreaView>
|
<SafeAreaView testID='create-channel-view'>
|
||||||
<RCTextInput
|
<RCTextInput
|
||||||
label='Channel Name'
|
label='Channel Name'
|
||||||
value={this.state.channelName}
|
value={this.state.channelName}
|
||||||
|
@ -98,6 +99,7 @@ export default class CreateChannelView extends LoggedView {
|
||||||
placeholder='Type the channel name here'
|
placeholder='Type the channel name here'
|
||||||
returnKeyType='done'
|
returnKeyType='done'
|
||||||
autoFocus
|
autoFocus
|
||||||
|
testID='create-channel-name'
|
||||||
/>
|
/>
|
||||||
{this.renderChannelNameError()}
|
{this.renderChannelNameError()}
|
||||||
{this.renderTypeSwitch()}
|
{this.renderTypeSwitch()}
|
||||||
|
@ -126,6 +128,7 @@ export default class CreateChannelView extends LoggedView {
|
||||||
? styles.disabledButton
|
? styles.disabledButton
|
||||||
: styles.enabledButton
|
: styles.enabledButton
|
||||||
]}
|
]}
|
||||||
|
testID='create-channel-submit'
|
||||||
>
|
>
|
||||||
<Text style={styles.button_white}>CREATE</Text>
|
<Text style={styles.button_white}>CREATE</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
|
@ -80,7 +80,7 @@ export default class ForgotPasswordView extends LoggedView {
|
||||||
keyboardVerticalOffset={128}
|
keyboardVerticalOffset={128}
|
||||||
>
|
>
|
||||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
|
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
|
||||||
<SafeAreaView>
|
<SafeAreaView testID='forgot-password-view'>
|
||||||
<View style={styles.loginView}>
|
<View style={styles.loginView}>
|
||||||
<View style={styles.formContainer}>
|
<View style={styles.formContainer}>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
@ -91,6 +91,7 @@ export default class ForgotPasswordView extends LoggedView {
|
||||||
returnKeyType='next'
|
returnKeyType='next'
|
||||||
onChangeText={email => this.validate(email)}
|
onChangeText={email => this.validate(email)}
|
||||||
onSubmitEditing={() => this.resetPassword()}
|
onSubmitEditing={() => this.resetPassword()}
|
||||||
|
testID='forgot-password-view-email'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<View style={styles.alignItemsFlexStart}>
|
<View style={styles.alignItemsFlexStart}>
|
||||||
|
@ -98,6 +99,7 @@ export default class ForgotPasswordView extends LoggedView {
|
||||||
title='Reset password'
|
title='Reset password'
|
||||||
type='primary'
|
type='primary'
|
||||||
onPress={this.resetPassword}
|
onPress={this.resetPassword}
|
||||||
|
testID='forgot-password-view-submit'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
|
|
@ -209,7 +209,7 @@ class ListServerView extends LoggedView {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.view}>
|
<SafeAreaView style={styles.view} testID='list-server-view'>
|
||||||
<SectionList
|
<SectionList
|
||||||
style={styles.list}
|
style={styles.list}
|
||||||
sections={this.state.sections}
|
sections={this.state.sections}
|
||||||
|
|
|
@ -277,7 +277,7 @@ export default class LoginSignupView extends LoggedView {
|
||||||
style={[sharedStyles.container, sharedStyles.containerScrollView]}
|
style={[sharedStyles.container, sharedStyles.containerScrollView]}
|
||||||
{...scrollPersistTaps}
|
{...scrollPersistTaps}
|
||||||
>
|
>
|
||||||
<SafeAreaView>
|
<SafeAreaView testID='welcome-view'>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Image
|
<Image
|
||||||
source={require('../static/images/logo.png')}
|
source={require('../static/images/logo.png')}
|
||||||
|
@ -294,11 +294,13 @@ export default class LoginSignupView extends LoggedView {
|
||||||
title='I have an account'
|
title='I have an account'
|
||||||
type='primary'
|
type='primary'
|
||||||
onPress={() => this.props.navigation.navigate({ key: 'Login', routeName: 'Login' })}
|
onPress={() => this.props.navigation.navigate({ key: 'Login', routeName: 'Login' })}
|
||||||
|
testID='welcome-view-login'
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
title='Create account'
|
title='Create account'
|
||||||
type='secondary'
|
type='secondary'
|
||||||
onPress={() => this.props.navigation.navigate({ key: 'Register', routeName: 'Register' })}
|
onPress={() => this.props.navigation.navigate({ key: 'Register', routeName: 'Register' })}
|
||||||
|
testID='welcome-view-register'
|
||||||
/>
|
/>
|
||||||
{this.renderServices()}
|
{this.renderServices()}
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -83,7 +83,7 @@ export default class LoginView extends LoggedView {
|
||||||
key='login-view'
|
key='login-view'
|
||||||
>
|
>
|
||||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
|
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
|
||||||
<SafeAreaView>
|
<SafeAreaView testID='login-view'>
|
||||||
<CloseModalButton navigation={this.props.navigation} />
|
<CloseModalButton navigation={this.props.navigation} />
|
||||||
<Text style={[styles.loginText, styles.loginTitle]}>Login</Text>
|
<Text style={[styles.loginText, styles.loginTitle]}>Login</Text>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
@ -94,6 +94,7 @@ export default class LoginView extends LoggedView {
|
||||||
iconLeft='at'
|
iconLeft='at'
|
||||||
onChangeText={username => this.setState({ username })}
|
onChangeText={username => this.setState({ username })}
|
||||||
onSubmitEditing={() => { this.password.focus(); }}
|
onSubmitEditing={() => { this.password.focus(); }}
|
||||||
|
testID='login-view-email'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
|
@ -105,6 +106,7 @@ export default class LoginView extends LoggedView {
|
||||||
secureTextEntry
|
secureTextEntry
|
||||||
onSubmitEditing={this.submit}
|
onSubmitEditing={this.submit}
|
||||||
onChangeText={password => this.setState({ password })}
|
onChangeText={password => this.setState({ password })}
|
||||||
|
testID='login-view-password'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{this.renderTOTP()}
|
{this.renderTOTP()}
|
||||||
|
@ -114,17 +116,20 @@ export default class LoginView extends LoggedView {
|
||||||
title='Login'
|
title='Login'
|
||||||
type='primary'
|
type='primary'
|
||||||
onPress={this.submit}
|
onPress={this.submit}
|
||||||
|
testID='login-view-submit'
|
||||||
/>
|
/>
|
||||||
<Text style={[styles.loginText, { marginTop: 10 }]}>New in Rocket.Chat?
|
|
||||||
<Text
|
<Text
|
||||||
style={{ color: COLOR_BUTTON_PRIMARY }}
|
style={[styles.loginText, { marginTop: 10 }]}
|
||||||
|
testID='login-view-register'
|
||||||
onPress={() => this.props.navigation.navigate('Register')}
|
onPress={() => this.props.navigation.navigate('Register')}
|
||||||
>Sign Up
|
>New in Rocket.Chat?
|
||||||
|
<Text style={{ color: COLOR_BUTTON_PRIMARY }}>Sign Up
|
||||||
</Text>
|
</Text>
|
||||||
</Text>
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
style={[styles.loginText, { marginTop: 20, fontSize: 13 }]}
|
style={[styles.loginText, { marginTop: 20, fontSize: 13 }]}
|
||||||
onPress={() => this.props.navigation.navigate('ForgotPassword')}
|
onPress={() => this.props.navigation.navigate('ForgotPassword')}
|
||||||
|
testID='login-view-forgot-password'
|
||||||
>Forgot password
|
>Forgot password
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -73,7 +73,7 @@ export default class MentionedMessagesView extends LoggedView {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderEmpty = () => (
|
renderEmpty = () => (
|
||||||
<View style={styles.listEmptyContainer}>
|
<View style={styles.listEmptyContainer} testID='mentioned-messages-view'>
|
||||||
<Text>No mentioned messages</Text>
|
<Text>No mentioned messages</Text>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
@ -99,8 +99,10 @@ export default class MentionedMessagesView extends LoggedView {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
[
|
||||||
<FlatList
|
<FlatList
|
||||||
key='mentioned-messages-view-list'
|
key='mentioned-messages-view-list'
|
||||||
|
testID='mentioned-messages-view'
|
||||||
data={messages}
|
data={messages}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
style={styles.list}
|
style={styles.list}
|
||||||
|
@ -109,6 +111,7 @@ export default class MentionedMessagesView extends LoggedView {
|
||||||
ListHeaderComponent={loading && <RCActivityIndicator />}
|
ListHeaderComponent={loading && <RCActivityIndicator />}
|
||||||
ListFooterComponent={loadingMore && <RCActivityIndicator />}
|
ListFooterComponent={loadingMore && <RCActivityIndicator />}
|
||||||
/>
|
/>
|
||||||
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ export default class NewServerView extends LoggedView {
|
||||||
keyboardVerticalOffset={128}
|
keyboardVerticalOffset={128}
|
||||||
>
|
>
|
||||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
|
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
|
||||||
<SafeAreaView>
|
<SafeAreaView testID='new-server-view'>
|
||||||
<Text style={[styles.loginText, styles.loginTitle]}>Sign in your server</Text>
|
<Text style={[styles.loginText, styles.loginTitle]}>Sign in your server</Text>
|
||||||
<TextInput
|
<TextInput
|
||||||
inputRef={e => this.input = e}
|
inputRef={e => this.input = e}
|
||||||
|
@ -115,6 +115,7 @@ export default class NewServerView extends LoggedView {
|
||||||
placeholder={this.state.defaultServer}
|
placeholder={this.state.defaultServer}
|
||||||
returnKeyType='done'
|
returnKeyType='done'
|
||||||
onChangeText={this.onChangeText}
|
onChangeText={this.onChangeText}
|
||||||
|
testID='new-server-view-input'
|
||||||
onSubmitEditing={this.submit}
|
onSubmitEditing={this.submit}
|
||||||
/>
|
/>
|
||||||
{this.renderValidation()}
|
{this.renderValidation()}
|
||||||
|
@ -124,6 +125,7 @@ export default class NewServerView extends LoggedView {
|
||||||
type='primary'
|
type='primary'
|
||||||
onPress={this.submit}
|
onPress={this.submit}
|
||||||
disabled={!validInstance}
|
disabled={!validInstance}
|
||||||
|
testID='new-server-view-button'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<Loading visible={this.props.addingServer} />
|
<Loading visible={this.props.addingServer} />
|
||||||
|
|
|
@ -97,7 +97,7 @@ export default class PinnedMessagesView extends LoggedView {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderEmpty = () => (
|
renderEmpty = () => (
|
||||||
<View style={styles.listEmptyContainer}>
|
<View style={styles.listEmptyContainer} testID='pinned-messages-view'>
|
||||||
<Text>No pinned messages</Text>
|
<Text>No pinned messages</Text>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
@ -126,6 +126,7 @@ export default class PinnedMessagesView extends LoggedView {
|
||||||
[
|
[
|
||||||
<FlatList
|
<FlatList
|
||||||
key='pinned-messages-view-list'
|
key='pinned-messages-view-list'
|
||||||
|
testID='pinned-messages-view'
|
||||||
data={messages}
|
data={messages}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
style={styles.list}
|
style={styles.list}
|
||||||
|
|
|
@ -108,6 +108,7 @@ export default class RegisterView extends LoggedView {
|
||||||
iconLeft='account'
|
iconLeft='account'
|
||||||
onChangeText={name => this.setState({ name })}
|
onChangeText={name => this.setState({ name })}
|
||||||
onSubmitEditing={() => { this.email.focus(); }}
|
onSubmitEditing={() => { this.email.focus(); }}
|
||||||
|
testID='register-view-name'
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
inputRef={(e) => { this.email = e; }}
|
inputRef={(e) => { this.email = e; }}
|
||||||
|
@ -119,6 +120,7 @@ export default class RegisterView extends LoggedView {
|
||||||
onChangeText={email => this.setState({ email })}
|
onChangeText={email => this.setState({ email })}
|
||||||
onSubmitEditing={() => { this.password.focus(); }}
|
onSubmitEditing={() => { this.password.focus(); }}
|
||||||
error={this.invalidEmail()}
|
error={this.invalidEmail()}
|
||||||
|
testID='register-view-email'
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
inputRef={(e) => { this.password = e; }}
|
inputRef={(e) => { this.password = e; }}
|
||||||
|
@ -129,6 +131,7 @@ export default class RegisterView extends LoggedView {
|
||||||
secureTextEntry
|
secureTextEntry
|
||||||
onChangeText={password => this.setState({ password })}
|
onChangeText={password => this.setState({ password })}
|
||||||
onSubmitEditing={() => { this.confirmPassword.focus(); }}
|
onSubmitEditing={() => { this.confirmPassword.focus(); }}
|
||||||
|
testID='register-view-password'
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
inputRef={(e) => { this.confirmPassword = e; }}
|
inputRef={(e) => { this.confirmPassword = e; }}
|
||||||
|
@ -144,6 +147,7 @@ export default class RegisterView extends LoggedView {
|
||||||
secureTextEntry
|
secureTextEntry
|
||||||
onChangeText={confirmPassword => this.setState({ confirmPassword })}
|
onChangeText={confirmPassword => this.setState({ confirmPassword })}
|
||||||
onSubmitEditing={this.submit}
|
onSubmitEditing={this.submit}
|
||||||
|
testID='register-view-repeat-password'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<View style={styles.alignItemsFlexStart}>
|
<View style={styles.alignItemsFlexStart}>
|
||||||
|
@ -157,10 +161,9 @@ export default class RegisterView extends LoggedView {
|
||||||
title='Register'
|
title='Register'
|
||||||
type='primary'
|
type='primary'
|
||||||
onPress={this.submit}
|
onPress={this.submit}
|
||||||
|
testID='register-view-submit'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{this.props.login.failure && <Text style={styles.error}>{this.props.login.error.reason}</Text>}
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -179,6 +182,7 @@ export default class RegisterView extends LoggedView {
|
||||||
iconLeft='at'
|
iconLeft='at'
|
||||||
onChangeText={username => this.setState({ username })}
|
onChangeText={username => this.setState({ username })}
|
||||||
onSubmitEditing={() => { this.usernameSubmit(); }}
|
onSubmitEditing={() => { this.usernameSubmit(); }}
|
||||||
|
testID='register-view-username'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<View style={styles.alignItemsFlexStart}>
|
<View style={styles.alignItemsFlexStart}>
|
||||||
|
@ -186,10 +190,9 @@ export default class RegisterView extends LoggedView {
|
||||||
title='Register'
|
title='Register'
|
||||||
type='primary'
|
type='primary'
|
||||||
onPress={this.usernameSubmit}
|
onPress={this.usernameSubmit}
|
||||||
|
testID='register-view-submit-username'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{this.props.login.failure && <Text style={styles.error}>{this.props.login.error.reason}</Text>}
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -198,11 +201,16 @@ export default class RegisterView extends LoggedView {
|
||||||
return (
|
return (
|
||||||
<KeyboardView contentContainerStyle={styles.container}>
|
<KeyboardView contentContainerStyle={styles.container}>
|
||||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
|
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
|
||||||
<SafeAreaView>
|
<SafeAreaView testID='register-view'>
|
||||||
<CloseModalButton navigation={this.props.navigation} />
|
<CloseModalButton navigation={this.props.navigation} />
|
||||||
<Text style={[styles.loginText, styles.loginTitle]}>Sign Up</Text>
|
<Text style={[styles.loginText, styles.loginTitle]}>Sign Up</Text>
|
||||||
{this._renderRegister()}
|
{this._renderRegister()}
|
||||||
{this._renderUsername()}
|
{this._renderUsername()}
|
||||||
|
{this.props.login.failure &&
|
||||||
|
<Text style={styles.error} testID='register-view-error'>
|
||||||
|
{this.props.login.error.reason}
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
<Loading visible={this.props.login.isFetching} />
|
<Loading visible={this.props.login.isFetching} />
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
|
@ -134,13 +134,24 @@ export default class RoomActionsView extends LoggedView {
|
||||||
icon: 'ios-star',
|
icon: 'ios-star',
|
||||||
name: 'USER',
|
name: 'USER',
|
||||||
route: 'RoomInfo',
|
route: 'RoomInfo',
|
||||||
params: { rid }
|
params: { rid },
|
||||||
|
testID: 'room-actions-info'
|
||||||
}],
|
}],
|
||||||
renderItem: this.renderRoomInfo
|
renderItem: this.renderRoomInfo
|
||||||
}, {
|
}, {
|
||||||
data: [
|
data: [
|
||||||
{ icon: 'ios-call-outline', name: 'Voice call', disabled: true },
|
{
|
||||||
{ icon: 'ios-videocam-outline', name: 'Video call', disabled: true }
|
icon: 'ios-call-outline',
|
||||||
|
name: 'Voice call',
|
||||||
|
disabled: true,
|
||||||
|
testID: 'room-actions-voice'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'ios-videocam-outline',
|
||||||
|
name: 'Video call',
|
||||||
|
disabled: true,
|
||||||
|
testID: 'room-actions-video'
|
||||||
|
}
|
||||||
],
|
],
|
||||||
renderItem: this.renderItem
|
renderItem: this.renderItem
|
||||||
}, {
|
}, {
|
||||||
|
@ -149,43 +160,55 @@ export default class RoomActionsView extends LoggedView {
|
||||||
icon: 'ios-attach',
|
icon: 'ios-attach',
|
||||||
name: 'Files',
|
name: 'Files',
|
||||||
route: 'RoomFiles',
|
route: 'RoomFiles',
|
||||||
params: { rid }
|
params: { rid },
|
||||||
|
testID: 'room-actions-files'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'ios-at-outline',
|
icon: 'ios-at-outline',
|
||||||
name: 'Mentions',
|
name: 'Mentions',
|
||||||
route: 'MentionedMessages',
|
route: 'MentionedMessages',
|
||||||
params: { rid }
|
params: { rid },
|
||||||
|
testID: 'room-actions-mentioned'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'ios-star-outline',
|
icon: 'ios-star-outline',
|
||||||
name: 'Starred',
|
name: 'Starred',
|
||||||
route: 'StarredMessages',
|
route: 'StarredMessages',
|
||||||
params: { rid }
|
params: { rid },
|
||||||
|
testID: 'room-actions-starred'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'ios-search',
|
icon: 'ios-search',
|
||||||
name: 'Search',
|
name: 'Search',
|
||||||
route: 'SearchMessages',
|
route: 'SearchMessages',
|
||||||
params: { rid }
|
params: { rid },
|
||||||
|
testID: 'room-actions-search'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'ios-share-outline',
|
||||||
|
name: 'Share',
|
||||||
|
disabled: true,
|
||||||
|
testID: 'room-actions-share'
|
||||||
},
|
},
|
||||||
{ icon: 'ios-share-outline', name: 'Share', disabled: true },
|
|
||||||
{
|
{
|
||||||
icon: 'ios-pin',
|
icon: 'ios-pin',
|
||||||
name: 'Pinned',
|
name: 'Pinned',
|
||||||
route: 'PinnedMessages',
|
route: 'PinnedMessages',
|
||||||
params: { rid }
|
params: { rid },
|
||||||
|
testID: 'room-actions-pinned'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'ios-code',
|
icon: 'ios-code',
|
||||||
name: 'Snippets',
|
name: 'Snippets',
|
||||||
route: 'SnippetedMessages',
|
route: 'SnippetedMessages',
|
||||||
params: { rid }
|
params: { rid },
|
||||||
|
testID: 'room-actions-snippeted'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: `ios-notifications${ notifications ? '' : '-off' }-outline`,
|
icon: `ios-notifications${ notifications ? '' : '-off' }-outline`,
|
||||||
name: `${ notifications ? 'Enable' : 'Disable' } notifications`,
|
name: `${ notifications ? 'Enable' : 'Disable' } notifications`,
|
||||||
event: () => this.toggleNotifications()
|
event: () => this.toggleNotifications(),
|
||||||
|
testID: 'room-actions-notifications'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
renderItem: this.renderItem
|
renderItem: this.renderItem
|
||||||
|
@ -198,7 +221,8 @@ export default class RoomActionsView extends LoggedView {
|
||||||
icon: 'block',
|
icon: 'block',
|
||||||
name: `${ blocked ? 'Unblock' : 'Block' } user`,
|
name: `${ blocked ? 'Unblock' : 'Block' } user`,
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
event: () => this.toggleBlockUser()
|
event: () => this.toggleBlockUser(),
|
||||||
|
testID: 'room-actions-block-user'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
renderItem: this.renderItem
|
renderItem: this.renderItem
|
||||||
|
@ -209,7 +233,8 @@ export default class RoomActionsView extends LoggedView {
|
||||||
name: 'Members',
|
name: 'Members',
|
||||||
description: (onlineMembers.length === 1 ? `${ onlineMembers.length } member` : `${ onlineMembers.length } members`),
|
description: (onlineMembers.length === 1 ? `${ onlineMembers.length } member` : `${ onlineMembers.length } members`),
|
||||||
route: 'RoomMembers',
|
route: 'RoomMembers',
|
||||||
params: { rid, members: onlineMembers }
|
params: { rid, members: onlineMembers },
|
||||||
|
testID: 'room-actions-members'
|
||||||
}];
|
}];
|
||||||
|
|
||||||
if (this.canAddUser) {
|
if (this.canAddUser) {
|
||||||
|
@ -229,7 +254,8 @@ export default class RoomActionsView extends LoggedView {
|
||||||
this.props.setLoadingInvite(false);
|
this.props.setLoadingInvite(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
testID: 'room-actions-add-user'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
sections[2].data = [...actions, ...sections[2].data];
|
sections[2].data = [...actions, ...sections[2].data];
|
||||||
|
@ -239,7 +265,8 @@ export default class RoomActionsView extends LoggedView {
|
||||||
icon: 'block',
|
icon: 'block',
|
||||||
name: 'Leave channel',
|
name: 'Leave channel',
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
event: () => this.leaveChannel()
|
event: () => this.leaveChannel(),
|
||||||
|
testID: 'room-actions-leave-channel'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
renderItem: this.renderItem
|
renderItem: this.renderItem
|
||||||
|
@ -248,7 +275,7 @@ export default class RoomActionsView extends LoggedView {
|
||||||
return sections;
|
return sections;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleBlockUser = () => {
|
toggleBlockUser = async() => {
|
||||||
const { rid, blocked } = this.state.room;
|
const { rid, blocked } = this.state.room;
|
||||||
const { member } = this.state;
|
const { member } = this.state;
|
||||||
try {
|
try {
|
||||||
|
@ -316,6 +343,7 @@ export default class RoomActionsView extends LoggedView {
|
||||||
activeOpacity={0.5}
|
activeOpacity={0.5}
|
||||||
accessibilityLabel={item.name}
|
accessibilityLabel={item.name}
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
|
testID={item.testID}
|
||||||
>
|
>
|
||||||
<View style={[styles.sectionItem, item.disabled && styles.sectionItemDisabled]}>
|
<View style={[styles.sectionItem, item.disabled && styles.sectionItemDisabled]}>
|
||||||
{subview}
|
{subview}
|
||||||
|
@ -348,6 +376,7 @@ export default class RoomActionsView extends LoggedView {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
<View testID='room-actions-view'>
|
||||||
<SectionList
|
<SectionList
|
||||||
style={styles.container}
|
style={styles.container}
|
||||||
stickySectionHeadersEnabled={false}
|
stickySectionHeadersEnabled={false}
|
||||||
|
@ -355,7 +384,9 @@ export default class RoomActionsView extends LoggedView {
|
||||||
SectionSeparatorComponent={this.renderSectionSeparator}
|
SectionSeparatorComponent={this.renderSectionSeparator}
|
||||||
ItemSeparatorComponent={renderSeparator}
|
ItemSeparatorComponent={renderSeparator}
|
||||||
keyExtractor={item => item.name}
|
keyExtractor={item => item.name}
|
||||||
|
testID='room-actions-list'
|
||||||
/>
|
/>
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ export default class RoomFilesView extends LoggedView {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderEmpty = () => (
|
renderEmpty = () => (
|
||||||
<View style={styles.listEmptyContainer}>
|
<View style={styles.listEmptyContainer} testID='room-files-view'>
|
||||||
<Text>No files</Text>
|
<Text>No files</Text>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
@ -97,8 +97,10 @@ export default class RoomFilesView extends LoggedView {
|
||||||
|
|
||||||
const { loading, loadingMore } = this.state;
|
const { loading, loadingMore } = this.state;
|
||||||
return (
|
return (
|
||||||
|
[
|
||||||
<FlatList
|
<FlatList
|
||||||
key='room-files-view-list'
|
key='room-files-view-list'
|
||||||
|
testID='room-files-view'
|
||||||
data={messages}
|
data={messages}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
style={styles.list}
|
style={styles.list}
|
||||||
|
@ -107,6 +109,7 @@ export default class RoomFilesView extends LoggedView {
|
||||||
ListHeaderComponent={loading && <RCActivityIndicator />}
|
ListHeaderComponent={loading && <RCActivityIndicator />}
|
||||||
ListFooterComponent={loadingMore && <RCActivityIndicator />}
|
ListFooterComponent={loadingMore && <RCActivityIndicator />}
|
||||||
/>
|
/>
|
||||||
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,13 @@ export default class SwitchContainer extends React.PureComponent {
|
||||||
leftLabelSecondary: PropTypes.string,
|
leftLabelSecondary: PropTypes.string,
|
||||||
rightLabelPrimary: PropTypes.string,
|
rightLabelPrimary: PropTypes.string,
|
||||||
rightLabelSecondary: PropTypes.string,
|
rightLabelSecondary: PropTypes.string,
|
||||||
onValueChange: PropTypes.func
|
onValueChange: PropTypes.func,
|
||||||
|
testID: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
value, disabled, onValueChange, leftLabelPrimary, leftLabelSecondary, rightLabelPrimary, rightLabelSecondary
|
value, disabled, onValueChange, leftLabelPrimary, leftLabelSecondary, rightLabelPrimary, rightLabelSecondary, testID
|
||||||
} = this.props;
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
[
|
[
|
||||||
|
@ -32,6 +33,7 @@ export default class SwitchContainer extends React.PureComponent {
|
||||||
onValueChange={onValueChange}
|
onValueChange={onValueChange}
|
||||||
value={value}
|
value={value}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
testID={testID}
|
||||||
/>
|
/>
|
||||||
<View style={styles.switchLabelContainer}>
|
<View style={styles.switchLabelContainer}>
|
||||||
<Text style={styles.switchLabelPrimary}>{rightLabelPrimary}</Text>
|
<Text style={styles.switchLabelPrimary}>{rightLabelPrimary}</Text>
|
||||||
|
|
|
@ -74,9 +74,9 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
this.rooms.removeAllListeners();
|
this.rooms.removeAllListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRoom = () => {
|
updateRoom = async() => {
|
||||||
const [room] = this.rooms;
|
const [room] = this.rooms;
|
||||||
this.setState({ room });
|
await this.setState({ room });
|
||||||
}
|
}
|
||||||
|
|
||||||
init = () => {
|
init = () => {
|
||||||
|
@ -259,8 +259,12 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
contentContainerStyle={sharedStyles.container}
|
contentContainerStyle={sharedStyles.container}
|
||||||
keyboardVerticalOffset={128}
|
keyboardVerticalOffset={128}
|
||||||
>
|
>
|
||||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
|
<ScrollView
|
||||||
<SafeAreaView>
|
contentContainerStyle={sharedStyles.containerScrollView}
|
||||||
|
testID='room-info-edit-view-list'
|
||||||
|
{...scrollPersistTaps}
|
||||||
|
>
|
||||||
|
<SafeAreaView testID='room-info-edit-view'>
|
||||||
<View style={sharedStyles.formContainer}>
|
<View style={sharedStyles.formContainer}>
|
||||||
<RCTextInput
|
<RCTextInput
|
||||||
inputRef={(e) => { this.name = e; }}
|
inputRef={(e) => { this.name = e; }}
|
||||||
|
@ -269,6 +273,7 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
onChangeText={value => this.setState({ name: value })}
|
onChangeText={value => this.setState({ name: value })}
|
||||||
onSubmitEditing={() => { this.description.focus(); }}
|
onSubmitEditing={() => { this.description.focus(); }}
|
||||||
error={nameError}
|
error={nameError}
|
||||||
|
testID='room-info-edit-view-name'
|
||||||
/>
|
/>
|
||||||
<RCTextInput
|
<RCTextInput
|
||||||
inputRef={(e) => { this.description = e; }}
|
inputRef={(e) => { this.description = e; }}
|
||||||
|
@ -276,6 +281,7 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
value={description}
|
value={description}
|
||||||
onChangeText={value => this.setState({ description: value })}
|
onChangeText={value => this.setState({ description: value })}
|
||||||
onSubmitEditing={() => { this.topic.focus(); }}
|
onSubmitEditing={() => { this.topic.focus(); }}
|
||||||
|
testID='room-info-edit-view-description'
|
||||||
/>
|
/>
|
||||||
<RCTextInput
|
<RCTextInput
|
||||||
inputRef={(e) => { this.topic = e; }}
|
inputRef={(e) => { this.topic = e; }}
|
||||||
|
@ -283,6 +289,7 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
value={topic}
|
value={topic}
|
||||||
onChangeText={value => this.setState({ topic: value })}
|
onChangeText={value => this.setState({ topic: value })}
|
||||||
onSubmitEditing={() => { this.announcement.focus(); }}
|
onSubmitEditing={() => { this.announcement.focus(); }}
|
||||||
|
testID='room-info-edit-view-topic'
|
||||||
/>
|
/>
|
||||||
<RCTextInput
|
<RCTextInput
|
||||||
inputRef={(e) => { this.announcement = e; }}
|
inputRef={(e) => { this.announcement = e; }}
|
||||||
|
@ -290,6 +297,7 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
value={announcement}
|
value={announcement}
|
||||||
onChangeText={value => this.setState({ announcement: value })}
|
onChangeText={value => this.setState({ announcement: value })}
|
||||||
onSubmitEditing={() => { this.joinCode.focus(); }}
|
onSubmitEditing={() => { this.joinCode.focus(); }}
|
||||||
|
testID='room-info-edit-view-announcement'
|
||||||
/>
|
/>
|
||||||
<RCTextInput
|
<RCTextInput
|
||||||
inputRef={(e) => { this.joinCode = e; }}
|
inputRef={(e) => { this.joinCode = e; }}
|
||||||
|
@ -298,6 +306,7 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
onChangeText={value => this.setState({ joinCode: value })}
|
onChangeText={value => this.setState({ joinCode: value })}
|
||||||
onSubmitEditing={this.submit}
|
onSubmitEditing={this.submit}
|
||||||
secureTextEntry
|
secureTextEntry
|
||||||
|
testID='room-info-edit-view-password'
|
||||||
/>
|
/>
|
||||||
<SwitchContainer
|
<SwitchContainer
|
||||||
value={t}
|
value={t}
|
||||||
|
@ -306,6 +315,7 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
rightLabelPrimary='Private'
|
rightLabelPrimary='Private'
|
||||||
rightLabelSecondary='Just invited people can access this channel'
|
rightLabelSecondary='Just invited people can access this channel'
|
||||||
onValueChange={value => this.setState({ t: value })}
|
onValueChange={value => this.setState({ t: value })}
|
||||||
|
testID='room-info-edit-view-t'
|
||||||
/>
|
/>
|
||||||
<SwitchContainer
|
<SwitchContainer
|
||||||
value={ro}
|
value={ro}
|
||||||
|
@ -315,6 +325,7 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
rightLabelSecondary='Only authorized users can write new messages'
|
rightLabelSecondary='Only authorized users can write new messages'
|
||||||
onValueChange={value => this.setState({ ro: value })}
|
onValueChange={value => this.setState({ ro: value })}
|
||||||
disabled={!this.permissions[PERMISSION_SET_READONLY]}
|
disabled={!this.permissions[PERMISSION_SET_READONLY]}
|
||||||
|
testID='room-info-edit-view-ro'
|
||||||
/>
|
/>
|
||||||
{ro &&
|
{ro &&
|
||||||
<SwitchContainer
|
<SwitchContainer
|
||||||
|
@ -325,12 +336,14 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
rightLabelSecondary='Reactions are enabled'
|
rightLabelSecondary='Reactions are enabled'
|
||||||
onValueChange={value => this.setState({ reactWhenReadOnly: value })}
|
onValueChange={value => this.setState({ reactWhenReadOnly: value })}
|
||||||
disabled={!this.permissions[PERMISSION_SET_REACT_WHEN_READONLY]}
|
disabled={!this.permissions[PERMISSION_SET_REACT_WHEN_READONLY]}
|
||||||
|
testID='room-info-edit-view-react-when-ro'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[sharedStyles.buttonContainer, !this.formIsChanged() && styles.buttonContainerDisabled]}
|
style={[sharedStyles.buttonContainer, !this.formIsChanged() && styles.buttonContainerDisabled]}
|
||||||
onPress={this.submit}
|
onPress={this.submit}
|
||||||
disabled={!this.formIsChanged()}
|
disabled={!this.formIsChanged()}
|
||||||
|
testID='room-info-edit-view-submit'
|
||||||
>
|
>
|
||||||
<Text style={sharedStyles.button} accessibilityTraits='button'>SAVE</Text>
|
<Text style={sharedStyles.button} accessibilityTraits='button'>SAVE</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
@ -338,6 +351,7 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[sharedStyles.buttonContainer_inverted, styles.buttonInverted, { flex: 1 }]}
|
style={[sharedStyles.buttonContainer_inverted, styles.buttonInverted, { flex: 1 }]}
|
||||||
onPress={this.reset}
|
onPress={this.reset}
|
||||||
|
testID='room-info-edit-view-reset'
|
||||||
>
|
>
|
||||||
<Text style={sharedStyles.button_inverted} accessibilityTraits='button'>RESET</Text>
|
<Text style={sharedStyles.button_inverted} accessibilityTraits='button'>RESET</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
@ -350,6 +364,7 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
]}
|
]}
|
||||||
onPress={this.toggleArchive}
|
onPress={this.toggleArchive}
|
||||||
disabled={!this.hasArchivePermission()}
|
disabled={!this.hasArchivePermission()}
|
||||||
|
testID='room-info-edit-view-archive'
|
||||||
>
|
>
|
||||||
<Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'>
|
<Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'>
|
||||||
{ room.archived ? 'UNARCHIVE' : 'ARCHIVE' }
|
{ room.archived ? 'UNARCHIVE' : 'ARCHIVE' }
|
||||||
|
@ -366,6 +381,7 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
]}
|
]}
|
||||||
onPress={this.delete}
|
onPress={this.delete}
|
||||||
disabled={!this.hasDeletePermission()}
|
disabled={!this.hasDeletePermission()}
|
||||||
|
testID='room-info-edit-view-delete'
|
||||||
>
|
>
|
||||||
<Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'>DELETE</Text>
|
<Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'>DELETE</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
|
@ -20,7 +20,10 @@ import RoomTypeIcon from '../../containers/RoomTypeIcon';
|
||||||
const PERMISSION_EDIT_ROOM = 'edit-room';
|
const PERMISSION_EDIT_ROOM = 'edit-room';
|
||||||
|
|
||||||
const camelize = str => str.replace(/^(.)/, (match, chr) => chr.toUpperCase());
|
const camelize = str => str.replace(/^(.)/, (match, chr) => chr.toUpperCase());
|
||||||
const getRoomTitle = room => (room.t === 'd' ? <Text>{room.fname}</Text> : <Text><RoomTypeIcon type={room.t} /> {room.name}</Text>);
|
const getRoomTitle = room => (room.t === 'd' ?
|
||||||
|
<Text testID='room-info-view-name'>{room.fname}</Text> :
|
||||||
|
[<RoomTypeIcon type={room.t} />, <Text testID='room-info-view-name'>{room.name}</Text>]
|
||||||
|
);
|
||||||
@connect(state => ({
|
@connect(state => ({
|
||||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
|
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
|
||||||
user: state.login.user,
|
user: state.login.user,
|
||||||
|
@ -52,6 +55,7 @@ export default class RoomInfoView extends LoggedView {
|
||||||
activeOpacity={0.5}
|
activeOpacity={0.5}
|
||||||
accessibilityLabel='edit'
|
accessibilityLabel='edit'
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
|
testID='room-info-view-edit-button'
|
||||||
>
|
>
|
||||||
<View style={styles.headerButton}>
|
<View style={styles.headerButton}>
|
||||||
<MaterialIcon name='edit' size={20} />
|
<MaterialIcon name='edit' size={20} />
|
||||||
|
@ -129,7 +133,11 @@ export default class RoomInfoView extends LoggedView {
|
||||||
renderItem = (key, room) => (
|
renderItem = (key, room) => (
|
||||||
<View style={styles.item}>
|
<View style={styles.item}>
|
||||||
<Text style={styles.itemLabel}>{camelize(key)}</Text>
|
<Text style={styles.itemLabel}>{camelize(key)}</Text>
|
||||||
<Text style={[styles.itemContent, !room[key] && styles.itemContent__empty]}>{ room[key] ? room[key] : `No ${ key } provided.` }</Text>
|
<Text
|
||||||
|
style={[styles.itemContent, !room[key] && styles.itemContent__empty]}
|
||||||
|
testID={`room-info-view-${ key }`}
|
||||||
|
>{ room[key] ? room[key] : `No ${ key } provided.` }
|
||||||
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -183,9 +191,9 @@ export default class RoomInfoView extends LoggedView {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ScrollView style={styles.container}>
|
<ScrollView style={styles.container}>
|
||||||
<View style={styles.avatarContainer}>
|
<View style={styles.avatarContainer} testID='room-info-view'>
|
||||||
{this.renderAvatar(room, roomUser)}
|
{this.renderAvatar(room, roomUser)}
|
||||||
<Text style={styles.roomTitle}>{ getRoomTitle(room) }</Text>
|
<View style={styles.roomTitle}>{ getRoomTitle(room) }</View>
|
||||||
</View>
|
</View>
|
||||||
{!this.isDirect() && this.renderItem('description', room)}
|
{!this.isDirect() && this.renderItem('description', room)}
|
||||||
{!this.isDirect() && this.renderItem('topic', room)}
|
{!this.isDirect() && this.renderItem('topic', room)}
|
||||||
|
|
|
@ -31,7 +31,8 @@ export default StyleSheet.create({
|
||||||
},
|
},
|
||||||
roomTitle: {
|
roomTitle: {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
paddingTop: 20
|
paddingTop: 20,
|
||||||
|
flexDirection: 'row'
|
||||||
},
|
},
|
||||||
roomDescription: {
|
roomDescription: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
|
|
@ -39,6 +39,7 @@ export default class MentionedMessagesView extends LoggedView {
|
||||||
accessibilityLabel={label}
|
accessibilityLabel={label}
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
style={styles.headerButtonTouchable}
|
style={styles.headerButtonTouchable}
|
||||||
|
testID='room-members-view-toggle-status'
|
||||||
>
|
>
|
||||||
<View style={styles.headerButton}>
|
<View style={styles.headerButton}>
|
||||||
<Text style={styles.headerButtonText}>{label}</Text>
|
<Text style={styles.headerButtonText}>{label}</Text>
|
||||||
|
@ -168,6 +169,7 @@ export default class MentionedMessagesView extends LoggedView {
|
||||||
blurOnSubmit
|
blurOnSubmit
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
autoCapitalize='none'
|
autoCapitalize='none'
|
||||||
|
testID='room-members-view-search'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
@ -185,6 +187,7 @@ export default class MentionedMessagesView extends LoggedView {
|
||||||
showLastMessage={false}
|
showLastMessage={false}
|
||||||
avatarSize={30}
|
avatarSize={30}
|
||||||
statusStyle={styles.status}
|
statusStyle={styles.status}
|
||||||
|
testID={`room-members-view-item-${ item.username }`}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -194,6 +197,7 @@ export default class MentionedMessagesView extends LoggedView {
|
||||||
[
|
[
|
||||||
<FlatList
|
<FlatList
|
||||||
key='room-members-view-list'
|
key='room-members-view-list'
|
||||||
|
testID='room-members-view'
|
||||||
data={filtering ? membersFiltered : members}
|
data={filtering ? membersFiltered : members}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
style={styles.list}
|
style={styles.list}
|
||||||
|
|
|
@ -136,7 +136,8 @@ export default class RoomHeaderView extends React.PureComponent {
|
||||||
style={styles.titleContainer}
|
style={styles.titleContainer}
|
||||||
accessibilityLabel={accessibilityLabel}
|
accessibilityLabel={accessibilityLabel}
|
||||||
accessibilityTraits='header'
|
accessibilityTraits='header'
|
||||||
onPress={() => this.props.navigation.navigate({ key: 'RoomInfo', routeName: 'RoomInfo', params: this.state.room })}
|
onPress={() => this.props.navigation.navigate({ key: 'RoomInfo', routeName: 'RoomInfo', params: { rid: this.state.room.rid } })}
|
||||||
|
testID='room-view-header-title'
|
||||||
>
|
>
|
||||||
|
|
||||||
<Avatar
|
<Avatar
|
||||||
|
@ -151,10 +152,12 @@ export default class RoomHeaderView extends React.PureComponent {
|
||||||
}
|
}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<View style={styles.titleTextContainer}>
|
<View style={styles.titleTextContainer}>
|
||||||
<Text style={styles.title} allowFontScaling={false}>
|
<View style={{ flexDirection: 'row' }}>
|
||||||
<RoomTypeIcon type={this.state.room.t} size={13} />
|
<RoomTypeIcon type={this.state.room.t} size={13} />
|
||||||
|
<Text style={styles.title} allowFontScaling={false} testID='room-view-title'>
|
||||||
{this.state.room.name}
|
{this.state.room.name}
|
||||||
</Text>
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
{ t && <Text style={styles.userStatus} allowFontScaling={false} numberOfLines={1}>{t}</Text>}
|
{ t && <Text style={styles.userStatus} allowFontScaling={false} numberOfLines={1}>{t}</Text>}
|
||||||
|
|
||||||
|
@ -176,6 +179,7 @@ export default class RoomHeaderView extends React.PureComponent {
|
||||||
}}
|
}}
|
||||||
accessibilityLabel='Star room'
|
accessibilityLabel='Star room'
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
|
testID='room-view-header-star'
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
name={`${ Platform.OS === 'ios' ? 'ios' : 'md' }-star${ this.state.room.f ? '' : '-outline' }`}
|
name={`${ Platform.OS === 'ios' ? 'ios' : 'md' }-star${ this.state.room.f ? '' : '-outline' }`}
|
||||||
|
@ -189,6 +193,7 @@ export default class RoomHeaderView extends React.PureComponent {
|
||||||
onPress={() => this.props.navigation.navigate({ key: 'RoomActions', routeName: 'RoomActions', params: { rid: this.state.room.rid } })}
|
onPress={() => this.props.navigation.navigate({ key: 'RoomActions', routeName: 'RoomActions', params: { rid: this.state.room.rid } })}
|
||||||
accessibilityLabel='Room actions'
|
accessibilityLabel='Room actions'
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
|
testID='room-view-header-actions'
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
name={Platform.OS === 'ios' ? 'ios-more' : 'md-more'}
|
name={Platform.OS === 'ios' ? 'ios-more' : 'md-more'}
|
||||||
|
@ -202,7 +207,7 @@ export default class RoomHeaderView extends React.PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<View style={styles.header}>
|
<View style={styles.header} testID='room-view-header'>
|
||||||
{this.renderLeft()}
|
{this.renderLeft()}
|
||||||
{this.renderCenter()}
|
{this.renderCenter()}
|
||||||
{this.renderRight()}
|
{this.renderRight()}
|
||||||
|
|
|
@ -77,6 +77,7 @@ export class List extends React.Component {
|
||||||
renderRow={(item, previousItem) => this.props.renderRow(item, previousItem)}
|
renderRow={(item, previousItem) => this.props.renderRow(item, previousItem)}
|
||||||
initialListSize={20}
|
initialListSize={20}
|
||||||
pageSize={20}
|
pageSize={20}
|
||||||
|
testID='room-view-messages'
|
||||||
{...scrollPersistTaps}
|
{...scrollPersistTaps}
|
||||||
/>);
|
/>);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,10 @@ export default class ReactionPicker extends React.Component {
|
||||||
animationIn='fadeIn'
|
animationIn='fadeIn'
|
||||||
animationOut='fadeOut'
|
animationOut='fadeOut'
|
||||||
>
|
>
|
||||||
<View style={[styles.reactionPickerContainer, { width: width - margin, height: Math.min(width, height) - (margin * 2) }]}>
|
<View
|
||||||
|
style={[styles.reactionPickerContainer, { width: width - margin, height: Math.min(width, height) - (margin * 2) }]}
|
||||||
|
testID='reaction-picker'
|
||||||
|
>
|
||||||
<EmojiPicker
|
<EmojiPicker
|
||||||
tabEmojiStyle={tabEmojiStyle}
|
tabEmojiStyle={tabEmojiStyle}
|
||||||
width={Math.min(width, height) - margin}
|
width={Math.min(width, height) - margin}
|
||||||
|
|
|
@ -74,8 +74,8 @@ export default class RoomView extends LoggedView {
|
||||||
this.onReactionPress = this.onReactionPress.bind(this);
|
this.onReactionPress = this.onReactionPress.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
componentDidMount() {
|
||||||
await this.updateRoom();
|
this.updateRoom();
|
||||||
this.rooms.addListener(this.updateRoom);
|
this.rooms.addListener(this.updateRoom);
|
||||||
}
|
}
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
|
@ -197,7 +197,7 @@ export default class RoomView extends LoggedView {
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container} testID='room-view'>
|
||||||
<List
|
<List
|
||||||
key='room-view-messages'
|
key='room-view-messages'
|
||||||
end={this.state.end}
|
end={this.state.end}
|
||||||
|
|
|
@ -121,7 +121,13 @@ export default class RoomsListHeaderView extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.left} accessible accessibilityLabel="Server's list" accessibilityTraits='button'>
|
<View
|
||||||
|
style={styles.left}
|
||||||
|
accessible
|
||||||
|
accessibilityLabel={`Connected to ${ this.props.baseUrl }. Tap to view servers list.`}
|
||||||
|
accessibilityTraits='button'
|
||||||
|
testID='rooms-list-view-sidebar'
|
||||||
|
>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.headerButton}
|
style={styles.headerButton}
|
||||||
onPress={() => this.props.navigation.openDrawer()}
|
onPress={() => this.props.navigation.openDrawer()}
|
||||||
|
@ -150,10 +156,15 @@ export default class RoomsListHeaderView extends React.PureComponent {
|
||||||
|
|
||||||
const t = title(offline, connecting, authenticating, logged);
|
const t = title(offline, connecting, authenticating, logged);
|
||||||
|
|
||||||
const accessibilityLabel = `${ user.username }, ${ this.getUserStatusLabel() }, double tap to change status`;
|
const accessibilityLabel = `${ user.username }, ${ this.getUserStatusLabel() }, tap to change status`;
|
||||||
return (
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
<TouchableOpacity style={styles.titleContainer} onPress={() => this.showModal()} accessibilityLabel={accessibilityLabel} accessibilityTraits='header'>
|
style={styles.titleContainer}
|
||||||
|
onPress={() => this.showModal()}
|
||||||
|
accessibilityLabel={accessibilityLabel}
|
||||||
|
accessibilityTraits='header'
|
||||||
|
testID='rooms-list-view-user'
|
||||||
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
text={user.username}
|
text={user.username}
|
||||||
size={24}
|
size={24}
|
||||||
|
@ -195,6 +206,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
|
||||||
onPress={() => this.createChannel()}
|
onPress={() => this.createChannel()}
|
||||||
accessibilityLabel='Create channel'
|
accessibilityLabel='Create channel'
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
|
testID='rooms-list-view-create-channel'
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
name='ios-add'
|
name='ios-add'
|
||||||
|
@ -215,6 +227,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.modalButton}
|
style={styles.modalButton}
|
||||||
onPress={() => this.onPressModalButton(status)}
|
onPress={() => this.onPressModalButton(status)}
|
||||||
|
testID={`rooms-list-view-user-presence-${ status }`}
|
||||||
>
|
>
|
||||||
<View style={statusStyle} />
|
<View style={statusStyle} />
|
||||||
<Text style={textStyle}>
|
<Text style={textStyle}>
|
||||||
|
@ -251,7 +264,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<View style={styles.header}>
|
<View style={styles.header} testID='rooms-list-view-header'>
|
||||||
{this.renderLeft()}
|
{this.renderLeft()}
|
||||||
{this.renderCenter()}
|
{this.renderCenter()}
|
||||||
{this.renderRight()}
|
{this.renderRight()}
|
||||||
|
@ -262,6 +275,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
|
||||||
style={{ alignItems: 'center' }}
|
style={{ alignItems: 'center' }}
|
||||||
onModalHide={() => this.hideModal()}
|
onModalHide={() => this.hideModal()}
|
||||||
onBackdropPress={() => this.hideModal()}
|
onBackdropPress={() => this.hideModal()}
|
||||||
|
testID='rooms-list-view-user-presence-modal'
|
||||||
>
|
>
|
||||||
<View style={styles.modal}>
|
<View style={styles.modal}>
|
||||||
{this.renderModalButton('online')}
|
{this.renderModalButton('online')}
|
||||||
|
|
|
@ -158,6 +158,7 @@ export default class RoomsListView extends LoggedView {
|
||||||
blurOnSubmit
|
blurOnSubmit
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
autoCapitalize='none'
|
autoCapitalize='none'
|
||||||
|
testID='rooms-list-view-search'
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
@ -177,6 +178,7 @@ export default class RoomsListView extends LoggedView {
|
||||||
type={item.t}
|
type={item.t}
|
||||||
baseUrl={this.props.Site_Url}
|
baseUrl={this.props.Site_Url}
|
||||||
onPress={() => this._onPressItem(item)}
|
onPress={() => this._onPressItem(item)}
|
||||||
|
testID={`rooms-list-view-item-${ item.name }`}
|
||||||
/>);
|
/>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,6 +193,7 @@ export default class RoomsListView extends LoggedView {
|
||||||
enableEmptySections
|
enableEmptySections
|
||||||
removeClippedSubviews
|
removeClippedSubviews
|
||||||
keyboardShouldPersistTaps='always'
|
keyboardShouldPersistTaps='always'
|
||||||
|
testID='rooms-list-view-list'
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -203,7 +206,7 @@ export default class RoomsListView extends LoggedView {
|
||||||
);
|
);
|
||||||
|
|
||||||
render = () => (
|
render = () => (
|
||||||
<View style={styles.container}>
|
<View style={styles.container} testID='rooms-list-view'>
|
||||||
{this.renderList()}
|
{this.renderList()}
|
||||||
{Platform.OS === 'android' && this.renderCreateButtons()}
|
{Platform.OS === 'android' && this.renderCreateButtons()}
|
||||||
</View>)
|
</View>)
|
||||||
|
|
|
@ -109,6 +109,7 @@ export default class SearchMessagesView extends LoggedView {
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={styles.container}
|
style={styles.container}
|
||||||
|
testID='search-messages-view'
|
||||||
>
|
>
|
||||||
<View style={styles.searchContainer}>
|
<View style={styles.searchContainer}>
|
||||||
<RCTextInput
|
<RCTextInput
|
||||||
|
@ -116,6 +117,7 @@ export default class SearchMessagesView extends LoggedView {
|
||||||
label='Search'
|
label='Search'
|
||||||
onChangeText={this.onChangeSearch}
|
onChangeText={this.onChangeSearch}
|
||||||
placeholder='Search Messages'
|
placeholder='Search Messages'
|
||||||
|
testID='search-message-view-input'
|
||||||
/>
|
/>
|
||||||
<Markdown msg='You can search using RegExp. e.g. `/^text$/i`' />
|
<Markdown msg='You can search using RegExp. e.g. `/^text$/i`' />
|
||||||
<View style={styles.divider} />
|
<View style={styles.divider} />
|
||||||
|
|
|
@ -103,6 +103,7 @@ export default class SelectedUsersView extends LoggedView {
|
||||||
onPress={() => params.nextAction()}
|
onPress={() => params.nextAction()}
|
||||||
accessibilityLabel='Submit'
|
accessibilityLabel='Submit'
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
|
testID='selected-users-view-submit'
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
name='ios-add'
|
name='ios-add'
|
||||||
|
@ -229,6 +230,7 @@ export default class SelectedUsersView extends LoggedView {
|
||||||
placeholder='Search'
|
placeholder='Search'
|
||||||
clearButtonMode='while-editing'
|
clearButtonMode='while-editing'
|
||||||
blurOnSubmit
|
blurOnSubmit
|
||||||
|
testID='select-users-view-search'
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
autoCapitalize='none'
|
autoCapitalize='none'
|
||||||
/>
|
/>
|
||||||
|
@ -255,6 +257,7 @@ export default class SelectedUsersView extends LoggedView {
|
||||||
key={item._id}
|
key={item._id}
|
||||||
style={styles.selectItemView}
|
style={styles.selectItemView}
|
||||||
onPress={() => this._onPressSelectedItem(item)}
|
onPress={() => this._onPressSelectedItem(item)}
|
||||||
|
testID={`selected-user-${ item.name }`}
|
||||||
>
|
>
|
||||||
<Avatar text={item.name} size={40} />
|
<Avatar text={item.name} size={40} />
|
||||||
<Text ellipsizeMode='tail' numberOfLines={1} style={{ fontSize: 10 }}>
|
<Text ellipsizeMode='tail' numberOfLines={1} style={{ fontSize: 10 }}>
|
||||||
|
@ -273,6 +276,7 @@ export default class SelectedUsersView extends LoggedView {
|
||||||
showLastMessage={false}
|
showLastMessage={false}
|
||||||
avatarSize={30}
|
avatarSize={30}
|
||||||
statusStyle={styles.status}
|
statusStyle={styles.status}
|
||||||
|
testID={`select-users-view-item-${ item.name }`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
renderList = () => (
|
renderList = () => (
|
||||||
|
@ -300,7 +304,7 @@ export default class SelectedUsersView extends LoggedView {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
render = () => (
|
render = () => (
|
||||||
<View style={styles.container}>
|
<View style={styles.container} testID='select-users-view'>
|
||||||
<SafeAreaView style={styles.safeAreaView}>
|
<SafeAreaView style={styles.safeAreaView}>
|
||||||
{this.renderList()}
|
{this.renderList()}
|
||||||
{this.renderCreateButton()}
|
{this.renderCreateButton()}
|
||||||
|
|
|
@ -73,7 +73,7 @@ export default class SnippetedMessagesView extends LoggedView {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderEmpty = () => (
|
renderEmpty = () => (
|
||||||
<View style={styles.listEmptyContainer}>
|
<View style={styles.listEmptyContainer} testID='snippeted-messages-view'>
|
||||||
<Text>No snippeted messages</Text>
|
<Text>No snippeted messages</Text>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
@ -99,8 +99,10 @@ export default class SnippetedMessagesView extends LoggedView {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
[
|
||||||
<FlatList
|
<FlatList
|
||||||
key='snippet-messages-view-list'
|
key='snippeted-messages-view-list'
|
||||||
|
testID='snippeted-messages-view'
|
||||||
data={messages}
|
data={messages}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
style={styles.list}
|
style={styles.list}
|
||||||
|
@ -109,6 +111,7 @@ export default class SnippetedMessagesView extends LoggedView {
|
||||||
ListHeaderComponent={loading && <RCActivityIndicator />}
|
ListHeaderComponent={loading && <RCActivityIndicator />}
|
||||||
ListFooterComponent={loadingMore && <RCActivityIndicator />}
|
ListFooterComponent={loadingMore && <RCActivityIndicator />}
|
||||||
/>
|
/>
|
||||||
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ export default class StarredMessagesView extends LoggedView {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderEmpty = () => (
|
renderEmpty = () => (
|
||||||
<View style={styles.listEmptyContainer}>
|
<View style={styles.listEmptyContainer} testID='starred-messages-view'>
|
||||||
<Text>No starred messages</Text>
|
<Text>No starred messages</Text>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
@ -126,6 +126,7 @@ export default class StarredMessagesView extends LoggedView {
|
||||||
[
|
[
|
||||||
<FlatList
|
<FlatList
|
||||||
key='starred-messages-view-list'
|
key='starred-messages-view-list'
|
||||||
|
testID='starred-messages-view'
|
||||||
data={messages}
|
data={messages}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
style={styles.list}
|
style={styles.list}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
const data = require('./data');
|
||||||
|
|
||||||
|
describe('Add server', () => {
|
||||||
|
before(async() => {
|
||||||
|
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Render', async() => {
|
||||||
|
it('should have add server screen', async() => {
|
||||||
|
await expect(element(by.id('new-server-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have server input', async() => {
|
||||||
|
await expect(element(by.id('new-server-view-input'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have submit button', async() => {
|
||||||
|
await expect(element(by.id('new-server-view-button'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Usage', async() => {
|
||||||
|
it('should insert "invalidtest" and get an invalid instance', async() => {
|
||||||
|
await element(by.id('new-server-view-input')).replaceText('invalidtest');
|
||||||
|
await waitFor(element(by.text(' is not a valid Rocket.Chat instance'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(' is not a valid Rocket.Chat instance'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a button to add a new server', async() => {
|
||||||
|
await element(by.id('new-server-view-input')).replaceText(data.server);
|
||||||
|
await waitFor(element(by.text(' is a valid Rocket.Chat instance'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('new-server-view-button'))).toBeVisible();
|
||||||
|
await element(by.id('new-server-view-button')).tap();
|
||||||
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('welcome-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,46 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
|
||||||
|
describe('Welcome screen', () => {
|
||||||
|
describe('Render', async() => {
|
||||||
|
it('should have welcome screen', async() => {
|
||||||
|
await expect(element(by.id('welcome-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have register button', async() => {
|
||||||
|
await expect(element(by.id('welcome-view-register'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have login button', async() => {
|
||||||
|
await expect(element(by.id('welcome-view-login'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: oauth
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Usage', async() => {
|
||||||
|
it('should navigate to login', async() => {
|
||||||
|
await element(by.id('welcome-view-login')).tap();
|
||||||
|
await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('login-view'))).toBeVisible();
|
||||||
|
await element(by.id('close-modal-button')).tap();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to register', async() => {
|
||||||
|
await element(by.id('welcome-view-register')).tap();
|
||||||
|
await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('register-view'))).toBeVisible();
|
||||||
|
await element(by.id('close-modal-button')).tap();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,45 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
const data = require('./data');
|
||||||
|
|
||||||
|
describe('Forgot password screen', () => {
|
||||||
|
before(async() => {
|
||||||
|
await element(by.id('welcome-view-login')).tap();
|
||||||
|
await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('login-view-forgot-password')).tap();
|
||||||
|
await waitFor(element(by.id('forgot-password-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Render', async() => {
|
||||||
|
it('should have forgot password screen', async() => {
|
||||||
|
await expect(element(by.id('forgot-password-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have email input', async() => {
|
||||||
|
await expect(element(by.id('forgot-password-view-email'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have submit button', async() => {
|
||||||
|
await expect(element(by.id('forgot-password-view-submit'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Usage', async() => {
|
||||||
|
it('should reset password and navigate to login', async() => {
|
||||||
|
await element(by.id('forgot-password-view-email')).replaceText(data.email);
|
||||||
|
await element(by.id('forgot-password-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('login-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,148 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
const { logout } = require('./helpers/app');
|
||||||
|
const data = require('./data');
|
||||||
|
|
||||||
|
async function navigateToRegister() {
|
||||||
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('welcome-view-register')).tap();
|
||||||
|
await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Create user screen', () => {
|
||||||
|
before(async() => {
|
||||||
|
await device.reloadReactNative();
|
||||||
|
await navigateToRegister();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Render', () => {
|
||||||
|
it('should have create user screen', async() => {
|
||||||
|
await expect(element(by.id('register-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have name input', async() => {
|
||||||
|
await expect(element(by.id('register-view-name'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have email input', async() => {
|
||||||
|
await expect(element(by.id('register-view-email'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have password input', async() => {
|
||||||
|
await expect(element(by.id('register-view-password'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have show password icon', async() => {
|
||||||
|
await expect(element(by.id('register-view-password-icon-right'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have repeat password input', async() => {
|
||||||
|
await expect(element(by.id('register-view-repeat-password'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have repeat password icon', async() => {
|
||||||
|
await expect(element(by.id('register-view-repeat-password-icon-right'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have submit button', async() => {
|
||||||
|
await expect(element(by.id('register-view-submit'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have close modal', async() => {
|
||||||
|
await expect(element(by.id('close-modal-button'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Usage', () => {
|
||||||
|
it('should navigate to welcome', async() => {
|
||||||
|
await element(by.id('close-modal-button')).tap();
|
||||||
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('welcome-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should submit empty form and raise error', async() => {
|
||||||
|
await navigateToRegister();
|
||||||
|
await element(by.id('register-view-submit')).tap();
|
||||||
|
await waitFor(element(by.text('Some field is invalid or empty'))).toBeVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('Some field is invalid or empty'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should submit different passwords and raise error', async() => {
|
||||||
|
await element(by.id('register-view-name')).replaceText(data.user);
|
||||||
|
await element(by.id('register-view-email')).replaceText(data.email);
|
||||||
|
await element(by.id('register-view-password')).replaceText('abc');
|
||||||
|
await element(by.id('register-view-repeat-password')).replaceText('xyz');
|
||||||
|
await element(by.id('register-view-submit')).tap();
|
||||||
|
await waitFor(element(by.text('Some field is invalid or empty'))).toBeVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('Some field is invalid or empty'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should submit invalid email and raise error', async() => {
|
||||||
|
await element(by.id('register-view-name')).replaceText(data.user);
|
||||||
|
await element(by.id('register-view-email')).replaceText('invalidemail');
|
||||||
|
await element(by.id('register-view-password')).replaceText(data.password);
|
||||||
|
await element(by.id('register-view-repeat-password')).replaceText(data.password);
|
||||||
|
await element(by.id('register-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('register-view-error'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('register-view-error'))).toBeVisible();
|
||||||
|
await expect(element(by.id('register-view-error'))).toHaveText('Invalid email invalidemail');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should submit email already taken and raise error', async() => {
|
||||||
|
await element(by.id('register-view-name')).replaceText(data.user);
|
||||||
|
await element(by.id('register-view-email')).replaceText('diego.mello@rocket.chat');
|
||||||
|
await element(by.id('register-view-password')).replaceText(data.password);
|
||||||
|
await element(by.id('register-view-repeat-password')).replaceText(data.password);
|
||||||
|
await element(by.id('register-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('register-view-error'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('register-view-error'))).toBeVisible();
|
||||||
|
await expect(element(by.id('register-view-error'))).toHaveText('Email already exists.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should complete first part of register', async() => {
|
||||||
|
await element(by.id('register-view-name')).replaceText(data.user);
|
||||||
|
await element(by.id('register-view-email')).replaceText(data.email);
|
||||||
|
await element(by.id('register-view-password')).replaceText(data.password);
|
||||||
|
await element(by.id('register-view-repeat-password')).replaceText(data.password);
|
||||||
|
await element(by.id('register-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('register-view-username'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('register-view-username'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should submit empty username and raise error', async() => {
|
||||||
|
await element(by.id('register-view-submit-username')).tap();
|
||||||
|
await waitFor(element(by.text('Username is empty'))).toBeVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('Username is empty'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should submit already taken username and raise error', async() => {
|
||||||
|
await element(by.id('register-view-username')).replaceText('diego.mello');
|
||||||
|
await element(by.id('register-view-submit-username')).tap();
|
||||||
|
await waitFor(element(by.id('register-view-error'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('register-view-error'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should finish register', async() => {
|
||||||
|
await element(by.id('register-view-username')).replaceText(data.user);
|
||||||
|
await element(by.id('register-view-submit-username')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: terms and privacy
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
await logout();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,92 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
const { navigateToLogin } = require('./helpers/app');
|
||||||
|
const data = require('./data');
|
||||||
|
|
||||||
|
describe('Login screen', () => {
|
||||||
|
before(async() => {
|
||||||
|
await navigateToLogin();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Render', () => {
|
||||||
|
it('should have login screen', async() => {
|
||||||
|
await expect(element(by.id('login-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have email input', async() => {
|
||||||
|
await expect(element(by.id('login-view-email'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have password input', async() => {
|
||||||
|
await expect(element(by.id('login-view-password'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have show password icon', async() => {
|
||||||
|
await expect(element(by.id('login-view-password-icon-right'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have submit button', async() => {
|
||||||
|
await expect(element(by.id('login-view-submit'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have register button', async() => {
|
||||||
|
await expect(element(by.id('login-view-register'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have forgot password button', async() => {
|
||||||
|
await expect(element(by.id('login-view-forgot-password'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have close modal button', async() => {
|
||||||
|
await expect(element(by.id('close-modal-button'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Usage', () => {
|
||||||
|
it('should navigate to register', async() => {
|
||||||
|
await element(by.id('login-view-register')).tap();
|
||||||
|
await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('register-view'))).toBeVisible();
|
||||||
|
await element(by.id('close-modal-button').withAncestor(by.id('register-view'))).tap();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to forgot password', async() => {
|
||||||
|
await element(by.id('login-view-forgot-password')).tap();
|
||||||
|
await waitFor(element(by.id('forgot-password-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('forgot-password-view'))).toBeVisible();
|
||||||
|
await element(by.id('header-back')).tap();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to welcome', async() => {
|
||||||
|
await element(by.id('close-modal-button')).tap();
|
||||||
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('welcome-view'))).toBeVisible();
|
||||||
|
await navigateToLogin();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should insert wrong password and get error', async() => {
|
||||||
|
await element(by.id('login-view-email')).replaceText(data.user);
|
||||||
|
await element(by.id('login-view-password')).replaceText('error');
|
||||||
|
await element(by.id('login-view-submit')).tap();
|
||||||
|
await waitFor(element(by.text('User or Password incorrect'))).toBeVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('User or Password incorrect'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should login with success', async() => {
|
||||||
|
await element(by.id('login-view-password')).replaceText(data.password);
|
||||||
|
await element(by.id('login-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,112 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
const { login, navigateToLogin } = require('./helpers/app');
|
||||||
|
const data = require('./data');
|
||||||
|
|
||||||
|
describe('Rooms list screen', () => {
|
||||||
|
before(async() => {
|
||||||
|
await device.reloadReactNative(); // TODO: remove this after fix logout subscription
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Render', async() => {
|
||||||
|
it('should have rooms list screen', async() => {
|
||||||
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have rooms list', async() => {
|
||||||
|
await expect(element(by.id('rooms-list-view-list'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have room item', async() => {
|
||||||
|
await expect(element(by.id('rooms-list-view-item-general'))).toExist();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Render - Header
|
||||||
|
describe('Header', async() => {
|
||||||
|
it('should have header', async() => {
|
||||||
|
await expect(element(by.id('rooms-list-view-header'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have create channel button', async() => {
|
||||||
|
await expect(element(by.id('rooms-list-view-create-channel'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have user', async() => {
|
||||||
|
await expect(element(by.id('rooms-list-view-user'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have sidebar button', async() => {
|
||||||
|
await expect(element(by.id('rooms-list-view-sidebar'))).toBeVisible();
|
||||||
|
await expect(element(by.id('rooms-list-view-sidebar'))).toHaveLabel(`Connected to ${ data.server }. Tap to view servers list.`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Usage', async() => {
|
||||||
|
it('should change user presence modal', async() => {
|
||||||
|
await waitFor(element(by.label(`${ data.user }, Online, tap to change status`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.label(`${ data.user }, Online, tap to change status`))).toBeVisible();
|
||||||
|
await element(by.id('rooms-list-view-user')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view-user-presence-modal'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('rooms-list-view-user-presence-modal'))).toBeVisible();
|
||||||
|
await element(by.id('rooms-list-view-user-presence-busy')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view-user-presence-modal'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.id('rooms-list-view-user-presence-modal'))).toBeNotVisible();
|
||||||
|
await waitFor(element(by.label(`${ data.user }, Busy, tap to change status`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.label(`${ data.user }, Busy, tap to change status`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should search room and navigate', async() => {
|
||||||
|
await element(by.id('rooms-list-view-list')).swipe('down');
|
||||||
|
await waitFor(element(by.id('rooms-list-view-search'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('rooms-list-view-search'))).toBeVisible();
|
||||||
|
await element(by.id('rooms-list-view-search')).replaceText('rocket.cat');
|
||||||
|
await waitFor(element(by.id('rooms-list-view-item-rocket.cat'))).toBeVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.id('rooms-list-view-item-rocket.cat'))).toBeVisible();
|
||||||
|
await element(by.id('rooms-list-view-item-rocket.cat')).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.id('room-view'))).toBeVisible();
|
||||||
|
await waitFor(element(by.id('room-view-title'))).toHaveText('rocket.cat').withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-view-title'))).toHaveText('rocket.cat');
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
|
await waitFor(element(by.id('rooms-list-view-item-rocket.cat'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('rooms-list-view-item-rocket.cat'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Usage - Sidebar
|
||||||
|
describe('Sidebar', async() => {
|
||||||
|
it('should navigate to add server', async() => {
|
||||||
|
await element(by.id('rooms-list-view-sidebar')).tap();
|
||||||
|
await waitFor(element(by.id('sidebar'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('sidebar-add-server')).tap();
|
||||||
|
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('new-server-view'))).toBeVisible();
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should logout', async() => {
|
||||||
|
await element(by.id('rooms-list-view-sidebar')).tap();
|
||||||
|
await waitFor(element(by.id('sidebar'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('sidebar-logout')).tap();
|
||||||
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('welcome-view'))).toBeVisible();
|
||||||
|
await navigateToLogin();
|
||||||
|
await login();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,109 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
const data = require('./data');
|
||||||
|
|
||||||
|
describe('Create room screen', () => {
|
||||||
|
before(async() => {
|
||||||
|
await device.reloadReactNative(); // TODO: remove this after fix logout subscription
|
||||||
|
await element(by.id('rooms-list-view-create-channel')).tap();
|
||||||
|
await waitFor(element(by.id('select-users-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Render', async() => {
|
||||||
|
it('should have select users screen', async() => {
|
||||||
|
await expect(element(by.id('select-users-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have search input', async() => {
|
||||||
|
await expect(element(by.id('select-users-view-search'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Usage', async() => {
|
||||||
|
it('should back to rooms list', async() => {
|
||||||
|
await element(by.id('header-back')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
|
await element(by.id('rooms-list-view-create-channel')).tap();
|
||||||
|
await waitFor(element(by.id('select-users-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should search users', async() => {
|
||||||
|
await element(by.id('select-users-view-search')).replaceText('rocket.cat');
|
||||||
|
await waitFor(element(by.id(`select-users-view-item-rocket.cat`))).toBeVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.id(`select-users-view-item-rocket.cat`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should select/unselect user', async() => {
|
||||||
|
await element(by.id('select-users-view-item-rocket.cat')).tap();
|
||||||
|
await waitFor(element(by.id('selected-user-rocket.cat'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.id('selected-user-rocket.cat'))).toBeVisible();
|
||||||
|
await expect(element(by.id('selected-users-view-submit'))).toBeVisible();
|
||||||
|
await element(by.id('selected-user-rocket.cat')).tap();
|
||||||
|
await waitFor(element(by.id('selected-user-rocket.cat'))).toBeNotVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.id('selected-user-rocket.cat'))).toBeNotVisible();
|
||||||
|
await expect(element(by.id('selected-users-view-submit'))).toBeNotVisible();
|
||||||
|
await element(by.id('select-users-view-item-rocket.cat')).tap();
|
||||||
|
await waitFor(element(by.id('selected-user-rocket.cat'))).toBeVisible().withTimeout(5000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to create channel view', async() => {
|
||||||
|
await element(by.id('selected-users-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('create-channel-view'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.id('create-channel-view'))).toBeVisible();
|
||||||
|
await expect(element(by.id('create-channel-name'))).toBeVisible();
|
||||||
|
await expect(element(by.id('create-channel-type'))).toBeVisible();
|
||||||
|
await expect(element(by.id('create-channel-submit'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get invalid room', async() => {
|
||||||
|
await element(by.id('create-channel-name')).replaceText('general');
|
||||||
|
await element(by.id('create-channel-submit')).tap();
|
||||||
|
await waitFor(element(by.id('create-channel-error'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('create-channel-error'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create private room', async() => {
|
||||||
|
await element(by.id('create-channel-name')).replaceText(`private${ data.random }`);
|
||||||
|
await element(by.id('create-channel-type')).tap();
|
||||||
|
await element(by.id('create-channel-submit')).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-view'))).toBeVisible();
|
||||||
|
await waitFor(element(by.id('room-view-title'))).toHaveText(`private${ data.random }`).withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-view-title'))).toHaveText(`private${ data.random }`);
|
||||||
|
await element(by.id('header-back')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await waitFor(element(by.id(`rooms-list-view-item-private${ data.random }`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`rooms-list-view-item-private${ data.random }`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create public room', async() => {
|
||||||
|
await element(by.id('rooms-list-view-create-channel')).tap();
|
||||||
|
await waitFor(element(by.id('select-users-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('select-users-view-item-rocket.cat')).tap();
|
||||||
|
await waitFor(element(by.id('selected-user-rocket.cat'))).toBeVisible().withTimeout(5000);
|
||||||
|
await element(by.id('selected-users-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('create-channel-view'))).toBeVisible().withTimeout(5000);
|
||||||
|
await element(by.id('create-channel-name')).replaceText(`public${ data.random }`);
|
||||||
|
await element(by.id('create-channel-submit')).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-view'))).toBeVisible();
|
||||||
|
await waitFor(element(by.id('room-view-title'))).toHaveText(`public${ data.random }`).withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-view-title'))).toHaveText(`public${ data.random }`);
|
||||||
|
await element(by.id('header-back')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await waitFor(element(by.id(`rooms-list-view-item-public${ data.random }`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`rooms-list-view-item-public${ data.random }`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,318 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
const data = require('./data');
|
||||||
|
|
||||||
|
async function mockMessage(message) {
|
||||||
|
await element(by.id('messagebox-input')).tap();
|
||||||
|
await element(by.id('messagebox-input')).typeText(`${ data.random }${ message }`);
|
||||||
|
await element(by.id('messagebox-send-message')).tap();
|
||||||
|
await waitFor(element(by.text(`${ data.random }${ message }`))).toBeVisible().withTimeout(60000);
|
||||||
|
};
|
||||||
|
|
||||||
|
async function navigateToRoom() {
|
||||||
|
await waitFor(element(by.id(`rooms-list-view-item-private${ data.random }`))).toBeVisible().withTimeout(60000);
|
||||||
|
await element(by.id(`rooms-list-view-item-private${ data.random }`)).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Room screen', () => {
|
||||||
|
before(async() => {
|
||||||
|
await navigateToRoom();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Render', async() => {
|
||||||
|
it('should have room screen', async() => {
|
||||||
|
await expect(element(by.id('room-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have messages list', async() => {
|
||||||
|
await expect(element(by.id('room-view-messages'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Render - Header
|
||||||
|
describe('Header', async() => {
|
||||||
|
it('should have room header', async() => {
|
||||||
|
await expect(element(by.id('room-view-header'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have back button', async() => {
|
||||||
|
await expect(element(by.id('header-back'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have title', async() => {
|
||||||
|
await expect(element(by.id('room-view-header-title'))).toBeVisible();
|
||||||
|
await expect(element(by.id('room-view-title'))).toHaveText(`private${ data.random }`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have star button', async() => {
|
||||||
|
await expect(element(by.id('room-view-header-star'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have actions button ', async() => {
|
||||||
|
await expect(element(by.id('room-view-header-actions'))).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Render - Messagebox
|
||||||
|
describe('Messagebox', async() => {
|
||||||
|
it('should have messagebox', async() => {
|
||||||
|
await expect(element(by.id('messagebox'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have open emoji button', async() => {
|
||||||
|
await expect(element(by.id('messagebox-open-emoji'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have message input', async() => {
|
||||||
|
await expect(element(by.id('messagebox-input'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have audio button', async() => {
|
||||||
|
await expect(element(by.id('messagebox-send-audio'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have actions button', async() => {
|
||||||
|
await expect(element(by.id('messagebox-actions'))).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Usage', async() => {
|
||||||
|
describe('Header', async() => {
|
||||||
|
it('should back to rooms list', async() => {
|
||||||
|
await element(by.id('header-back')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
|
await navigateToRoom();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should tap on title and navigate to room info', async() => {
|
||||||
|
await element(by.id('room-view-header-title')).tap();
|
||||||
|
await waitFor(element(by.id('room-info-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('room-info-view'))).toBeVisible();
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should tap on more and navigate to room actions', async() => {
|
||||||
|
await element(by.id('room-view-header-actions')).tap();
|
||||||
|
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('room-actions-view'))).toBeVisible();
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Messagebox', async() => {
|
||||||
|
it('should send message', async() => {
|
||||||
|
await mockMessage('message');
|
||||||
|
await waitFor(element(by.text(`${ data.random }message`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(`${ data.random }message`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show/hide emoji keyboard', async() => {
|
||||||
|
await element(by.id('messagebox-open-emoji')).tap();
|
||||||
|
await waitFor(element(by.id('messagebox-keyboard-emoji'))).toBeVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.id('messagebox-keyboard-emoji'))).toBeVisible();
|
||||||
|
await expect(element(by.id('messagebox-close-emoji'))).toBeVisible();
|
||||||
|
await expect(element(by.id('messagebox-open-emoji'))).toBeNotVisible();
|
||||||
|
await element(by.id('messagebox-close-emoji')).tap();
|
||||||
|
await waitFor(element(by.id('messagebox-keyboard-emoji'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.id('messagebox-keyboard-emoji'))).toBeNotVisible();
|
||||||
|
await expect(element(by.id('messagebox-close-emoji'))).toBeNotVisible();
|
||||||
|
await expect(element(by.id('messagebox-open-emoji'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show/hide emoji autocomplete', async() => {
|
||||||
|
await element(by.id('messagebox-input')).tap();
|
||||||
|
await element(by.id('messagebox-input')).replaceText(':');
|
||||||
|
await element(by.id('messagebox-input')).typeText('joy'); // workaround for number keyboard
|
||||||
|
await waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.id('messagebox-container'))).toBeVisible();
|
||||||
|
await element(by.id('messagebox-input')).clearText();
|
||||||
|
await waitFor(element(by.id('messagebox-container'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.id('messagebox-container'))).toBeNotVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show and tap on emoji autocomplete', async() => {
|
||||||
|
await element(by.id('messagebox-input')).tap();
|
||||||
|
await element(by.id('messagebox-input')).replaceText(':');
|
||||||
|
await element(by.id('messagebox-input')).typeText('joy'); // workaround for number keyboard
|
||||||
|
await waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.id('messagebox-container'))).toBeVisible();
|
||||||
|
await element(by.id('mention-item-joy')).tap();
|
||||||
|
await expect(element(by.id('messagebox-input'))).toHaveText(':joy: ');
|
||||||
|
await element(by.id('messagebox-input')).clearText();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show and tap on user autocomplete and send mention', async() => {
|
||||||
|
await element(by.id('messagebox-input')).tap();
|
||||||
|
await element(by.id('messagebox-input')).typeText(`@${ data.user }`);
|
||||||
|
await waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('messagebox-container'))).toBeVisible();
|
||||||
|
await element(by.id(`mention-item-${ data.user }`)).tap();
|
||||||
|
await expect(element(by.id('messagebox-input'))).toHaveText(`@${ data.user } `);
|
||||||
|
await element(by.id('messagebox-input')).tap();
|
||||||
|
await element(by.id('messagebox-input')).typeText('test');
|
||||||
|
await element(by.id('messagebox-send-message')).tap();
|
||||||
|
await waitFor(element(by.text(`@${ data.user } test`))).toBeVisible().withTimeout(60000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show and tap on room autocomplete', async() => {
|
||||||
|
await element(by.id('messagebox-input')).tap();
|
||||||
|
await element(by.id('messagebox-input')).typeText('#general');
|
||||||
|
await waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('messagebox-container'))).toBeVisible();
|
||||||
|
await element(by.id('mention-item-general')).tap();
|
||||||
|
await expect(element(by.id('messagebox-input'))).toHaveText('#general ');
|
||||||
|
await element(by.id('messagebox-input')).clearText();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Message', async() => {
|
||||||
|
before(async() => {
|
||||||
|
await mockMessage('reply');
|
||||||
|
await mockMessage('edit');
|
||||||
|
await mockMessage('quote');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show message actions', async() => {
|
||||||
|
await element(by.text(`${ data.random }message`)).longPress();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Messages actions'))).toBeVisible();
|
||||||
|
await element(by.text('Cancel')).tap();
|
||||||
|
await waitFor(element(by.text('Cancel'))).toBeNotVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reply message', async() => {
|
||||||
|
await element(by.text(`${ data.random }reply`)).longPress();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Messages actions'))).toBeVisible();
|
||||||
|
await element(by.text('Reply')).tap();
|
||||||
|
await element(by.id('messagebox-input')).typeText('replied');
|
||||||
|
await element(by.id('messagebox-send-message')).tap();
|
||||||
|
// TODO: test if reply was sent
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should edit message', async() => {
|
||||||
|
await element(by.text(`${ data.random }edit`)).longPress();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Messages actions'))).toBeVisible();
|
||||||
|
await element(by.text('Edit')).tap();
|
||||||
|
await element(by.id('messagebox-input')).typeText('ed');
|
||||||
|
await element(by.id('messagebox-send-message')).tap();
|
||||||
|
await waitFor(element(by.text(`${ data.random }edited`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(`${ data.random }edited`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should copy permalink', async() => {
|
||||||
|
await element(by.text(`${ data.random }message`)).longPress();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Messages actions'))).toBeVisible();
|
||||||
|
await element(by.text('Copy Permalink')).tap();
|
||||||
|
await expect(element(by.text('Permalink copied to clipboard!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('Permalink copied to clipboard!'))).toBeNotVisible().withTimeout(5000);
|
||||||
|
|
||||||
|
// TODO: test clipboard
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should copy message', async() => {
|
||||||
|
await element(by.text(`${ data.random }message`)).longPress();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Messages actions'))).toBeVisible();
|
||||||
|
await element(by.text('Copy Message')).tap();
|
||||||
|
await expect(element(by.text('Copied to clipboard!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('Copied to clipboard!'))).toBeNotVisible().withTimeout(5000);
|
||||||
|
// TODO: test clipboard
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should quote message', async() => {
|
||||||
|
await element(by.text(`${ data.random }quote`)).longPress();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Messages actions'))).toBeVisible();
|
||||||
|
await element(by.text('Quote')).tap();
|
||||||
|
await element(by.id('messagebox-input')).typeText(`${ data.random }quoted`);
|
||||||
|
await element(by.id('messagebox-send-message')).tap();
|
||||||
|
// TODO: test if quote was sent
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should star message', async() => {
|
||||||
|
await element(by.text(`${ data.random }message`)).longPress();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Messages actions'))).toBeVisible();
|
||||||
|
await element(by.text('Star')).tap();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeNotVisible().withTimeout(5000);
|
||||||
|
await element(by.text(`${ data.random }message`)).longPress();
|
||||||
|
await waitFor(element(by.text('Unstar'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.text('Unstar'))).toBeVisible();
|
||||||
|
await element(by.text('Cancel')).tap();
|
||||||
|
await waitFor(element(by.text('Cancel'))).toBeNotVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should react to message', async() => {
|
||||||
|
await element(by.text(`${ data.random }message`)).longPress();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Messages actions'))).toBeVisible();
|
||||||
|
await element(by.text('Add Reaction')).tap();
|
||||||
|
await waitFor(element(by.id('reaction-picker'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('reaction-picker'))).toBeVisible();
|
||||||
|
await element(by.id('reaction-picker-😃')).tap();
|
||||||
|
await waitFor(element(by.id('reaction-picker-grinning'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('reaction-picker-grinning'))).toBeVisible();
|
||||||
|
await element(by.id('reaction-picker-grinning')).tap();
|
||||||
|
await waitFor(element(by.id('message-reaction-:grinning:'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('message-reaction-:grinning:'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show reaction picker on add reaction button pressed and have frequently used emoji', async() => {
|
||||||
|
await element(by.id('message-add-reaction')).tap();
|
||||||
|
await waitFor(element(by.id('reaction-picker'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('reaction-picker'))).toBeVisible();
|
||||||
|
await waitFor(element(by.id('reaction-picker-grinning'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('reaction-picker-grinning'))).toBeVisible();
|
||||||
|
await element(by.id('reaction-picker-😃')).tap();
|
||||||
|
await waitFor(element(by.id('reaction-picker-grimacing'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('reaction-picker-grimacing')).tap();
|
||||||
|
await waitFor(element(by.id('message-reaction-:grimacing:'))).toBeVisible().withTimeout(60000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove reaction', async() => {
|
||||||
|
await element(by.id('message-reaction-:grinning:')).tap();
|
||||||
|
await waitFor(element(by.id('message-reaction-:grinning:'))).toBeNotVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('message-reaction-:grinning:'))).toBeNotVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pin message', async() => {
|
||||||
|
await element(by.text(`${ data.random }edited`)).longPress();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Messages actions'))).toBeVisible();
|
||||||
|
await element(by.text('Pin')).tap();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeNotVisible().withTimeout(5000);
|
||||||
|
await waitFor(element(by.text(`${ data.random }edited`)).atIndex(1)).toBeVisible().withTimeout(60000);
|
||||||
|
await element(by.text(`${ data.random }edited`)).atIndex(0).longPress();
|
||||||
|
await waitFor(element(by.text('Unpin'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.text('Unpin'))).toBeVisible();
|
||||||
|
await element(by.text('Cancel')).tap();
|
||||||
|
await waitFor(element(by.text('Cancel'))).toBeNotVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: delete message - swipe on action sheet missing
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
await element(by.id('header-back')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,403 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
const data = require('./data');
|
||||||
|
|
||||||
|
const scrollDown = 200;
|
||||||
|
|
||||||
|
async function navigateToRoomActions(type) {
|
||||||
|
let room;
|
||||||
|
if (type === 'd') {
|
||||||
|
room = 'rocket.cat';
|
||||||
|
} else {
|
||||||
|
room = `private${ data.random }`;
|
||||||
|
}
|
||||||
|
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id(`rooms-list-view-item-${ room }`)).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('room-view-header-actions')).tap();
|
||||||
|
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function backToActions() {
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('rooms-actions-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function backToRoomsList() {
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Room actions screen', () => {
|
||||||
|
describe('Render', async() => {
|
||||||
|
describe('Direct', async() => {
|
||||||
|
before(async() => {
|
||||||
|
await navigateToRoomActions('d');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have room actions screen', async() => {
|
||||||
|
await expect(element(by.id('room-actions-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have info', async() => {
|
||||||
|
await expect(element(by.id('room-actions-info'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have voice', async() => {
|
||||||
|
await expect(element(by.id('room-actions-voice'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have video', async() => {
|
||||||
|
await expect(element(by.id('room-actions-video'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have files', async() => {
|
||||||
|
await expect(element(by.id('room-actions-files'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have mentions', async() => {
|
||||||
|
await expect(element(by.id('room-actions-mentioned'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have starred', async() => {
|
||||||
|
await expect(element(by.id('room-actions-starred'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have search', async() => {
|
||||||
|
await expect(element(by.id('room-actions-search'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have share', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-share'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await expect(element(by.id('room-actions-share'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have pinned', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-pinned'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await expect(element(by.id('room-actions-pinned'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have snippeted', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-snippeted'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await expect(element(by.id('room-actions-snippeted'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have notifications', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-notifications'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await expect(element(by.id('room-actions-notifications'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have block user', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-block-user'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await expect(element(by.id('room-actions-block-user'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
await backToRoomsList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Channel/Group', async() => {
|
||||||
|
before(async() => {
|
||||||
|
await navigateToRoomActions('c');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have room actions screen', async() => {
|
||||||
|
await expect(element(by.id('room-actions-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have info', async() => {
|
||||||
|
await expect(element(by.id('room-actions-info'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have voice', async() => {
|
||||||
|
await expect(element(by.id('room-actions-voice'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have video', async() => {
|
||||||
|
await expect(element(by.id('room-actions-video'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have members', async() => {
|
||||||
|
await expect(element(by.id('room-actions-members'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have add user', async() => {
|
||||||
|
await expect(element(by.id('room-actions-add-user'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have files', async() => {
|
||||||
|
await expect(element(by.id('room-actions-files'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have mentions', async() => {
|
||||||
|
await expect(element(by.id('room-actions-mentioned'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have starred', async() => {
|
||||||
|
await expect(element(by.id('room-actions-starred'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have search', async() => {
|
||||||
|
await expect(element(by.id('room-actions-search'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have share', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-share'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await expect(element(by.id('room-actions-share'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have pinned', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-pinned'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await expect(element(by.id('room-actions-pinned'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have snippeted', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-snippeted'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await expect(element(by.id('room-actions-snippeted'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have notifications', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-notifications'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await expect(element(by.id('room-actions-notifications'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have leave channel', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-leave-channel'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await expect(element(by.id('room-actions-leave-channel'))).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Usage', async() => {
|
||||||
|
describe('TDB', async() => {
|
||||||
|
it('should NOT navigate to voice call', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-voice'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'up');
|
||||||
|
await element(by.id('room-actions-voice')).tap();
|
||||||
|
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('room-actions-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT navigate to video call', async() => {
|
||||||
|
await element(by.id('room-actions-video')).tap();
|
||||||
|
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('room-actions-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT navigate to share messages', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-share'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await element(by.id('room-actions-share')).tap();
|
||||||
|
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('room-actions-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Common', async() => {
|
||||||
|
it('should show mentioned messages', async() => {
|
||||||
|
await element(by.id('room-actions-mentioned')).tap();
|
||||||
|
await waitFor(element(by.id('mentioned-messages-view'))).toExist().withTimeout(2000);
|
||||||
|
await waitFor(element(by.text(`@${ data.user } test`).withAncestor(by.id('mentioned-messages-view')))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(`@${ data.user } test`).withAncestor(by.id('mentioned-messages-view')))).toBeVisible();
|
||||||
|
await backToActions();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show starred message and unstar it', async() => {
|
||||||
|
await element(by.id('room-actions-starred')).tap();
|
||||||
|
await waitFor(element(by.id('starred-messages-view'))).toExist().withTimeout(2000);
|
||||||
|
await waitFor(element(by.text(`${ data.random }message`).withAncestor(by.id('starred-messages-view')))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(`${ data.random }message`).withAncestor(by.id('starred-messages-view')))).toBeVisible();
|
||||||
|
await element(by.text(`${ data.random }message`).withAncestor(by.id('starred-messages-view'))).longPress();
|
||||||
|
await waitFor(element(by.text('Unstar'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.text('Unstar'))).toBeVisible();
|
||||||
|
await element(by.text('Unstar')).tap();
|
||||||
|
await waitFor(element(by.text(`${ data.random }message`).withAncestor(by.id('starred-messages-view')))).toBeNotVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(`${ data.random }message`).withAncestor(by.id('starred-messages-view')))).toBeNotVisible();
|
||||||
|
await backToActions();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show pinned message and unpin it', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-pinned'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await element(by.id('room-actions-pinned')).tap();
|
||||||
|
await waitFor(element(by.id('pinned-messages-view'))).toExist().withTimeout(2000);
|
||||||
|
await waitFor(element(by.text(`${ data.random }edited`).withAncestor(by.id('pinned-messages-view'))).atIndex(0)).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(`${ data.random }edited`).withAncestor(by.id('pinned-messages-view')))).toBeVisible();
|
||||||
|
await element(by.text(`${ data.random }edited`).withAncestor(by.id('pinned-messages-view'))).longPress();
|
||||||
|
await waitFor(element(by.text('Unpin'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.text('Unpin'))).toBeVisible();
|
||||||
|
await element(by.text('Unpin')).tap();
|
||||||
|
await waitFor(element(by.text(`${ data.random }edited`).withAncestor(by.id('pinned-messages-view'))).atIndex(0)).toBeNotVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(`${ data.random }edited`).withAncestor(by.id('pinned-messages-view')))).toBeNotVisible();
|
||||||
|
await backToActions();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should search and find a message', async() => {
|
||||||
|
await element(by.id('room-actions-search')).tap();
|
||||||
|
await waitFor(element(by.id('search-messages-view'))).toExist().withTimeout(2000);
|
||||||
|
await expect(element(by.id('search-message-view-input'))).toBeVisible();
|
||||||
|
await element(by.id('search-message-view-input')).tap();
|
||||||
|
await element(by.id('search-message-view-input')).replaceText(`/${ data.random }message/`);
|
||||||
|
await waitFor(element(by.text(`${ data.random }message`).withAncestor(by.id('search-messages-view'))).atIndex(0)).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(`${ data.random }message`).withAncestor(by.id('search-messages-view'))).atIndex(0)).toBeVisible();
|
||||||
|
await backToActions();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should enable/disable notifications', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-notifications'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await expect(element(by.text('Disable notifications'))).toBeVisible();
|
||||||
|
await element(by.id('room-actions-notifications')).tap();
|
||||||
|
await waitFor(element(by.text('Enable notifications'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Enable notifications'))).toBeVisible();
|
||||||
|
await element(by.id('room-actions-notifications')).tap();
|
||||||
|
await waitFor(element(by.text('Disable notifications'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Disable notifications'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Channel/Group', async() => {
|
||||||
|
// Currently, there's no way to add more owners to the room
|
||||||
|
// So we test only for the 'You are the last owner...' message
|
||||||
|
it('should tap on leave channel and raise alert', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-leave-channel'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await expect(element(by.id('room-actions-leave-channel'))).toBeVisible();
|
||||||
|
await element(by.id('room-actions-leave-channel')).tap();
|
||||||
|
await waitFor(element(by.text('Yes, leave it!'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.text('Yes, leave it!'))).toBeVisible();
|
||||||
|
await element(by.text('Yes, leave it!')).tap();
|
||||||
|
await waitFor(element(by.text('You are the last owner. Please set new owner before leaving the room.'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('You are the last owner. Please set new owner before leaving the room.'))).toBeVisible();
|
||||||
|
await takeScreenshot();
|
||||||
|
await element(by.text('OK')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-actions-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Add User', async() => {
|
||||||
|
it('should add user to the room', async() => {
|
||||||
|
const user = 'detoxrn';
|
||||||
|
await waitFor(element(by.id('room-actions-add-user'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'up');
|
||||||
|
await element(by.id('room-actions-add-user')).tap();
|
||||||
|
await element(by.id('select-users-view-search')).tap();
|
||||||
|
await element(by.id('select-users-view-search')).replaceText(user);
|
||||||
|
await waitFor(element(by.id(`select-users-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`select-users-view-item-${ user }`))).toBeVisible();
|
||||||
|
await element(by.id(`select-users-view-item-${ user }`)).tap();
|
||||||
|
await waitFor(element(by.id(`selected-user-${ user }`))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.id(`selected-user-${ user }`))).toBeVisible();
|
||||||
|
await element(by.id('selected-users-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await element(by.id('room-view-header-actions')).tap();
|
||||||
|
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('room-actions-members')).tap();
|
||||||
|
await element(by.id('room-members-view-toggle-status')).tap();
|
||||||
|
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeVisible();
|
||||||
|
await backToActions();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Room Members', async() => {
|
||||||
|
const user = 'detoxrn';
|
||||||
|
before(async() => {
|
||||||
|
await element(by.id('room-actions-members')).tap();
|
||||||
|
await waitFor(element(by.id('room-members-view'))).toExist().withTimeout(2000);
|
||||||
|
await expect(element(by.id('room-members-view'))).toExist();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show/hide all users', async() => {
|
||||||
|
await element(by.id('room-members-view-toggle-status')).tap();
|
||||||
|
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeVisible();
|
||||||
|
await element(by.id('room-members-view-toggle-status')).tap();
|
||||||
|
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeNotVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeNotVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should filter user', async() => {
|
||||||
|
await element(by.id('room-members-view-toggle-status')).tap();
|
||||||
|
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeVisible();
|
||||||
|
await element(by.id('room-members-view-search')).replaceText('rocket');
|
||||||
|
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeNotVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeNotVisible();
|
||||||
|
await element(by.id('room-members-view-search')).tap();
|
||||||
|
await element(by.id('room-members-view-search')).clearText('');
|
||||||
|
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should mute user', async() => {
|
||||||
|
await element(by.id(`room-members-view-item-${ user }`)).longPress();
|
||||||
|
await waitFor(element(by.text('Mute'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Mute'))).toBeVisible();
|
||||||
|
await element(by.text('Mute')).tap();
|
||||||
|
await waitFor(element(by.text('User has been muted!'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('User has been muted!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('User has been muted!'))).toBeNotVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('User has been muted!'))).toBeNotVisible();
|
||||||
|
await element(by.id(`room-members-view-item-${ user }`)).longPress();
|
||||||
|
await waitFor(element(by.text('Unmute'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.text('Unmute'))).toBeVisible();
|
||||||
|
await element(by.text('Unmute')).tap();
|
||||||
|
await waitFor(element(by.text('User has been unmuted!'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('User has been unmuted!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('User has been unmuted!'))).toBeNotVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('User has been unmuted!'))).toBeNotVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to direct room', async() => {
|
||||||
|
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toExist().withTimeout(5000);
|
||||||
|
await element(by.id(`room-members-view-item-${ user }`)).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-view'))).toBeVisible();
|
||||||
|
await waitFor(element(by.id('room-view-title'))).toHaveText(user).withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-view-title'))).toHaveText(user);
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('room-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Direct', async() => {
|
||||||
|
before(async() => {
|
||||||
|
await navigateToRoomActions('d');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should block/unblock user', async() => {
|
||||||
|
await waitFor(element(by.id('room-actions-block-user'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down');
|
||||||
|
await element(by.id('room-actions-block-user')).tap();
|
||||||
|
await waitFor(element(by.text('Unblock user'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Unblock user'))).toBeVisible();
|
||||||
|
await element(by.id('room-actions-block-user')).tap();
|
||||||
|
await waitFor(element(by.text('Block user'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Block user'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,326 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
const data = require('./data');
|
||||||
|
|
||||||
|
async function navigateToRoomInfo() {
|
||||||
|
const room = `private${ data.random }`;
|
||||||
|
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id(`rooms-list-view-item-${ room }`)).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('room-view-header-title')).tap();
|
||||||
|
await waitFor(element(by.id('room-info-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function backToRoomsList() {
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Room info screen', () => {
|
||||||
|
describe('Direct', async() => {
|
||||||
|
before(async() => {
|
||||||
|
// last test positioned simulator at rooms-list-actions on a direct room
|
||||||
|
await waitFor(element(by.id('room-actions-info'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(500, 'up');
|
||||||
|
await element(by.id('room-actions-info')).tap();
|
||||||
|
await waitFor(element(by.id('room-info-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to room info', async() => {
|
||||||
|
await expect(element(by.id('room-info-view'))).toBeVisible();
|
||||||
|
await expect(element(by.id('room-info-view-name'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
await takeScreenshot();
|
||||||
|
await backToRoomsList();
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Channel/Group', async() => {
|
||||||
|
before(async() => {
|
||||||
|
await navigateToRoomInfo();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Render', async() => {
|
||||||
|
it('should have room info view', async() => {
|
||||||
|
await expect(element(by.id('room-info-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have name', async() => {
|
||||||
|
await expect(element(by.id('room-info-view-name'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have description', async() => {
|
||||||
|
await expect(element(by.id('room-info-view-description'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have topic', async() => {
|
||||||
|
await expect(element(by.id('room-info-view-topic'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have announcement', async() => {
|
||||||
|
await expect(element(by.id('room-info-view-announcement'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have edit button', async() => {
|
||||||
|
await expect(element(by.id('room-info-view-edit-button'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Render Edit', async() => {
|
||||||
|
before(async() => {
|
||||||
|
await waitFor(element(by.id('room-info-view-edit-button'))).toBeVisible().withTimeout(10000);
|
||||||
|
await element(by.id('room-info-view-edit-button')).tap();
|
||||||
|
await waitFor(element(by.id('room-info-edit-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have room info edit view', async() => {
|
||||||
|
await expect(element(by.id('room-info-edit-view'))).toExist();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have name input', async() => {
|
||||||
|
await expect(element(by.id('room-info-edit-view-name'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have description input', async() => {
|
||||||
|
await expect(element(by.id('room-info-edit-view-description'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have topic input', async() => {
|
||||||
|
await expect(element(by.id('room-info-edit-view-topic'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have announcement input', async() => {
|
||||||
|
await expect(element(by.id('room-info-edit-view-announcement'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have password input', async() => {
|
||||||
|
await expect(element(by.id('room-info-edit-view-password'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have type switch', async() => {
|
||||||
|
await element(by.id('room-info-edit-view-list')).swipe('up');
|
||||||
|
await expect(element(by.id('room-info-edit-view-t'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have ready only switch', async() => {
|
||||||
|
await expect(element(by.id('room-info-edit-view-ro'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have submit button', async() => {
|
||||||
|
await expect(element(by.id('room-info-edit-view-submit'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have reset button', async() => {
|
||||||
|
await expect(element(by.id('room-info-edit-view-reset'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have archive button', async() => {
|
||||||
|
await expect(element(by.id('room-info-edit-view-archive'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have delete button', async() => {
|
||||||
|
await expect(element(by.id('room-info-edit-view-delete'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
await takeScreenshot();
|
||||||
|
await element(by.id('room-info-edit-view-list')).swipe('down');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Usage', async() => {
|
||||||
|
const room = `private${ data.random }`;
|
||||||
|
// it('should enter "invalid name" and get error', async() => {
|
||||||
|
// await element(by.id('room-info-edit-view-list')).swipe('down');
|
||||||
|
// await element(by.id('room-info-edit-view-name')).replaceText('invalid name');
|
||||||
|
// await element(by.id('room-info-edit-view-list')).swipe('up');
|
||||||
|
// await element(by.id('room-info-edit-view-submit')).tap();
|
||||||
|
// await waitFor(element(by.text('There was an error while saving settings!'))).toBeVisible().withTimeout(60000);
|
||||||
|
// await expect(element(by.text('There was an error while saving settings!'))).toBeVisible();
|
||||||
|
// await element(by.text('OK')).tap();
|
||||||
|
// await waitFor(element(by.text('There was an error while saving settings!'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
// await element(by.id('room-info-edit-view-list')).swipe('down');
|
||||||
|
// });
|
||||||
|
|
||||||
|
it('should change room name', async() => {
|
||||||
|
await element(by.id('room-info-edit-view-name')).replaceText(`${ room }new`);
|
||||||
|
await element(by.id('room-info-edit-view-list')).swipe('up');
|
||||||
|
await element(by.id('room-info-edit-view-submit')).tap();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('room-info-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await waitFor(element(by.id('room-info-view-name'))).toHaveText(`${ room }new`).withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-info-view-name'))).toHaveText(`${ room }new`);
|
||||||
|
// change name to original
|
||||||
|
await element(by.id('room-info-view-edit-button')).tap();
|
||||||
|
await waitFor(element(by.id('room-info-edit-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('room-info-edit-view-name')).replaceText(`${ room }`);
|
||||||
|
await element(by.id('room-info-edit-view-list')).swipe('up');
|
||||||
|
await element(by.id('room-info-edit-view-submit')).tap();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
|
||||||
|
await element(by.id('room-info-edit-view-list')).swipe('down');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reset form', async() => {
|
||||||
|
await element(by.id('room-info-edit-view-name')).replaceText('abc');
|
||||||
|
await element(by.id('room-info-edit-view-description')).replaceText('abc');
|
||||||
|
await element(by.id('room-info-edit-view-topic')).replaceText('abc');
|
||||||
|
await element(by.id('room-info-edit-view-announcement')).replaceText('abc');
|
||||||
|
await element(by.id('room-info-edit-view-password')).replaceText('abc');
|
||||||
|
await element(by.id('room-info-edit-view-list')).swipe('up');
|
||||||
|
await element(by.id('room-info-edit-view-t')).tap();
|
||||||
|
await element(by.id('room-info-edit-view-ro')).tap();
|
||||||
|
await element(by.id('room-info-edit-view-react-when-ro')).tap();
|
||||||
|
await element(by.id('room-info-edit-view-reset')).tap();
|
||||||
|
// after reset
|
||||||
|
await expect(element(by.id('room-info-edit-view-name'))).toHaveText(room);
|
||||||
|
await expect(element(by.id('room-info-edit-view-description'))).toHaveText('');
|
||||||
|
await expect(element(by.id('room-info-edit-view-topic'))).toHaveText('');
|
||||||
|
await expect(element(by.id('room-info-edit-view-announcement'))).toHaveText('');
|
||||||
|
await expect(element(by.id('room-info-edit-view-password'))).toHaveText('');
|
||||||
|
await expect(element(by.id('room-info-edit-view-t'))).toHaveValue('1');
|
||||||
|
await expect(element(by.id('room-info-edit-view-ro'))).toHaveValue('0');
|
||||||
|
await expect(element(by.id('room-info-edit-view-react-when-ro'))).toBeNotVisible();
|
||||||
|
await element(by.id('room-info-edit-view-list')).swipe('down');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change room description', async() => {
|
||||||
|
await element(by.id('room-info-edit-view-description')).replaceText('new description');
|
||||||
|
await element(by.id('room-info-edit-view-list')).swipe('up');
|
||||||
|
await element(by.id('room-info-edit-view-submit')).tap();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('room-info-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await waitFor(element(by.id('room-info-view-description'))).toHaveText('new description').withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-info-view-description'))).toHaveText('new description');
|
||||||
|
await waitFor(element(by.id('room-info-view-edit-button'))).toBeVisible().withTimeout(10000);
|
||||||
|
await element(by.id('room-info-view-edit-button')).tap();
|
||||||
|
await waitFor(element(by.id('room-info-edit-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change room topic', async() => {
|
||||||
|
await element(by.id('room-info-edit-view-topic')).replaceText('new topic');
|
||||||
|
await element(by.id('room-info-edit-view-list')).swipe('up');
|
||||||
|
await element(by.id('room-info-edit-view-submit')).tap();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('room-info-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await waitFor(element(by.id('room-info-view-topic'))).toHaveText('new topic').withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-info-view-topic'))).toHaveText('new topic');
|
||||||
|
await waitFor(element(by.id('room-info-view-edit-button'))).toBeVisible().withTimeout(10000);
|
||||||
|
await element(by.id('room-info-view-edit-button')).tap();
|
||||||
|
await waitFor(element(by.id('room-info-edit-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change room announcement', async() => {
|
||||||
|
await element(by.id('room-info-edit-view-announcement')).replaceText('new announcement');
|
||||||
|
await element(by.id('room-info-edit-view-list')).swipe('up');
|
||||||
|
await element(by.id('room-info-edit-view-submit')).tap();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('room-info-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await waitFor(element(by.id('room-info-view-announcement'))).toHaveText('new announcement').withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-info-view-announcement'))).toHaveText('new announcement');
|
||||||
|
await waitFor(element(by.id('room-info-view-edit-button'))).toBeVisible().withTimeout(10000);
|
||||||
|
await element(by.id('room-info-view-edit-button')).tap();
|
||||||
|
await waitFor(element(by.id('room-info-edit-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change room password', async() => {
|
||||||
|
await element(by.id('room-info-edit-view-list')).swipe('up');
|
||||||
|
await element(by.id('room-info-edit-view-password')).replaceText('password');
|
||||||
|
await element(by.id('room-info-edit-view-submit')).tap();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change room type', async() => {
|
||||||
|
await element(by.id('room-info-edit-view-t')).tap();
|
||||||
|
await element(by.id('room-info-edit-view-submit')).tap();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
|
||||||
|
await element(by.id('room-info-edit-view-t')).tap();
|
||||||
|
await element(by.id('room-info-edit-view-submit')).tap();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change room read only and allow reactions', async() => {
|
||||||
|
await element(by.id('room-info-edit-view-ro')).tap();
|
||||||
|
await waitFor(element(by.id('room-info-edit-view-react-when-ro'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('room-info-edit-view-react-when-ro'))).toBeVisible();
|
||||||
|
await element(by.id('room-info-edit-view-react-when-ro')).tap();
|
||||||
|
await element(by.id('room-info-edit-view-submit')).tap();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
|
||||||
|
await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
|
||||||
|
// TODO: test if it's possible to react
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should archive room', async() => {
|
||||||
|
await element(by.id('room-info-edit-view-archive')).tap();
|
||||||
|
await waitFor(element(by.text('Yes, archive it!'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Yes, archive it!'))).toBeVisible();
|
||||||
|
await element(by.text('Yes, archive it!')).tap();
|
||||||
|
await waitFor(element(by.text('UNARCHIVE'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('UNARCHIVE'))).toBeVisible();
|
||||||
|
// TODO: needs permission to unarchive
|
||||||
|
// await element(by.id('room-info-edit-view-archive')).tap();
|
||||||
|
// await waitFor(element(by.text('Yes, unarchive it!'))).toBeVisible().withTimeout(5000);
|
||||||
|
// await expect(element(by.text('Yes, unarchive it!'))).toBeVisible();
|
||||||
|
// await element(by.text('Yes, unarchive it!')).tap();
|
||||||
|
// await waitFor(element(by.text('ARCHIVE'))).toBeVisible().withTimeout(60000);
|
||||||
|
// await expect(element(by.text('ARCHIVE'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete room', async() => {
|
||||||
|
await element(by.id('room-info-edit-view-list')).swipe('up');
|
||||||
|
await element(by.id('room-info-edit-view-delete')).tap();
|
||||||
|
await waitFor(element(by.text('Yes, delete it!'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Yes, delete it!'))).toBeVisible();
|
||||||
|
await element(by.text('Yes, delete it!')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,60 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
const data = require('./data');
|
||||||
|
|
||||||
|
describe('Change server', () => {
|
||||||
|
before(async() => {
|
||||||
|
await device.reloadReactNative();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add server and create new user', async() => {
|
||||||
|
// Navigate to add server
|
||||||
|
await element(by.id('rooms-list-view-sidebar')).tap();
|
||||||
|
await waitFor(element(by.id('sidebar'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('sidebar-add-server')).tap();
|
||||||
|
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
// Add server
|
||||||
|
await element(by.id('new-server-view-input')).replaceText(data.alternateServer);
|
||||||
|
await waitFor(element(by.text(' is a valid Rocket.Chat instance'))).toBeVisible().withTimeout(60000);
|
||||||
|
await element(by.id('new-server-view-button')).tap();
|
||||||
|
// Navigate to register
|
||||||
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('welcome-view-register')).tap();
|
||||||
|
await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
// Register new user
|
||||||
|
await element(by.id('register-view-name')).replaceText(data.user);
|
||||||
|
await element(by.id('register-view-email')).replaceText(data.email);
|
||||||
|
await element(by.id('register-view-password')).replaceText(data.password);
|
||||||
|
await element(by.id('register-view-repeat-password')).replaceText(data.password);
|
||||||
|
await element(by.id('register-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('register-view-username'))).toBeVisible().withTimeout(60000);
|
||||||
|
await element(by.id('register-view-username')).replaceText(data.user);
|
||||||
|
await element(by.id('register-view-submit-username')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
|
await expect(element(by.id('rooms-list-view-sidebar'))).toHaveLabel(`Connected to ${ data.alternateServer }. Tap to view servers list.`);
|
||||||
|
// For a sanity test, to make sure roomslist is showing correct rooms
|
||||||
|
// app CANNOT show public room created on previous tests
|
||||||
|
await waitFor(element(by.id(`rooms-list-view-item-public${ data.random }`))).toBeNotVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`rooms-list-view-item-public${ data.random }`))).toBeNotVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change server', async() => {
|
||||||
|
await element(by.id('rooms-list-view-sidebar')).tap();
|
||||||
|
await waitFor(element(by.id('sidebar'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id(`sidebar-${ data.server }`)).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
|
||||||
|
await waitFor(element(by.id('rooms-list-view-sidebar').and(by.label(`Connected to ${ data.server }. Tap to view servers list.`)))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('rooms-list-view-sidebar'))).toHaveLabel(`Connected to ${ data.server }. Tap to view servers list.`);
|
||||||
|
// For a sanity test, to make sure roomslist is showing correct rooms
|
||||||
|
// app MUST show public room created on previous tests
|
||||||
|
await waitFor(element(by.id(`rooms-list-view-item-public${ data.random }`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`rooms-list-view-item-public${ data.random }`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,11 @@
|
||||||
|
const random = require('./helpers/random');
|
||||||
|
const value = random(20);
|
||||||
|
const data = {
|
||||||
|
server: 'https://unstable.rocket.chat',
|
||||||
|
alternateServer: 'https://stable.rocket.chat',
|
||||||
|
user: `user${ value }`,
|
||||||
|
password: `password${ value }`,
|
||||||
|
email: `detoxrn+${ value }@rocket.chat`,
|
||||||
|
random: value
|
||||||
|
}
|
||||||
|
module.exports = data;
|
|
@ -0,0 +1,41 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const data = require('../data');
|
||||||
|
|
||||||
|
async function addServer() {
|
||||||
|
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('new-server-view-input')).replaceText(data.server);
|
||||||
|
await waitFor(element(by.text(' is a valid Rocket.Chat instance'))).toBeVisible().withTimeout(2000);
|
||||||
|
await waitFor(element(by.id('new-server-view-button'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('new-server-view-button')).tap();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function navigateToLogin() {
|
||||||
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('welcome-view-login')).tap();
|
||||||
|
await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function login() {
|
||||||
|
await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('login-view-email')).replaceText(data.user);
|
||||||
|
await element(by.id('login-view-password')).replaceText(data.password);
|
||||||
|
await element(by.id('login-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function logout() {
|
||||||
|
await element(by.id('rooms-list-view-sidebar')).tap();
|
||||||
|
await waitFor(element(by.id('sidebar'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('sidebar-logout')).tap();
|
||||||
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('welcome-view'))).toBeVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addServer,
|
||||||
|
navigateToLogin,
|
||||||
|
login,
|
||||||
|
logout
|
||||||
|
};
|
|
@ -0,0 +1,9 @@
|
||||||
|
function random(length) {
|
||||||
|
let text = '';
|
||||||
|
const possible = 'abcdefghijklmnopqrstuvwxyz';
|
||||||
|
for (let i = 0; i < length; i += 1) {
|
||||||
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
module.exports = random;
|
|
@ -0,0 +1,23 @@
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
const { existsSync, mkdirSync } = require('fs');
|
||||||
|
|
||||||
|
const SCREENSHOT_DIR = '/tmp/screenshots';
|
||||||
|
|
||||||
|
const SCREENSHOT_OPTIONS = {
|
||||||
|
timeout: 2000,
|
||||||
|
killSignal: 'SIGKILL'
|
||||||
|
};
|
||||||
|
|
||||||
|
let screenshotIndex = 0;
|
||||||
|
|
||||||
|
const takeScreenshot = () => {
|
||||||
|
if (!existsSync(SCREENSHOT_DIR)) { mkdirSync(SCREENSHOT_DIR); }
|
||||||
|
const screenshotFilename = `${ SCREENSHOT_DIR }/screenshot-${ screenshotIndex++ }.png`;
|
||||||
|
try {
|
||||||
|
execSync(`xcrun simctl io booted screenshot ${ screenshotFilename }`, SCREENSHOT_OPTIONS);
|
||||||
|
} catch (error) {
|
||||||
|
console.log('erro');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = { takeScreenshot };
|
|
@ -0,0 +1,11 @@
|
||||||
|
const detox = require('detox');
|
||||||
|
const config = require('../package.json').detox;
|
||||||
|
|
||||||
|
before(async() => {
|
||||||
|
await detox.init(config);
|
||||||
|
await device.launchApp({ permissions: { notifications: 'YES' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
await detox.cleanup();
|
||||||
|
});
|
|
@ -0,0 +1 @@
|
||||||
|
--recursive --timeout 120000
|
|
@ -3619,6 +3619,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"browser-stdout": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
|
||||||
|
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"browserify-aes": {
|
"browserify-aes": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
||||||
|
@ -3941,6 +3947,29 @@
|
||||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
|
||||||
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
|
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
|
||||||
},
|
},
|
||||||
|
"child-process-promise": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/child-process-promise/-/child-process-promise-2.2.1.tgz",
|
||||||
|
"integrity": "sha1-RzChHvYQ+tRQuPIjx50x172tgHQ=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"cross-spawn": "4.0.2",
|
||||||
|
"node-version": "1.1.3",
|
||||||
|
"promise-polyfill": "6.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"cross-spawn": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
|
||||||
|
"integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"lru-cache": "4.1.1",
|
||||||
|
"which": "1.3.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"chokidar": {
|
"chokidar": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
|
||||||
|
@ -5534,6 +5563,59 @@
|
||||||
"defined": "1.0.0"
|
"defined": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"detox": {
|
||||||
|
"version": "7.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/detox/-/detox-7.3.5.tgz",
|
||||||
|
"integrity": "sha512-qFAlpFAR7KOZLFoVyGHUfvvfeC6ULzdFCMnM/qlCt2rRkCC4hB1KEtzsPng92N+Si+ZNeByJ+mjWt68nbamsUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"child-process-promise": "2.2.1",
|
||||||
|
"commander": "2.15.1",
|
||||||
|
"detox-server": "7.0.0",
|
||||||
|
"fs-extra": "4.0.3",
|
||||||
|
"get-port": "2.1.0",
|
||||||
|
"ini": "1.3.5",
|
||||||
|
"lodash": "4.17.10",
|
||||||
|
"npmlog": "4.1.2",
|
||||||
|
"shell-utils": "1.0.9",
|
||||||
|
"tail": "1.2.3",
|
||||||
|
"telnet-client": "0.15.3",
|
||||||
|
"ws": "1.1.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"fs-extra": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "4.1.11",
|
||||||
|
"jsonfile": "4.0.0",
|
||||||
|
"universalify": "0.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jsonfile": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "4.1.11"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"detox-server": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/detox-server/-/detox-server-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-zs9ZP/MgeEmaZD/+MCl5PVcYHRjUtFBkBx3xQRPcsjJ/PmpCKy/BvygjLO6tRsR/2SC9UYay6W+BdguEYeft8g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"lodash": "4.17.10",
|
||||||
|
"npmlog": "4.1.2",
|
||||||
|
"ws": "1.1.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"diff": {
|
"diff": {
|
||||||
"version": "3.5.0",
|
"version": "3.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||||
|
@ -7901,6 +7983,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",
|
||||||
"integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U="
|
"integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U="
|
||||||
},
|
},
|
||||||
|
"get-port": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-port/-/get-port-2.1.0.tgz",
|
||||||
|
"integrity": "sha1-h4P53OvR7qSVozThpqJR54iHqxo=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"pinkie-promise": "2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"get-stdin": {
|
"get-stdin": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz",
|
||||||
|
@ -8063,6 +8154,12 @@
|
||||||
"lodash": "4.17.10"
|
"lodash": "4.17.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"growl": {
|
||||||
|
"version": "1.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz",
|
||||||
|
"integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"growly": {
|
"growly": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
|
||||||
|
@ -11452,6 +11549,51 @@
|
||||||
"resolved": "https://registry.npmjs.org/mobx/-/mobx-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/mobx/-/mobx-2.7.0.tgz",
|
||||||
"integrity": "sha1-zz2C0YwMp/RY2PKiQIF7PcflSgE="
|
"integrity": "sha1-zz2C0YwMp/RY2PKiQIF7PcflSgE="
|
||||||
},
|
},
|
||||||
|
"mocha": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mocha/-/mocha-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-kKKs/H1KrMMQIEsWNxGmb4/BGsmj0dkeyotEvbrAuQ01FcWRLssUNXCEUZk6SZtyJBi6EE7SL0zDDtItw1rGhw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"browser-stdout": "1.3.1",
|
||||||
|
"commander": "2.11.0",
|
||||||
|
"debug": "3.1.0",
|
||||||
|
"diff": "3.5.0",
|
||||||
|
"escape-string-regexp": "1.0.5",
|
||||||
|
"glob": "7.1.2",
|
||||||
|
"growl": "1.10.3",
|
||||||
|
"he": "1.1.1",
|
||||||
|
"minimatch": "3.0.4",
|
||||||
|
"mkdirp": "0.5.1",
|
||||||
|
"supports-color": "4.4.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"commander": {
|
||||||
|
"version": "2.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
|
||||||
|
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.22.1",
|
"version": "2.22.1",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.22.1.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.22.1.tgz",
|
||||||
|
@ -11890,6 +12032,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node-version": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-version/-/node-version-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-rEwE51JWn0yN3Wl5BXeGn5d52OGbSXzWiiXRjAQeuyvcGKyvuSILW2rb3G7Xh+nexzLwhTpek6Ehxd6IjvHePg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"nopt": {
|
"nopt": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
|
||||||
|
@ -13769,6 +13917,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
|
||||||
"integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM="
|
"integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM="
|
||||||
},
|
},
|
||||||
|
"promise-polyfill": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-6.1.0.tgz",
|
||||||
|
"integrity": "sha1-36lpQ+qcEh/KTem1hoyznTRy4Fc=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"prop-types": {
|
"prop-types": {
|
||||||
"version": "15.6.1",
|
"version": "15.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz",
|
||||||
|
@ -16137,6 +16291,15 @@
|
||||||
"jsonify": "0.0.0"
|
"jsonify": "0.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"shell-utils": {
|
||||||
|
"version": "1.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/shell-utils/-/shell-utils-1.0.9.tgz",
|
||||||
|
"integrity": "sha512-JbTHnKpMyj9TUUbL+Us2Rx2iVHFvH5QyQoke9SN1L0pueiZeO2Gzlzopmloi7oqObL4qtvdSuZPE3UfdIzmlag==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"lodash": "4.17.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"shelljs": {
|
"shelljs": {
|
||||||
"version": "0.8.2",
|
"version": "0.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz",
|
||||||
|
@ -17243,6 +17406,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tail": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tail/-/tail-1.2.3.tgz",
|
||||||
|
"integrity": "sha1-sI1vp5+5KIaWMaNBpRwUSXwcQlU=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"tapable": {
|
"tapable": {
|
||||||
"version": "0.2.8",
|
"version": "0.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz",
|
||||||
|
@ -17287,6 +17456,15 @@
|
||||||
"xtend": "4.0.1"
|
"xtend": "4.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"telnet-client": {
|
||||||
|
"version": "0.15.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/telnet-client/-/telnet-client-0.15.3.tgz",
|
||||||
|
"integrity": "sha512-GSfdzQV0BKIYsmeXq7bJFJ2wHeJud6icaIxCUf6QCGQUD6R0BBGbT1+yLDhq67JRdgRpwyPwUbV7JxFeRrZomQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"bluebird": "3.5.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"temp": {
|
"temp": {
|
||||||
"version": "0.8.3",
|
"version": "0.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz",
|
||||||
|
|
15
package.json
15
package.json
|
@ -87,6 +87,7 @@
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"babel-preset-es2015": "^6.24.1",
|
||||||
"babel-preset-react-native": "^4.0.0",
|
"babel-preset-react-native": "^4.0.0",
|
||||||
"codecov": "^3.0.2",
|
"codecov": "^3.0.2",
|
||||||
|
"detox": "^7.3.5",
|
||||||
"eslint": "^4.19.1",
|
"eslint": "^4.19.1",
|
||||||
"eslint-config-airbnb": "^16.1.0",
|
"eslint-config-airbnb": "^16.1.0",
|
||||||
"eslint-plugin-import": "^2.12.0",
|
"eslint-plugin-import": "^2.12.0",
|
||||||
|
@ -96,6 +97,7 @@
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"jest": "^22.4.4",
|
"jest": "^22.4.4",
|
||||||
"jest-cli": "^22.4.4",
|
"jest-cli": "^22.4.4",
|
||||||
|
"mocha": "^5.1.1",
|
||||||
"react-dom": "^16.3.2",
|
"react-dom": "^16.3.2",
|
||||||
"react-native-bundle-visualizer": "^1.2.0",
|
"react-native-bundle-visualizer": "^1.2.0",
|
||||||
"react-test-renderer": "^16.3.2",
|
"react-test-renderer": "^16.3.2",
|
||||||
|
@ -104,6 +106,9 @@
|
||||||
"reactotron-redux-saga": "^1.13.0"
|
"reactotron-redux-saga": "^1.13.0"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
|
"testPathIgnorePatterns": [
|
||||||
|
"e2e"
|
||||||
|
],
|
||||||
"preset": "react-native",
|
"preset": "react-native",
|
||||||
"coverageDirectory": "./coverage/",
|
"coverageDirectory": "./coverage/",
|
||||||
"collectCoverage": true,
|
"collectCoverage": true,
|
||||||
|
@ -115,5 +120,15 @@
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.x",
|
"node": ">=8.x",
|
||||||
"npm": ">=4.x"
|
"npm": ">=4.x"
|
||||||
|
},
|
||||||
|
"detox": {
|
||||||
|
"configurations": {
|
||||||
|
"ios.sim.debug": {
|
||||||
|
"binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/RocketChatRN.app",
|
||||||
|
"build": "xcodebuild -project ios/RocketChatRN.xcodeproj -scheme RocketChatRN -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
|
||||||
|
"type": "ios.simulator",
|
||||||
|
"name": "iPhone 7"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue