Detox/E2E: Messaging e2e tests in Gekidou (#6228)
This commit is contained in:
parent
1760b75dbf
commit
9d3c7c9496
28 changed files with 1007 additions and 31 deletions
|
|
@ -92,7 +92,10 @@ const JumboEmoji = ({baseTextStyle, isEdited, value}: JumboEmojiProps) => {
|
|||
];
|
||||
|
||||
return (
|
||||
<Text style={styles}>
|
||||
<Text
|
||||
style={styles}
|
||||
testID='edited_indicator'
|
||||
>
|
||||
{spacer}
|
||||
<FormattedText
|
||||
id='post_message_view.edited'
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@ const Markdown = ({
|
|||
return (
|
||||
<Text
|
||||
style={styles}
|
||||
testID='edited_indicator'
|
||||
>
|
||||
{spacer}
|
||||
<FormattedText
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ const BottomSheet = ({closeButtonId, componentId, initialSnapIndex = 0, renderCo
|
|||
sheetRef.current?.snapTo(lastSnap);
|
||||
}
|
||||
}}
|
||||
testID={`${testID}.backdrop`}
|
||||
>
|
||||
<Animated.View
|
||||
style={[StyleSheet.absoluteFill, backdropStyle]}
|
||||
|
|
|
|||
|
|
@ -38,14 +38,14 @@ const PostError = ({errorLine, errorExtra}: PostErrorProps) => {
|
|||
>
|
||||
{Boolean(errorLine) && (
|
||||
<ErrorText
|
||||
testID='edit_post.error.text'
|
||||
testID='edit_post.message.input.error'
|
||||
error={errorLine!}
|
||||
textStyle={styles.errorWrap}
|
||||
/>
|
||||
)}
|
||||
{Boolean(errorExtra) && (
|
||||
<ErrorText
|
||||
testID='edit_post.error.text.extra'
|
||||
testID='edit_post.message.input.error.extra'
|
||||
error={errorExtra!}
|
||||
textStyle={!errorLine && styles.errorWrapper}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ const GlobalThreads = ({componentId}: Props) => {
|
|||
edges={edges}
|
||||
mode='margin'
|
||||
style={styles.flex}
|
||||
testID='global_threads'
|
||||
testID='global_threads.screen'
|
||||
>
|
||||
<NavigationHeader
|
||||
showBackButton={!isTablet}
|
||||
|
|
@ -68,7 +68,7 @@ const GlobalThreads = ({componentId}: Props) => {
|
|||
forceQueryAfterAppState={appState}
|
||||
setTab={setTab}
|
||||
tab={tab}
|
||||
testID={'global_threads.list'}
|
||||
testID={'global_threads.threads_list'}
|
||||
/>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
|
|
|
|||
|
|
@ -143,14 +143,12 @@ const Header = ({setTab, tab, teamId, testID, unreadsCount}: Props) => {
|
|||
hasUnreads ? undefined : styles.markAllReadIconDisabled,
|
||||
], [styles, hasUnreads]);
|
||||
|
||||
const testIDPrefix = `${testID}.header`;
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.menuContainer}>
|
||||
<TouchableOpacity
|
||||
onPress={handleViewAllThreads}
|
||||
testID={`${testIDPrefix}.all_threads`}
|
||||
testID={`${testID}.all_threads.button`}
|
||||
>
|
||||
<View style={allThreadsContainerStyle}>
|
||||
<FormattedText
|
||||
|
|
@ -162,7 +160,7 @@ const Header = ({setTab, tab, teamId, testID, unreadsCount}: Props) => {
|
|||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={handleViewUnreadThreads}
|
||||
testID={`${testIDPrefix}.unread_threads`}
|
||||
testID={`${testID}.unread_threads.button`}
|
||||
>
|
||||
<View style={unreadsContainerStyle}>
|
||||
<View>
|
||||
|
|
@ -174,7 +172,7 @@ const Header = ({setTab, tab, teamId, testID, unreadsCount}: Props) => {
|
|||
{hasUnreads ? (
|
||||
<View
|
||||
style={styles.unreadsDot}
|
||||
testID={`${testIDPrefix}.unreads_dot`}
|
||||
testID={`${testID}.unreads_dot`}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
|
|
@ -185,7 +183,7 @@ const Header = ({setTab, tab, teamId, testID, unreadsCount}: Props) => {
|
|||
<TouchableOpacity
|
||||
disabled={!hasUnreads}
|
||||
onPress={handleMarkAllAsRead}
|
||||
testID={`${testIDPrefix}.mark_all_read`}
|
||||
testID={`${testID}.mark_all_as_read.button`}
|
||||
>
|
||||
<CompassIcon
|
||||
name='playlist-check'
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ const ThreadsList = ({
|
|||
setTab={setTab}
|
||||
tab={tab}
|
||||
teamId={teamId}
|
||||
testID={testID}
|
||||
testID={`${testID}.header`}
|
||||
unreadsCount={unreadsCount}
|
||||
/>
|
||||
<FlatList
|
||||
|
|
@ -151,6 +151,7 @@ const ThreadsList = ({
|
|||
onEndReached={handleEndReached}
|
||||
removeClippedSubviews={true}
|
||||
renderItem={renderItem}
|
||||
testID={`${testID}.flat_list`}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ exports[`Threads Component should match snapshot 1`] = `
|
|||
"opacity": 1,
|
||||
}
|
||||
}
|
||||
testID="channel_list.threads.button"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
|
|
|
|||
|
|
@ -81,7 +81,10 @@ const ThreadsButton = ({currentChannelId, unreadsAndMentions}: Props) => {
|
|||
}, [customStyles, isActive, styles, unreads]);
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={handlePress}>
|
||||
<TouchableOpacity
|
||||
onPress={handlePress}
|
||||
testID='channel_list.threads.button'
|
||||
>
|
||||
<View style={customStyles.baseContainer}>
|
||||
<View style={containerStyle}>
|
||||
<CompassIcon
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ const Thread = ({rootPost}: ThreadProps) => {
|
|||
style={styles.flex}
|
||||
mode='margin'
|
||||
edges={edges}
|
||||
testID='thread.screen'
|
||||
>
|
||||
{Boolean(rootPost?.id) &&
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ class Alert {
|
|||
|
||||
return isAndroid() ? element(by.text(title)) : element(by.label(title)).atIndex(0);
|
||||
};
|
||||
messageLengthTitle = isAndroid() ? element(by.text('Message Length')) : element(by.label('Message Length')).atIndex(0);
|
||||
removeServerTitle = (serverDisplayName: string) => {
|
||||
const title = `Are you sure you want to remove ${serverDisplayName}?`;
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ class Alert {
|
|||
cancelButton = isAndroid() ? element(by.text('CANCEL')) : element(by.label('Cancel')).atIndex(1);
|
||||
deleteButton = isAndroid() ? element(by.text('DELETE')) : element(by.label('Delete')).atIndex(0);
|
||||
logoutButton = isAndroid() ? element(by.text('LOG OUT')) : element(by.label('Log out')).atIndex(1);
|
||||
okButton = isAndroid() ? element(by.text('OK')) : element(by.label('OK')).atIndex(1);
|
||||
removeButton = isAndroid() ? element(by.text('REMOVE')) : element(by.label('Remove')).atIndex(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ class Post {
|
|||
testID = {
|
||||
postProfilePicturePrefix: 'post_profile_picture.profile_picture.',
|
||||
blockQuote: 'markdown_block_quote',
|
||||
editedIndicator: 'edited_indicator',
|
||||
emoji: 'markdown_emoji',
|
||||
image: 'markdown_image',
|
||||
message: 'markdown_text',
|
||||
|
|
@ -28,6 +29,7 @@ class Post {
|
|||
getPost = (postItemSourceTestID: string, postId: string, postMessage: string, postProfileOptions: any = {}) => {
|
||||
const postItemMatcher = this.getPostItemMatcher(postItemSourceTestID, postId, postMessage);
|
||||
const postItemBlockQuoteMatcher = by.id(this.testID.blockQuote).withAncestor(postItemMatcher);
|
||||
const postItemEditedIndicator = by.id(this.testID.editedIndicator).withAncestor(postItemMatcher);
|
||||
const postItemEmojiMatcher = by.id(this.testID.emoji).withAncestor(postItemMatcher);
|
||||
const postItemImageMatcher = by.id(this.testID.image).withAncestor(postItemMatcher);
|
||||
const postItemMessageMatcher = by.id(this.testID.message).withAncestor(postItemMatcher);
|
||||
|
|
@ -41,6 +43,7 @@ class Post {
|
|||
return {
|
||||
postItem: element(postItemMatcher),
|
||||
postItemBlockQuote: element(postItemBlockQuoteMatcher),
|
||||
postItemEditedIndicator: element(postItemEditedIndicator),
|
||||
postItemEmoji: element(postItemEmojiMatcher),
|
||||
postItemImage: element(postItemImageMatcher),
|
||||
postItemMessage: element(postItemMessageMatcher),
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class PostList {
|
|||
const {
|
||||
postItem,
|
||||
postItemBlockQuote,
|
||||
postItemEditedIndicator,
|
||||
postItemEmoji,
|
||||
postItemHeaderCommentedOn,
|
||||
postItemHeaderDateTime,
|
||||
|
|
@ -54,6 +55,7 @@ class PostList {
|
|||
return {
|
||||
postListPostItem: postItem,
|
||||
postListPostItemBlockQuote: postItemBlockQuote,
|
||||
postListPostItemEditedIndicator: postItemEditedIndicator,
|
||||
postListPostItemEmoji: postItemEmoji,
|
||||
postListPostItemHeaderCommentedOn: postItemHeaderCommentedOn,
|
||||
postListPostItemHeaderDateTime: postItemHeaderDateTime,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import {
|
|||
PostOptionsScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {timeouts} from '@support/utils';
|
||||
import {timeouts, wait} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
class ChannelScreen {
|
||||
|
|
@ -27,6 +27,7 @@ class ChannelScreen {
|
|||
introOptionAddPeopleItem: 'channel_post_list.intro.option_item.add_people',
|
||||
introOptionSetHeaderItem: 'channel_post_list.intro.option_item.set_header',
|
||||
introOptionChannelDetailsItem: 'channel_post_list.intro.option_item.channel_details',
|
||||
flatPostList: 'channel.post_list.flat_list',
|
||||
};
|
||||
|
||||
channelScreen = element(by.id(this.testID.channelScreen));
|
||||
|
|
@ -34,6 +35,7 @@ class ChannelScreen {
|
|||
introOptionAddPeopleItem = element(by.id(this.testID.introOptionAddPeopleItem));
|
||||
introOptionSetHeaderItem = element(by.id(this.testID.introOptionSetHeaderItem));
|
||||
introOptionChannelDetailsItem = element(by.id(this.testID.introOptionChannelDetailsItem));
|
||||
flatPostList = element(by.id(this.testID.flatPostList));
|
||||
|
||||
// convenience props
|
||||
backButton = NavigationHeader.backButton;
|
||||
|
|
@ -102,6 +104,7 @@ class ChannelScreen {
|
|||
// # Open post options
|
||||
await postListPostItem.longPress();
|
||||
await PostOptionsScreen.toBeVisible();
|
||||
await wait(timeouts.TWO_SEC);
|
||||
};
|
||||
|
||||
openReplyThreadFor = async (postId: string, text: string) => {
|
||||
|
|
|
|||
32
detox/e2e/support/ui/screen/edit_post.ts
Normal file
32
detox/e2e/support/ui/screen/edit_post.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {timeouts} from '@support/utils';
|
||||
|
||||
class EditPostScreen {
|
||||
testID = {
|
||||
editPostScreen: 'edit_post.screen',
|
||||
closeButton: 'close.edit_post.button',
|
||||
saveButton: 'edit_post.save.button',
|
||||
messageInput: 'edit_post.message.input',
|
||||
messageInputError: 'edit_post.message.input.error',
|
||||
messageInputErrorExtra: 'edit_post.message.input.error.extra',
|
||||
};
|
||||
|
||||
editPostScreen = element(by.id(this.testID.editPostScreen));
|
||||
closeButton = element(by.id(this.testID.closeButton));
|
||||
saveButton = element(by.id(this.testID.saveButton));
|
||||
messageInput = element(by.id(this.testID.messageInput));
|
||||
messageInputError = element(by.id(this.testID.messageInputError));
|
||||
messageInputErrorExtra = element(by.id(this.testID.messageInputErrorExtra));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await waitFor(this.editPostScreen).toExist().withTimeout(timeouts.TEN_SEC);
|
||||
await waitFor(this.messageInput).toBeVisible().withTimeout(timeouts.TEN_SEC);
|
||||
|
||||
return this.editPostScreen;
|
||||
};
|
||||
}
|
||||
|
||||
const editPostScreen = new EditPostScreen();
|
||||
export default editPostScreen;
|
||||
31
detox/e2e/support/ui/screen/global_threads.ts
Normal file
31
detox/e2e/support/ui/screen/global_threads.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {NavigationHeader} from '@support/ui/component';
|
||||
import {timeouts} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
class GlobalThreadsScreen {
|
||||
testID = {
|
||||
globalThreadsScreen: 'global_threads.screen',
|
||||
};
|
||||
|
||||
globalThreadsScreen = element(by.id(this.testID.globalThreadsScreen));
|
||||
|
||||
// convenience props
|
||||
backButton = NavigationHeader.backButton;
|
||||
|
||||
toBeVisible = async () => {
|
||||
await waitFor(this.globalThreadsScreen).toExist().withTimeout(timeouts.TEN_SEC);
|
||||
|
||||
return this.globalThreadsScreen;
|
||||
};
|
||||
|
||||
back = async () => {
|
||||
await this.backButton.tap();
|
||||
await expect(this.globalThreadsScreen).not.toBeVisible();
|
||||
};
|
||||
}
|
||||
|
||||
const globalThreadsScreen = new GlobalThreadsScreen();
|
||||
export default globalThreadsScreen;
|
||||
|
|
@ -8,7 +8,9 @@ import ChannelDropdownMenuScreen from './channel_dropdown_menu';
|
|||
import ChannelListScreen from './channel_list';
|
||||
import CreateDirectMessageScreen from './create_direct_message';
|
||||
import CreateOrEditChannelScreen from './create_or_edit_channel';
|
||||
import EditPostScreen from './edit_post';
|
||||
import EditServerScreen from './edit_server';
|
||||
import GlobalThreadsScreen from './global_threads';
|
||||
import HomeScreen from './home';
|
||||
import LoginScreen from './login';
|
||||
import PostOptionsScreen from './post_options';
|
||||
|
|
@ -24,7 +26,9 @@ export {
|
|||
ChannelListScreen,
|
||||
CreateDirectMessageScreen,
|
||||
CreateOrEditChannelScreen,
|
||||
EditPostScreen,
|
||||
EditServerScreen,
|
||||
GlobalThreadsScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
PostOptionsScreen,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ class PostOptionsScreen {
|
|||
testID = {
|
||||
reactionEmojiPrefix: 'post_options.reaction_bar.reaction.',
|
||||
postOptionsScreen: 'post_options.screen',
|
||||
postOptionsBackdrop: 'post_options.backdrop',
|
||||
pickReaction: 'post_options.reaction_bar.pick_reaction',
|
||||
replyPostOption: 'post_options.reply.post.option',
|
||||
copyLinkOption: 'post_options.copy.permalink.option',
|
||||
|
|
@ -24,6 +25,7 @@ class PostOptionsScreen {
|
|||
};
|
||||
|
||||
postOptionsScreen = element(by.id(this.testID.postOptionsScreen));
|
||||
postOptionsBackdrop = element(by.id(this.testID.postOptionsBackdrop));
|
||||
pickReaction = element(by.id(this.testID.pickReaction));
|
||||
replyPostOption = element(by.id(this.testID.replyPostOption));
|
||||
copyLinkOption = element(by.id(this.testID.copyLinkOption));
|
||||
|
|
@ -48,7 +50,7 @@ class PostOptionsScreen {
|
|||
};
|
||||
|
||||
close = async () => {
|
||||
await this.postOptionsScreen.tap({x: 5, y: 10});
|
||||
await this.postOptionsBackdrop.tap({x: 5, y: 10});
|
||||
await expect(this.postOptionsScreen).not.toBeVisible();
|
||||
};
|
||||
|
||||
|
|
@ -66,11 +68,11 @@ class PostOptionsScreen {
|
|||
if (confirm) {
|
||||
await deleteButton.tap();
|
||||
await wait(timeouts.ONE_SEC);
|
||||
await expect(this.postOptionsScreen).not.toBeVisible();
|
||||
await expect(this.postOptionsScreen).not.toExist();
|
||||
} else {
|
||||
await cancelButton.tap();
|
||||
await wait(timeouts.ONE_SEC);
|
||||
await expect(this.postOptionsScreen).toBeVisible();
|
||||
await expect(this.postOptionsScreen).toExist();
|
||||
await this.close();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@ import {expect} from 'detox';
|
|||
class ServerListScreen {
|
||||
testID = {
|
||||
serverListScreen: 'server_list.screen',
|
||||
serverListBackdrop: 'server_list.backdrop',
|
||||
serverListTitle: 'server_list.title',
|
||||
addServerButton: 'server_list.add_a_server.button',
|
||||
};
|
||||
|
||||
serverListScreen = element(by.id(this.testID.serverListScreen));
|
||||
serverListBackdrop = element(by.id(this.testID.serverListBackdrop));
|
||||
serverListTitle = element(by.id(this.testID.serverListTitle));
|
||||
addServerButton = element(by.id(this.testID.addServerButton));
|
||||
|
||||
|
|
@ -65,7 +67,7 @@ class ServerListScreen {
|
|||
};
|
||||
|
||||
close = async () => {
|
||||
await this.serverListScreen.tap({x: 5, y: 10});
|
||||
await this.serverListBackdrop.tap({x: 5, y: 10});
|
||||
await expect(this.serverListScreen).not.toBeVisible();
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,58 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {NavigationHeader} from '@support/ui/component';
|
||||
import {timeouts} from '@support/utils';
|
||||
import {
|
||||
CameraQuickAction,
|
||||
FileQuickAction,
|
||||
ImageQuickAction,
|
||||
InputQuickAction,
|
||||
PostDraft,
|
||||
PostList,
|
||||
SendButton,
|
||||
} from '@support/ui/component';
|
||||
import {PostOptionsScreen} from '@support/ui/screen';
|
||||
import {timeouts, wait} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
class ThreadScreen {
|
||||
testID = {
|
||||
threadScreen: 'channel.screen',
|
||||
threadScreenPrefix: 'thread.',
|
||||
threadScreen: 'thread.screen',
|
||||
backButton: 'screen.back.button',
|
||||
flatPostList: 'thread.post_list.flat_list',
|
||||
};
|
||||
|
||||
threadScreen = element(by.id(this.testID.threadScreen));
|
||||
backButton = element(by.id(this.testID.backButton));
|
||||
flatPostList = element(by.id(this.testID.flatPostList));
|
||||
|
||||
// convenience props
|
||||
backButton = NavigationHeader.backButton;
|
||||
atInputQuickAction = InputQuickAction.getAtInputQuickAction(this.testID.threadScreenPrefix);
|
||||
atInputQuickActionDisabled = InputQuickAction.getAtInputQuickActionDisabled(this.testID.threadScreenPrefix);
|
||||
slashInputQuickAction = InputQuickAction.getSlashInputQuickAction(this.testID.threadScreenPrefix);
|
||||
slashInputQuickActionDisabled = InputQuickAction.getSlashInputQuickActionDisabled(this.testID.threadScreenPrefix);
|
||||
fileQuickAction = FileQuickAction.getFileQuickAction(this.testID.threadScreenPrefix);
|
||||
fileQuickActionDisabled = FileQuickAction.getFileQuickActionDisabled(this.testID.threadScreenPrefix);
|
||||
imageQuickAction = ImageQuickAction.getImageQuickAction(this.testID.threadScreenPrefix);
|
||||
imageQuickActionDisabled = ImageQuickAction.getImageQuickActionDisabled(this.testID.threadScreenPrefix);
|
||||
cameraQuickAction = CameraQuickAction.getCameraQuickAction(this.testID.threadScreenPrefix);
|
||||
cameraQuickActionDisabled = CameraQuickAction.getCameraQuickActionDisabled(this.testID.threadScreenPrefix);
|
||||
postDraft = PostDraft.getPostDraft(this.testID.threadScreenPrefix);
|
||||
postDraftArchived = PostDraft.getPostDraftArchived(this.testID.threadScreenPrefix);
|
||||
postDraftReadOnly = PostDraft.getPostDraftReadOnly(this.testID.threadScreenPrefix);
|
||||
postInput = PostDraft.getPostInput(this.testID.threadScreenPrefix);
|
||||
sendButton = SendButton.getSendButton(this.testID.threadScreenPrefix);
|
||||
sendButtonDisabled = SendButton.getSendButtonDisabled(this.testID.threadScreenPrefix);
|
||||
|
||||
postList = new PostList(this.testID.threadScreenPrefix);
|
||||
|
||||
getPostListPostItem = (postId: string, text: string, postProfileOptions: any = {}) => {
|
||||
return this.postList.getPost(postId, text, postProfileOptions);
|
||||
};
|
||||
|
||||
getPostMessageAtIndex = (index: number) => {
|
||||
return this.postList.getPostMessageAtIndex(index);
|
||||
};
|
||||
|
||||
toBeVisible = async () => {
|
||||
await waitFor(this.threadScreen).toExist().withTimeout(timeouts.TEN_SEC);
|
||||
|
|
@ -25,6 +64,41 @@ class ThreadScreen {
|
|||
await this.backButton.tap();
|
||||
await expect(this.threadScreen).not.toBeVisible();
|
||||
};
|
||||
|
||||
openPostOptionsFor = async (postId: string, text: string) => {
|
||||
const {postListPostItem} = this.getPostListPostItem(postId, text);
|
||||
await expect(postListPostItem).toBeVisible();
|
||||
|
||||
// # Open post options
|
||||
await postListPostItem.longPress();
|
||||
await PostOptionsScreen.toBeVisible();
|
||||
await wait(timeouts.TWO_SEC);
|
||||
};
|
||||
|
||||
postMessage = async (message: string) => {
|
||||
// # Post message
|
||||
await this.postInput.tap();
|
||||
await this.postInput.replaceText(message);
|
||||
await this.tapSendButton();
|
||||
};
|
||||
|
||||
tapSendButton = async () => {
|
||||
// # Tap send button
|
||||
await this.sendButton.tap();
|
||||
await expect(this.sendButton).not.toExist();
|
||||
await expect(this.sendButtonDisabled).toBeVisible();
|
||||
};
|
||||
|
||||
hasPostMessage = async (postId: string, postMessage: string) => {
|
||||
const {postListPostItem} = this.getPostListPostItem(postId, postMessage);
|
||||
await expect(postListPostItem).toBeVisible();
|
||||
};
|
||||
|
||||
hasPostMessageAtIndex = async (index: number, postMessage: string) => {
|
||||
await expect(
|
||||
this.getPostMessageAtIndex(index),
|
||||
).toHaveText(postMessage);
|
||||
};
|
||||
}
|
||||
|
||||
const threadScreen = new ThreadScreen();
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
import {
|
||||
Setup,
|
||||
System,
|
||||
Team,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
|
|
@ -21,6 +22,7 @@ import {
|
|||
ChannelListScreen,
|
||||
CreateDirectMessageScreen,
|
||||
CreateOrEditChannelScreen,
|
||||
GlobalThreadsScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
ServerScreen,
|
||||
|
|
@ -38,6 +40,12 @@ describe('Channels - Channel List', () => {
|
|||
let testUser: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
System.apiUpdateConfig(siteOneUrl, {
|
||||
ServiceSettings: {
|
||||
CollapsedThreads: 'default_on',
|
||||
},
|
||||
});
|
||||
|
||||
const {channel, team, user} = await Setup.apiInit(siteOneUrl);
|
||||
testChannel = channel;
|
||||
testTeam = team;
|
||||
|
|
@ -83,7 +91,7 @@ describe('Channels - Channel List', () => {
|
|||
await expect(ChannelScreen.introDisplayName).toHaveText(testChannel.display_name);
|
||||
|
||||
// # Go back to channel list screen and tap on a second channel
|
||||
await ChannelScreen.backButton.tap();
|
||||
await ChannelScreen.back();
|
||||
await ChannelListScreen.toBeVisible();
|
||||
await ChannelListScreen.getChannelListItemDisplayName(channelsCategory, offTopicChannelName).tap();
|
||||
|
||||
|
|
@ -98,9 +106,8 @@ describe('Channels - Channel List', () => {
|
|||
|
||||
it('MM-T4728_3 - should be able to collapse and expand categories', async () => {
|
||||
// # Go to a channel to make it active and go back to channel list screen
|
||||
await ChannelListScreen.getChannelListItemDisplayName(channelsCategory, testChannel.name).tap();
|
||||
await ChannelScreen.toBeVisible();
|
||||
await ChannelScreen.backButton.tap();
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.back();
|
||||
|
||||
// * Verify on channel list screen
|
||||
await ChannelListScreen.toBeVisible();
|
||||
|
|
@ -160,8 +167,15 @@ describe('Channels - Channel List', () => {
|
|||
await CreateOrEditChannelScreen.close();
|
||||
});
|
||||
|
||||
xit('MM-T4728_7 - should be able to go to threads screen', async () => {
|
||||
// NOT YET IMPLEMENTED
|
||||
it('MM-T4728_7 - should be able to go to global threads screen', async () => {
|
||||
// # Tap on threads button
|
||||
await ChannelListScreen.threadsButton.tap();
|
||||
|
||||
// * Verify on global threads screen
|
||||
await GlobalThreadsScreen.toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await GlobalThreadsScreen.back();
|
||||
});
|
||||
|
||||
xit('MM-T4728_8 - should be able to find channels', async () => {
|
||||
|
|
@ -169,9 +183,10 @@ describe('Channels - Channel List', () => {
|
|||
});
|
||||
|
||||
it('MM-T4728_9 - should be able to switch between teams', async () => {
|
||||
// # As admin, create a second team and add user to the second team
|
||||
// # As admin, create a second team and add user to the second team; as user, terminate app and relaunch app
|
||||
const {team: testTeamTwo} = await Team.apiCreateTeam(siteOneUrl, {prefix: 'a'});
|
||||
await Team.apiAddUserToTeam(siteOneUrl, testUser.id, testTeamTwo.id);
|
||||
await device.reloadReactNative();
|
||||
|
||||
// * Verify on first team and team sidebar item is selected and has correct display name abbreviation
|
||||
await expect(ChannelListScreen.headerTeamDisplayName).toHaveText(testTeam.display_name);
|
||||
|
|
|
|||
125
detox/e2e/test/messaging/message_delete.e2e.ts
Normal file
125
detox/e2e/test/messaging/message_delete.e2e.ts
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// *******************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a screen)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {
|
||||
Post,
|
||||
Setup,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {
|
||||
ChannelScreen,
|
||||
ChannelListScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
PostOptionsScreen,
|
||||
ServerScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Messaging - Message Delete', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
let testChannel: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {channel, user} = await Setup.apiInit(siteOneUrl);
|
||||
testChannel = channel;
|
||||
|
||||
// # Log in to server
|
||||
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
|
||||
await LoginScreen.login(user);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
// * Verify on channel list screen
|
||||
await ChannelListScreen.toBeVisible();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// # Log out
|
||||
await HomeScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T4784_1 - should be able to delete a post message and confirm', async () => {
|
||||
// # Open a channel screen and post a message
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(message);
|
||||
|
||||
// * Verify message is added to post list
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem} = ChannelScreen.getPostListPostItem(post.id, message);
|
||||
await expect(postListPostItem).toExist();
|
||||
|
||||
// # Open post options for the message that was just posted, tap delete option and confirm
|
||||
await ChannelScreen.openPostOptionsFor(post.id, message);
|
||||
await PostOptionsScreen.deletePost({confirm: true});
|
||||
|
||||
// * Verify post message is deleted
|
||||
await expect(postListPostItem).not.toExist();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4784_2 - should be able to delete a post message and cancel', async () => {
|
||||
// # Open a channel screen and post a message
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(message);
|
||||
|
||||
// * Verify message is added to post list
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem} = ChannelScreen.getPostListPostItem(post.id, message);
|
||||
await expect(postListPostItem).toExist();
|
||||
|
||||
// # Open post options for the message that was just posted, tap delete option and cancel
|
||||
await ChannelScreen.openPostOptionsFor(post.id, message);
|
||||
await PostOptionsScreen.deletePost({confirm: false});
|
||||
|
||||
// * Verify post message is not deleted
|
||||
await expect(postListPostItem).toExist();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4784_3 - should be able to delete a post message from reply thread', async () => {
|
||||
// # Open a channel screen, post a message, and tap on the post to open reply thread
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(message);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem: parentPostListPostItem} = ChannelScreen.getPostListPostItem(parentPost.id, message);
|
||||
await parentPostListPostItem.tap();
|
||||
|
||||
// * Verify on thread screen
|
||||
await ThreadScreen.toBeVisible();
|
||||
|
||||
// # Post a reply, open post options for the reply message, tap delete option and confirm
|
||||
const replyMessage = `${message} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
const {post: replyPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem: replyPostListPostItem} = ChannelScreen.getPostListPostItem(replyPost.id, replyMessage);
|
||||
await ThreadScreen.openPostOptionsFor(replyPost.id, replyMessage);
|
||||
await PostOptionsScreen.deletePost({confirm: true});
|
||||
|
||||
// * Verify reply message is deleted
|
||||
await expect(replyPostListPostItem).not.toExist();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
});
|
||||
166
detox/e2e/test/messaging/message_draft.e2e.ts
Normal file
166
detox/e2e/test/messaging/message_draft.e2e.ts
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// *******************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a screen)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {
|
||||
Post,
|
||||
Setup,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {Alert} from '@support/ui/component';
|
||||
import {
|
||||
ChannelScreen,
|
||||
ChannelListScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
ServerScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Messaging - Message Draft', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
const offTopicChannelName = 'off-topic';
|
||||
let testChannel: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {channel, user} = await Setup.apiInit(siteOneUrl);
|
||||
testChannel = channel;
|
||||
|
||||
// # Log in to server
|
||||
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
|
||||
await LoginScreen.login(user);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
// * Verify on channel list screen
|
||||
await ChannelListScreen.toBeVisible();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// # Log out
|
||||
await HomeScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T4781_1 - should be able to create a message draft', async () => {
|
||||
// # Open a channel screen and create a message draft
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postInput.tap();
|
||||
await ChannelScreen.postInput.replaceText(message);
|
||||
|
||||
// * Verify message exists in post draft and is not yet added to post list
|
||||
await expect(ChannelScreen.postInput).toHaveValue(message);
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem} = ChannelScreen.getPostListPostItem(post.id, message);
|
||||
await expect(postListPostItem).not.toExist();
|
||||
|
||||
// # Switch to another channel and go back to original channel
|
||||
await ChannelScreen.back();
|
||||
await ChannelScreen.open(channelsCategory, offTopicChannelName);
|
||||
await ChannelScreen.back();
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
|
||||
// * Verify message draft still exists in post draft
|
||||
await expect(ChannelScreen.postInput).toHaveValue(message);
|
||||
|
||||
// # Clear post draft and go back to channel list screen
|
||||
await ChannelScreen.postInput.clearText();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4781_2 - should save message draft when app is closed then re-opened', async () => {
|
||||
// # Open a channel screen and create a message draft
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postInput.tap();
|
||||
await ChannelScreen.postInput.replaceText(message);
|
||||
|
||||
// * Verify message draft exists in post draft
|
||||
await expect(ChannelScreen.postInput).toHaveValue(message);
|
||||
|
||||
// # Send app to home and re-open
|
||||
await device.sendToHome();
|
||||
await device.launchApp({newInstance: false});
|
||||
|
||||
// * Verify message draft still exists in post draft
|
||||
await expect(ChannelScreen.postInput).toHaveValue(message);
|
||||
|
||||
// # Clear post draft and go back to channel list screen
|
||||
await ChannelScreen.postInput.clearText();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4781_3 - should show character count warning when message exceeds character limit', async () => {
|
||||
// # Open a channel screen and create a message draft that exceeds character limit (> 16383)
|
||||
let message = '1234567890'.repeat(1638) + '1234';
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postInput.tap();
|
||||
await ChannelScreen.postInput.replaceText(message);
|
||||
|
||||
// * Verify warning message is displayed and send button is disabled
|
||||
await expect(Alert.messageLengthTitle).toBeVisible();
|
||||
await expect(element(by.text('Your current message is too long. Current character count: 16384/16383'))).toBeVisible();
|
||||
await Alert.okButton.tap();
|
||||
await expect(ChannelScreen.sendButtonDisabled).toBeVisible();
|
||||
|
||||
// # Replace message draft with length less than the character limit (16383)
|
||||
message = '1234567890'.repeat(1638) + '123';
|
||||
await ChannelScreen.postInput.replaceText(message);
|
||||
|
||||
// * Verify warning message is not displayed and send button is enabled
|
||||
await expect(Alert.messageLengthTitle).not.toBeVisible();
|
||||
await expect(element(by.text('Your current message is too long. Current character count: 16383/16383'))).not.toBeVisible();
|
||||
await expect(ChannelScreen.sendButton).toBeVisible();
|
||||
|
||||
// # Clear post draft and go back to channel list screen
|
||||
await ChannelScreen.postInput.clearText();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4781_4 - should be able to create a message draft from reply thread', async () => {
|
||||
// # Open a channel screen, post a message, and tap on the post to open reply thread
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(message);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem: parentPostListPostItem} = ChannelScreen.getPostListPostItem(parentPost.id, message);
|
||||
await parentPostListPostItem.tap();
|
||||
|
||||
// * Verify on thread screen
|
||||
await ThreadScreen.toBeVisible();
|
||||
|
||||
// # Create a reply message draft
|
||||
const replyMessage = `${message} reply`;
|
||||
await ThreadScreen.postInput.tap();
|
||||
await ThreadScreen.postInput.replaceText(replyMessage);
|
||||
|
||||
// * Verify reply message exists in post draft and is not yet added to post list
|
||||
await expect(ThreadScreen.postInput).toHaveValue(replyMessage);
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem: replyPostListPostItem} = ThreadScreen.getPostListPostItem(post.id, replyMessage);
|
||||
await expect(replyPostListPostItem).not.toExist();
|
||||
|
||||
// # Go back to channel screen and tap on parent post again
|
||||
await ThreadScreen.back();
|
||||
await parentPostListPostItem.tap();
|
||||
|
||||
// * Verify reply message draft still exists in post draft
|
||||
await expect(ThreadScreen.postInput).toHaveValue(replyMessage);
|
||||
|
||||
// # Clear reply post draft and go back to channel list screen
|
||||
await ThreadScreen.postInput.clearText();
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
});
|
||||
153
detox/e2e/test/messaging/message_edit.e2e.ts
Normal file
153
detox/e2e/test/messaging/message_edit.e2e.ts
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// *******************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a screen)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {
|
||||
Post,
|
||||
Setup,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {
|
||||
ChannelScreen,
|
||||
ChannelListScreen,
|
||||
EditPostScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
PostOptionsScreen,
|
||||
ServerScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Messaging - Message Edit', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
let testChannel: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {channel, user} = await Setup.apiInit(siteOneUrl);
|
||||
testChannel = channel;
|
||||
|
||||
// # Log in to server
|
||||
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
|
||||
await LoginScreen.login(user);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
// * Verify on channel list screen
|
||||
await ChannelListScreen.toBeVisible();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// # Log out
|
||||
await HomeScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T4783_1 - should be able to edit a post message and save', async () => {
|
||||
// # Open a channel screen and post a message
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(message);
|
||||
|
||||
// * Verify message is added to post list
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem: originalPostListPostItem} = ChannelScreen.getPostListPostItem(post.id, message);
|
||||
await expect(originalPostListPostItem).toExist();
|
||||
|
||||
// # Open post options for the message that was just posted and tap edit option
|
||||
await ChannelScreen.openPostOptionsFor(post.id, message);
|
||||
await PostOptionsScreen.editPostOption.tap();
|
||||
|
||||
// * Verify on edit post screen
|
||||
await EditPostScreen.toBeVisible();
|
||||
|
||||
// # Edit post message and tap save button
|
||||
const updatedMessage = `${message} edit`;
|
||||
await EditPostScreen.messageInput.replaceText(updatedMessage);
|
||||
await EditPostScreen.saveButton.tap();
|
||||
|
||||
// * Verify post message is updated and displays edited indicator '(edited)'
|
||||
const {postListPostItem: updatedPostListPostItem, postListPostItemEditedIndicator} = ChannelScreen.getPostListPostItem(post.id, updatedMessage);
|
||||
await expect(updatedPostListPostItem).toExist();
|
||||
await expect(postListPostItemEditedIndicator).toHaveText('(edited)');
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4783_2 - should be able to edit a post message and cancel', async () => {
|
||||
// # Open a channel screen and post a message
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(message);
|
||||
|
||||
// * Verify message is added to post list
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem} = ChannelScreen.getPostListPostItem(post.id, message);
|
||||
await expect(postListPostItem).toExist();
|
||||
|
||||
// # Open post options for the message that was just posted and tap edit option
|
||||
await ChannelScreen.openPostOptionsFor(post.id, message);
|
||||
await PostOptionsScreen.editPostOption.tap();
|
||||
|
||||
// * Verify on edit post screen
|
||||
await EditPostScreen.toBeVisible();
|
||||
|
||||
// # Edit post message and tap close button
|
||||
const updatedMessage = `${message} edit`;
|
||||
await EditPostScreen.messageInput.replaceText(updatedMessage);
|
||||
await EditPostScreen.closeButton.tap();
|
||||
|
||||
// * Verify post message is not updated
|
||||
await expect(postListPostItem).toExist();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4783_3 - should be able to edit a post message from reply thread', async () => {
|
||||
// # Open a channel screen, post a message, and tap on the post to open reply thread
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(message);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem: parentPostListPostItem} = ChannelScreen.getPostListPostItem(parentPost.id, message);
|
||||
await parentPostListPostItem.tap();
|
||||
|
||||
// * Verify on thread screen
|
||||
await ThreadScreen.toBeVisible();
|
||||
|
||||
// # Post a reply, open post options for the reply message and tap edit option
|
||||
const replyMessage = `${message} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
const {post: replyPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ThreadScreen.openPostOptionsFor(replyPost.id, replyMessage);
|
||||
await PostOptionsScreen.editPostOption.tap();
|
||||
|
||||
// * Verify on edit post screen
|
||||
await EditPostScreen.toBeVisible();
|
||||
|
||||
// # Edit reply post message and tap save button
|
||||
const updatedReplyMessage = `${replyMessage} edit`;
|
||||
await EditPostScreen.messageInput.replaceText(updatedReplyMessage);
|
||||
await EditPostScreen.saveButton.tap();
|
||||
|
||||
// * Verify reply post message is updated and displays edited indicator '(edited)'
|
||||
const {postListPostItem: updatedReplyPostListPostItem, postListPostItemEditedIndicator} = ThreadScreen.getPostListPostItem(replyPost.id, updatedReplyMessage);
|
||||
await expect(updatedReplyPostListPostItem).toExist();
|
||||
await expect(postListPostItemEditedIndicator).toHaveText('(edited)');
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
});
|
||||
103
detox/e2e/test/messaging/message_post.e2e.ts
Normal file
103
detox/e2e/test/messaging/message_post.e2e.ts
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// *******************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a screen)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {
|
||||
Post,
|
||||
Setup,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {
|
||||
ChannelScreen,
|
||||
ChannelListScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
ServerScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Messaging - Message Post', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
let testChannel: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {channel, user} = await Setup.apiInit(siteOneUrl);
|
||||
testChannel = channel;
|
||||
|
||||
// # Log in to server
|
||||
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
|
||||
await LoginScreen.login(user);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
// * Verify on channel list screen
|
||||
await ChannelListScreen.toBeVisible();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// # Log out
|
||||
await HomeScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T4782_1 - should be able to post a message when send button is tapped', async () => {
|
||||
// # Open a channel screen
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
|
||||
// * Verify send button is disabled
|
||||
await expect(ChannelScreen.sendButtonDisabled).toBeVisible();
|
||||
|
||||
// # Create a message draft
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.postInput.tap();
|
||||
await ChannelScreen.postInput.replaceText(message);
|
||||
|
||||
// * Verify send button is enabled
|
||||
await expect(ChannelScreen.sendButton).toBeVisible();
|
||||
|
||||
// # Tap send button
|
||||
await ChannelScreen.sendButton.tap();
|
||||
|
||||
// * Verify message is added to post list, cleared from post draft, and send button is disabled again
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem} = ChannelScreen.getPostListPostItem(post.id, message);
|
||||
await expect(postListPostItem).toExist();
|
||||
await expect(ChannelScreen.postInput).not.toHaveValue(message);
|
||||
await expect(ChannelScreen.sendButtonDisabled).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4782_2 - should be able to post a long message', async () => {
|
||||
// # Open a channel screen, post a long message, and a short message after
|
||||
const longMessage = 'The quick brown fox jumps over the lazy dog.'.repeat(20);
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(longMessage);
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.postMessage('short message');
|
||||
|
||||
// * Verify long message is posted and displays show more button (chevron down button)
|
||||
const {postListPostItem, postListPostItemShowLessButton, postListPostItemShowMoreButton} = ChannelScreen.getPostListPostItem(post.id, longMessage);
|
||||
await expect(postListPostItem).toExist();
|
||||
await expect(postListPostItemShowMoreButton).toExist();
|
||||
|
||||
// # Tap on show more button on long message post
|
||||
await postListPostItemShowMoreButton.tap();
|
||||
|
||||
// * Verify long message post displays show less button (chevron up button)
|
||||
await expect(postListPostItemShowLessButton).toExist();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
});
|
||||
133
detox/e2e/test/messaging/message_reply.e2e.ts
Normal file
133
detox/e2e/test/messaging/message_reply.e2e.ts
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// *******************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a screen)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {
|
||||
Post,
|
||||
Setup,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {
|
||||
ChannelScreen,
|
||||
ChannelListScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
PostOptionsScreen,
|
||||
ServerScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Messaging - Message Reply', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
let testChannel: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {channel, user} = await Setup.apiInit(siteOneUrl);
|
||||
testChannel = channel;
|
||||
|
||||
// # Log in to server
|
||||
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
|
||||
await LoginScreen.login(user);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
// * Verify on channel list screen
|
||||
await ChannelListScreen.toBeVisible();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// # Log out
|
||||
await HomeScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T4785_1 - should be able to reply to a post via post options reply option', async () => {
|
||||
// # Open a channel screen and post a message
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(message);
|
||||
|
||||
// * Verify message is added to post list
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem} = ChannelScreen.getPostListPostItem(post.id, message);
|
||||
await expect(postListPostItem).toExist();
|
||||
|
||||
// # Open post options for the message that was just posted, tap reply option
|
||||
await ChannelScreen.openPostOptionsFor(post.id, message);
|
||||
await PostOptionsScreen.replyPostOption.tap();
|
||||
|
||||
// * Verify on reply thread screen and parent post is shown
|
||||
await ThreadScreen.toBeVisible();
|
||||
const {postListPostItem: threadParentPostListPostItem} = ThreadScreen.getPostListPostItem(post.id, message);
|
||||
await expect(threadParentPostListPostItem).toExist();
|
||||
|
||||
// # Reply to parent post
|
||||
const replyMessage = `${message} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
|
||||
// * Verify reply message is posted
|
||||
const {post: replyPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem: replyPostListPostItem} = ThreadScreen.getPostListPostItem(replyPost.id, replyMessage);
|
||||
await expect(replyPostListPostItem).toExist();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4785_2 - should be able to open reply thread by tapping the post', async () => {
|
||||
// # Open a channel screen and post a message
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(message);
|
||||
|
||||
// * Verify message is added to post list
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem} = ChannelScreen.getPostListPostItem(post.id, message);
|
||||
await expect(postListPostItem).toExist();
|
||||
|
||||
// # Tap the post
|
||||
await postListPostItem.tap();
|
||||
|
||||
// * Verify on reply thread screen
|
||||
await ThreadScreen.toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4785_3 - should not have reply option available on reply thread post options', async () => {
|
||||
// # Open a channel screen, post a message, and tap on the post
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(message);
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem} = ChannelScreen.getPostListPostItem(post.id, message);
|
||||
await postListPostItem.tap();
|
||||
|
||||
// * Verify on reply thread screen
|
||||
await ThreadScreen.toBeVisible();
|
||||
|
||||
// # Open post options for the parent message
|
||||
await ThreadScreen.openPostOptionsFor(post.id, message);
|
||||
|
||||
// * Verify reply option is not available
|
||||
await expect(PostOptionsScreen.replyPostOption).not.toExist();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await PostOptionsScreen.close();
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
});
|
||||
|
|
@ -229,8 +229,6 @@ describe('Server Login - Server List', () => {
|
|||
|
||||
// # Log back in to first server
|
||||
await ServerListScreen.getServerItemLoginOption(serverOneDisplayName).tap();
|
||||
await expect(ServerScreen.headerTitleAddServer).toBeVisible();
|
||||
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
|
||||
await LoginScreen.login(serverOneUser);
|
||||
});
|
||||
|
||||
|
|
|
|||
119
detox/e2e/test/smoke_test/messaging.e2e.ts
Normal file
119
detox/e2e/test/smoke_test/messaging.e2e.ts
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// *******************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a screen)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {
|
||||
Post,
|
||||
Setup,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {
|
||||
ChannelScreen,
|
||||
ChannelListScreen,
|
||||
EditPostScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
PostOptionsScreen,
|
||||
ServerScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Smoke Test - Messaging', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
let testChannel: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {channel, user} = await Setup.apiInit(siteOneUrl);
|
||||
testChannel = channel;
|
||||
|
||||
// # Log in to server
|
||||
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
|
||||
await LoginScreen.login(user);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
// * Verify on channel list screen
|
||||
await ChannelListScreen.toBeVisible();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// # Log out
|
||||
await HomeScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T4786_1 - should be able to post, edit, and delete a message', async () => {
|
||||
// # Open a channel screen and post a message
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(message);
|
||||
|
||||
// * Verify message is added to post list
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem: originalPostListPostItem} = ChannelScreen.getPostListPostItem(post.id, message);
|
||||
await expect(originalPostListPostItem).toExist();
|
||||
|
||||
// # Open post options for the message that was just posted and tap edit option
|
||||
await ChannelScreen.openPostOptionsFor(post.id, message);
|
||||
await PostOptionsScreen.editPostOption.tap();
|
||||
|
||||
// * Verify on edit post screen
|
||||
await EditPostScreen.toBeVisible();
|
||||
|
||||
// # Edit post message and tap save button
|
||||
const updatedMessage = `${message} edit`;
|
||||
await EditPostScreen.messageInput.replaceText(updatedMessage);
|
||||
await EditPostScreen.saveButton.tap();
|
||||
|
||||
// * Verify post message is updated and displays edited indicator '(edited)'
|
||||
const {postListPostItem: updatedPostListPostItem, postListPostItemEditedIndicator} = ChannelScreen.getPostListPostItem(post.id, updatedMessage);
|
||||
await expect(updatedPostListPostItem).toExist();
|
||||
await expect(postListPostItemEditedIndicator).toHaveText('(edited)');
|
||||
|
||||
// # Open post options for the updated message, tap delete option and confirm
|
||||
await ChannelScreen.openPostOptionsFor(post.id, updatedMessage);
|
||||
await PostOptionsScreen.deletePost({confirm: true});
|
||||
|
||||
// * Verify post message is deleted
|
||||
await expect(updatedPostListPostItem).not.toExist();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4786_2 - should be able to reply to a message', async () => {
|
||||
// # Open a channel screen, post a message, and tap on the post
|
||||
const message = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(message);
|
||||
const {post} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem} = ChannelScreen.getPostListPostItem(post.id, message);
|
||||
await postListPostItem.tap();
|
||||
|
||||
// * Verify on reply thread screen
|
||||
await ThreadScreen.toBeVisible();
|
||||
|
||||
// # Reply to parent post
|
||||
const replyMessage = `${message} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
|
||||
// * Verify reply message is posted
|
||||
const {post: replyPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem: replyPostListPostItem} = ThreadScreen.getPostListPostItem(replyPost.id, replyMessage);
|
||||
await expect(replyPostListPostItem).toExist();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue