Detox/E2E: Global threads e2e tests in Gekidou (#6300)
* Detox/E2E: Global threads e2e tests in Gekidou * Revert update deps
This commit is contained in:
parent
b6e3c2c66d
commit
558d83719c
39 changed files with 1497 additions and 62 deletions
|
|
@ -35,7 +35,7 @@ const CopyPermalinkOption = ({teamName, post, sourceScreen}: Props) => {
|
|||
defaultMessage='Copy Link'
|
||||
onPress={handleCopyLink}
|
||||
iconName='link-variant'
|
||||
testID='post_options.copy.permalink.option'
|
||||
testID='post_options.copy_permalink.option'
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -52,11 +52,13 @@ const FollowThreadOption = ({thread, teamId}: FollowThreadOptionProps) => {
|
|||
dismissBottomSheet(Screens.POST_OPTIONS);
|
||||
};
|
||||
|
||||
const followThreadOptionTestId = thread.isFollowing ? 'post_options.following_thread.option' : 'post_options.follow_thread.option';
|
||||
|
||||
return (
|
||||
<BaseOption
|
||||
i18nId={id}
|
||||
defaultMessage={defaultMessage}
|
||||
testID='post_options.follow.thread.option'
|
||||
testID={followThreadOptionTestId}
|
||||
iconName={icon}
|
||||
onPress={handleToggleFollow}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ const ReplyOption = ({post, location}: Props) => {
|
|||
defaultMessage='Reply'
|
||||
iconName='reply-outline'
|
||||
onPress={handleReply}
|
||||
testID='post_options.reply.post.option'
|
||||
testID='post_options.reply_post.option'
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ const SaveOption = ({isSaved, postId}: CopyTextProps) => {
|
|||
defaultMessage={defaultMessage}
|
||||
iconName='bookmark-outline'
|
||||
onPress={onHandlePress}
|
||||
testID={`post_options.${defaultMessage.toLocaleLowerCase()}.channel.option`}
|
||||
testID={`post_options.${defaultMessage.toLocaleLowerCase()}_post.option`}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import type UserModel from '@typings/database/models/servers/user';
|
|||
type Props = {
|
||||
participants: UserModel[];
|
||||
teamId?: string;
|
||||
testID: string;
|
||||
thread: ThreadModel;
|
||||
};
|
||||
|
||||
|
|
@ -77,7 +76,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
};
|
||||
});
|
||||
|
||||
const Footer = ({participants, teamId, testID, thread}: Props) => {
|
||||
const Footer = ({participants, teamId, thread}: Props) => {
|
||||
const serverUrl = useServerUrl();
|
||||
const theme = useTheme();
|
||||
const styles = getStyleSheet(theme);
|
||||
|
|
@ -102,7 +101,7 @@ const Footer = ({participants, teamId, testID, thread}: Props) => {
|
|||
</View>
|
||||
<FormattedText
|
||||
style={styles.replies}
|
||||
testID={`${testID}.reply_count`}
|
||||
testID='post_footer.reply_count'
|
||||
id='threads.replies'
|
||||
defaultMessage='{count} {count, plural, one {reply} other {replies}}'
|
||||
values={{
|
||||
|
|
@ -117,7 +116,7 @@ const Footer = ({participants, teamId, testID, thread}: Props) => {
|
|||
<TouchableOpacity
|
||||
onPress={toggleFollow}
|
||||
style={styles.followingButtonContainer}
|
||||
testID={`${testID}.following`}
|
||||
testID='post_footer.following_thread.button'
|
||||
>
|
||||
<FormattedText
|
||||
id='threads.following'
|
||||
|
|
@ -133,7 +132,7 @@ const Footer = ({participants, teamId, testID, thread}: Props) => {
|
|||
<TouchableOpacity
|
||||
onPress={toggleFollow}
|
||||
style={styles.notFollowingButtonContainer}
|
||||
testID={`${testID}.follow`}
|
||||
testID='post_footer.follow_thread.button'
|
||||
>
|
||||
<FormattedText
|
||||
id='threads.follow'
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ const HeaderReply = ({commentCount, location, post, theme}: HeaderReplyProps) =>
|
|||
{location !== SEARCH && commentCount > 0 &&
|
||||
<Text
|
||||
style={style.replyText}
|
||||
testID='post_header.reply.count'
|
||||
testID='post_header.reply_count'
|
||||
>
|
||||
{commentCount}
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -294,15 +294,12 @@ const Post = ({
|
|||
if (isCRTEnabled && thread) {
|
||||
if (thread.replyCount > 0 || thread.isFollowing) {
|
||||
footer = (
|
||||
<Footer
|
||||
testID={`${itemTestID}.footer`}
|
||||
thread={thread}
|
||||
/>
|
||||
<Footer thread={thread}/>
|
||||
);
|
||||
}
|
||||
if (thread.unreadMentions || thread.unreadReplies) {
|
||||
unreadDot = (
|
||||
<UnreadDot testID={`${itemTestID}.badge`}/>
|
||||
<UnreadDot/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ import {View} from 'react-native';
|
|||
import {useTheme} from '@context/theme';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
type Props = {
|
||||
testID: string;
|
||||
};
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
return {
|
||||
badgeContainer: {
|
||||
|
|
@ -30,13 +26,13 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
};
|
||||
});
|
||||
|
||||
const UnreadDot = ({testID}: Props) => {
|
||||
const UnreadDot = () => {
|
||||
const theme = useTheme();
|
||||
const styles = getStyleSheet(theme);
|
||||
return (
|
||||
<View
|
||||
style={styles.badgeContainer}
|
||||
testID={testID}
|
||||
testID='post_unread_dot.badge'
|
||||
>
|
||||
<View style={styles.unreadDot}/>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ exports[`ThreadOverview should match snapshot when post is not saved and 0 repli
|
|||
"marginHorizontal": 4,
|
||||
}
|
||||
}
|
||||
testID="thread-overview.no_replies"
|
||||
>
|
||||
No replies yet
|
||||
</Text>
|
||||
|
|
@ -60,7 +61,7 @@ exports[`ThreadOverview should match snapshot when post is not saved and 0 repli
|
|||
onGestureHandlerStateChange={[Function]}
|
||||
onHandlerStateChange={[Function]}
|
||||
rippleColor={0}
|
||||
testID="thread-overview.save"
|
||||
testID="thread-overview.unsave.button"
|
||||
>
|
||||
<View
|
||||
accessible={true}
|
||||
|
|
@ -89,7 +90,7 @@ exports[`ThreadOverview should match snapshot when post is not saved and 0 repli
|
|||
onGestureHandlerStateChange={[Function]}
|
||||
onHandlerStateChange={[Function]}
|
||||
rippleColor={0}
|
||||
testID="thread-overview.options"
|
||||
testID="thread-overview.post_options.button"
|
||||
>
|
||||
<View
|
||||
accessible={true}
|
||||
|
|
@ -148,6 +149,7 @@ exports[`ThreadOverview should match snapshot when post is saved and has replies
|
|||
"marginHorizontal": 4,
|
||||
}
|
||||
}
|
||||
testID="thread-overview.replies_count"
|
||||
>
|
||||
2 replies
|
||||
</Text>
|
||||
|
|
@ -169,7 +171,7 @@ exports[`ThreadOverview should match snapshot when post is saved and has replies
|
|||
onGestureHandlerStateChange={[Function]}
|
||||
onHandlerStateChange={[Function]}
|
||||
rippleColor={0}
|
||||
testID="thread-overview.save"
|
||||
testID="thread-overview.save.button"
|
||||
>
|
||||
<View
|
||||
accessible={true}
|
||||
|
|
@ -198,7 +200,7 @@ exports[`ThreadOverview should match snapshot when post is saved and has replies
|
|||
onGestureHandlerStateChange={[Function]}
|
||||
onHandlerStateChange={[Function]}
|
||||
rippleColor={0}
|
||||
testID="thread-overview.options"
|
||||
testID="thread-overview.post_options.button"
|
||||
>
|
||||
<View
|
||||
accessible={true}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,8 @@ const ThreadOverview = ({isSaved, repliesCount, rootPost, style, testID}: Props)
|
|||
return container;
|
||||
}, [repliesCount, style]);
|
||||
|
||||
const saveButtonTestId = isSaved ? `${testID}.unsave.button` : `${testID}.save.button`;
|
||||
|
||||
return (
|
||||
<View
|
||||
style={containerStyle}
|
||||
|
|
@ -108,6 +110,7 @@ const ThreadOverview = ({isSaved, repliesCount, rootPost, style, testID}: Props)
|
|||
style={styles.repliesCount}
|
||||
id='thread.repliesCount'
|
||||
defaultMessage='{repliesCount, number} {repliesCount, plural, one {reply} other {replies}}'
|
||||
testID={`${testID}.replies_count`}
|
||||
values={{repliesCount}}
|
||||
/>
|
||||
) : (
|
||||
|
|
@ -115,6 +118,7 @@ const ThreadOverview = ({isSaved, repliesCount, rootPost, style, testID}: Props)
|
|||
style={styles.repliesCount}
|
||||
id='thread.noReplies'
|
||||
defaultMessage='No replies yet'
|
||||
testID={`${testID}.no_replies`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -123,7 +127,7 @@ const ThreadOverview = ({isSaved, repliesCount, rootPost, style, testID}: Props)
|
|||
<TouchableOpacity
|
||||
onPress={onHandleSavePress}
|
||||
style={styles.optionContainer}
|
||||
testID={`${testID}.save`}
|
||||
testID={saveButtonTestId}
|
||||
>
|
||||
<CompassIcon
|
||||
size={24}
|
||||
|
|
@ -134,7 +138,7 @@ const ThreadOverview = ({isSaved, repliesCount, rootPost, style, testID}: Props)
|
|||
<TouchableOpacity
|
||||
onPress={showPostOptions}
|
||||
style={styles.optionContainer}
|
||||
testID={`${testID}.options`}
|
||||
testID={`${testID}.post_options.button`}
|
||||
>
|
||||
<CompassIcon
|
||||
size={24}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,10 @@ function EmptyState({isUnreads}: Props) {
|
|||
});
|
||||
}
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<View
|
||||
style={style.container}
|
||||
testID='global_threads.threads_list.empty_state'
|
||||
>
|
||||
<EmptyStateIllustration theme={theme}/>
|
||||
<View style={style.textContainer}>
|
||||
<Text style={style.title}>
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ const Header = ({setTab, tab, teamId, testID, unreadsCount}: Props) => {
|
|||
{hasUnreads ? (
|
||||
<View
|
||||
style={styles.unreadsDot}
|
||||
testID={`${testID}.unreads_dot`}
|
||||
testID={`${testID}.unreads_dot.badge`}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ const Thread = ({author, channel, post, teammateNameDisplay, testID, thread}: Pr
|
|||
}, [isTablet, theme, thread]);
|
||||
|
||||
const threadStarterName = displayUsername(author, intl.locale, teammateNameDisplay);
|
||||
const testIDPrefix = `${testID}.${thread.id}`;
|
||||
const threadItemTestId = `${testID}.thread_item.${thread.id}`;
|
||||
|
||||
const needBadge = thread.unreadMentions || thread.unreadReplies;
|
||||
let badgeComponent;
|
||||
|
|
@ -152,7 +152,7 @@ const Thread = ({author, channel, post, teammateNameDisplay, testID, thread}: Pr
|
|||
badgeComponent = (
|
||||
<View
|
||||
style={styles.mentionBadge}
|
||||
testID={`${testIDPrefix}.unread_mentions`}
|
||||
testID={`${threadItemTestId}.unread_mentions.badge`}
|
||||
>
|
||||
<Text style={styles.mentionBadgeText}>{thread.unreadMentions > 99 ? '99+' : thread.unreadMentions}</Text>
|
||||
</View>
|
||||
|
|
@ -161,7 +161,7 @@ const Thread = ({author, channel, post, teammateNameDisplay, testID, thread}: Pr
|
|||
badgeComponent = (
|
||||
<View
|
||||
style={styles.unreadDot}
|
||||
testID={`${testIDPrefix}.unread_dot`}
|
||||
testID={`${threadItemTestId}.unread_dot.badge`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -176,6 +176,7 @@ const Thread = ({author, channel, post, teammateNameDisplay, testID, thread}: Pr
|
|||
defaultMessage='Original Message Deleted'
|
||||
style={[styles.threadStarter, styles.threadDeleted]}
|
||||
numberOfLines={1}
|
||||
testID={`${threadItemTestId}.thread_starter.user_display_name`}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
|
|
@ -183,6 +184,7 @@ const Thread = ({author, channel, post, teammateNameDisplay, testID, thread}: Pr
|
|||
<Text
|
||||
style={styles.threadStarter}
|
||||
numberOfLines={1}
|
||||
testID={`${threadItemTestId}.thread_starter.user_display_name`}
|
||||
>
|
||||
{threadStarterName}
|
||||
</Text>
|
||||
|
|
@ -207,7 +209,7 @@ const Thread = ({author, channel, post, teammateNameDisplay, testID, thread}: Pr
|
|||
underlayColor={changeOpacity(theme.buttonBg, 0.08)}
|
||||
onLongPress={showThreadOptions}
|
||||
onPress={showThread}
|
||||
testID={`${testIDPrefix}.item`}
|
||||
testID={threadItemTestId}
|
||||
>
|
||||
<View style={styles.container}>
|
||||
<View style={styles.badgeContainer}>
|
||||
|
|
@ -222,6 +224,7 @@ const Thread = ({author, channel, post, teammateNameDisplay, testID, thread}: Pr
|
|||
<Text
|
||||
style={styles.channelName}
|
||||
numberOfLines={1}
|
||||
testID={`${threadItemTestId}.thread_starter.channel_display_name`}
|
||||
>
|
||||
{channel?.displayName}
|
||||
</Text>
|
||||
|
|
@ -236,7 +239,7 @@ const Thread = ({author, channel, post, teammateNameDisplay, testID, thread}: Pr
|
|||
{postBody}
|
||||
<ThreadFooter
|
||||
author={author}
|
||||
testID={`${testIDPrefix}.footer`}
|
||||
testID={`${threadItemTestId}.footer`}
|
||||
thread={thread}
|
||||
/>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -161,7 +161,10 @@ function Permalink({channel, postId}: Props) {
|
|||
}), []);
|
||||
|
||||
return (
|
||||
<SafeAreaView style={containerStyle}>
|
||||
<SafeAreaView
|
||||
style={containerStyle}
|
||||
testID='permalink.screen'
|
||||
>
|
||||
<Animated.View style={style.wrapper}>
|
||||
<View style={style.header}>
|
||||
<TouchableOpacity
|
||||
|
|
@ -211,6 +214,7 @@ function Permalink({channel, postId}: Props) {
|
|||
<TouchableOpacity
|
||||
style={[style.footer, style.bottom]}
|
||||
onPress={handlePress}
|
||||
testID='permalink.jump_to_recent_messages.button'
|
||||
>
|
||||
<FormattedText
|
||||
testID='permalink.search.jump'
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const CopyTextOption = ({postMessage, sourceScreen}: Props) => {
|
|||
defaultMessage='Copy Text'
|
||||
iconName='content-copy'
|
||||
onPress={handleCopyText}
|
||||
testID='post_options.copy.text.option'
|
||||
testID='post_options.copy_text.option'
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ const DeletePostOption = ({combinedPost, post}: Props) => {
|
|||
defaultMessage='Delete'
|
||||
iconName='trash-can-outline'
|
||||
onPress={onPress}
|
||||
testID='post_options.delete.post.option'
|
||||
testID='post_options.delete_post.option'
|
||||
isDestructive={true}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ const EditOption = ({post, canDelete}: Props) => {
|
|||
defaultMessage='Edit'
|
||||
onPress={onPress}
|
||||
iconName='pencil-outline'
|
||||
testID='post_options.edit.post.option'
|
||||
testID='post_options.edit_post.option'
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ const MarkAsUnreadOption = ({sourceScreen, post, teamId}: Props) => {
|
|||
defaultMessage='Mark as Unread'
|
||||
iconName='mark-as-unread'
|
||||
onPress={onPress}
|
||||
testID='post_options.mark.unread.option'
|
||||
testID='post_options.mark_as_unread.option'
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ const PinChannelOption = ({isPostPinned, postId}: PinChannelProps) => {
|
|||
defaultMessage={defaultMessage}
|
||||
iconName='pin-outline'
|
||||
onPress={onPress}
|
||||
testID={`post_options.${key}.channel.option`}
|
||||
testID={`post_options.${key}_post.option`}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -72,8 +72,13 @@ function ThreadFollow({isFollowing, teamId, threadId}: Props) {
|
|||
};
|
||||
}
|
||||
|
||||
const followThreadButtonTestId = isFollowing ? 'thread.following_thread.button' : 'thread.follow_thread.button';
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={onPress}>
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
testID={followThreadButtonTestId}
|
||||
>
|
||||
<View style={containerStyle}>
|
||||
<FormattedText
|
||||
{...followTextProps}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ const MarkAsUnreadOption = ({teamId, thread}: Props) => {
|
|||
|
||||
const id = thread.unreadReplies ? t('global_threads.options.mark_as_read') : t('mobile.post_info.mark_unread');
|
||||
const defaultMessage = thread.unreadReplies ? 'Mark as Read' : 'Mark as Unread';
|
||||
const markAsUnreadTestId = thread.unreadReplies ? 'thread_options.mark_as_read.option' : 'thread_options.mark_as_unread.option';
|
||||
|
||||
return (
|
||||
<BaseOption
|
||||
|
|
@ -37,7 +38,7 @@ const MarkAsUnreadOption = ({teamId, thread}: Props) => {
|
|||
defaultMessage={defaultMessage}
|
||||
iconName='mark-as-unread'
|
||||
onPress={onHandlePress}
|
||||
testID='thread.options.mark_as_read'
|
||||
testID={markAsUnreadTestId}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const OpenInChannelOption = ({threadId}: Props) => {
|
|||
defaultMessage='Open in Channel'
|
||||
iconName='globe'
|
||||
onPress={onHandlePress}
|
||||
testID='thread.options.open_in_channel'
|
||||
testID='thread_options.open_in_channel.option'
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ const ThreadOptions = ({
|
|||
componentId={Screens.THREAD_OPTIONS}
|
||||
initialSnapIndex={0}
|
||||
snapPoints={[((options.length + 2) * ITEM_HEIGHT), 10]}
|
||||
testID='thread_options'
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ class Alert {
|
|||
|
||||
return isAndroid() ? element(by.text(title)) : element(by.label(title)).atIndex(0);
|
||||
};
|
||||
markAllAsReadTitle = isAndroid() ? element(by.text('Are you sure you want to mark all threads as read?')) : element(by.label('Are you sure you want to mark all threads as read?')).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}?`;
|
||||
|
|
@ -22,6 +23,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);
|
||||
markReadButton = isAndroid() ? element(by.text('MARK READ')) : element(by.label('Mark read')).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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,14 +11,18 @@ class Post {
|
|||
emoji: 'markdown_emoji',
|
||||
image: 'markdown_image',
|
||||
message: 'markdown_text',
|
||||
postFooterFollowButton: 'post_footer.follow_thread.button',
|
||||
postFooterFollowingButton: 'post_footer.following_thread.button',
|
||||
postFooterReplyCount: 'post_footer.reply_count',
|
||||
postHeaderCommentedOn: 'post_header.commented_on',
|
||||
postHeaderDateTime: 'post_header.date_time',
|
||||
postHeaderDisplayName: 'post_header.display_name',
|
||||
postHeaderBotTag: 'post_header.bot_tag',
|
||||
postHeaderGuestTag: 'post_header.guest_tag',
|
||||
postHeaderReply: 'post_header.reply',
|
||||
postHeaderReplyCount: 'post_header.reply.count',
|
||||
postHeaderReplyCount: 'post_header.reply_count',
|
||||
postPreHeaderText: 'post_pre_header.text',
|
||||
postUnreadDotBadge: 'post_unread_dot.badge',
|
||||
showLessButton: 'show_more.button.chevron-up',
|
||||
showMoreButton: 'show_more.button.chevron-down',
|
||||
table: 'markdown_table',
|
||||
|
|
@ -39,6 +43,7 @@ class Post {
|
|||
const postItemTableMatcher = by.id(this.testID.table).withAncestor(postItemMatcher);
|
||||
const postItemTableExpandButtonMatcher = by.id(this.testID.tableExpandButton).withAncestor(postItemMatcher);
|
||||
const postItemThematicBreakMatcher = by.id(this.testID.thematicBreak).withAncestor(postItemMatcher);
|
||||
const postItemUnreadDotBadgeMatcher = by.id(this.testID.postUnreadDotBadge).withAncestor(postItemMatcher);
|
||||
|
||||
return {
|
||||
postItem: element(postItemMatcher),
|
||||
|
|
@ -53,11 +58,25 @@ class Post {
|
|||
postItemTable: element(postItemTableMatcher),
|
||||
postItemTableExpandButton: element(postItemTableExpandButtonMatcher),
|
||||
postItemThematicBreak: element(postItemThematicBreakMatcher),
|
||||
postItemUnreadDotBadge: element(postItemUnreadDotBadgeMatcher),
|
||||
...this.getPostFooter(postItemMatcher),
|
||||
...this.getPostHeader(postItemMatcher),
|
||||
...this.getPostProfilePicture(postItemMatcher, postProfileOptions),
|
||||
};
|
||||
};
|
||||
|
||||
getPostFooter = (postItemMatcher: Detox.NativeMatcher) => {
|
||||
const postItemFooterFollowButtonMatcher = by.id(this.testID.postFooterFollowButton).withAncestor(postItemMatcher);
|
||||
const postItemFooterFollowingButtonMatcher = by.id(this.testID.postFooterFollowingButton).withAncestor(postItemMatcher);
|
||||
const postItemFooterReplyCountMatcher = by.id(this.testID.postFooterReplyCount).withAncestor(postItemMatcher);
|
||||
|
||||
return {
|
||||
postItemFooterFollowButton: element(postItemFooterFollowButtonMatcher),
|
||||
postItemFooterFollowingButton: element(postItemFooterFollowingButtonMatcher),
|
||||
postItemFooterReplyCount: element(postItemFooterReplyCountMatcher),
|
||||
};
|
||||
};
|
||||
|
||||
getPostHeader = (postItemMatcher: Detox.NativeMatcher) => {
|
||||
const postItemHeaderCommentedOnMatcher = by.id(this.testID.postHeaderCommentedOn).withAncestor(postItemMatcher);
|
||||
const postItemHeaderDateTimeMatcher = by.id(this.testID.postHeaderDateTime).withAncestor(postItemMatcher);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@ class PostList {
|
|||
flatList: `${screenPrefix}post_list.flat_list`,
|
||||
moreMessagesButton: `${screenPrefix}post_list.more_messages_button`,
|
||||
newMessagesDivider: `${screenPrefix}post_list.new_messages_line`,
|
||||
threadOverview: `${screenPrefix}post_list.thread_overview`,
|
||||
threadOverviewRepliesCount: `${screenPrefix}post_list.replies_count`,
|
||||
threadOverviewNoReplies: `${screenPrefix}post_list.no_replies`,
|
||||
threadOverviewSaveButton: `${screenPrefix}post_list.thread_overview.save.button`,
|
||||
threadOverviewUnsaveButton: `${screenPrefix}post_list.thread_overview.unsave.button`,
|
||||
threadOverviewPostOptionsButton: `${screenPrefix}post_list.thread_overview.post_options.button`,
|
||||
postListPostItem: `${screenPrefix}post_list.post`,
|
||||
};
|
||||
}
|
||||
|
|
@ -27,12 +33,39 @@ class PostList {
|
|||
return element(by.id(this.testID.newMessagesDivider));
|
||||
};
|
||||
|
||||
getThreadOverview = () => {
|
||||
return element(by.id(this.testID.threadOverview));
|
||||
};
|
||||
|
||||
getThreadOverviewRepliesCount = () => {
|
||||
return element(by.id(this.testID.threadOverviewRepliesCount));
|
||||
};
|
||||
|
||||
getThreadOverviewNoReplies = () => {
|
||||
return element(by.id(this.testID.threadOverviewNoReplies));
|
||||
};
|
||||
|
||||
getThreadOverviewSaveButton = () => {
|
||||
return element(by.id(this.testID.threadOverviewSaveButton));
|
||||
};
|
||||
|
||||
getThreadOverviewUnsaveButton = () => {
|
||||
return element(by.id(this.testID.threadOverviewUnsaveButton));
|
||||
};
|
||||
|
||||
getThreadOverviewPostOptionsButton = () => {
|
||||
return element(by.id(this.testID.threadOverviewPostOptionsButton));
|
||||
};
|
||||
|
||||
getPost = (postId: string, postMessage: string, postProfileOptions = {}) => {
|
||||
const {
|
||||
postItem,
|
||||
postItemBlockQuote,
|
||||
postItemEditedIndicator,
|
||||
postItemEmoji,
|
||||
postItemFooterFollowButton,
|
||||
postItemFooterFollowingButton,
|
||||
postItemFooterReplyCount,
|
||||
postItemHeaderCommentedOn,
|
||||
postItemHeaderDateTime,
|
||||
postItemHeaderDisplayName,
|
||||
|
|
@ -50,6 +83,7 @@ class PostList {
|
|||
postItemTable,
|
||||
postItemTableExpandButton,
|
||||
postItemThematicBreak,
|
||||
postItemUnreadDotBadge,
|
||||
} = Post.getPost(this.testID.postListPostItem, postId, postMessage, postProfileOptions);
|
||||
|
||||
return {
|
||||
|
|
@ -57,6 +91,9 @@ class PostList {
|
|||
postListPostItemBlockQuote: postItemBlockQuote,
|
||||
postListPostItemEditedIndicator: postItemEditedIndicator,
|
||||
postListPostItemEmoji: postItemEmoji,
|
||||
postListPostItemFooterFollowButton: postItemFooterFollowButton,
|
||||
postListPostItemFooterFollowingButton: postItemFooterFollowingButton,
|
||||
postListPostItemFooterReplyCount: postItemFooterReplyCount,
|
||||
postListPostItemHeaderCommentedOn: postItemHeaderCommentedOn,
|
||||
postListPostItemHeaderDateTime: postItemHeaderDateTime,
|
||||
postListPostItemHeaderDisplayName: postItemHeaderDisplayName,
|
||||
|
|
@ -74,6 +111,7 @@ class PostList {
|
|||
postListPostItemTable: postItemTable,
|
||||
postListPostItemTableExpandButton: postItemTableExpandButton,
|
||||
postListPostItemThematicBreak: postItemThematicBreak,
|
||||
postListPostItemUnreadDotBadge: postItemUnreadDotBadge,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,29 +2,90 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import {NavigationHeader} from '@support/ui/component';
|
||||
import {timeouts} from '@support/utils';
|
||||
import {
|
||||
ChannelListScreen,
|
||||
ThreadOptionsScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {timeouts, wait} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
class GlobalThreadsScreen {
|
||||
testID = {
|
||||
globalThreadsScreen: 'global_threads.screen',
|
||||
headerAllThreadsButton: 'global_threads.threads_list.header.all_threads.button',
|
||||
headerUnreadThreadsButton: 'global_threads.threads_list.header.unread_threads.button',
|
||||
headerUnreadDotBadge: 'global_threads.threads_list.header.unread_dot.badge',
|
||||
headerMarkAllAsReadButton: 'global_threads.threads_list.header.mark_all_as_read.button',
|
||||
emptyThreadsList: 'global_threads.threads_list.empty_state',
|
||||
flatThreadsList: 'global_threads.threads_list.flat_list',
|
||||
};
|
||||
|
||||
globalThreadsScreen = element(by.id(this.testID.globalThreadsScreen));
|
||||
headerAllThreadsButton = element(by.id(this.testID.headerAllThreadsButton));
|
||||
headerUnreadThreadsButton = element(by.id(this.testID.headerUnreadThreadsButton));
|
||||
headerUnreadDotBadge = element(by.id(this.testID.headerUnreadDotBadge));
|
||||
headerMarkAllAsReadButton = element(by.id(this.testID.headerMarkAllAsReadButton));
|
||||
emptyThreadsList = element(by.id(this.testID.emptyThreadsList));
|
||||
flatThreadsList = element(by.id(this.testID.flatThreadsList));
|
||||
|
||||
// convenience props
|
||||
backButton = NavigationHeader.backButton;
|
||||
|
||||
getThreadItem = (threadId: string) => {
|
||||
return element(by.id(`global_threads.threads_list.thread_item.${threadId}`));
|
||||
};
|
||||
|
||||
getThreadItemUnreadMentionsBadge = (threadId: string) => {
|
||||
return element(by.id(`global_threads.threads_list.thread_item.${threadId}.unread_mentions.badge`));
|
||||
};
|
||||
|
||||
getThreadItemUnreadDotBadge = (threadId: string) => {
|
||||
return element(by.id(`global_threads.threads_list.thread_item.${threadId}.unread_dot.badge`));
|
||||
};
|
||||
|
||||
getThreadItemThreadStarterUserDisplayName = (threadId: string) => {
|
||||
return element(by.id(`global_threads.threads_list.thread_item.${threadId}.thread_starter.user_display_name`));
|
||||
};
|
||||
|
||||
getThreadItemThreadStarterChannelDisplayName = (threadId: string) => {
|
||||
return element(by.id(`global_threads.threads_list.thread_item.${threadId}.thread_starter.channel_display_name`));
|
||||
};
|
||||
|
||||
getThreadItemFooterUnreadReplies = (threadId: string) => {
|
||||
return element(by.id(`global_threads.threads_list.thread_item.${threadId}.footer.unread_replies`));
|
||||
};
|
||||
|
||||
getThreadItemFooterReplyCount = (threadId: string) => {
|
||||
return element(by.id(`global_threads.threads_list.thread_item.${threadId}.footer.reply_count`));
|
||||
};
|
||||
|
||||
toBeVisible = async () => {
|
||||
await waitFor(this.globalThreadsScreen).toExist().withTimeout(timeouts.TEN_SEC);
|
||||
|
||||
return this.globalThreadsScreen;
|
||||
};
|
||||
|
||||
open = async () => {
|
||||
// # Open global threads screen
|
||||
await ChannelListScreen.threadsButton.tap();
|
||||
|
||||
return this.toBeVisible();
|
||||
};
|
||||
|
||||
back = async () => {
|
||||
await this.backButton.tap();
|
||||
await expect(this.globalThreadsScreen).not.toBeVisible();
|
||||
};
|
||||
|
||||
openThreadOptionsFor = async (postId: string) => {
|
||||
const threadItem = this.getThreadItem(postId);
|
||||
await expect(threadItem).toBeVisible();
|
||||
|
||||
// # Open thread options
|
||||
await threadItem.longPress();
|
||||
await ThreadOptionsScreen.toBeVisible();
|
||||
await wait(timeouts.TWO_SEC);
|
||||
};
|
||||
}
|
||||
|
||||
const globalThreadsScreen = new GlobalThreadsScreen();
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@ import EditServerScreen from './edit_server';
|
|||
import GlobalThreadsScreen from './global_threads';
|
||||
import HomeScreen from './home';
|
||||
import LoginScreen from './login';
|
||||
import PermalinkScreen from './permalink';
|
||||
import PostOptionsScreen from './post_options';
|
||||
import ServerScreen from './server';
|
||||
import ServerListScreen from './server_list';
|
||||
import ThreadScreen from './thread';
|
||||
import ThreadOptionsScreen from './thread_options';
|
||||
|
||||
export {
|
||||
AccountScreen,
|
||||
|
|
@ -31,8 +33,10 @@ export {
|
|||
GlobalThreadsScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
PermalinkScreen,
|
||||
PostOptionsScreen,
|
||||
ServerScreen,
|
||||
ServerListScreen,
|
||||
ThreadScreen,
|
||||
ThreadOptionsScreen,
|
||||
};
|
||||
|
|
|
|||
54
detox/e2e/support/ui/screen/permalink.ts
Normal file
54
detox/e2e/support/ui/screen/permalink.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {PostList} from '@support/ui/component';
|
||||
import {expect} from 'detox';
|
||||
|
||||
class PermalinkScreen {
|
||||
testID = {
|
||||
permalinkScreenPrefix: 'permalink.',
|
||||
permalinkScreen: 'permalink.screen',
|
||||
permalinkPostList: 'permalink.post_list',
|
||||
jumpToRecentMessagesButton: 'permalink.jump_to_recent_messages.button',
|
||||
};
|
||||
|
||||
permalinkScreen = element(by.id(this.testID.permalinkScreen));
|
||||
permalinkPostList = element(by.id(this.testID.permalinkPostList));
|
||||
jumpToRecentMessagesButton = element(by.id(this.testID.jumpToRecentMessagesButton));
|
||||
|
||||
postList = new PostList(this.testID.permalinkScreenPrefix);
|
||||
|
||||
getPostListPostItem = (postId: string, text: string, postProfileOptions = {}) => {
|
||||
return this.postList.getPost(postId, text, postProfileOptions);
|
||||
};
|
||||
|
||||
getPostMessageAtIndex = (index: number) => {
|
||||
return this.postList.getPostMessageAtIndex(index);
|
||||
};
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.permalinkScreen).toBeVisible();
|
||||
|
||||
return this.permalinkScreen;
|
||||
};
|
||||
|
||||
jumpToRecentMessages = async () => {
|
||||
// # Jump to recent messages
|
||||
await this.jumpToRecentMessagesButton.tap();
|
||||
await expect(this.permalinkScreen).not.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 permalinkScreen = new PermalinkScreen();
|
||||
export default permalinkScreen;
|
||||
|
|
@ -11,33 +11,35 @@ class PostOptionsScreen {
|
|||
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',
|
||||
saveChannelOption: 'post_options.save.channel.option',
|
||||
unsaveChannelOption: 'post_options.unsave.channel.option',
|
||||
copyTextOption: 'post_options.copy.text.option',
|
||||
pinChannelOption: 'post_options.pin.channel.option',
|
||||
unpinChannelOption: 'post_options.unpin.channel.option',
|
||||
editPostOption: 'post_options.edit.post.option',
|
||||
deletePostOption: 'post_options.delete.post.option',
|
||||
followThreadOption: 'post_options.follow.thread.option',
|
||||
markUnreadOption: 'post_options.mark.unread.option',
|
||||
replyPostOption: 'post_options.reply_post.option',
|
||||
followThreadOption: 'post_options.follow_thread.option',
|
||||
followingThreadOption: 'post_options.following_thread.option',
|
||||
markAsUnreadOption: 'post_options.mark_as_unread.option',
|
||||
copyLinkOption: 'post_options.copy_permalink.option',
|
||||
savePostOption: 'post_options.save_post.option',
|
||||
unsavePostOption: 'post_options.unsave_post.option',
|
||||
copyTextOption: 'post_options.copy_text.option',
|
||||
pinPostOption: 'post_options.pin_post.option',
|
||||
unpinPostOption: 'post_options.unpin_post.option',
|
||||
editPostOption: 'post_options.edit_post.option',
|
||||
deletePostOption: 'post_options.delete_post.option',
|
||||
};
|
||||
|
||||
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));
|
||||
followThreadOption = element(by.id(this.testID.followThreadOption));
|
||||
followingThreadOption = element(by.id(this.testID.followingThreadOption));
|
||||
markAsUnreadOption = element(by.id(this.testID.markAsUnreadOption));
|
||||
copyLinkOption = element(by.id(this.testID.copyLinkOption));
|
||||
saveChannelOption = element(by.id(this.testID.saveChannelOption));
|
||||
unsaveChannelOption = element(by.id(this.testID.unsaveChannelOption));
|
||||
savePostOption = element(by.id(this.testID.savePostOption));
|
||||
unsavePostOption = element(by.id(this.testID.unsavePostOption));
|
||||
copyTextOption = element(by.id(this.testID.copyTextOption));
|
||||
pinChannelOption = element(by.id(this.testID.pinChannelOption));
|
||||
unpinChannelOption = element(by.id(this.testID.unpinChannelOption));
|
||||
pinPostOption = element(by.id(this.testID.pinPostOption));
|
||||
unpinPostOption = element(by.id(this.testID.unpinPostOption));
|
||||
editPostOption = element(by.id(this.testID.editPostOption));
|
||||
deletePostOption = element(by.id(this.testID.deletePostOption));
|
||||
followThreadOption = element(by.id(this.testID.followThreadOption));
|
||||
markUnreadOption = element(by.id(this.testID.markUnreadOption));
|
||||
|
||||
getReactionEmoji = (emojiName: string) => {
|
||||
return element(by.id(`${this.testID.reactionEmojiPrefix}${emojiName}`));
|
||||
|
|
|
|||
|
|
@ -19,11 +19,15 @@ class ThreadScreen {
|
|||
threadScreenPrefix: 'thread.',
|
||||
threadScreen: 'thread.screen',
|
||||
backButton: 'screen.back.button',
|
||||
followButton: 'thread.follow_thread.button',
|
||||
followingButton: 'thread.following_thread.button',
|
||||
flatPostList: 'thread.post_list.flat_list',
|
||||
};
|
||||
|
||||
threadScreen = element(by.id(this.testID.threadScreen));
|
||||
backButton = element(by.id(this.testID.backButton));
|
||||
followButton = element(by.id(this.testID.followButton));
|
||||
followingButton = element(by.id(this.testID.followingButton));
|
||||
flatPostList = element(by.id(this.testID.flatPostList));
|
||||
|
||||
// convenience props
|
||||
|
|
@ -46,6 +50,30 @@ class ThreadScreen {
|
|||
|
||||
postList = new PostList(this.testID.threadScreenPrefix);
|
||||
|
||||
getThreadOverview = () => {
|
||||
return this.postList.getThreadOverview();
|
||||
};
|
||||
|
||||
getThreadOverviewRepliesCount = () => {
|
||||
return this.postList.getThreadOverviewRepliesCount();
|
||||
};
|
||||
|
||||
getThreadOverviewNoReplies = () => {
|
||||
return this.postList.getThreadOverviewNoReplies();
|
||||
};
|
||||
|
||||
getThreadOverviewSaveButton = () => {
|
||||
return this.postList.getThreadOverviewSaveButton();
|
||||
};
|
||||
|
||||
getThreadOverviewUnsaveButton = () => {
|
||||
return this.postList.getThreadOverviewUnsaveButton();
|
||||
};
|
||||
|
||||
getThreadOverviewPostOptionsButton = () => {
|
||||
return this.postList.getThreadOverviewPostOptionsButton();
|
||||
};
|
||||
|
||||
getPostListPostItem = (postId: string, text: string, postProfileOptions: any = {}) => {
|
||||
return this.postList.getPost(postId, text, postProfileOptions);
|
||||
};
|
||||
|
|
|
|||
47
detox/e2e/support/ui/screen/thread_options.ts
Normal file
47
detox/e2e/support/ui/screen/thread_options.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {timeouts} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
class ThreadOptionsScreen {
|
||||
testID = {
|
||||
threadOptionsScreen: 'thread_options.screen',
|
||||
threadOptionsBackdrop: 'thread_options.backdrop',
|
||||
replyThreadOption: 'post_options.reply_post.option',
|
||||
followThreadOption: 'post_options.follow_thread.option',
|
||||
followingThreadOption: 'post_options.following_thread.option',
|
||||
openInChannelOption: 'thread_options.open_in_channel.option',
|
||||
markAsReadOption: 'thread_options.mark_as_unread.option',
|
||||
markAsUnreadOption: 'thread_options.mark_as_unread.option',
|
||||
saveThreadOption: 'post_options.save_post.option',
|
||||
unsaveThreadOption: 'post_options.unsave_post.option',
|
||||
copyLinkOption: 'post_options.copy_permalink.option',
|
||||
};
|
||||
|
||||
threadOptionsScreen = element(by.id(this.testID.threadOptionsScreen));
|
||||
threadOptionsBackdrop = element(by.id(this.testID.threadOptionsBackdrop));
|
||||
replyThreadOption = element(by.id(this.testID.replyThreadOption));
|
||||
followThreadOption = element(by.id(this.testID.followThreadOption));
|
||||
followingThreadOption = element(by.id(this.testID.followingThreadOption));
|
||||
openInChannelOption = element(by.id(this.testID.openInChannelOption));
|
||||
markAsReadOption = element(by.id(this.testID.markAsUnreadOption));
|
||||
markAsUnreadOption = element(by.id(this.testID.markAsUnreadOption));
|
||||
saveThreadOption = element(by.id(this.testID.saveThreadOption));
|
||||
unsaveThreadOption = element(by.id(this.testID.unsaveThreadOption));
|
||||
copyLinkOption = element(by.id(this.testID.copyLinkOption));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await waitFor(this.threadOptionsScreen).toExist().withTimeout(timeouts.TEN_SEC);
|
||||
|
||||
return threadOptionsScreen;
|
||||
};
|
||||
|
||||
close = async () => {
|
||||
await this.threadOptionsBackdrop.tap({x: 5, y: 10});
|
||||
await expect(this.threadOptionsScreen).not.toBeVisible();
|
||||
};
|
||||
}
|
||||
|
||||
const threadOptionsScreen = new ThreadOptionsScreen();
|
||||
export default threadOptionsScreen;
|
||||
161
detox/e2e/test/smoke_test/threads.e2e.ts
Normal file
161
detox/e2e/test/smoke_test/threads.e2e.ts
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
// 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,
|
||||
System,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {
|
||||
ChannelScreen,
|
||||
ChannelListScreen,
|
||||
GlobalThreadsScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
PermalinkScreen,
|
||||
ServerScreen,
|
||||
ThreadOptionsScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Smoke Test - Threads', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
const savedText = 'Saved';
|
||||
let testChannel: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
System.apiUpdateConfig(siteOneUrl, {
|
||||
ServiceSettings: {
|
||||
CollapsedThreads: 'default_on',
|
||||
},
|
||||
});
|
||||
|
||||
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-T4811_1 - should be able to create a thread, follow/unfollow a thread, mark a thread as read/unread, and reply to thread', async () => {
|
||||
// # Create a thread and unfollow thread via thread navigation
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
await ThreadScreen.postMessage(`${parentMessage} reply`);
|
||||
await ThreadScreen.followingButton.tap();
|
||||
|
||||
// * Verify thread is not followed by user via thread navigation
|
||||
await expect(ThreadScreen.followButton).toBeVisible();
|
||||
|
||||
// # Follow thread via thread navigation
|
||||
await ThreadScreen.followButton.tap();
|
||||
|
||||
// * Verify thread is followed by user via thread navigation
|
||||
await expect(ThreadScreen.followingButton).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen, then go to global threads screen, tap on all your threads button, open thread options for thread, tap on mark as unread option, and tap on unread threads button
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
await GlobalThreadsScreen.headerAllThreadsButton.tap();
|
||||
await GlobalThreadsScreen.openThreadOptionsFor(parentPost.id);
|
||||
await ThreadOptionsScreen.markAsUnreadOption.tap();
|
||||
await GlobalThreadsScreen.headerUnreadThreadsButton.tap();
|
||||
|
||||
// * Verify thread is displayed in unread threads section
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
|
||||
// # Open thread options for thread and tap on mark as read option
|
||||
await GlobalThreadsScreen.openThreadOptionsFor(parentPost.id);
|
||||
await ThreadOptionsScreen.markAsReadOption.tap();
|
||||
|
||||
// * Verify thread is not displayed anymore in unread threads section
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).not.toBeVisible();
|
||||
|
||||
// # Tap on all your threads button, tap on the thread, and add new reply to thread
|
||||
await GlobalThreadsScreen.headerAllThreadsButton.tap();
|
||||
await GlobalThreadsScreen.getThreadItem(parentPost.id).tap();
|
||||
const newReplyMessage = `${parentMessage} new reply`;
|
||||
await ThreadScreen.postMessage(newReplyMessage);
|
||||
|
||||
// * Verify new reply is posted
|
||||
const {post: newReplyPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem} = ThreadScreen.getPostListPostItem(newReplyPost.id, newReplyMessage);
|
||||
await expect(postListPostItem).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await GlobalThreadsScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4811_2 - should be able to save/unsave a thread and open a thread in channel', async () => {
|
||||
// # Create a thread, go back to channel list screen, then go to global threads screen, open thread options for thread, tap on save option, and tap on thread
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
await GlobalThreadsScreen.openThreadOptionsFor(parentPost.id);
|
||||
await ThreadOptionsScreen.saveThreadOption.tap();
|
||||
await GlobalThreadsScreen.getThreadItem(parentPost.id).tap();
|
||||
|
||||
// * Verify saved text is displayed on the post pre-header
|
||||
const {postListPostItemPreHeaderText} = ThreadScreen.getPostListPostItem(parentPost.id, parentMessage);
|
||||
await expect(postListPostItemPreHeaderText).toHaveText(savedText);
|
||||
|
||||
// # Go back to global threads screen, open thread options for thread, tap on save option, and tap on thread
|
||||
await ThreadScreen.back();
|
||||
await GlobalThreadsScreen.openThreadOptionsFor(parentPost.id);
|
||||
await ThreadOptionsScreen.unsaveThreadOption.tap();
|
||||
await GlobalThreadsScreen.getThreadItem(parentPost.id).tap();
|
||||
|
||||
// * Verify saved text is not displayed on the post pre-header
|
||||
await expect(postListPostItemPreHeaderText).not.toBeVisible();
|
||||
|
||||
// # Go back to global threads screen, open thread options for thread, tap on open in channel option, and jump to recent messages
|
||||
await ThreadScreen.back();
|
||||
await GlobalThreadsScreen.openThreadOptionsFor(parentPost.id);
|
||||
await ThreadOptionsScreen.openInChannelOption.tap();
|
||||
await PermalinkScreen.jumpToRecentMessages();
|
||||
|
||||
// * Verify on channel screen and thread is displayed
|
||||
await ChannelScreen.toBeVisible();
|
||||
const {postListPostItem} = ThreadScreen.getPostListPostItem(parentPost.id, parentMessage);
|
||||
await expect(postListPostItem).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
});
|
||||
201
detox/e2e/test/threads/follow_and_unfollow_thread.e2e.ts
Normal file
201
detox/e2e/test/threads/follow_and_unfollow_thread.e2e.ts
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
// 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,
|
||||
System,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {
|
||||
ChannelListScreen,
|
||||
ChannelScreen,
|
||||
GlobalThreadsScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
PostOptionsScreen,
|
||||
ServerScreen,
|
||||
ThreadOptionsScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Threads - Follow and Unfollow Thread', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
let testChannel: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
System.apiUpdateConfig(siteOneUrl, {
|
||||
ServiceSettings: {
|
||||
CollapsedThreads: 'default_on',
|
||||
},
|
||||
});
|
||||
|
||||
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-T4806_1 - should be able to follow/unfollow a thread via thread navigation', async () => {
|
||||
// # Create a thread
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
await ThreadScreen.postMessage(`${parentMessage} reply`);
|
||||
|
||||
// * Verify thread is followed by user by default via thread navigation
|
||||
await expect(ThreadScreen.followingButton).toBeVisible();
|
||||
|
||||
// # Unfollow thread via thread navigation
|
||||
await ThreadScreen.followingButton.tap();
|
||||
|
||||
// * Verify thread is not followed by user via thread navigation
|
||||
await expect(ThreadScreen.followButton).toBeVisible();
|
||||
|
||||
// # Follow thread via thread navigation
|
||||
await ThreadScreen.followButton.tap();
|
||||
|
||||
// * Verify thread is followed by user via thread navigation
|
||||
await expect(ThreadScreen.followingButton).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4806_2 - should be able to follow/unfollow a thread via post footer', async () => {
|
||||
// # Create a thread and go back to channel screen
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
await ThreadScreen.postMessage(`${parentMessage} reply`);
|
||||
await ThreadScreen.back();
|
||||
|
||||
// * Verify thread is followed by user by default via post footer
|
||||
const {postListPostItemFooterFollowButton, postListPostItemFooterFollowingButton} = ChannelScreen.getPostListPostItem(parentPost.id, parentMessage);
|
||||
await expect(postListPostItemFooterFollowingButton).toBeVisible();
|
||||
|
||||
// # Unfollow thread via post footer
|
||||
await postListPostItemFooterFollowingButton.tap();
|
||||
|
||||
// * Verify thread is not followed by user via post footer
|
||||
await expect(postListPostItemFooterFollowButton).toBeVisible();
|
||||
|
||||
// # Follow thread via post footer
|
||||
await postListPostItemFooterFollowButton.tap();
|
||||
|
||||
// * Verify thread is followed by user via post footer
|
||||
await expect(postListPostItemFooterFollowingButton).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4806_3 - should be able to follow/unfollow a thread via post options', async () => {
|
||||
// # Create a thread, go back to channel screen, and open post options for thread
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
await ThreadScreen.postMessage(`${parentMessage} reply`);
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.openPostOptionsFor(parentPost.id, parentMessage);
|
||||
|
||||
// * Verify thread is followed by user by default via post options
|
||||
await expect(PostOptionsScreen.followingThreadOption).toBeVisible();
|
||||
|
||||
// # Unfollow thread via post options
|
||||
await PostOptionsScreen.followingThreadOption.tap();
|
||||
|
||||
// * Verify thread is not followed by user via post footer
|
||||
const {postListPostItemFooterFollowButton, postListPostItemFooterFollowingButton} = ChannelScreen.getPostListPostItem(parentPost.id, parentMessage);
|
||||
await expect(postListPostItemFooterFollowButton).toBeVisible();
|
||||
|
||||
// # Open post options for thread
|
||||
await ChannelScreen.openPostOptionsFor(parentPost.id, parentMessage);
|
||||
|
||||
// * Verify thread is not followed by user via post options
|
||||
await expect(PostOptionsScreen.followThreadOption).toBeVisible();
|
||||
|
||||
// # Open post options for thread and follow thread via post options
|
||||
await ChannelScreen.openPostOptionsFor(parentPost.id, parentMessage);
|
||||
await PostOptionsScreen.followThreadOption.tap();
|
||||
|
||||
// * Verify thread is followed by user via post footer
|
||||
await expect(postListPostItemFooterFollowingButton).toBeVisible();
|
||||
|
||||
// # Open post options for thread
|
||||
await ChannelScreen.openPostOptionsFor(parentPost.id, parentMessage);
|
||||
|
||||
// * Verify thread is followed by user via post options
|
||||
await expect(PostOptionsScreen.followingThreadOption).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await PostOptionsScreen.close();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4806_4 - should be able to unfollow a thread via thread options', async () => {
|
||||
// # Create a thread, go back to channel list screen, then go to global threads screen, and tap on all your threads button
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
await GlobalThreadsScreen.headerAllThreadsButton.tap();
|
||||
|
||||
// * Verify thread is displayed
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
|
||||
// # Open thread options for thread
|
||||
await GlobalThreadsScreen.openThreadOptionsFor(parentPost.id);
|
||||
|
||||
// * Verify thread is followed by user via thread options
|
||||
await expect(ThreadOptionsScreen.followingThreadOption).toBeVisible();
|
||||
|
||||
// # Unfollow thread via thread options
|
||||
await ThreadOptionsScreen.followingThreadOption.tap();
|
||||
|
||||
// * Verify thread is not displayed anymore in all your threads section
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await GlobalThreadsScreen.back();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
});
|
||||
211
detox/e2e/test/threads/global_threads.e2e.ts
Normal file
211
detox/e2e/test/threads/global_threads.e2e.ts
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
// 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,
|
||||
System,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {
|
||||
ChannelListScreen,
|
||||
ChannelScreen,
|
||||
GlobalThreadsScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
ServerScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Threads - Global Threads', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
let testChannel: any;
|
||||
let testUser: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
System.apiUpdateConfig(siteOneUrl, {
|
||||
ServiceSettings: {
|
||||
CollapsedThreads: 'default_on',
|
||||
},
|
||||
});
|
||||
|
||||
const {channel, user} = await Setup.apiInit(siteOneUrl);
|
||||
testChannel = channel;
|
||||
testUser = user;
|
||||
|
||||
// # 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-T4805_1 - should match elements on global threads screen', async () => {
|
||||
// # Open global threads screen
|
||||
await ChannelListScreen.open();
|
||||
|
||||
// * Verify basic elements on global threads screen
|
||||
await expect(GlobalThreadsScreen.headerAllThreadsButton).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.headerUnreadThreadsButton).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.headerMarkAllAsReadButton).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.emptyThreadsList).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await GlobalThreadsScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4805_2 - should be able to go to a thread a user started and followed', async () => {
|
||||
// # Create a thread started by the current user
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
const {post: replyPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem: replyPostListPostItem} = ThreadScreen.getPostListPostItem(replyPost.id, replyMessage);
|
||||
|
||||
// * Verify thread is followed by the current user by default
|
||||
await expect(ThreadScreen.followingButton).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen, then go to global threads screen, and tap on all your threads button
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
await GlobalThreadsScreen.headerAllThreadsButton.tap();
|
||||
|
||||
// * Verify the thread started by the current user is displayed
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemThreadStarterUserDisplayName(parentPost.id)).toHaveText(testUser.username);
|
||||
await expect(GlobalThreadsScreen.getThreadItemThreadStarterChannelDisplayName(parentPost.id)).toHaveText(testChannel.display_name.toUpperCase());
|
||||
await expect(GlobalThreadsScreen.getThreadItemFooterUnreadReplies(parentPost.id)).toHaveText('1 new reply');
|
||||
|
||||
// # Tap on the thread
|
||||
await GlobalThreadsScreen.getThreadItem(parentPost.id).tap();
|
||||
|
||||
// * Verify on thread screen
|
||||
await ThreadScreen.toBeVisible();
|
||||
await expect(replyPostListPostItem).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await GlobalThreadsScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4805_3 - should not display a thread a user started but not followed', async () => {
|
||||
// # Create a thread started by the current user and current user unfollows the thread
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
await ThreadScreen.postMessage(`${parentMessage} reply`);
|
||||
await ThreadScreen.followingButton.tap();
|
||||
|
||||
// * Verify thread is not followed by the current user
|
||||
await expect(ThreadScreen.followButton).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen, then go to global threads screen, and tap on all your threads button
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
await GlobalThreadsScreen.headerAllThreadsButton.tap();
|
||||
|
||||
// * Verify the thread started by the current user is not displayed
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).not.toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await GlobalThreadsScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4805_4 - should be able to go to a thread a user replied to and followed', async () => {
|
||||
// # Create a thread started by another user which the current user replied to
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
const {post: parentPost} = await Post.apiCreatePost(siteOneUrl, {
|
||||
channelId: testChannel.id,
|
||||
message: parentMessage,
|
||||
});
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
const {post: replyPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem: replyPostListPostItem} = ThreadScreen.getPostListPostItem(replyPost.id, replyMessage);
|
||||
|
||||
// * Verify thread is followed by the current user by default after replying to post
|
||||
await expect(ThreadScreen.followingButton).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen, then go to global threads screen, and tap on all your threads button
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await device.reloadReactNative();
|
||||
await GlobalThreadsScreen.open();
|
||||
await GlobalThreadsScreen.headerAllThreadsButton.tap();
|
||||
|
||||
// * Verify the thread replied to by the current user is displayed
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemThreadStarterUserDisplayName(parentPost.id)).toHaveText('sysadmin');
|
||||
await expect(GlobalThreadsScreen.getThreadItemThreadStarterChannelDisplayName(parentPost.id)).toHaveText(testChannel.display_name.toUpperCase());
|
||||
await expect(GlobalThreadsScreen.getThreadItemFooterUnreadReplies(parentPost.id)).toHaveText('1 new reply');
|
||||
|
||||
// # Tap on the thread
|
||||
await GlobalThreadsScreen.getThreadItem(parentPost.id).tap();
|
||||
|
||||
// * Verify on thread screen
|
||||
await ThreadScreen.toBeVisible();
|
||||
await expect(replyPostListPostItem).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await GlobalThreadsScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4805_5 - should not display a thread a user replied to but not followed', async () => {
|
||||
// # Create a thread started by another user which the current user replied to and current user unfollows the thread
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
const {post: parentPost} = await Post.apiCreatePost(siteOneUrl, {
|
||||
channelId: testChannel.id,
|
||||
message: parentMessage,
|
||||
});
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
await ThreadScreen.postMessage(`${parentMessage} reply`);
|
||||
await ThreadScreen.followingButton.tap();
|
||||
|
||||
// * Verify thread is not followed by the current user
|
||||
await expect(ThreadScreen.followButton).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen, then go to global threads screen, and tap on all your threads button
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
await GlobalThreadsScreen.headerAllThreadsButton.tap();
|
||||
|
||||
// * Verify the thread replied to by the current user is not displayed
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).not.toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await GlobalThreadsScreen.back();
|
||||
});
|
||||
});
|
||||
183
detox/e2e/test/threads/mark_thread_as_read_and_unread.e2e.ts
Normal file
183
detox/e2e/test/threads/mark_thread_as_read_and_unread.e2e.ts
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
// 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,
|
||||
System,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {Alert} from '@support/ui/component';
|
||||
import {
|
||||
ChannelListScreen,
|
||||
ChannelScreen,
|
||||
GlobalThreadsScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
ServerScreen,
|
||||
ThreadOptionsScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Threads - Mark Thread as Read and Unread', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
let testChannel: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
System.apiUpdateConfig(siteOneUrl, {
|
||||
ServiceSettings: {
|
||||
CollapsedThreads: 'default_on',
|
||||
},
|
||||
});
|
||||
|
||||
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-T4807_1 - should be able to mark a thread as read by opening thread', async () => {
|
||||
// # Create a thread, go back to channel list screen, then go to global threads screen, and tap on unread threads button
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
await GlobalThreadsScreen.headerUnreadThreadsButton.tap();
|
||||
|
||||
// * Verify thread is displayed as unread in unread threads section with unread dot badge and footer unread replies
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemUnreadDotBadge(parentPost.id)).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemFooterUnreadReplies(parentPost.id)).toHaveText('1 new reply');
|
||||
|
||||
// # Tap on the thread and go back to global threads screen
|
||||
await GlobalThreadsScreen.getThreadItem(parentPost.id).tap();
|
||||
await ThreadScreen.back();
|
||||
|
||||
// * Verify thread is not displayed anymore in unread threads section
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).not.toBeVisible();
|
||||
|
||||
// # Tap on all your threads button
|
||||
await GlobalThreadsScreen.headerAllThreadsButton.tap();
|
||||
|
||||
// * Verify thread is displayed as read in all your threads section without unread dot badge and with footer reply count
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemUnreadDotBadge(parentPost.id)).not.toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemFooterReplyCount(parentPost.id)).toHaveText('1 reply');
|
||||
|
||||
// # Go back to channel list screen
|
||||
await GlobalThreadsScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4807_2 - should be able to mark a thread as read/unread via thread options', async () => {
|
||||
// # Create a thread, go back to channel list screen, then go to global threads screen, and tap on unread threads button
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
await GlobalThreadsScreen.headerUnreadThreadsButton.tap();
|
||||
|
||||
// * Verify thread is displayed as unread in unread threads section with unread dot badge and footer unread replies
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemUnreadDotBadge(parentPost.id)).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemFooterUnreadReplies(parentPost.id)).toHaveText('1 new reply');
|
||||
|
||||
// # Open thread options for thread and tap on mark as read option
|
||||
await GlobalThreadsScreen.openThreadOptionsFor(parentPost.id);
|
||||
await ThreadOptionsScreen.markAsReadOption.tap();
|
||||
|
||||
// * Verify thread is not displayed anymore in unread threads section
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).not.toBeVisible();
|
||||
|
||||
// # Tap on all your threads button
|
||||
await GlobalThreadsScreen.headerAllThreadsButton.tap();
|
||||
|
||||
// * Verify thread is displayed as read in all your threads section without unread dot badge and with footer reply count
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemUnreadDotBadge(parentPost.id)).not.toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemFooterReplyCount(parentPost.id)).toHaveText('1 reply');
|
||||
|
||||
// # Open thread options for thread and tap on mark as unread option
|
||||
await GlobalThreadsScreen.openThreadOptionsFor(parentPost.id);
|
||||
await ThreadOptionsScreen.markAsUnreadOption.tap();
|
||||
|
||||
// * Verify thread is displayed as unread in all your threads section with unread dot badge and footer unread replies
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemUnreadDotBadge(parentPost.id)).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemFooterUnreadReplies(parentPost.id)).toHaveText('1 new reply');
|
||||
|
||||
// # Go back to channel list screen
|
||||
await GlobalThreadsScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4807_3 - should be able to mark all threads as read', async () => {
|
||||
// # Create a thread, go back to channel list screen, then go to global threads screen, and tap on unread threads button
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
await GlobalThreadsScreen.headerUnreadThreadsButton.tap();
|
||||
|
||||
// * Verify thread is displayed as unread in unread threads section with unread dot badge and footer unread replies
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemUnreadDotBadge(parentPost.id)).toBeVisible();
|
||||
await expect(GlobalThreadsScreen.getThreadItemFooterUnreadReplies(parentPost.id)).toHaveText('1 new reply');
|
||||
|
||||
// # Tap on mark all as read button
|
||||
await GlobalThreadsScreen.headerMarkAllAsReadButton.tap();
|
||||
|
||||
// * Verify mark all as read alert is displayed
|
||||
await expect(Alert.markAllAsReadTitle).toBeVisible();
|
||||
|
||||
// # Tap on mark read button
|
||||
await Alert.markReadButton.tap();
|
||||
|
||||
// * Verify thread is not displayed anymore and unread threads section is empty
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).not.toBeVisible();
|
||||
await expect(GlobalThreadsScreen.emptyThreadsList).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await GlobalThreadsScreen.back();
|
||||
});
|
||||
});
|
||||
137
detox/e2e/test/threads/open_thread_in_channel.e2e.ts
Normal file
137
detox/e2e/test/threads/open_thread_in_channel.e2e.ts
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// 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,
|
||||
System,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {
|
||||
ChannelListScreen,
|
||||
ChannelScreen,
|
||||
GlobalThreadsScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
PermalinkScreen,
|
||||
ServerScreen,
|
||||
ThreadOptionsScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId, timeouts, wait} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Threads - Open Thread in Channel', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
let testChannel: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
System.apiUpdateConfig(siteOneUrl, {
|
||||
ServiceSettings: {
|
||||
CollapsedThreads: 'default_on',
|
||||
},
|
||||
});
|
||||
|
||||
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-T4810_1 - should be able to open a thread in channel via thread options', async () => {
|
||||
// # Create a thread, go back to channel list screen, and then go to global threads screen
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
|
||||
// * Verify thread is displayed
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
|
||||
// # Open thread options for thread and tap open in channel option
|
||||
await GlobalThreadsScreen.openThreadOptionsFor(parentPost.id);
|
||||
await ThreadOptionsScreen.openInChannelOption.tap();
|
||||
|
||||
// * Verify on permalink screen
|
||||
await PermalinkScreen.toBeVisible();
|
||||
|
||||
// # Jump to recent messages
|
||||
await PermalinkScreen.jumpToRecentMessages();
|
||||
|
||||
// * Verify on channel screen and thread is displayed
|
||||
await ChannelScreen.toBeVisible();
|
||||
const {postListPostItem} = ThreadScreen.getPostListPostItem(parentPost.id, parentMessage);
|
||||
await expect(postListPostItem).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4810_1 - should be able to open a thread in channel by permalink', async () => {
|
||||
// # Create a thread, go back to channel list screen, and then go to global threads screen
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
|
||||
// * Verify thread is displayed
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
|
||||
// # Open thread options for thread, tap on copy link option, go back to channel list screen, go to another channel, post the permalink, and tap on permalink
|
||||
const permalinkLabel = `permalink-${Date.now().toString()}`;
|
||||
const permalinkMessage = `[${permalinkLabel}](/_redirect/pl/${parentPost.id})`;
|
||||
await GlobalThreadsScreen.back();
|
||||
await ChannelScreen.open(channelsCategory, 'off-topic');
|
||||
await ChannelScreen.postMessage(permalinkMessage);
|
||||
await element(by.text(permalinkLabel)).tap({x: 5, y: 10});
|
||||
await wait(timeouts.ONE_SEC);
|
||||
|
||||
// * Verify on permalink screen
|
||||
await PermalinkScreen.toBeVisible();
|
||||
|
||||
// # Jump to recent messages
|
||||
await PermalinkScreen.jumpToRecentMessages();
|
||||
|
||||
// * Verify on channel screen and thread is displayed
|
||||
await ChannelScreen.toBeVisible();
|
||||
const {postListPostItem} = ThreadScreen.getPostListPostItem(parentPost.id, parentMessage);
|
||||
await expect(postListPostItem).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
});
|
||||
134
detox/e2e/test/threads/reply_to_thread.e2e.ts
Normal file
134
detox/e2e/test/threads/reply_to_thread.e2e.ts
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
// 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,
|
||||
System,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {
|
||||
ChannelListScreen,
|
||||
ChannelScreen,
|
||||
GlobalThreadsScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
ServerScreen,
|
||||
ThreadOptionsScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Threads - Reply to Thread', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
let testChannel: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
System.apiUpdateConfig(siteOneUrl, {
|
||||
ServiceSettings: {
|
||||
CollapsedThreads: 'default_on',
|
||||
},
|
||||
});
|
||||
|
||||
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-T4809_1 - should be able to reply to a thread via thread options', async () => {
|
||||
// # Create a thread, go back to channel list screen, and then go to global threads screen
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
|
||||
// * Verify thread is displayed
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
|
||||
// # Open thread options for thread and tap on reply option
|
||||
await GlobalThreadsScreen.openThreadOptionsFor(parentPost.id);
|
||||
await ThreadOptionsScreen.replyThreadOption.tap();
|
||||
|
||||
// * Verify on thread screen
|
||||
await ThreadScreen.toBeVisible();
|
||||
|
||||
// # Add new reply to thread
|
||||
const newReplyMessage = `${parentMessage} new reply`;
|
||||
await ThreadScreen.postMessage(newReplyMessage);
|
||||
|
||||
// * Verify new reply is posted
|
||||
const {post: newReplyPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem} = ThreadScreen.getPostListPostItem(newReplyPost.id, newReplyMessage);
|
||||
await expect(postListPostItem).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await GlobalThreadsScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4809_2 - should be able to reply to a thread by opening thread', async () => {
|
||||
// # Create a thread, go back to channel list screen, and then go to global threads screen
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
|
||||
// * Verify thread is displayed
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
|
||||
// # Tap on the thread
|
||||
await GlobalThreadsScreen.getThreadItem(parentPost.id).tap();
|
||||
|
||||
// * Verify on thread screen
|
||||
await ThreadScreen.toBeVisible();
|
||||
|
||||
// # Add new reply to thread
|
||||
const newReplyMessage = `${parentMessage} new reply`;
|
||||
await ThreadScreen.postMessage(newReplyMessage);
|
||||
|
||||
// * Verify new reply is posted
|
||||
const {post: newReplyPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
const {postListPostItem} = ThreadScreen.getPostListPostItem(newReplyPost.id, newReplyMessage);
|
||||
await expect(postListPostItem).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await GlobalThreadsScreen.back();
|
||||
});
|
||||
});
|
||||
136
detox/e2e/test/threads/save_and_unsave_thread.e2e.ts
Normal file
136
detox/e2e/test/threads/save_and_unsave_thread.e2e.ts
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
// 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,
|
||||
System,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {
|
||||
ChannelListScreen,
|
||||
ChannelScreen,
|
||||
GlobalThreadsScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
ServerScreen,
|
||||
ThreadOptionsScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {getRandomId} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Threads - Save and Unsave Thread', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
const savedText = 'Saved';
|
||||
let testChannel: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
System.apiUpdateConfig(siteOneUrl, {
|
||||
ServiceSettings: {
|
||||
CollapsedThreads: 'default_on',
|
||||
},
|
||||
});
|
||||
|
||||
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-T4808_1 - should be able to save/unsave a thread via thread options', async () => {
|
||||
// # Create a thread, go back to channel list screen, and then go to global threads screen
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
|
||||
// * Verify thread is displayed
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
|
||||
// # Open thread options for thread, tap on save option, and tap on thread
|
||||
await GlobalThreadsScreen.openThreadOptionsFor(parentPost.id);
|
||||
await ThreadOptionsScreen.saveThreadOption.tap();
|
||||
await GlobalThreadsScreen.getThreadItem(parentPost.id).tap();
|
||||
|
||||
// * Verify saved text is displayed on the post pre-header
|
||||
const {postListPostItemPreHeaderText} = ThreadScreen.getPostListPostItem(parentPost.id, parentMessage);
|
||||
await expect(postListPostItemPreHeaderText).toHaveText(savedText);
|
||||
|
||||
// # Go back to global threads screen, open thread options for thread, tap on save option, and tap on thread
|
||||
await ThreadScreen.back();
|
||||
await GlobalThreadsScreen.openThreadOptionsFor(parentPost.id);
|
||||
await ThreadOptionsScreen.unsaveThreadOption.tap();
|
||||
await GlobalThreadsScreen.getThreadItem(parentPost.id).tap();
|
||||
|
||||
// * Verify saved text is not displayed on the post pre-header
|
||||
await expect(postListPostItemPreHeaderText).not.toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T4808_2 - should be able to save/unsave a thread via thread overview', async () => {
|
||||
// # Create a thread, go back to channel list screen, and then go to global threads screen
|
||||
const parentMessage = `Message ${getRandomId()}`;
|
||||
await ChannelScreen.open(channelsCategory, testChannel.name);
|
||||
await ChannelScreen.postMessage(parentMessage);
|
||||
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
|
||||
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
|
||||
const replyMessage = `${parentMessage} reply`;
|
||||
await ThreadScreen.postMessage(replyMessage);
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
await GlobalThreadsScreen.open();
|
||||
|
||||
// * Verify thread is displayed
|
||||
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
|
||||
|
||||
// # Tap on thread and tap on thread overview save button
|
||||
await GlobalThreadsScreen.getThreadItem(parentPost.id).tap();
|
||||
await ThreadScreen.getThreadOverviewSaveButton().tap();
|
||||
|
||||
// * Verify saved text is displayed on the post pre-header
|
||||
const {postListPostItemPreHeaderText} = ThreadScreen.getPostListPostItem(parentPost.id, parentMessage);
|
||||
await expect(postListPostItemPreHeaderText).toHaveText(savedText);
|
||||
|
||||
// # Tap on thread overview unsave button
|
||||
await ThreadScreen.getThreadOverviewUnsaveButton().tap();
|
||||
|
||||
// * Verify saved text is not displayed on the post pre-header
|
||||
await expect(postListPostItemPreHeaderText).not.toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ThreadScreen.back();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue