MM-30076 Detox/E2E: Update UI test structure for reusability (#4931)
* update UI test structure for reusability * fix Android tests * improve autocomplete test * minor cleanup
This commit is contained in:
parent
2eaeb4e040
commit
a819f63d99
74 changed files with 1056 additions and 434 deletions
|
|
@ -266,7 +266,7 @@ export default class AtMention extends PureComponent {
|
|||
|
||||
return (
|
||||
<SectionList
|
||||
testID='autocomplete.at_mention.list'
|
||||
testID='at_mention_suggestion.list'
|
||||
keyboardShouldPersistTaps='always'
|
||||
keyExtractor={this.keyExtractor}
|
||||
style={[style.listView, {maxHeight: maxListHeight}]}
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@ export default class Autocomplete extends PureComponent {
|
|||
return (
|
||||
<View style={wrapperStyles}>
|
||||
<View
|
||||
testID='autocomplete'
|
||||
ref={this.containerRef}
|
||||
style={containerStyles}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ export default class ChannelMention extends PureComponent {
|
|||
|
||||
return (
|
||||
<SectionList
|
||||
testID='autocomplete.channel_mention.list'
|
||||
testID='channel_mention_suggestion.list'
|
||||
keyboardShouldPersistTaps='always'
|
||||
keyExtractor={this.keyExtractor}
|
||||
style={[style.listView, {maxHeight: maxListHeight}]}
|
||||
|
|
|
|||
|
|
@ -3051,7 +3051,7 @@ exports[`components/autocomplete/emoji_suggestion should match snapshot 2`] = `
|
|||
},
|
||||
]
|
||||
}
|
||||
testID="autocomplete.emoji_suggestion.list"
|
||||
testID="emoji_suggestion.list"
|
||||
updateCellsBatchingPeriod={50}
|
||||
windowSize={21}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ export default class EmojiSuggestion extends PureComponent {
|
|||
|
||||
return (
|
||||
<FlatList
|
||||
testID='autocomplete.emoji_suggestion.list'
|
||||
testID='emoji_suggestion.list'
|
||||
keyboardShouldPersistTaps='always'
|
||||
style={[style.listView, {maxHeight: maxListHeight}]}
|
||||
extraData={this.state}
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ export default class SlashSuggestion extends PureComponent {
|
|||
|
||||
return (
|
||||
<FlatList
|
||||
testID='autocomplete.slash_suggestion'
|
||||
testID='slash_suggestion.list'
|
||||
keyboardShouldPersistTaps='always'
|
||||
style={[style.listView, {maxHeight: maxListHeight}]}
|
||||
extraData={this.state}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ exports[`EditChannelInfo should match snapshot 1`] = `
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="edit_channel.scroll"
|
||||
>
|
||||
<TouchableWithoutFeedback
|
||||
onPress={[Function]}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ export default class EditChannelInfo extends PureComponent {
|
|||
oldHeader: PropTypes.string,
|
||||
oldPurpose: PropTypes.string,
|
||||
isLandscape: PropTypes.bool.isRequired,
|
||||
testID: PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -204,6 +205,7 @@ export default class EditChannelInfo extends PureComponent {
|
|||
isLandscape,
|
||||
error,
|
||||
saving,
|
||||
testID,
|
||||
} = this.props;
|
||||
const {keyboardVisible, keyboardPosition} = this.state;
|
||||
const bottomStyle = {
|
||||
|
|
@ -241,7 +243,7 @@ export default class EditChannelInfo extends PureComponent {
|
|||
<React.Fragment>
|
||||
<StatusBar/>
|
||||
<KeyboardAwareScrollView
|
||||
testID='edit_channel.scroll'
|
||||
testID={testID}
|
||||
ref={this.scroll}
|
||||
style={style.container}
|
||||
keyboardShouldPersistTaps={'always'}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ exports[`ErrorText should match snapshot 1`] = `
|
|||
},
|
||||
]
|
||||
}
|
||||
testID="error_text"
|
||||
testID="error.text"
|
||||
>
|
||||
Username must begin with a letter and contain between 3 and 22 characters including numbers, lowercase letters, and the symbols
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export default class ErrorText extends PureComponent {
|
|||
if (intl) {
|
||||
return (
|
||||
<FormattedText
|
||||
testID='error_text'
|
||||
testID='error.text'
|
||||
id={intl.id}
|
||||
defaultMessage={intl.defaultMessage}
|
||||
values={intl.values}
|
||||
|
|
@ -40,7 +40,7 @@ export default class ErrorText extends PureComponent {
|
|||
|
||||
return (
|
||||
<Text
|
||||
testID='error_text'
|
||||
testID='error.text'
|
||||
style={[GlobalStyles.errorLabel, style.errorLabel, textStyle]}
|
||||
>
|
||||
{error.message || error}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ exports[`PasteableTextInput should render pasteable text input 1`] = `
|
|||
allowFontScaling={true}
|
||||
onPaste={[Function]}
|
||||
rejectResponderTermination={true}
|
||||
testID="post_input"
|
||||
testID="post.input"
|
||||
underlineColorAndroid="transparent"
|
||||
>
|
||||
My Text
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export class PasteableTextInput extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<TextInput
|
||||
testID='post_input'
|
||||
testID='post.input'
|
||||
{...props}
|
||||
onPaste={this.onPaste}
|
||||
ref={forwardRef}
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ exports[`PostDraft Should render the DraftInput 1`] = `
|
|||
"paddingTop": 6,
|
||||
}
|
||||
}
|
||||
testID="post_input"
|
||||
testID="post.input"
|
||||
textContentType="none"
|
||||
underlineColorAndroid="transparent"
|
||||
/>
|
||||
|
|
@ -531,7 +531,7 @@ exports[`PostDraft Should render the DraftInput 1`] = `
|
|||
"paddingRight": 8,
|
||||
}
|
||||
}
|
||||
testID="disabled_send_button"
|
||||
testID="disabled_send.button"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ describe('PostDraft', () => {
|
|||
);
|
||||
|
||||
expect(toJSON()).toMatchSnapshot();
|
||||
expect(getByTestId('post_input')).toBeTruthy();
|
||||
expect(getByTestId('post.input')).toBeTruthy();
|
||||
expect(queryByText('Close Channel')).toBeNull();
|
||||
});
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ describe('PostDraft', () => {
|
|||
expect(toJSON()).toMatchSnapshot();
|
||||
|
||||
// Should not render text input
|
||||
expect(queryByTestId('post_input')).toBeNull();
|
||||
expect(queryByTestId('post.input')).toBeNull();
|
||||
|
||||
// Should match text description
|
||||
expect(getByText('You are viewing an ')).toBeTruthy();
|
||||
|
|
@ -100,7 +100,7 @@ describe('PostDraft', () => {
|
|||
expect(toJSON()).toMatchSnapshot();
|
||||
|
||||
// Should not render text input
|
||||
expect(queryByTestId('post_input')).toBeNull();
|
||||
expect(queryByTestId('post.input')).toBeNull();
|
||||
|
||||
// Should match text description
|
||||
expect(getByText('You are viewing an ')).toBeTruthy();
|
||||
|
|
@ -121,7 +121,7 @@ describe('PostDraft', () => {
|
|||
expect(toJSON()).toMatchSnapshot();
|
||||
|
||||
// Should not render text input
|
||||
expect(queryByTestId('post_input')).toBeNull();
|
||||
expect(queryByTestId('post.input')).toBeNull();
|
||||
|
||||
// Should match text description
|
||||
expect(getByText('This channel is read-only.')).toBeTruthy();
|
||||
|
|
@ -140,7 +140,7 @@ describe('PostDraft', () => {
|
|||
expect(toJSON()).toMatchSnapshot();
|
||||
|
||||
// Should not render text input
|
||||
expect(queryByTestId('post_input')).toBeNull();
|
||||
expect(queryByTestId('post.input')).toBeNull();
|
||||
|
||||
// Should match text description
|
||||
expect(getByText('This channel is read-only.')).toBeTruthy();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ exports[`SendAction should change theme backgroundColor to 0.3 opacity 1`] = `
|
|||
"paddingRight": 8,
|
||||
}
|
||||
}
|
||||
testID="disabled_send_button"
|
||||
testID="disabled_send.button"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
|
|
@ -45,7 +45,7 @@ exports[`SendAction should match snapshot 1`] = `
|
|||
"paddingRight": 8,
|
||||
}
|
||||
}
|
||||
testID="send_button"
|
||||
testID="send.button"
|
||||
type="opacity"
|
||||
>
|
||||
<View
|
||||
|
|
@ -78,7 +78,7 @@ exports[`SendAction should render theme backgroundColor 1`] = `
|
|||
"paddingRight": 8,
|
||||
}
|
||||
}
|
||||
testID="send_button"
|
||||
testID="send.button"
|
||||
type="opacity"
|
||||
>
|
||||
<View
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ function SendButton(props) {
|
|||
if (props.disabled) {
|
||||
return (
|
||||
<View
|
||||
testID='disabled_send_button'
|
||||
testID='disabled_send.button'
|
||||
style={style.sendButtonContainer}
|
||||
>
|
||||
<View style={[style.sendButton, style.disableButton]}>
|
||||
|
|
@ -32,7 +32,7 @@ function SendButton(props) {
|
|||
|
||||
return (
|
||||
<TouchableWithFeedback
|
||||
testID='send_button'
|
||||
testID='send.button'
|
||||
onPress={props.handleSendMessage}
|
||||
style={style.sendButtonContainer}
|
||||
type={'opacity'}
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ exports[`Reactions Should match snapshot with default emojis 1`] = `
|
|||
/>
|
||||
<TouchableWithoutFeedback
|
||||
onPress={[MockFunction]}
|
||||
testID="reaction_picker.open"
|
||||
testID="open.reaction_picker"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
|
|
@ -492,7 +492,7 @@ exports[`Reactions Should match snapshot with default emojis 2`] = `
|
|||
/>
|
||||
<TouchableWithoutFeedback
|
||||
onPress={[MockFunction]}
|
||||
testID="reaction_picker.open"
|
||||
testID="open.reaction_picker"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ export default class ReactionPicker extends PureComponent {
|
|||
{list}
|
||||
<TouchableWithoutFeedback
|
||||
onPress={this.props.openReactionScreen}
|
||||
testID='reaction_picker.open'
|
||||
testID='open.reaction_picker'
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
|
|
|
|||
|
|
@ -315,7 +315,6 @@ export default class Search extends PureComponent {
|
|||
]}
|
||||
>
|
||||
<SearchBar
|
||||
testID='search.bar'
|
||||
autoCapitalize={this.props.autoCapitalize}
|
||||
autoCorrect={false}
|
||||
autoFocus={this.props.autoFocus}
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ export default class ChannelsList extends PureComponent {
|
|||
return (
|
||||
<View
|
||||
style={styles.container}
|
||||
testID='channels_list'
|
||||
testID='channels.list'
|
||||
>
|
||||
<View style={styles.headerContainer}>
|
||||
{title}
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ export default class MainSidebarBase extends Component {
|
|||
showTeams={showTeams}
|
||||
drawerOpened={this.state.drawerOpened}
|
||||
drawerWidth={drawerWidth - offset}
|
||||
testID='main_sidebar'
|
||||
testID='main.sidebar'
|
||||
>
|
||||
{lists}
|
||||
</DrawerSwiper>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export default class AddReaction extends PureComponent {
|
|||
|
||||
leftButton = {
|
||||
id: 'close-add-reaction',
|
||||
testID: 'screen.add_reaction.close',
|
||||
testID: 'close.add_reaction.button',
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
|
@ -60,7 +60,10 @@ export default class AddReaction extends PureComponent {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View
|
||||
testID='add_reaction.screen'
|
||||
style={styles.container}
|
||||
>
|
||||
<EmojiPicker onEmojiPress={this.handleEmojiPress}/>
|
||||
</View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export default class ChannelAndroid extends ChannelBase {
|
|||
component = (
|
||||
<KeyboardLayout>
|
||||
<View
|
||||
testID='channel_screen'
|
||||
testID='channel.screen'
|
||||
style={style.flex}
|
||||
>
|
||||
<ChannelPostList registerTypingAnimation={this.registerTypingAnimation}/>
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ export default class ChannelIOS extends ChannelBase {
|
|||
|
||||
return (
|
||||
<MainSidebar
|
||||
testID='channel_screen'
|
||||
testID='channel.screen'
|
||||
ref={this.mainSidebarRef}
|
||||
>
|
||||
<SettingsSidebar ref={this.settingsSidebarRef}>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ exports[`channelInfo should match snapshot 1`] = `
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="channel_info.screen"
|
||||
>
|
||||
<Connect(StatusBar) />
|
||||
<ScrollView
|
||||
|
|
|
|||
|
|
@ -179,7 +179,10 @@ export default class ChannelInfo extends PureComponent {
|
|||
const channelIsArchived = currentChannel.delete_at !== 0;
|
||||
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<View
|
||||
testID='channel_info.screen'
|
||||
style={style.container}
|
||||
>
|
||||
<StatusBar/>
|
||||
<ScrollView
|
||||
style={style.scrollView}
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ export default class CreateChannel extends PureComponent {
|
|||
|
||||
return (
|
||||
<EditChannelInfo
|
||||
testID='create_channel.screen'
|
||||
theme={theme}
|
||||
enableRightButton={this.emitCanCreateChannel}
|
||||
error={error}
|
||||
|
|
|
|||
|
|
@ -315,6 +315,7 @@ export default class EditChannel extends PureComponent {
|
|||
excludeFooter={true}
|
||||
>
|
||||
<EditChannelInfo
|
||||
testID='edit_channel.screen'
|
||||
theme={theme}
|
||||
enableRightButton={this.emitCanUpdateChannel}
|
||||
error={error}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ exports[`EditPost should match snapshot 1`] = `
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="edit_post.screen"
|
||||
>
|
||||
<Connect(StatusBar) />
|
||||
<View
|
||||
|
|
|
|||
|
|
@ -250,7 +250,10 @@ export default class EditPost extends PureComponent {
|
|||
|
||||
return (
|
||||
<>
|
||||
<View style={style.container}>
|
||||
<View
|
||||
testID='edit_post.screen'
|
||||
style={style.container}
|
||||
>
|
||||
<StatusBar/>
|
||||
<View style={style.scrollView}>
|
||||
{displayError}
|
||||
|
|
|
|||
|
|
@ -339,7 +339,7 @@ export default class Login extends PureComponent {
|
|||
|
||||
proceed = (
|
||||
<Button
|
||||
testID='signin_button'
|
||||
testID='signin.button'
|
||||
onPress={this.preSignIn}
|
||||
containerStyle={[GlobalStyles.signupButton, additionalStyle]}
|
||||
>
|
||||
|
|
@ -387,7 +387,7 @@ export default class Login extends PureComponent {
|
|||
size={76}
|
||||
style={GlobalStyles.logo}
|
||||
/>
|
||||
<View testID='login_screen'>
|
||||
<View testID='login.screen'>
|
||||
<Text style={GlobalStyles.header}>
|
||||
{this.props.config.SiteName}
|
||||
</Text>
|
||||
|
|
@ -399,7 +399,7 @@ export default class Login extends PureComponent {
|
|||
</View>
|
||||
<ErrorText error={this.state.error}/>
|
||||
<TextInput
|
||||
testID='username_input'
|
||||
testID='username.input'
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
blurOnSubmit={false}
|
||||
|
|
@ -415,7 +415,7 @@ export default class Login extends PureComponent {
|
|||
underlineColorAndroid='transparent'
|
||||
/>
|
||||
<TextInput
|
||||
testID='password_input'
|
||||
testID='password.input'
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
disableFullscreenUI={true}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ exports[`MoreChannels should match snapshot 1`] = `
|
|||
"paddingLeft": 8,
|
||||
}
|
||||
}
|
||||
testID="more_channels.screen"
|
||||
>
|
||||
<View
|
||||
style={null}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ export default class MoreChannels extends PureComponent {
|
|||
id: 'create-pub-channel',
|
||||
text: context.intl.formatMessage({id: 'mobile.create_channel', defaultMessage: 'Create'}),
|
||||
showAsAction: 'always',
|
||||
testID: 'public_channels.create.button',
|
||||
testID: 'public_channel.create.button',
|
||||
};
|
||||
|
||||
this.leftButton = {
|
||||
|
|
@ -454,7 +454,10 @@ export default class MoreChannels extends PureComponent {
|
|||
|
||||
content = (
|
||||
<React.Fragment>
|
||||
<View style={style.searchBar}>
|
||||
<View
|
||||
testID='more_channels.screen'
|
||||
style={style.searchBar}
|
||||
>
|
||||
<View style={padding(isLandscape)}>
|
||||
<SearchBar
|
||||
ref={this.setSearchBarRef}
|
||||
|
|
|
|||
|
|
@ -477,7 +477,7 @@ export default class MoreDirectMessages extends PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<KeyboardLayout testID='direct_channels_screen'>
|
||||
<KeyboardLayout testID='direct_channels.screen'>
|
||||
<StatusBar/>
|
||||
<View style={style.searchBar}>
|
||||
<View style={padding(isLandscape)}>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ exports[`PostOptions should match snapshot, no option for system message to user
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="post.options"
|
||||
>
|
||||
<Connect(SlideUpPanel)
|
||||
allowStayMiddle={false}
|
||||
|
|
@ -201,6 +202,7 @@ exports[`PostOptions should match snapshot, showing Delete option only for syste
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="post.options"
|
||||
>
|
||||
<Connect(SlideUpPanel)
|
||||
allowStayMiddle={false}
|
||||
|
|
@ -431,6 +433,7 @@ exports[`PostOptions should match snapshot, showing all possible options 1`] = `
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="post.options"
|
||||
>
|
||||
<Connect(SlideUpPanel)
|
||||
allowStayMiddle={false}
|
||||
|
|
|
|||
|
|
@ -413,7 +413,10 @@ export default class PostOptions extends PureComponent {
|
|||
const initialPosition = getInitialPosition(deviceHeight, marginFromTop);
|
||||
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<View
|
||||
testID='post.options'
|
||||
style={style.container}
|
||||
>
|
||||
<SlideUpPanel
|
||||
allowStayMiddle={false}
|
||||
ref={this.refSlideUpPanel}
|
||||
|
|
|
|||
|
|
@ -712,7 +712,10 @@ export default class Search extends PureComponent {
|
|||
<SafeAreaView style={style.flex}>
|
||||
<KeyboardLayout>
|
||||
<StatusBar/>
|
||||
<View style={[style.header, paddingRes]}>
|
||||
<View
|
||||
testID='search.screen'
|
||||
style={[style.header, paddingRes]}
|
||||
>
|
||||
<SearchBar
|
||||
ref={this.setSearchBarRef}
|
||||
placeholder={intl.formatMessage({id: 'search_bar.search', defaultMessage: 'Search'})}
|
||||
|
|
|
|||
|
|
@ -499,7 +499,7 @@ export default class SelectServer extends PureComponent {
|
|||
|
||||
return (
|
||||
<SafeAreaView
|
||||
testID='select_server_screen'
|
||||
testID='select_server.screen'
|
||||
style={style.container}
|
||||
>
|
||||
<KeyboardAvoidingView
|
||||
|
|
@ -520,7 +520,7 @@ export default class SelectServer extends PureComponent {
|
|||
style={GlobalStyles.logo}
|
||||
/>
|
||||
|
||||
<View>
|
||||
<View testID='header.text'>
|
||||
<FormattedText
|
||||
style={[GlobalStyles.header, GlobalStyles.label]}
|
||||
id='mobile.components.select_server_view.enterServerUrl'
|
||||
|
|
@ -528,7 +528,7 @@ export default class SelectServer extends PureComponent {
|
|||
/>
|
||||
</View>
|
||||
<TextInput
|
||||
testID='server_url_input'
|
||||
testID='server_url.input'
|
||||
ref={this.inputRef}
|
||||
value={url}
|
||||
editable={!inputDisabled}
|
||||
|
|
@ -548,7 +548,7 @@ export default class SelectServer extends PureComponent {
|
|||
disableFullscreenUI={true}
|
||||
/>
|
||||
<Button
|
||||
testID='connect_button'
|
||||
testID='connect.button'
|
||||
onPress={this.handleConnect}
|
||||
containerStyle={[GlobalStyles.signupButton, style.connectButton]}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ describe('SelectServer', () => {
|
|||
const button = getByText('Connect');
|
||||
fireEvent.press(button);
|
||||
|
||||
await waitFor(() => expect(getByTestId('error_text')).toBeTruthy());
|
||||
await waitFor(() => expect(getByTestId('error.text')).toBeTruthy());
|
||||
expect(getByText('Please enter a valid server URL')).toBeTruthy();
|
||||
});
|
||||
|
||||
|
|
@ -41,13 +41,13 @@ describe('SelectServer', () => {
|
|||
<SelectServer {...baseProps}/>,
|
||||
);
|
||||
|
||||
const urlInput = getByTestId('server_url_input');
|
||||
const urlInput = getByTestId('server_url.input');
|
||||
fireEvent.changeText(urlInput, ' ');
|
||||
|
||||
const button = getByText('Connect');
|
||||
fireEvent.press(button);
|
||||
|
||||
await waitFor(() => expect(getByTestId('error_text')).toBeTruthy());
|
||||
await waitFor(() => expect(getByTestId('error.text')).toBeTruthy());
|
||||
expect(getByText('Please enter a valid server URL')).toBeTruthy();
|
||||
});
|
||||
|
||||
|
|
@ -56,13 +56,13 @@ describe('SelectServer', () => {
|
|||
<SelectServer {...baseProps}/>,
|
||||
);
|
||||
|
||||
const urlInput = getByTestId('server_url_input');
|
||||
const urlInput = getByTestId('server_url.input');
|
||||
fireEvent.changeText(urlInput, 'ht://invalid:8065');
|
||||
|
||||
const button = getByText('Connect');
|
||||
fireEvent.press(button);
|
||||
|
||||
await waitFor(() => expect(getByTestId('error_text')).toBeTruthy());
|
||||
await waitFor(() => expect(getByTestId('error.text')).toBeTruthy());
|
||||
expect(getByText('URL must start with http:// or https://')).toBeTruthy();
|
||||
});
|
||||
|
||||
|
|
@ -71,13 +71,13 @@ describe('SelectServer', () => {
|
|||
<SelectServer {...baseProps}/>,
|
||||
);
|
||||
|
||||
const urlInput = getByTestId('server_url_input');
|
||||
const urlInput = getByTestId('server_url.input');
|
||||
fireEvent.changeText(urlInput, 'http://localhost:8065');
|
||||
|
||||
const button = getByText('Connect');
|
||||
fireEvent.press(button);
|
||||
|
||||
expect(queryByTestId('error_text')).toBeNull();
|
||||
expect(queryByTestId('error.text')).toBeNull();
|
||||
await waitFor(() => expect(getByText('Connecting...')).toBeTruthy());
|
||||
});
|
||||
});
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"presets": ["@babel/preset-env"],
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-transform-runtime",
|
||||
["module-resolver", {
|
||||
"root": ["."],
|
||||
|
|
|
|||
37
detox/e2e/support/ui/component/autocomplete.js
Normal file
37
detox/e2e/support/ui/component/autocomplete.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
class Autocomplete {
|
||||
testID = {
|
||||
autocomplete: 'autocomplete',
|
||||
atMentionSuggestionList: 'at_mention_suggestion.list',
|
||||
channelMentionSuggestionList: 'channel_mention_suggestion.list',
|
||||
dateSuggestion: 'autocomplete.date_suggestion',
|
||||
emojiSuggestionList: 'emoji_suggestion.list',
|
||||
slashSuggestionList: 'slash_suggestion.list',
|
||||
}
|
||||
|
||||
autocomplete = element(by.id(this.testID.autocomplete));
|
||||
atMentionSuggestionList = element(by.id(this.testID.atMentionSuggestionList));
|
||||
channelMentionSuggestionList = element(by.id(this.testID.channelMentionSuggestionList));
|
||||
dateSuggestion = element(by.id(this.testID.dateSuggestion));
|
||||
emojiSuggestionList = element(by.id(this.testID.emojiSuggestionList));
|
||||
slashSuggestionList = element(by.id(this.testID.slashSuggestionList));
|
||||
|
||||
getAtMentionItem = (userId) => {
|
||||
return element(by.id(`autocomplete.at_mention.item.${userId}`));
|
||||
}
|
||||
|
||||
toBeVisible = async (isVisible = true) => {
|
||||
if (isVisible) {
|
||||
await expect(this.autocomplete.atIndex(0)).toBeVisible();
|
||||
return this.autocomplete;
|
||||
}
|
||||
|
||||
await expect(this.autocomplete).not.toBeVisible();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const autocomplete = new Autocomplete();
|
||||
export default autocomplete;
|
||||
35
detox/e2e/support/ui/component/channel_sidebar.js
Normal file
35
detox/e2e/support/ui/component/channel_sidebar.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
class ChannelSidebar {
|
||||
testID = {
|
||||
mainSidebar: 'main.sidebar',
|
||||
channelItemDisplayName: 'channel_item.display_name',
|
||||
channelsList: 'channels.list',
|
||||
addChannel: 'action_button_sidebar.channels',
|
||||
addDirectChannel: 'action_button_sidebar.direct',
|
||||
}
|
||||
|
||||
mainSidebar = element(by.id(this.testID.mainSidebar));
|
||||
channelItemDisplayName = element(by.id(this.testID.channelItemDisplayName));
|
||||
channelsList = element(by.id(this.testID.channelsList));
|
||||
addChannel = element(by.id(this.testID.addChannel));
|
||||
addDirectChannel = element(by.id(this.testID.addDirectChannel));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(element(by.id(this.testID.mainSidebar))).toBeVisible();
|
||||
}
|
||||
|
||||
getChannelByDisplayName = (displayName) => {
|
||||
return element(by.text(displayName).withAncestor(by.id(this.testID.channelsList)));
|
||||
}
|
||||
|
||||
hasChannelAtIndex = async (index, channelDisplayName) => {
|
||||
await expect(
|
||||
element(by.id(this.testID.channelItemDisplayName).withAncestor(by.id(this.testID.channelsList))).atIndex(index),
|
||||
).toHaveText(channelDisplayName);
|
||||
}
|
||||
}
|
||||
|
||||
const channelSidebar = new ChannelSidebar();
|
||||
export default channelSidebar;
|
||||
12
detox/e2e/support/ui/component/index.js
Normal file
12
detox/e2e/support/ui/component/index.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import Autocomplete from './autocomplete';
|
||||
import ChannelSidebar from './channel_sidebar';
|
||||
import PostOptions from './post_options';
|
||||
|
||||
export {
|
||||
Autocomplete,
|
||||
ChannelSidebar,
|
||||
PostOptions,
|
||||
};
|
||||
18
detox/e2e/support/ui/component/post_options.js
Normal file
18
detox/e2e/support/ui/component/post_options.js
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
class PostOptions {
|
||||
testID = {
|
||||
postOptions: 'post.options',
|
||||
openReactionPicker: 'open.reaction_picker',
|
||||
}
|
||||
|
||||
openReactionPicker = element(by.id(this.testID.openReactionPicker));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(element(by.id(this.testID.postOptions))).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
const postOptions = new PostOptions();
|
||||
export default postOptions;
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {serverUrl} from '../test_config';
|
||||
|
||||
// ****************************************************************
|
||||
// Select Server Screen
|
||||
// ****************************************************************
|
||||
|
||||
/**
|
||||
* fulfillSelectServerScreen enters server URL on Select Server screen and then tap connect button.
|
||||
* @param {String} url - server URL
|
||||
*/
|
||||
export async function fulfillSelectServerScreen(url) {
|
||||
await expect(element(by.id('select_server_screen'))).toBeVisible();
|
||||
|
||||
await element(by.id('server_url_input')).replaceText(url);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text('Enter Server URL')).tap();
|
||||
|
||||
await element(by.id('connect_button')).tap();
|
||||
}
|
||||
|
||||
// ****************************************************************
|
||||
// Login Screen
|
||||
// ****************************************************************
|
||||
|
||||
/**
|
||||
* fulfillLoginScreen enters credential on Login screen and then tap "Sign in" button to log in.
|
||||
* @param {Object} user - user to login with username and password
|
||||
*/
|
||||
export async function fulfillLoginScreen(user = {}) {
|
||||
await expect(element(by.id('login_screen'))).toBeVisible();
|
||||
|
||||
await element(by.id('username_input')).replaceText(user.username);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.id('login_screen')).tap({x: 10, y: 10});
|
||||
|
||||
await element(by.id('password_input')).replaceText(user.password);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.id('login_screen')).tap({x: 10, y: 10});
|
||||
|
||||
await element(by.id('signin_button')).tap();
|
||||
}
|
||||
|
||||
// ****************************************************************
|
||||
// Channel Screen
|
||||
// ****************************************************************
|
||||
|
||||
export async function toChannelScreen(user) {
|
||||
await fulfillSelectServerScreen(serverUrl);
|
||||
await fulfillLoginScreen(user);
|
||||
}
|
||||
|
||||
export async function logoutUser() {
|
||||
await element(by.id('sidebar.settings.button')).tap();
|
||||
await element(by.text('Logout')).tap();
|
||||
await waitFor(element(by.id('select_server_screen'))).toBeVisible();
|
||||
}
|
||||
36
detox/e2e/support/ui/screen/add_reaction.js
Normal file
36
detox/e2e/support/ui/screen/add_reaction.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {PostOptions} from '@support/ui/component';
|
||||
|
||||
class AddReactionScreen {
|
||||
testID = {
|
||||
addReactionScreen: 'add_reaction.screen',
|
||||
closeAddReactionButton: 'close.add_reaction.button',
|
||||
}
|
||||
|
||||
addReactionScreen = element(by.id(this.testID.addReactionScreen));
|
||||
closeAddReactionButton = element(by.id(this.testID.closeAddReactionButton));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.addReactionScreen).toBeVisible();
|
||||
|
||||
return this.addReactionScreen;
|
||||
}
|
||||
|
||||
open = async (message) => {
|
||||
await element(by.text(message)).longPress();
|
||||
await PostOptions.toBeVisible();
|
||||
await PostOptions.openReactionPicker.tap();
|
||||
|
||||
return this.toBeVisible();
|
||||
}
|
||||
|
||||
close = async () => {
|
||||
await this.closeAddReactionButton.tap();
|
||||
await expect(this.addReactionScreen).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
const addReactionScreen = new AddReactionScreen();
|
||||
export default addReactionScreen;
|
||||
52
detox/e2e/support/ui/screen/channel.js
Normal file
52
detox/e2e/support/ui/screen/channel.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {LoginScreen, SelectServerScreen} from '@support/ui/screen';
|
||||
|
||||
class ChannelScreen {
|
||||
testID = {
|
||||
channelScreen: 'channel.screen',
|
||||
channelDrawerButton: 'channel_drawer.button',
|
||||
channelIntro: 'channel_intro.beginning.text',
|
||||
channelNavBarTitle: 'channel.nav_bar.title',
|
||||
channelSearchButton: 'channel.search.button',
|
||||
channelTitleButton: 'channel.title.button',
|
||||
disabledSendButton: 'disabled_send.button',
|
||||
postInput: 'post.input',
|
||||
sendButton: 'send.button',
|
||||
sidebarSettingsButton: 'sidebar.settings.button',
|
||||
}
|
||||
|
||||
channelScreen = element(by.id(this.testID.channelScreen));
|
||||
channelDrawerButton = element(by.id(this.testID.channelDrawerButton));
|
||||
channelIntro = element(by.id(this.testID.channelIntro));
|
||||
channelNavBarTitle = element(by.id(this.testID.channelNavBarTitle));
|
||||
channelSearchButton = element(by.id(this.testID.channelSearchButton));
|
||||
channelTitleButton = element(by.id(this.testID.channelTitleButton));
|
||||
disabledSendButton = element(by.id(this.testID.disabledSendButton));
|
||||
postInput = element(by.id(this.testID.postInput));
|
||||
sendButton = element(by.id(this.testID.sendButton));
|
||||
sidebarSettingsButton = element(by.id(this.testID.sidebarSettingsButton));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.channelScreen).toBeVisible();
|
||||
|
||||
return this.channelScreen;
|
||||
}
|
||||
|
||||
open = async (user) => {
|
||||
await SelectServerScreen.connectToServer();
|
||||
await LoginScreen.login(user);
|
||||
|
||||
return this.toBeVisible();
|
||||
}
|
||||
|
||||
logout = async () => {
|
||||
await this.sidebarSettingsButton.tap();
|
||||
await element(by.text('Logout')).tap();
|
||||
await SelectServerScreen.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
const channelScreen = new ChannelScreen();
|
||||
export default channelScreen;
|
||||
38
detox/e2e/support/ui/screen/channel_info.js
Normal file
38
detox/e2e/support/ui/screen/channel_info.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ChannelScreen} from '@support/ui/screen';
|
||||
|
||||
class ChannelInfoScreen {
|
||||
testID = {
|
||||
channelInfoScreen: 'channel_info.screen',
|
||||
channelInfoClose: 'screen.channel_info.close',
|
||||
channelIconGMMemberCount: 'channel_icon.gm_member_count',
|
||||
}
|
||||
|
||||
channelInfoScreen = element(by.id(this.testID.channelInfoScreen));
|
||||
channelInfoClose = element(by.id(this.testID.channelInfoClose));
|
||||
channelIconGMMemberCount = element(by.id(this.testID.channelIconGMMemberCount));
|
||||
|
||||
toBeVisible = async () => {
|
||||
const screen = await this.channelInfoScreen;
|
||||
await expect(screen).toBeVisible();
|
||||
|
||||
return screen;
|
||||
}
|
||||
|
||||
open = async () => {
|
||||
// # Open channel info
|
||||
await ChannelScreen.channelTitleButton.tap();
|
||||
|
||||
return this.toBeVisible();
|
||||
}
|
||||
|
||||
close = async () => {
|
||||
await this.channelInfoClose.tap();
|
||||
await expect(this.channelInfoScreen).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
const channelInfoScreen = new ChannelInfoScreen();
|
||||
export default channelInfoScreen;
|
||||
44
detox/e2e/support/ui/screen/create_channel.js
Normal file
44
detox/e2e/support/ui/screen/create_channel.js
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ChannelScreen} from '@support/ui/screen';
|
||||
|
||||
class CreateChannelScreen {
|
||||
testID = {
|
||||
createChannelScreen: 'create_channel.screen',
|
||||
nameInput: 'edit_channel.name.input',
|
||||
purposeInput: 'edit_channel.purpose.input',
|
||||
headerInput: 'edit_channel.header.input',
|
||||
createButton: 'edit_channel.create.button',
|
||||
backButton: 'screen.back.button',
|
||||
}
|
||||
|
||||
createChannelScreen = element(by.id(this.testID.createChannelScreen));
|
||||
nameInput = element(by.id(this.testID.nameInput));
|
||||
purposeInput = element(by.id(this.testID.purposeInput));
|
||||
headerInput = element(by.id(this.testID.headerInput));
|
||||
createButton = element(by.id(this.testID.createButton));
|
||||
backButton = element(by.id(this.testID.backButton));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.createChannelScreen).toBeVisible();
|
||||
|
||||
return this.createChannelScreen;
|
||||
}
|
||||
|
||||
open = async () => {
|
||||
// # Open channel info then tap 'Edit Channel'
|
||||
await ChannelScreen.channelTitleButton.tap();
|
||||
await element(by.text('Edit Channel')).tap();
|
||||
|
||||
return this.toBeVisible();
|
||||
}
|
||||
|
||||
back = async () => {
|
||||
await this.backButton.tap();
|
||||
await expect(this.createChannelScreen).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
const createChannelScreen = new CreateChannelScreen();
|
||||
export default createChannelScreen;
|
||||
35
detox/e2e/support/ui/screen/direct_channels.js
Normal file
35
detox/e2e/support/ui/screen/direct_channels.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ChannelScreen} from '@support/ui/component';
|
||||
import {ChannelSidebar} from '@support/ui/screen';
|
||||
|
||||
class DirectChannelsScreen {
|
||||
testID = {
|
||||
directChannelsScreen: 'direct_channels.screen',
|
||||
startButton: 'start-conversation',
|
||||
}
|
||||
|
||||
directChannelsScreen = element(by.id(this.testID.directChannelsScreen));
|
||||
startButton = element(by.id(this.testID.startButton));
|
||||
|
||||
getUserAtIndex = (index) => {
|
||||
return element(by.id('more_dms.user').withAncestor(by.id('more_dms.list'))).atIndex(index);
|
||||
}
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.directChannelsScreen).toBeVisible();
|
||||
|
||||
return this.directChannelsScreen;
|
||||
}
|
||||
|
||||
open = async () => {
|
||||
await ChannelScreen.channelDrawerButton.tap();
|
||||
await ChannelSidebar.addDirectChannel.tap();
|
||||
|
||||
return this.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
const directChannelsScreen = new DirectChannelsScreen();
|
||||
export default directChannelsScreen;
|
||||
38
detox/e2e/support/ui/screen/edit_channel.js
Normal file
38
detox/e2e/support/ui/screen/edit_channel.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ChannelScreen} from '@support/ui/screen';
|
||||
|
||||
class EditChannelScreen {
|
||||
testID = {
|
||||
editChannelScreen: 'edit_channel.screen',
|
||||
editChannelHeaderInput: 'edit_channel.header.input',
|
||||
backButton: 'screen.back.button',
|
||||
}
|
||||
|
||||
editChannelScreen = element(by.id(this.testID.editChannelScreen));
|
||||
editChannelHeaderInput = element(by.id(this.testID.editChannelHeaderInput));
|
||||
backButton = element(by.id(this.testID.backButton));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.editChannelScreen).toBeVisible();
|
||||
|
||||
return this.editChannelScreen;
|
||||
}
|
||||
|
||||
open = async () => {
|
||||
// # Open channel menu then tap 'Edit Channel'
|
||||
await ChannelScreen.channelTitleButton.tap();
|
||||
await element(by.text('Edit Channel')).tap();
|
||||
|
||||
return this.toBeVisible();
|
||||
}
|
||||
|
||||
back = async () => {
|
||||
await this.backButton.tap();
|
||||
await expect(this.editChannelScreen).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
const editChannelScreen = new EditChannelScreen();
|
||||
export default editChannelScreen;
|
||||
42
detox/e2e/support/ui/screen/edit_post.js
Normal file
42
detox/e2e/support/ui/screen/edit_post.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {isAndroid} from '@support/utils';
|
||||
|
||||
class EditPostScreen {
|
||||
testID = {
|
||||
editPostScreen: 'edit_post.screen',
|
||||
editPostInput: 'edit_post.input',
|
||||
editPostClose: 'edit_post.close',
|
||||
}
|
||||
|
||||
editPostInput = element(by.id(this.testID.editPostInput));
|
||||
editPostClose = element(by.id(this.testID.editPostClose));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.editPostScreen).toBeVisible();
|
||||
|
||||
return this.editPostScreen;
|
||||
}
|
||||
|
||||
open = async (message) => {
|
||||
// # Open edit post screen
|
||||
await element(by.text(message)).longPress();
|
||||
|
||||
// # Swipe up panel on Android
|
||||
if (isAndroid()) {
|
||||
const slide = element(by.id('slide_up_panel'));
|
||||
await slide.swipe('up');
|
||||
}
|
||||
|
||||
await element(by.text('Edit')).tap();
|
||||
}
|
||||
|
||||
back = async () => {
|
||||
await this.backButton.tap();
|
||||
await expect(this.editPostScreen).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
const editPostScreen = new EditPostScreen();
|
||||
export default editPostScreen;
|
||||
30
detox/e2e/support/ui/screen/index.js
Normal file
30
detox/e2e/support/ui/screen/index.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import AddReactionScreen from './add_reaction';
|
||||
import ChannelInfoScreen from './channel_info';
|
||||
import ChannelScreen from './channel';
|
||||
import CreateChannelScreen from './create_channel';
|
||||
import DirectChannelsScreen from './direct_channels';
|
||||
import EditChannelScreen from './edit_channel';
|
||||
import EditPostScreen from './edit_post';
|
||||
import LoginScreen from './login';
|
||||
import MoreChannelsScreen from './more_channels';
|
||||
import NotificationScreen from './notification';
|
||||
import SearchScreen from './search';
|
||||
import SelectServerScreen from './select_server';
|
||||
|
||||
export {
|
||||
AddReactionScreen,
|
||||
ChannelScreen,
|
||||
ChannelInfoScreen,
|
||||
CreateChannelScreen,
|
||||
DirectChannelsScreen,
|
||||
EditChannelScreen,
|
||||
EditPostScreen,
|
||||
LoginScreen,
|
||||
MoreChannelsScreen,
|
||||
NotificationScreen,
|
||||
SearchScreen,
|
||||
SelectServerScreen,
|
||||
};
|
||||
55
detox/e2e/support/ui/screen/login.js
Normal file
55
detox/e2e/support/ui/screen/login.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {SelectServerScreen} from '@support/ui/screen';
|
||||
|
||||
class LoginScreen {
|
||||
testID = {
|
||||
loginScreen: 'login.screen',
|
||||
errorText: 'error.text',
|
||||
passwordInput: 'password.input',
|
||||
signinButton: 'signin.button',
|
||||
usernameInput: 'username.input',
|
||||
}
|
||||
|
||||
loginScreen = element(by.id(this.testID.loginScreen));
|
||||
errorText = element(by.id(this.testID.errorText));
|
||||
passwordInput = element(by.id(this.testID.passwordInput));
|
||||
signinButton = element(by.id(this.testID.signinButton));
|
||||
usernameInput = element(by.id(this.testID.usernameInput));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.loginScreen).toBeVisible();
|
||||
|
||||
return this.loginScreen;
|
||||
}
|
||||
|
||||
open = async () => {
|
||||
await SelectServerScreen.connectToServer();
|
||||
|
||||
return this.toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* login enters credential on Login screen and then tap "Sign in" button to log in.
|
||||
* @param {Object} user - user to login with username and password
|
||||
*/
|
||||
login = async (user = {}) => {
|
||||
const screen = await this.toBeVisible();
|
||||
|
||||
await this.usernameInput.replaceText(user.username);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await screen.tap({x: 10, y: 10});
|
||||
|
||||
await this.passwordInput.replaceText(user.password);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await screen.tap({x: 10, y: 10});
|
||||
|
||||
await this.signinButton.tap();
|
||||
}
|
||||
}
|
||||
|
||||
const loginScreen = new LoginScreen();
|
||||
export default loginScreen;
|
||||
31
detox/e2e/support/ui/screen/more_channels.js
Normal file
31
detox/e2e/support/ui/screen/more_channels.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ChannelScreen} from '@support/ui/component';
|
||||
import {ChannelSidebar} from '@support/ui/screen';
|
||||
|
||||
class MoreChannelsScreen {
|
||||
testID = {
|
||||
moreChannelsScreen: 'more_channels.screen',
|
||||
publicChannelCreateButton: 'public_channel.create.button',
|
||||
}
|
||||
|
||||
moreChannelsScreen = element(by.id(this.testID.moreChannelsScreen));
|
||||
publicChannelCreateButton = element(by.id(this.testID.publicChannelCreateButton));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.moreChannelsScreen).toBeVisible();
|
||||
|
||||
return this.moreChannelsScreen;
|
||||
}
|
||||
|
||||
open = async () => {
|
||||
await ChannelScreen.channelDrawerButton.tap();
|
||||
await ChannelSidebar.addChannel.tap();
|
||||
|
||||
return this.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
const moreChannelsScreen = new MoreChannelsScreen();
|
||||
export default moreChannelsScreen;
|
||||
25
detox/e2e/support/ui/screen/notification.js
Normal file
25
detox/e2e/support/ui/screen/notification.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
class NotificationScreen {
|
||||
testID = {
|
||||
inAppNotification: 'in_app_notification',
|
||||
inAppNotificationIcon: 'in_app_notification.icon',
|
||||
inAppNotificationTitle: 'in_app_notification.title',
|
||||
inAppNotificationMessage: 'in_app_notification.message',
|
||||
}
|
||||
|
||||
inAppNotification = element(by.id(this.testID.inAppNotification));
|
||||
inAppNotificationIcon = element(by.id(this.testID.inAppNotificationIcon));
|
||||
inAppNotificationTitle = element(by.id(this.testID.inAppNotificationTitle));
|
||||
inAppNotificationMessage = element(by.id(this.testID.inAppNotificationMessage));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.inAppNotification).toBeVisible();
|
||||
|
||||
return this.inAppNotification;
|
||||
}
|
||||
}
|
||||
|
||||
const notificationScreen = new NotificationScreen();
|
||||
export default notificationScreen;
|
||||
44
detox/e2e/support/ui/screen/search.js
Normal file
44
detox/e2e/support/ui/screen/search.js
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ChannelScreen} from '@support/ui/screen';
|
||||
import {isAndroid} from '@support/utils';
|
||||
|
||||
class SearchScreen {
|
||||
testID = {
|
||||
searchScreen: 'search.screen',
|
||||
searchInput: 'searchInput',
|
||||
searchFromSection: 'search_from.section',
|
||||
searchInSection: 'search_in.section',
|
||||
searchOnSection: 'search_on.section',
|
||||
}
|
||||
|
||||
searchScreen = element(by.id(this.testID.searchScreen));
|
||||
searchInput = element(by.id(this.testID.searchInput));
|
||||
searchFromSection = element(by.id(this.testID.searchFromSection));
|
||||
searchInSection = element(by.id(this.testID.searchInSection));
|
||||
searchOnSection = element(by.id(this.testID.searchOnSection));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.searchScreen).toBeVisible();
|
||||
|
||||
return this.searchScreen;
|
||||
}
|
||||
|
||||
open = async () => {
|
||||
await ChannelScreen.channelSearchButton.tap();
|
||||
|
||||
return this.toBeVisible();
|
||||
}
|
||||
|
||||
cancel = async () => {
|
||||
if (isAndroid()) {
|
||||
await device.pressBack();
|
||||
} else {
|
||||
await element(by.text('Cancel')).atIndex(0).tap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const searchScreen = new SearchScreen();
|
||||
export default searchScreen;
|
||||
42
detox/e2e/support/ui/screen/select_server.js
Normal file
42
detox/e2e/support/ui/screen/select_server.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {serverUrl} from '@support/test_config';
|
||||
|
||||
class SelectServerScreen {
|
||||
testID = {
|
||||
selectServerScreen: 'select_server.screen',
|
||||
connectButton: 'connect.button',
|
||||
errorText: 'error.text',
|
||||
headerText: 'header.text',
|
||||
serverUrlInput: 'server_url.input',
|
||||
}
|
||||
|
||||
selectServerScreen = element(by.id(this.testID.selectServerScreen));
|
||||
serverUrlInput = element(by.id(this.testID.serverUrlInput));
|
||||
connectButton = element(by.id(this.testID.connectButton));
|
||||
errorText = element(by.id(this.testID.errorText));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.selectServerScreen).toBeVisible();
|
||||
|
||||
return this.selectServerScreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* connectToServer enters server URL on Select Server screen and then tap connect button.
|
||||
*/
|
||||
connectToServer = async () => {
|
||||
const screen = await this.toBeVisible();
|
||||
|
||||
await this.serverUrlInput.replaceText(serverUrl);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await screen.tap({x: 5, y: 10});
|
||||
|
||||
await this.connectButton.tap();
|
||||
}
|
||||
}
|
||||
|
||||
const selectServerScreen = new SelectServerScreen();
|
||||
export default selectServerScreen;
|
||||
|
|
@ -7,164 +7,165 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {logoutUser, toChannelScreen} from '@support/ui/screen';
|
||||
import {Autocomplete} from '@support/ui/component';
|
||||
import {ChannelScreen} from '@support/ui/screen';
|
||||
import {Setup} from '@support/server_api';
|
||||
|
||||
describe('Autocomplete', () => {
|
||||
let user;
|
||||
let postInput;
|
||||
const {postInput} = ChannelScreen;
|
||||
const {atMentionSuggestionList} = Autocomplete;
|
||||
let userAtMentionAutocomplete;
|
||||
|
||||
beforeAll(async () => {
|
||||
({user} = await Setup.apiInit());
|
||||
await toChannelScreen(user);
|
||||
userAtMentionAutocomplete = Autocomplete.getAtMentionItem(user.id);
|
||||
await ChannelScreen.open(user);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await device.reloadReactNative();
|
||||
|
||||
// # Select post draft
|
||||
await expect(element(by.id('channel_screen'))).toBeVisible();
|
||||
postInput = await element(by.id('post_input'));
|
||||
await postInput.tap();
|
||||
// # Clear text and verify that Autocomplete disappeared
|
||||
await postInput.clearText();
|
||||
await Autocomplete.toBeVisible(false);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3409_1 should suggest user based on username', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
|
||||
// # Type username
|
||||
await postInput.typeText(user.username);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
await expect(userAtMentionAutocomplete).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_2 should suggest user based on nickname', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
|
||||
// # Type nickname
|
||||
await postInput.typeText(user.nickname);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
await expect(userAtMentionAutocomplete).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_3 should suggest user based on first name', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
|
||||
// # Type first name
|
||||
await postInput.typeText(user.first_name);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
await expect(userAtMentionAutocomplete).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_4 should suggest user based on last name', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
|
||||
// # Type last name
|
||||
await postInput.typeText(user.last_name);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
await expect(userAtMentionAutocomplete).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_5 should suggest user based on lowercase first name', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
|
||||
// # Type lowercase first name
|
||||
await postInput.typeText(user.first_name.toLowerCase());
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
await expect(userAtMentionAutocomplete).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_6 should suggest user based on lowercase last name', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
|
||||
// # Type lowercase last name
|
||||
await postInput.typeText(user.last_name.toLowerCase());
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
await expect(userAtMentionAutocomplete).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_7 should suggest user based on full name with space', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
|
||||
// # Type full name
|
||||
await postInput.typeText(`${user.first_name} ${user.last_name}`);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
await expect(userAtMentionAutocomplete).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_8 should suggest user based on partial full name with space', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
|
||||
// # Type partial full name
|
||||
await postInput.typeText(`${user.first_name} ${user.last_name.substring(0, user.last_name.length - 6)}`);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
await expect(userAtMentionAutocomplete).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_9 should stop suggesting user after full name with trailing space', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
|
||||
// # Type full name
|
||||
await postInput.typeText(`${user.first_name} ${user.last_name}`);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
await expect(userAtMentionAutocomplete).toExist();
|
||||
|
||||
// # Type trailing space
|
||||
await postInput.typeText(' ');
|
||||
|
||||
// * Expect at mention autocomplete not to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).not.toExist();
|
||||
await expect(userAtMentionAutocomplete).not.toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_10 should stop suggesting user when keyword is not associated with any user', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
|
||||
// # Type keyword not associated with any user
|
||||
await postInput.typeText(Date.now().toString());
|
||||
|
||||
// * Expect at mention autocomplete not to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).not.toExist();
|
||||
await expect(userAtMentionAutocomplete).not.toExist();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,36 +7,39 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {logoutUser, toChannelScreen} from '@support/ui/screen';
|
||||
import {Autocomplete} from '@support/ui/component';
|
||||
import {
|
||||
ChannelScreen,
|
||||
ChannelInfoScreen,
|
||||
EditChannelScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {Setup} from '@support/server_api';
|
||||
|
||||
describe('Autocomplete', () => {
|
||||
beforeAll(async () => {
|
||||
const {user} = await Setup.apiInit();
|
||||
await toChannelScreen(user);
|
||||
await ChannelScreen.open(user);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3390 should render autocomplete in channel header edit screen', async () => {
|
||||
// # Open channel info modal
|
||||
await element(by.id('channel.title.button')).tap();
|
||||
|
||||
// # Open edit channel menu
|
||||
await element(by.text('Edit Channel')).tap();
|
||||
// # Open edit channel modal
|
||||
await EditChannelScreen.open();
|
||||
|
||||
// # Activate at_mention autocomplete
|
||||
await element(by.id('edit_channel.header.input')).typeText('@');
|
||||
await EditChannelScreen.editChannelHeaderInput.typeText('@');
|
||||
|
||||
// * Expect autocomplete to render
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(Autocomplete.atMentionSuggestionList).toExist();
|
||||
|
||||
// # Go to previous screen
|
||||
await element(by.id('screen.back.button')).tap();
|
||||
await EditChannelScreen.back();
|
||||
|
||||
// # Close channel info screen
|
||||
await element(by.id('screen.channel_info.close')).tap();
|
||||
await ChannelInfoScreen.close();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,30 +7,31 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {logoutUser, toChannelScreen} from '@support/ui/screen';
|
||||
import {Autocomplete} from '@support/ui/component';
|
||||
import {ChannelScreen, EditPostScreen} from '@support/ui/screen';
|
||||
import {isAndroid, timeouts, wait} from '@support/utils';
|
||||
import {Setup} from '@support/server_api';
|
||||
|
||||
describe('Autocomplete', () => {
|
||||
beforeAll(async () => {
|
||||
const {user} = await Setup.apiInit();
|
||||
await toChannelScreen(user);
|
||||
await ChannelScreen.open(user);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3391 should render autocomplete in post edit screen', async () => {
|
||||
const message = Date.now().toString();
|
||||
const {postInput, sendButton} = ChannelScreen;
|
||||
|
||||
// # Type a message
|
||||
const postInput = await element(by.id('post_input'));
|
||||
await postInput.tap();
|
||||
await postInput.typeText(message);
|
||||
|
||||
// # Tap the send button
|
||||
await element(by.id('send_button')).tap();
|
||||
await sendButton.tap();
|
||||
|
||||
// # Explicitly wait on Android before verifying error message
|
||||
if (isAndroid()) {
|
||||
|
|
@ -38,25 +39,19 @@ describe('Autocomplete', () => {
|
|||
}
|
||||
|
||||
// # Open edit screen
|
||||
await element(by.text(message)).longPress();
|
||||
await EditPostScreen.open(message);
|
||||
|
||||
// # Swipe up panel on Android
|
||||
if (isAndroid()) {
|
||||
const slide = element(by.id('slide_up_panel'));
|
||||
await slide.swipe('up');
|
||||
}
|
||||
|
||||
const edit = element(by.text('Edit'));
|
||||
await edit.tap();
|
||||
const {atMentionSuggestionList} = Autocomplete;
|
||||
const {editPostInput, editPostClose} = EditPostScreen;
|
||||
|
||||
// # Open autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await element(by.id('edit_post.input')).typeText(' @');
|
||||
await expect(atMentionSuggestionList).not.toExist();
|
||||
await editPostInput.typeText(' @');
|
||||
|
||||
// * Expect at_mention autocomplete to render
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
|
||||
// # Close edit post screen
|
||||
await element(by.id('edit_post.close')).tap();
|
||||
await editPostClose.tap();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,60 +7,68 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {logoutUser, toChannelScreen} from '@support/ui/screen';
|
||||
import {Autocomplete} from '@support/ui/component';
|
||||
import {ChannelScreen} from '@support/ui/screen';
|
||||
import {Setup} from '@support/server_api';
|
||||
|
||||
describe('Autocomplete', () => {
|
||||
const {postInput} = ChannelScreen;
|
||||
const {
|
||||
atMentionSuggestionList,
|
||||
channelMentionSuggestionList,
|
||||
emojiSuggestionList,
|
||||
slashSuggestionList,
|
||||
} = Autocomplete;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {user} = await Setup.apiInit();
|
||||
await toChannelScreen(user);
|
||||
await ChannelScreen.open(user);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
// # Select post draft
|
||||
await expect(element(by.id('channel_screen'))).toBeVisible();
|
||||
await element(by.id('post_input')).clearText();
|
||||
await element(by.id('post_input')).tap();
|
||||
// # Clear text on input
|
||||
await postInput.clearText();
|
||||
await postInput.tap();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await element(by.id('post_input')).clearText();
|
||||
await logoutUser();
|
||||
await postInput.clearText();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3392_1 should render emoji_suggestion component', async () => {
|
||||
// # Type ":" to activate emoji suggestions
|
||||
await expect(element(by.id('autocomplete.emoji_suggestion.list'))).not.toExist();
|
||||
await element(by.id('post_input')).typeText(':');
|
||||
await expect(emojiSuggestionList).not.toExist();
|
||||
await postInput.typeText(':');
|
||||
|
||||
// * Expect emoji suggestions to render
|
||||
await expect(element(by.id('autocomplete.emoji_suggestion.list'))).toExist();
|
||||
await expect(emojiSuggestionList).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3392_2 should render at_mention component', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await element(by.id('post_input')).typeText('@');
|
||||
await expect(atMentionSuggestionList).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
|
||||
// * Expect at mention autocomplete to render
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3392_3 should render channel_mention component', async () => {
|
||||
// # Type "~" to activate channel mention autocomplete
|
||||
await expect(element(by.id('autocomplete.channel_mention.list'))).not.toExist();
|
||||
await element(by.id('post_input')).typeText('~');
|
||||
await expect(channelMentionSuggestionList).not.toExist();
|
||||
await postInput.typeText('~');
|
||||
|
||||
// * Expect channel mention to render
|
||||
await expect(element(by.id('autocomplete.channel_mention.list'))).toExist();
|
||||
await expect(channelMentionSuggestionList).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3392_4 should render slash_suggestion component', async () => {
|
||||
// # Type "/" to activate slash command suggestions
|
||||
await expect(element(by.id('autocomplete.slash_suggestion'))).not.toExist();
|
||||
await element(by.id('post_input')).typeText('/');
|
||||
await expect(slashSuggestionList).not.toExist();
|
||||
await postInput.typeText('/');
|
||||
|
||||
// * Expect slash suggestions to render
|
||||
await expect(element(by.id('autocomplete.slash_suggestion'))).toExist();
|
||||
await expect(slashSuggestionList).toExist();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,54 +7,61 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {logoutUser, toChannelScreen} from '@support/ui/screen';
|
||||
import {Autocomplete} from '@support/ui/component';
|
||||
import {ChannelScreen, SearchScreen} from '@support/ui/screen';
|
||||
import {Setup} from '@support/server_api';
|
||||
|
||||
describe('Autocomplete', () => {
|
||||
const {
|
||||
atMentionSuggestionList,
|
||||
channelMentionSuggestionList,
|
||||
dateSuggestion,
|
||||
} = Autocomplete;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {user} = await Setup.apiInit();
|
||||
await toChannelScreen(user);
|
||||
await ChannelScreen.open(user);
|
||||
|
||||
// # Open search screen
|
||||
await SearchScreen.open();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await device.reloadReactNative();
|
||||
|
||||
// # Enter search screen
|
||||
await element(by.id('channel.search.button')).tap();
|
||||
await SearchScreen.searchInput.atIndex(0).clearText();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await device.reloadReactNative();
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3393_1 should render at_mention component', async () => {
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await expect(atMentionSuggestionList).not.toExist();
|
||||
|
||||
// # Tap "from:" modifier
|
||||
await element(by.id('search_from.section')).tap();
|
||||
await SearchScreen.searchFromSection.tap();
|
||||
|
||||
// * Expect at mention to render
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3393_2 should render channel_mention component', async () => {
|
||||
await expect(element(by.id('autocomplete.channel_mention.list'))).not.toExist();
|
||||
await expect(channelMentionSuggestionList).not.toExist();
|
||||
|
||||
// # Tap "in:" modifier
|
||||
await element(by.id('search_in.section')).tap();
|
||||
await SearchScreen.searchInSection.tap();
|
||||
|
||||
// * Expect channel mention to render
|
||||
await expect(element(by.id('autocomplete.channel_mention.list'))).toExist();
|
||||
await expect(channelMentionSuggestionList).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3393_3 should render date_suggestion component', async () => {
|
||||
await expect(element(by.id('autocomplete.date_suggestion'))).not.toExist();
|
||||
await expect(dateSuggestion).not.toExist();
|
||||
|
||||
// # Tap "on:" modifier
|
||||
await element(by.id('search_on.section')).tap();
|
||||
await SearchScreen.searchOnSection.tap();
|
||||
|
||||
// * Expect date suggestion to render
|
||||
await expect(element(by.id('autocomplete.date_suggestion'))).toExist();
|
||||
await expect(dateSuggestion).toExist();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,47 +7,54 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {logoutUser, toChannelScreen} from '@support/ui/screen';
|
||||
import {ChannelSidebar} from '@support/ui/component';
|
||||
import {
|
||||
ChannelScreen,
|
||||
ChannelInfoScreen,
|
||||
DirectChannelsScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {timeouts, wait} from '@support/utils';
|
||||
import {Setup} from '@support/server_api';
|
||||
|
||||
describe('Channel Info Header', () => {
|
||||
beforeAll(async () => {
|
||||
const {user} = await Setup.apiInit();
|
||||
await toChannelScreen(user);
|
||||
await ChannelScreen.open(user);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3406 should render correct GM member count in channel info header', async () => {
|
||||
// # Open drawer
|
||||
await element(by.id('channel_drawer.button')).tap();
|
||||
await ChannelScreen.channelDrawerButton.tap();
|
||||
await expect(element(by.text('DIRECT MESSAGES'))).toBeVisible();
|
||||
|
||||
// # Open Direct Channels screen
|
||||
await element(by.id('action_button_sidebar.direct')).tap();
|
||||
await expect(element(by.id('direct_channels_screen'))).toBeVisible();
|
||||
await ChannelSidebar.addDirectChannel.tap();
|
||||
await DirectChannelsScreen.toBeVisible();
|
||||
|
||||
// # Wait for some profiles to load
|
||||
await wait(timeouts.ONE_SEC);
|
||||
|
||||
const {getUserAtIndex, startButton} = DirectChannelsScreen;
|
||||
|
||||
// # Select 3 profiles
|
||||
await element(by.id('more_dms.user').withAncestor(by.id('more_dms.list'))).atIndex(0).tap();
|
||||
await element(by.id('more_dms.user').withAncestor(by.id('more_dms.list'))).atIndex(1).tap();
|
||||
await element(by.id('more_dms.user').withAncestor(by.id('more_dms.list'))).atIndex(2).tap();
|
||||
await getUserAtIndex(0).tap();
|
||||
await getUserAtIndex(1).tap();
|
||||
await getUserAtIndex(2).tap();
|
||||
|
||||
// # Create a GM with selected profiles
|
||||
await element(by.id('start-conversation')).tap();
|
||||
await startButton.tap();
|
||||
|
||||
// # Open channel info modal
|
||||
await element(by.id('channel.title.button')).tap();
|
||||
await ChannelInfoScreen.open();
|
||||
|
||||
// * Verify GM member count is 3
|
||||
await expect(element(by.id('channel_icon.gm_member_count')).atIndex(0)).toHaveText('3');
|
||||
await expect(element(by.id(ChannelInfoScreen.testID.channelIconGMMemberCount)).atIndex(0)).toHaveText('3');
|
||||
|
||||
// # Close channel info screen
|
||||
await element(by.id('screen.channel_info.close')).tap();
|
||||
await ChannelInfoScreen.close();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,67 +9,83 @@
|
|||
|
||||
import jestExpect from 'expect';
|
||||
|
||||
import {logoutUser, toChannelScreen} from '@support/ui/screen';
|
||||
import {ChannelSidebar} from '@support/ui/component';
|
||||
import {
|
||||
ChannelScreen,
|
||||
ChannelInfoScreen,
|
||||
CreateChannelScreen,
|
||||
MoreChannelsScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {Setup} from '@support/server_api';
|
||||
|
||||
describe('Channels', () => {
|
||||
beforeAll(async () => {
|
||||
const {user} = await Setup.apiInit();
|
||||
|
||||
await toChannelScreen(user);
|
||||
await ChannelScreen.open(user);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3201 Create public channel', async () => {
|
||||
// # Go to channel sidebar list
|
||||
await element(by.id('channel_drawer.button')).tap();
|
||||
await ChannelScreen.channelDrawerButton.tap();
|
||||
|
||||
// # Tap on + public channels
|
||||
await element(by.id('action_button_sidebar.channels')).tap();
|
||||
await ChannelSidebar.addChannel.tap();
|
||||
|
||||
// * Expect a list of public channels, initially empty
|
||||
await MoreChannelsScreen.toBeVisible();
|
||||
await expect(element(by.text('No more channels to join'))).toBeVisible();
|
||||
|
||||
// # Tap to create new channel
|
||||
await element(by.id('public_channels.create.button')).tap();
|
||||
await MoreChannelsScreen.publicChannelCreateButton.tap();
|
||||
|
||||
// * Expect a new screen to create a new public channel
|
||||
const createChannelScreen = await CreateChannelScreen.toBeVisible();
|
||||
await expect(element(by.text('New Public Channel'))).toBeVisible();
|
||||
|
||||
const {
|
||||
nameInput,
|
||||
purposeInput,
|
||||
headerInput,
|
||||
} = CreateChannelScreen;
|
||||
|
||||
// # Fill data
|
||||
await element(by.id('edit_channel.name.input')).typeText('a');
|
||||
await nameInput.typeText('a');
|
||||
await attemptToTapButton('edit_channel.create.button');
|
||||
|
||||
// * Expect to be in the same screen since the channel name must be longer
|
||||
await expect(element(by.id('edit_channel.name.input'))).toBeVisible();
|
||||
await expect(nameInput).toBeVisible();
|
||||
|
||||
await element(by.id('edit_channel.name.input')).typeText('bc');
|
||||
await element(by.id('edit_channel.purpose.input')).typeText('This sentence has');
|
||||
await element(by.id('edit_channel.purpose.input')).tapReturnKey();
|
||||
await element(by.id('edit_channel.purpose.input')).typeText('multiple lines');
|
||||
await element(by.id('edit_channel.scroll')).scroll(200, 'down');
|
||||
await expect(element(by.id('edit_channel.header.input'))).toBeVisible();
|
||||
await nameInput.typeText('bc');
|
||||
await purposeInput.typeText('This sentence has');
|
||||
await purposeInput.tapReturnKey();
|
||||
await purposeInput.typeText('multiple lines');
|
||||
await createChannelScreen.scroll(200, 'down');
|
||||
await expect(headerInput).toBeVisible();
|
||||
const expectedChannelHeader = 'I 🌮 love 🌮 tacos 🌮';
|
||||
await element(by.id('edit_channel.header.input')).replaceText(expectedChannelHeader);
|
||||
await headerInput.replaceText(expectedChannelHeader);
|
||||
|
||||
await element(by.id('edit_channel.create.button')).tap();
|
||||
await CreateChannelScreen.createButton.tap();
|
||||
|
||||
const expectedChannelName = 'abc';
|
||||
const expectedPurpose = 'This sentence has\nmultiple lines';
|
||||
|
||||
// * Expect a redirection to the created channel
|
||||
await expect(element(by.id('channel_intro.beginning.text'))).toHaveText('Beginning of ' + expectedChannelName);
|
||||
await element(by.id('channel.title.button')).tap();
|
||||
await expect(ChannelScreen.channelIntro).toHaveText('Beginning of ' + expectedChannelName);
|
||||
|
||||
// # Open channel info
|
||||
await ChannelInfoScreen.open();
|
||||
|
||||
// * Expect to see channel header and purpose in channel info
|
||||
await expect(element(by.text(expectedChannelHeader))).toBeVisible();
|
||||
await expect(element(by.text(expectedPurpose))).toBeVisible();
|
||||
|
||||
// # Close channel info screen
|
||||
await element(by.id('screen.channel_info.close')).tap();
|
||||
await ChannelInfoScreen.close();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {logoutUser, toChannelScreen} from '@support/ui/screen';
|
||||
import {AddReactionScreen, ChannelScreen, NotificationScreen} from '@support/ui/screen';
|
||||
import {isAndroid, timeouts, wait} from '@support/utils';
|
||||
import {Setup} from '@support/server_api';
|
||||
|
||||
|
|
@ -61,30 +61,30 @@ describe('in-app Notification', () => {
|
|||
const {channel, team, user} = await Setup.apiInit();
|
||||
testChannel = channel;
|
||||
testNotification = getNotification(channel, team, user);
|
||||
await toChannelScreen(user);
|
||||
await ChannelScreen.open(user);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3440 should render an in-app notification', async () => {
|
||||
const message = Date.now().toString();
|
||||
|
||||
const {postInput, sendButton} = ChannelScreen;
|
||||
|
||||
// # Type a message
|
||||
const postInput = await element(by.id('post_input'));
|
||||
await postInput.tap();
|
||||
await postInput.typeText(message);
|
||||
|
||||
// # Tap the send button
|
||||
await element(by.id('send_button')).tap();
|
||||
await sendButton.tap();
|
||||
await wait(timeouts.HALF_SEC);
|
||||
|
||||
// # Open Add reaction screen
|
||||
await element(by.text(message)).longPress();
|
||||
await element(by.id('reaction_picker.open')).tap();
|
||||
await element(by.id('screen.add_reaction.close')).tap();
|
||||
await AddReactionScreen.open(message);
|
||||
await AddReactionScreen.closeAddReactionButton.tap();
|
||||
|
||||
// # Skip on Android for now
|
||||
if (isAndroid()) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Skipping on Android until https://github.com/wix/Detox/issues/2141');
|
||||
|
|
@ -96,15 +96,22 @@ describe('in-app Notification', () => {
|
|||
await wait(timeouts.HALF_SEC);
|
||||
|
||||
// * Verify in-app notification is shown
|
||||
await expect(element(by.id('in_app_notification'))).toBeVisible();
|
||||
await expect(element(by.id('in_app_notification.icon'))).toBeVisible();
|
||||
await expect(element(by.id('in_app_notification.title'))).toHaveText(testChannel.name);
|
||||
await expect(element(by.id('in_app_notification.message'))).toHaveText('This is an e2e test message');
|
||||
const {
|
||||
inAppNotification,
|
||||
inAppNotificationIcon,
|
||||
inAppNotificationTitle,
|
||||
inAppNotificationMessage,
|
||||
} = NotificationScreen;
|
||||
|
||||
await NotificationScreen.toBeVisible();
|
||||
await expect(inAppNotificationIcon).toBeVisible();
|
||||
await expect(inAppNotificationTitle).toHaveText(testChannel.name);
|
||||
await expect(inAppNotificationMessage).toHaveText('This is an e2e test message');
|
||||
|
||||
// # Wait for some profiles to load
|
||||
await wait(5 * timeouts.ONE_SEC);
|
||||
|
||||
// * Verify in-app notification is hidden
|
||||
await expect(element(by.id('in_app_notification'))).not.toBeVisible();
|
||||
await expect(inAppNotification).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {logoutUser, toChannelScreen} from '@support/ui/screen';
|
||||
import {ChannelSidebar} from '@support/ui/component';
|
||||
import {ChannelScreen} from '@support/ui/screen';
|
||||
import {isAndroid} from '@support/utils';
|
||||
import {Setup} from '@support/server_api';
|
||||
|
||||
|
|
@ -18,36 +19,39 @@ describe('Select channel', () => {
|
|||
const {user, channel} = await Setup.apiInit();
|
||||
newChannel = channel;
|
||||
|
||||
await toChannelScreen(user);
|
||||
await ChannelScreen.open(user);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3412 should close the sidebar menu when selecting the same channel', async () => {
|
||||
const {channelDrawerButton, channelNavBarTitle} = ChannelScreen;
|
||||
|
||||
// # Open channel drawer (with at least one unread channel)
|
||||
await element(by.id('channel_drawer.button')).tap();
|
||||
await channelDrawerButton.tap();
|
||||
|
||||
// * Main sidebar should be visible
|
||||
await expect(element(by.id('main_sidebar'))).toBeVisible();
|
||||
await ChannelSidebar.toBeVisible();
|
||||
|
||||
// # Tap a channel to view it
|
||||
await element(by.text(newChannel.display_name).withAncestor(by.id('channels_list'))).tap();
|
||||
const channelItem = ChannelSidebar.getChannelByDisplayName(newChannel.display_name);
|
||||
await channelItem.tap();
|
||||
|
||||
// * Selected channel should be visible
|
||||
await expect(element(by.id('channel.nav_bar.title'))).toHaveText(newChannel.display_name);
|
||||
await expect(channelNavBarTitle).toHaveText(newChannel.display_name);
|
||||
|
||||
// # Open channel drawer again and select the same channel
|
||||
await element(by.id('channel_drawer.button')).tap();
|
||||
await element(by.text(newChannel.display_name).withAncestor(by.id('channels_list'))).tap();
|
||||
await channelDrawerButton.tap();
|
||||
await channelItem.tap();
|
||||
|
||||
// * Drawer should not be visible on Android
|
||||
if (isAndroid()) {
|
||||
await expect(element(by.id('main_sidebar'))).not.toBeVisible();
|
||||
await expect(ChannelSidebar.mainSidebar).not.toBeVisible();
|
||||
}
|
||||
|
||||
// * Selected channel should remain the same
|
||||
await expect(element(by.id('channel.nav_bar.title'))).toHaveText(newChannel.display_name);
|
||||
await expect(channelNavBarTitle).toHaveText(newChannel.display_name);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,38 +7,42 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {logoutUser, toChannelScreen} from '@support/ui/screen';
|
||||
import {ChannelScreen} from '@support/ui/screen';
|
||||
import {Setup} from '@support/server_api';
|
||||
|
||||
describe('Messaging', () => {
|
||||
beforeAll(async () => {
|
||||
const {user} = await Setup.apiInit();
|
||||
|
||||
await toChannelScreen(user);
|
||||
await ChannelScreen.open(user);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('should post a message on tap to paper send button', async () => {
|
||||
// * Verify channel screen and post input exist and send button to not exist
|
||||
await expect(element(by.id('channel_screen'))).toBeVisible();
|
||||
await expect(element(by.id('post_input'))).toExist();
|
||||
await expect(element(by.id('send_button'))).not.toExist();
|
||||
// * Verify channel screen is visible
|
||||
await ChannelScreen.toBeVisible();
|
||||
|
||||
const {postInput, sendButton} = ChannelScreen;
|
||||
|
||||
// * Post input should exist while send button should not
|
||||
await expect(postInput).toBeVisible();
|
||||
await expect(sendButton).not.toExist();
|
||||
|
||||
// # Tap on post input
|
||||
await element(by.id('post_input')).tap();
|
||||
await postInput.tap();
|
||||
|
||||
// # Type text on post input
|
||||
const text = Date.now().toString();
|
||||
await element(by.id('post_input')).typeText(text);
|
||||
await postInput.typeText(text);
|
||||
|
||||
// # Tap send button
|
||||
await expect(element(by.id('send_button'))).toBeVisible();
|
||||
await element(by.id('send_button')).tap();
|
||||
await expect(sendButton).toBeVisible();
|
||||
await sendButton.tap();
|
||||
|
||||
// * Verify text to exist
|
||||
await expect(element(by.text(text))).toExist();
|
||||
await expect(element(by.text(text))).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import jestExpect from 'expect';
|
||||
|
||||
import {logoutUser, toChannelScreen} from '@support/ui/screen';
|
||||
import {ChannelScreen} from '@support/ui/screen';
|
||||
import {Channel, Post, Setup} from '@support/server_api';
|
||||
|
||||
describe('Messaging', () => {
|
||||
|
|
@ -19,29 +19,28 @@ describe('Messaging', () => {
|
|||
beforeAll(async () => {
|
||||
({team, user} = await Setup.apiInit());
|
||||
|
||||
await toChannelScreen(user);
|
||||
await ChannelScreen.open(user);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T109 User can\'t send the same message repeatedly', async () => {
|
||||
const message = Date.now().toString();
|
||||
|
||||
const {disabledSendButton, sendButton, postInput} = ChannelScreen;
|
||||
|
||||
// # Type a message
|
||||
const postInput = await element(by.id('post_input'));
|
||||
await postInput.tap();
|
||||
await postInput.typeText(message);
|
||||
|
||||
// # Tap the send button
|
||||
const sendButton = await element(by.id('send_button'));
|
||||
await expect(sendButton).toBeVisible();
|
||||
await sendButton.tap();
|
||||
await expect(sendButton).not.toExist();
|
||||
|
||||
// # Then tap send button repeatedly
|
||||
const disabledSendButton = await element(by.id('disabled_send_button'));
|
||||
await expect(disabledSendButton).toBeVisible();
|
||||
await expect(disabledSendButton).toExist();
|
||||
await disabledSendButton.multiTap(3);
|
||||
|
|
|
|||
|
|
@ -7,17 +7,32 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {Setup, System} from '@support/server_api';
|
||||
import {Setup} from '@support/server_api';
|
||||
import {
|
||||
ChannelScreen,
|
||||
LoginScreen,
|
||||
SelectServerScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {serverUrl} from '@support/test_config';
|
||||
import {fulfillSelectServerScreen, logoutUser} from '@support/ui/screen';
|
||||
import {isAndroid, timeouts, wait} from '@support/utils';
|
||||
|
||||
describe('On boarding', () => {
|
||||
let config;
|
||||
let user;
|
||||
|
||||
const {
|
||||
connectButton,
|
||||
errorText,
|
||||
serverUrlInput,
|
||||
} = SelectServerScreen;
|
||||
|
||||
const {
|
||||
errorText: loginErrorText,
|
||||
usernameInput,
|
||||
passwordInput,
|
||||
signinButton,
|
||||
} = LoginScreen;
|
||||
|
||||
beforeAll(async () => {
|
||||
({config} = await System.apiGetConfig());
|
||||
({user} = await Setup.apiInit());
|
||||
});
|
||||
|
||||
|
|
@ -26,30 +41,31 @@ describe('On boarding', () => {
|
|||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('should show Select server screen on initial load', async () => {
|
||||
// * Verify basic elements on Select Server screen
|
||||
await expect(element(by.id('select_server_screen'))).toBeVisible();
|
||||
await expect(element(by.id('server_url_input'))).toBeVisible();
|
||||
await expect(element(by.id('connect_button'))).toBeVisible();
|
||||
await SelectServerScreen.toBeVisible();
|
||||
|
||||
await expect(serverUrlInput).toBeVisible();
|
||||
await expect(connectButton).toBeVisible();
|
||||
});
|
||||
|
||||
it('MM-T3383 should show error on empty server URL', async () => {
|
||||
await expect(element(by.id('select_server_screen'))).toBeVisible();
|
||||
const screen = await SelectServerScreen.toBeVisible();
|
||||
|
||||
// # Enter an empty server URL
|
||||
await element(by.id('server_url_input')).typeText(' ');
|
||||
await serverUrlInput.typeText(' ');
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text('Enter Server URL')).tap();
|
||||
await screen.tap({x: 5, y: 10});
|
||||
|
||||
// * Verify that the error message does not exist
|
||||
await waitFor(element(by.id('error_text'))).not.toExist().withTimeout(timeouts.HALF_SEC);
|
||||
await waitFor(errorText).not.toExist().withTimeout(timeouts.HALF_SEC);
|
||||
|
||||
// # Tap connect button
|
||||
await element(by.id('connect_button')).tap();
|
||||
await connectButton.tap();
|
||||
|
||||
// # Explicitly wait on Android before verifying error message
|
||||
if (isAndroid()) {
|
||||
|
|
@ -57,146 +73,132 @@ describe('On boarding', () => {
|
|||
}
|
||||
|
||||
// * Verify error message
|
||||
await waitFor(element(by.id('error_text'))).toBeVisible().withTimeout(timeouts.ONE_SEC);
|
||||
await expect(element(by.id('error_text'))).toHaveText('Please enter a valid server URL');
|
||||
await waitFor(errorText).toBeVisible().withTimeout(timeouts.ONE_SEC);
|
||||
await expect(errorText).toHaveText('Please enter a valid server URL');
|
||||
});
|
||||
|
||||
it('should show error on invalid server URL', async () => {
|
||||
await expect(element(by.id('select_server_screen'))).toBeVisible();
|
||||
const screen = await SelectServerScreen.toBeVisible();
|
||||
|
||||
// # Enter invalid server URL
|
||||
const input = element(by.id('server_url_input'));
|
||||
await input.clearText();
|
||||
await input.typeText('http://invalid:8065');
|
||||
await serverUrlInput.clearText();
|
||||
await serverUrlInput.typeText(serverUrl.substring(0, serverUrl.length - 1));
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text('Enter Server URL')).tap();
|
||||
await screen.tap({x: 5, y: 10});
|
||||
|
||||
// * Verify that the error message does not exist
|
||||
await waitFor(element(by.id('error_text'))).not.toExist().withTimeout(timeouts.HALF_SEC);
|
||||
await waitFor(errorText).not.toExist().withTimeout(timeouts.HALF_SEC);
|
||||
|
||||
// # Tap connect button
|
||||
await element(by.id('connect_button')).tap();
|
||||
|
||||
// # Explicitly wait on Android before verifying error message
|
||||
if (isAndroid()) {
|
||||
await wait(timeouts.TWO_SEC);
|
||||
}
|
||||
await connectButton.tap();
|
||||
|
||||
// * Verify error message
|
||||
await waitFor(element(by.id('error_text'))).toBeVisible().withTimeout(timeouts.ONE_SEC);
|
||||
await expect(element(by.id('error_text'))).toHaveText('Cannot connect to the server. Please check your server URL and internet connection.');
|
||||
await waitFor(errorText).toBeVisible().withTimeout(timeouts.ONE_SEC);
|
||||
await expect(errorText).toHaveText('Cannot connect to the server. Please check your server URL and internet connection.');
|
||||
});
|
||||
|
||||
it('should move to Login screen on valid server URL', async () => {
|
||||
await expect(element(by.id('select_server_screen'))).toBeVisible();
|
||||
await SelectServerScreen.toBeVisible();
|
||||
|
||||
// # Enter valid server URL
|
||||
await element(by.id('server_url_input')).replaceText(serverUrl);
|
||||
await serverUrlInput.replaceText(serverUrl);
|
||||
|
||||
// # Tap connect button
|
||||
await element(by.id('connect_button')).tap();
|
||||
await connectButton.tap();
|
||||
|
||||
// * Verify that it goes into Login screen
|
||||
await expect(element(by.id('login_screen'))).toBeVisible();
|
||||
await LoginScreen.toBeVisible();
|
||||
});
|
||||
|
||||
it('should match elements on Login screen', async () => {
|
||||
await fulfillSelectServerScreen(serverUrl);
|
||||
await LoginScreen.open();
|
||||
|
||||
// * Verify basic elements on Login screen
|
||||
await expect(element(by.id('login_screen'))).toBeVisible();
|
||||
await expect(usernameInput).toBeVisible();
|
||||
await expect(passwordInput).toBeVisible();
|
||||
|
||||
await expect(element(by.id('username_input'))).toBeVisible();
|
||||
await expect(element(by.id('password_input'))).toBeVisible();
|
||||
|
||||
await expect(element(by.id('signin_button'))).toBeVisible();
|
||||
await expect(signinButton).toBeVisible();
|
||||
});
|
||||
|
||||
it('should show error on missing any of the username or password', async () => {
|
||||
await fulfillSelectServerScreen(serverUrl);
|
||||
|
||||
await expect(element(by.id('login_screen'))).toBeVisible();
|
||||
const loginScreen = await LoginScreen.open();
|
||||
|
||||
// # On Login screen, enter invalid username
|
||||
await element(by.id('username_input')).typeText('any');
|
||||
await usernameInput.typeText('any');
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
await loginScreen.tap({x: 5, y: 10});
|
||||
|
||||
// # Tap "Sign in" button
|
||||
await element(by.id('signin_button')).tap();
|
||||
await signinButton.tap();
|
||||
|
||||
// * Verify that the error message is shown as expected
|
||||
await expect(element(by.id('error_text'))).toBeVisible();
|
||||
await expect(element(by.id('error_text'))).toHaveText('Please enter your password');
|
||||
await expect(loginErrorText).toBeVisible();
|
||||
await expect(loginErrorText).toHaveText('Please enter your password');
|
||||
|
||||
// # Clear input to username and enter invalid password
|
||||
await element(by.id('username_input')).replaceText('');
|
||||
await element(by.id('password_input')).typeText('any');
|
||||
await usernameInput.replaceText('');
|
||||
await passwordInput.typeText('any');
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
await loginScreen.tap({x: 5, y: 10});
|
||||
|
||||
// # Tap "Sign in" button
|
||||
await element(by.id('signin_button')).tap();
|
||||
await signinButton.tap();
|
||||
|
||||
// * Verify that the error message is shown as expected
|
||||
await expect(element(by.id('error_text'))).toBeVisible();
|
||||
await expect(element(by.id('error_text'))).toHaveText('Please enter your email or username');
|
||||
await expect(loginErrorText).toBeVisible();
|
||||
await expect(loginErrorText).toHaveText('Please enter your email or username');
|
||||
});
|
||||
|
||||
it('should show error on incorrect credential', async () => {
|
||||
await fulfillSelectServerScreen(serverUrl);
|
||||
|
||||
await expect(element(by.id('login_screen'))).toBeVisible();
|
||||
const loginScreen = await LoginScreen.open();
|
||||
|
||||
// # Enter invalid username
|
||||
await element(by.id('username_input')).replaceText('any');
|
||||
await usernameInput.replaceText('any');
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
await loginScreen.tap({x: 5, y: 10});
|
||||
|
||||
// # Enter invalid password
|
||||
await element(by.id('password_input')).replaceText('any');
|
||||
await passwordInput.replaceText('any');
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
await loginScreen.tap({x: 5, y: 10});
|
||||
|
||||
// # Tap "Sign in" button
|
||||
await element(by.id('signin_button')).tap();
|
||||
await signinButton.tap();
|
||||
|
||||
// * Verify that the error message is shown as expected
|
||||
await expect(element(by.id('error_text'))).toBeVisible();
|
||||
await expect(element(by.id('error_text'))).toHaveText('Enter a valid email or username and/or password.');
|
||||
await expect(loginErrorText).toBeVisible();
|
||||
await expect(loginErrorText).toHaveText('Enter a valid email or username and/or password.');
|
||||
});
|
||||
|
||||
it('should move to Channel screen on successful login', async () => {
|
||||
await fulfillSelectServerScreen(serverUrl);
|
||||
|
||||
await expect(element(by.id('login_screen'))).toBeVisible();
|
||||
const loginScreen = await LoginScreen.open();
|
||||
|
||||
// # Enter valid username
|
||||
await element(by.id('username_input')).replaceText(user.username);
|
||||
await usernameInput.replaceText(user.username);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
await loginScreen.tap({x: 5, y: 10});
|
||||
|
||||
// # Enter valid password
|
||||
await element(by.id('password_input')).replaceText(user.password);
|
||||
await passwordInput.replaceText(user.password);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
await loginScreen.tap({x: 5, y: 10});
|
||||
|
||||
// # Tap "Sign in" button
|
||||
await element(by.id('signin_button')).tap();
|
||||
await signinButton.tap();
|
||||
|
||||
// * Verify that it goes into Channel screen
|
||||
await expect(element(by.id('channel_screen'))).toBeVisible();
|
||||
await ChannelScreen.toBeVisible();
|
||||
});
|
||||
|
||||
it('should directly go into Channel screen on reload', async () => {
|
||||
// # On reload and after successful login, verify that it goes straight into Channel screen
|
||||
await expect(element(by.id('channel_screen'))).toBeVisible();
|
||||
await ChannelScreen.toBeVisible();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {logoutUser, toChannelScreen} from '@support/ui/screen';
|
||||
import {ChannelScreen} from '@support/ui/screen';
|
||||
import {ChannelSidebar} from '@support/ui/component';
|
||||
import {Setup, Channel} from '@support/server_api';
|
||||
|
||||
describe('Unread channels', () => {
|
||||
|
|
@ -25,41 +26,46 @@ describe('Unread channels', () => {
|
|||
({channel: zChannel} = await Channel.apiCreateChannel({type: 'O', prefix: 'z-channel', teamId: team.id}));
|
||||
await Channel.apiAddUserToChannel(user.id, zChannel.id);
|
||||
|
||||
await toChannelScreen(user);
|
||||
await ChannelScreen.open(user);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3187 Unread channels sort at top', async () => {
|
||||
const {channelDrawerButton} = ChannelScreen;
|
||||
|
||||
// # Open channel drawer (with at least one unread channel)
|
||||
await element(by.id('channel_drawer.button')).tap();
|
||||
await channelDrawerButton.tap();
|
||||
|
||||
// * Channel should be visible
|
||||
await ChannelSidebar.toBeVisible();
|
||||
|
||||
// * Verify unread channel(s) display at top of channel list (with mentions first, if any), in alphabetical order, with title "Unreads"
|
||||
await expect(element(by.text('UNREADS'))).toBeVisible();
|
||||
await expect(element(by.id('channel_item.display_name').withAncestor(by.id('channels_list'))).atIndex(0)).toHaveText(aChannel.display_name);
|
||||
await expect(element(by.id('channel_item.display_name').withAncestor(by.id('channels_list'))).atIndex(1)).toHaveText(newChannel.display_name);
|
||||
await expect(element(by.id('channel_item.display_name').withAncestor(by.id('channels_list'))).atIndex(2)).toHaveText(zChannel.display_name);
|
||||
await ChannelSidebar.hasChannelAtIndex(0, aChannel.display_name);
|
||||
await ChannelSidebar.hasChannelAtIndex(1, newChannel.display_name);
|
||||
await ChannelSidebar.hasChannelAtIndex(2, zChannel.display_name);
|
||||
|
||||
// # Tap an unread channel to view it
|
||||
await element(by.text(aChannel.display_name)).tap();
|
||||
await element(by.id('channel_drawer.button')).tap();
|
||||
await element(by.text(newChannel.display_name)).tap();
|
||||
await element(by.id('channel_drawer.button')).tap();
|
||||
await element(by.text(zChannel.display_name)).tap();
|
||||
await ChannelSidebar.getChannelByDisplayName(aChannel.display_name).tap();
|
||||
await channelDrawerButton.tap();
|
||||
await ChannelSidebar.getChannelByDisplayName(newChannel.display_name).tap();
|
||||
await channelDrawerButton.tap();
|
||||
await ChannelSidebar.getChannelByDisplayName(zChannel.display_name).tap();
|
||||
|
||||
// # Open channel drawer again
|
||||
await element(by.id('channel_drawer.button')).tap();
|
||||
await channelDrawerButton.tap();
|
||||
|
||||
// * Channel you just read is no longer listed in Unreads
|
||||
await expect(element(by.text('UNREADS'))).not.toBeVisible();
|
||||
await expect(element(by.text('PUBLIC CHANNELS'))).toBeVisible();
|
||||
await expect(element(by.id('channel_item.display_name').withAncestor(by.id('channels_list'))).atIndex(0)).toHaveText(aChannel.display_name);
|
||||
await expect(element(by.id('channel_item.display_name').withAncestor(by.id('channels_list'))).atIndex(1)).toHaveText(newChannel.display_name);
|
||||
await expect(element(by.id('channel_item.display_name').withAncestor(by.id('channels_list'))).atIndex(2)).toHaveText('Off-Topic');
|
||||
await expect(element(by.id('channel_item.display_name').withAncestor(by.id('channels_list'))).atIndex(3)).toHaveText('Town Square');
|
||||
await expect(element(by.id('channel_item.display_name').withAncestor(by.id('channels_list'))).atIndex(4)).toHaveText(zChannel.display_name);
|
||||
await element(by.text(aChannel.display_name)).tap();
|
||||
await ChannelSidebar.hasChannelAtIndex(0, aChannel.display_name);
|
||||
await ChannelSidebar.hasChannelAtIndex(1, newChannel.display_name);
|
||||
await ChannelSidebar.hasChannelAtIndex(2, 'Off-Topic');
|
||||
await ChannelSidebar.hasChannelAtIndex(3, 'Town Square');
|
||||
await ChannelSidebar.hasChannelAtIndex(4, zChannel.display_name);
|
||||
await ChannelSidebar.getChannelByDisplayName(aChannel.display_name).tap();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,47 +7,38 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {Setup, System} from '@support/server_api';
|
||||
import {logoutUser} from '@support/ui/screen';
|
||||
import {serverUrl} from '@support/test_config';
|
||||
import {Setup} from '@support/server_api';
|
||||
import {ChannelScreen, LoginScreen} from '@support/ui/screen';
|
||||
|
||||
describe('Smoke Tests', () => {
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3179 Log in - Email / password', async () => {
|
||||
const {config} = await System.apiGetConfig();
|
||||
const {user} = await Setup.apiInit();
|
||||
|
||||
// * Verify that it starts with the Select Server screen
|
||||
await expect(element(by.id('select_server_screen'))).toBeVisible();
|
||||
// # Navigate to Login screen
|
||||
const loginScreen = await LoginScreen.open();
|
||||
|
||||
// # Type in the server URL
|
||||
await element(by.id('server_url_input')).replaceText(serverUrl);
|
||||
|
||||
// # Tap connect button
|
||||
await element(by.text('Connect')).tap();
|
||||
|
||||
// # Verify that it goes into Login screen
|
||||
await expect(element(by.id('login_screen'))).toBeVisible();
|
||||
const {usernameInput, passwordInput, signinButton} = LoginScreen;
|
||||
|
||||
// # Type in username
|
||||
await element(by.id('username_input')).replaceText(user.username);
|
||||
await usernameInput.replaceText(user.username);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
await loginScreen.tap({x: 5, y: 10});
|
||||
|
||||
// # Type in password
|
||||
await element(by.id('password_input')).replaceText(user.password);
|
||||
await passwordInput.replaceText(user.password);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
await loginScreen.tap({x: 5, y: 10});
|
||||
|
||||
// # Tap "Sign in" button
|
||||
await element(by.text('Sign in')).tap();
|
||||
await signinButton.tap();
|
||||
|
||||
// * Verify that the user has successfully logged in by checking it redirects into the Channel screen
|
||||
await expect(element(by.id('channel_screen'))).toBeVisible();
|
||||
await ChannelScreen.toBeVisible();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,20 +8,18 @@
|
|||
// *******************************************************************
|
||||
|
||||
import {Ldap, Setup, System, Team, User} from '@support/server_api';
|
||||
import {logoutUser} from '@support/ui/screen';
|
||||
import {serverUrl} from '@support/test_config';
|
||||
import {ChannelScreen, LoginScreen} from '@support/ui/screen';
|
||||
import ldapUsers from '@support/fixtures/ldap_users.json';
|
||||
|
||||
describe('Smoke Tests', () => {
|
||||
const testOne = ldapUsers['test-1'];
|
||||
let config;
|
||||
|
||||
beforeAll(async () => {
|
||||
// * Verify that the server has license with LDAP feature
|
||||
await System.apiRequireLicenseForFeature('LDAP');
|
||||
|
||||
// # Enable LDAP
|
||||
({config} = await System.apiUpdateConfig({LdapSettings: {Enable: true}}));
|
||||
await System.apiUpdateConfig({LdapSettings: {Enable: true}});
|
||||
|
||||
// * Check that LDAP server can connect and is synchronized with Mattermost server
|
||||
await Ldap.apiRequireLDAPServer();
|
||||
|
|
@ -30,39 +28,32 @@ describe('Smoke Tests', () => {
|
|||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await logoutUser();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3180 Log in - LDAP', async () => {
|
||||
// * Verify that it starts with the Select Server screen
|
||||
await expect(element(by.id('select_server_screen'))).toBeVisible();
|
||||
// # Navigate to Login screen
|
||||
const loginScreen = await LoginScreen.open();
|
||||
|
||||
// # Type in the server URL
|
||||
await element(by.id('server_url_input')).replaceText(serverUrl);
|
||||
|
||||
// # Tap connect button
|
||||
await element(by.text('Connect')).tap();
|
||||
|
||||
// # Verify that it goes into Login screen
|
||||
await expect(element(by.id('login_screen'))).toBeVisible();
|
||||
const {usernameInput, passwordInput, signinButton} = LoginScreen;
|
||||
|
||||
// # Type in username
|
||||
await element(by.id('username_input')).replaceText(testOne.username);
|
||||
await usernameInput.replaceText(testOne.username);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
await loginScreen.tap({x: 5, y: 10});
|
||||
|
||||
// # Type in password
|
||||
await element(by.id('password_input')).replaceText(testOne.password);
|
||||
await passwordInput.replaceText(testOne.password);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
await loginScreen.tap({x: 5, y: 10});
|
||||
|
||||
// # Tap "Sign in" button
|
||||
await element(by.text('Sign in')).tap();
|
||||
await signinButton.tap();
|
||||
|
||||
// * Verify that the user has successfully logged in by checking it redirects into the Channel screen
|
||||
await expect(element(by.id('channel_screen'))).toBeVisible();
|
||||
await ChannelScreen.toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
"repository": "git@github.com:mattermost/mattermost-mobile.git",
|
||||
"author": "Mattermost, Inc.",
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-class-properties": "7.12.1",
|
||||
"@babel/plugin-transform-modules-commonjs": "7.12.1",
|
||||
"@babel/plugin-transform-runtime": "7.12.1",
|
||||
"@babel/preset-env": "7.12.1",
|
||||
|
|
|
|||
Loading…
Reference in a new issue