MM-30424 Detox/E2E: Add e2e for MM-T3237, MM-T3238, MM-T3251, MM-T3257, MM-T3258 (#5188)
This commit is contained in:
parent
3445e5bcaa
commit
141b5199ba
55 changed files with 767 additions and 92 deletions
|
|
@ -115,6 +115,7 @@ const AtMentionItem = (props: AtMentionItemProps) => {
|
|||
size={24}
|
||||
status={null}
|
||||
showStatus={false}
|
||||
testID={`${testID}.profile_picture`}
|
||||
/>
|
||||
</View>
|
||||
<BotTag
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ export default class ChannelMention extends PureComponent {
|
|||
<ChannelMentionItem
|
||||
channelId={item}
|
||||
onPress={this.completeMention}
|
||||
testID={`autocomplete.channel_mention.item.${item}`}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ const ChannelMentionItem = (props) => {
|
|||
isGuest,
|
||||
name,
|
||||
onPress,
|
||||
testID,
|
||||
theme,
|
||||
type,
|
||||
} = props;
|
||||
|
|
@ -78,6 +79,7 @@ const ChannelMentionItem = (props) => {
|
|||
onPress={completeMention}
|
||||
style={[style.row, margins]}
|
||||
type={'opacity'}
|
||||
testID={testID}
|
||||
>
|
||||
<Text style={style.rowDisplayName}>{'@' + displayName}</Text>
|
||||
<BotTag
|
||||
|
|
@ -98,6 +100,7 @@ const ChannelMentionItem = (props) => {
|
|||
style={margins}
|
||||
underlayColor={changeOpacity(theme.buttonBg, 0.08)}
|
||||
type={'native'}
|
||||
testID={testID}
|
||||
>
|
||||
<View style={style.row}>
|
||||
<CompassIcon
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ exports[`Avatars should match snapshot for overflow 1`] = `
|
|||
<Connect(ProfilePicture)
|
||||
showStatus={false}
|
||||
size={24}
|
||||
testID="avatars.profile_picture"
|
||||
userId="user1"
|
||||
/>
|
||||
</View>
|
||||
|
|
@ -49,6 +50,7 @@ exports[`Avatars should match snapshot for overflow 1`] = `
|
|||
<Connect(ProfilePicture)
|
||||
showStatus={false}
|
||||
size={24}
|
||||
testID="avatars.profile_picture"
|
||||
userId="user2"
|
||||
/>
|
||||
</View>
|
||||
|
|
@ -70,6 +72,7 @@ exports[`Avatars should match snapshot for overflow 1`] = `
|
|||
<Connect(ProfilePicture)
|
||||
showStatus={false}
|
||||
size={24}
|
||||
testID="avatars.profile_picture"
|
||||
userId="user3"
|
||||
/>
|
||||
</View>
|
||||
|
|
@ -147,6 +150,7 @@ exports[`Avatars should match snapshot for single avatar 1`] = `
|
|||
<Connect(ProfilePicture)
|
||||
showStatus={false}
|
||||
size={24}
|
||||
testID="avatars.profile_picture"
|
||||
userId="user1"
|
||||
/>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ export default class Avatars extends PureComponent<AvatarsProps> {
|
|||
userId={userId}
|
||||
size={ViewTypes.AVATAR_LIST_PICTURE_SIZE}
|
||||
showStatus={false}
|
||||
testID='avatars.profile_picture'
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ class ChannelIntro extends PureComponent {
|
|||
iconSize={48}
|
||||
statusBorderWidth={2}
|
||||
statusSize={25}
|
||||
testID='channel_intro.profile_picture'
|
||||
/>
|
||||
</TouchableWithFeedback>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ exports[`UserListRow should match snapshot 1`] = `
|
|||
<Connect(ProfilePicture)
|
||||
iconSize={24}
|
||||
size={32}
|
||||
testID="custom_list.user_item.21345.profile_picture"
|
||||
userId="21345"
|
||||
/>
|
||||
</View>
|
||||
|
|
@ -164,6 +165,7 @@ exports[`UserListRow should match snapshot for currentUser with (you) populated
|
|||
<Connect(ProfilePicture)
|
||||
iconSize={24}
|
||||
size={32}
|
||||
testID="custom_list.user_item.21345.profile_picture"
|
||||
userId="21345"
|
||||
/>
|
||||
</View>
|
||||
|
|
@ -297,6 +299,7 @@ exports[`UserListRow should match snapshot for deactivated user 1`] = `
|
|||
<Connect(ProfilePicture)
|
||||
iconSize={24}
|
||||
size={32}
|
||||
testID="custom_list.user_item.21345.profile_picture"
|
||||
userId="21345"
|
||||
/>
|
||||
</View>
|
||||
|
|
@ -443,6 +446,7 @@ exports[`UserListRow should match snapshot for guest user 1`] = `
|
|||
<Connect(ProfilePicture)
|
||||
iconSize={24}
|
||||
size={32}
|
||||
testID="custom_list.user_item.21345.profile_picture"
|
||||
userId="21345"
|
||||
/>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ export default class UserListRow extends React.PureComponent {
|
|||
const testID = this.props.testID;
|
||||
const itemTestID = `${testID}.${id}`;
|
||||
const displayUsernameTestID = `${testID}.display_username`;
|
||||
const profilePictureTestID = `${itemTestID}.profile_picture`;
|
||||
|
||||
return (
|
||||
<View style={style.container}>
|
||||
|
|
@ -82,6 +83,7 @@ export default class UserListRow extends React.PureComponent {
|
|||
userId={id}
|
||||
size={32}
|
||||
iconSize={24}
|
||||
testID={profilePictureTestID}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export default class FormattedTime extends React.PureComponent {
|
|||
children: PropTypes.func,
|
||||
hour12: PropTypes.bool,
|
||||
style: CustomPropTypes.Style,
|
||||
testID: PropTypes.string,
|
||||
};
|
||||
|
||||
getFormattedTime = () => {
|
||||
|
|
@ -38,13 +39,20 @@ export default class FormattedTime extends React.PureComponent {
|
|||
};
|
||||
|
||||
render() {
|
||||
const {children, style} = this.props;
|
||||
const {children, style, testID} = this.props;
|
||||
const formattedTime = this.getFormattedTime();
|
||||
|
||||
if (typeof children === 'function') {
|
||||
return children(formattedTime);
|
||||
}
|
||||
|
||||
return <Text style={style}>{formattedTime}</Text>;
|
||||
return (
|
||||
<Text
|
||||
style={style}
|
||||
testID={testID}
|
||||
>
|
||||
{formattedTime}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ exports[`PostHeader should match snapshot when just a base post 1`] = `
|
|||
"paddingVertical": 2,
|
||||
}
|
||||
}
|
||||
testID="post_header.display_name"
|
||||
>
|
||||
John Smith
|
||||
</Text>
|
||||
|
|
@ -62,6 +63,7 @@ exports[`PostHeader should match snapshot when just a base post 1`] = `
|
|||
"opacity": 0.5,
|
||||
}
|
||||
}
|
||||
testID="post_header.date_time"
|
||||
timeZone=""
|
||||
value={0}
|
||||
/>
|
||||
|
|
@ -119,6 +121,7 @@ exports[`PostHeader should match snapshot when just a base post in landscape mod
|
|||
"paddingVertical": 2,
|
||||
}
|
||||
}
|
||||
testID="post_header.display_name"
|
||||
>
|
||||
John Smith
|
||||
</Text>
|
||||
|
|
@ -134,6 +137,7 @@ exports[`PostHeader should match snapshot when just a base post in landscape mod
|
|||
"opacity": 0.5,
|
||||
}
|
||||
}
|
||||
testID="post_header.date_time"
|
||||
timeZone=""
|
||||
value={0}
|
||||
/>
|
||||
|
|
@ -187,6 +191,7 @@ exports[`PostHeader should match snapshot when post is autoresponder 1`] = `
|
|||
"paddingVertical": 2,
|
||||
}
|
||||
}
|
||||
testID="post_header.display_name"
|
||||
>
|
||||
John Smith
|
||||
</Text>
|
||||
|
|
@ -243,6 +248,7 @@ exports[`PostHeader should match snapshot when post is autoresponder 1`] = `
|
|||
"opacity": 0.5,
|
||||
}
|
||||
}
|
||||
testID="post_header.date_time"
|
||||
timeZone=""
|
||||
value={0}
|
||||
/>
|
||||
|
|
@ -295,6 +301,7 @@ exports[`PostHeader should match snapshot when post is from system message 1`] =
|
|||
},
|
||||
]
|
||||
}
|
||||
testID="post_header.display_name"
|
||||
/>
|
||||
</View>
|
||||
<FormattedTime
|
||||
|
|
@ -308,6 +315,7 @@ exports[`PostHeader should match snapshot when post is from system message 1`] =
|
|||
"opacity": 0.5,
|
||||
}
|
||||
}
|
||||
testID="post_header.date_time"
|
||||
timeZone=""
|
||||
value={0}
|
||||
/>
|
||||
|
|
@ -363,6 +371,7 @@ exports[`PostHeader should match snapshot when post is same thread, so dont disp
|
|||
"paddingVertical": 2,
|
||||
}
|
||||
}
|
||||
testID="post_header.display_name"
|
||||
>
|
||||
John Smith
|
||||
</Text>
|
||||
|
|
@ -378,6 +387,7 @@ exports[`PostHeader should match snapshot when post is same thread, so dont disp
|
|||
"opacity": 0.5,
|
||||
}
|
||||
}
|
||||
testID="post_header.date_time"
|
||||
timeZone=""
|
||||
value={0}
|
||||
/>
|
||||
|
|
@ -452,6 +462,7 @@ exports[`PostHeader should match snapshot when post isBot and shouldRenderReplyB
|
|||
"paddingVertical": 2,
|
||||
}
|
||||
}
|
||||
testID="post_header.display_name"
|
||||
>
|
||||
John Smith
|
||||
</Text>
|
||||
|
|
@ -505,6 +516,7 @@ exports[`PostHeader should match snapshot when post isBot and shouldRenderReplyB
|
|||
"opacity": 0.5,
|
||||
}
|
||||
}
|
||||
testID="post_header.date_time"
|
||||
timeZone=""
|
||||
value={0}
|
||||
/>
|
||||
|
|
@ -605,6 +617,7 @@ exports[`PostHeader should match snapshot when post isBot and shouldRenderReplyB
|
|||
"paddingVertical": 2,
|
||||
}
|
||||
}
|
||||
testID="post_header.display_name"
|
||||
>
|
||||
John Smith
|
||||
</Text>
|
||||
|
|
@ -658,6 +671,7 @@ exports[`PostHeader should match snapshot when post isBot and shouldRenderReplyB
|
|||
"opacity": 0.5,
|
||||
}
|
||||
}
|
||||
testID="post_header.date_time"
|
||||
timeZone=""
|
||||
value={0}
|
||||
/>
|
||||
|
|
@ -756,6 +770,7 @@ exports[`PostHeader should match snapshot when post renders Commented On for new
|
|||
"paddingVertical": 2,
|
||||
}
|
||||
}
|
||||
testID="post_header.display_name"
|
||||
>
|
||||
John Smith
|
||||
</Text>
|
||||
|
|
@ -771,6 +786,7 @@ exports[`PostHeader should match snapshot when post renders Commented On for new
|
|||
"opacity": 0.5,
|
||||
}
|
||||
}
|
||||
testID="post_header.date_time"
|
||||
timeZone=""
|
||||
value={0}
|
||||
/>
|
||||
|
|
@ -843,6 +859,7 @@ exports[`PostHeader should match snapshot when post should display reply button
|
|||
"paddingVertical": 2,
|
||||
}
|
||||
}
|
||||
testID="post_header.display_name"
|
||||
>
|
||||
John Smith
|
||||
</Text>
|
||||
|
|
@ -858,6 +875,7 @@ exports[`PostHeader should match snapshot when post should display reply button
|
|||
"opacity": 0.5,
|
||||
}
|
||||
}
|
||||
testID="post_header.date_time"
|
||||
timeZone=""
|
||||
value={0}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@ export default class PostHeader extends PureComponent {
|
|||
style={style.displayName}
|
||||
ellipsizeMode={'tail'}
|
||||
numberOfLines={1}
|
||||
testID='post_header.display_name'
|
||||
>
|
||||
{name}
|
||||
</Text>
|
||||
|
|
@ -177,6 +178,7 @@ export default class PostHeader extends PureComponent {
|
|||
id='post_info.system'
|
||||
defaultMessage='System'
|
||||
style={[style.displayName]}
|
||||
testID='post_header.display_name'
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
|
@ -191,6 +193,7 @@ export default class PostHeader extends PureComponent {
|
|||
style={style.displayName}
|
||||
ellipsizeMode={'tail'}
|
||||
numberOfLines={1}
|
||||
testID='post_header.display_name'
|
||||
>
|
||||
{displayName}
|
||||
</Text>
|
||||
|
|
@ -204,6 +207,7 @@ export default class PostHeader extends PureComponent {
|
|||
id='channel_loader.someone'
|
||||
defaultMessage='Someone'
|
||||
style={style.displayName}
|
||||
testID='post_header.display_name'
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
|
@ -302,6 +306,7 @@ export default class PostHeader extends PureComponent {
|
|||
timeZone={userTimezone}
|
||||
value={createAt}
|
||||
style={style.time}
|
||||
testID='post_header.date_time'
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
|
|
@ -311,6 +316,7 @@ export default class PostHeader extends PureComponent {
|
|||
hour12={!militaryTime}
|
||||
value={createAt}
|
||||
style={style.time}
|
||||
testID='post_header.date_time'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ export default class PostProfilePicture extends PureComponent {
|
|||
size={ViewTypes.PROFILE_PICTURE_SIZE}
|
||||
iconSize={24}
|
||||
showStatus={showProfileStatus}
|
||||
testID='post_profile_picture.profile_picture'
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export default class ProfilePicture extends PureComponent {
|
|||
profileImageUri: PropTypes.string,
|
||||
profileImageRemove: PropTypes.bool,
|
||||
theme: PropTypes.object.isRequired,
|
||||
testID: PropTypes.string,
|
||||
actions: PropTypes.shape({
|
||||
getStatusForId: PropTypes.func.isRequired,
|
||||
setProfileImageUri: PropTypes.func.isRequired,
|
||||
|
|
@ -109,7 +110,7 @@ export default class ProfilePicture extends PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {edit, showStatus, theme, user, size} = this.props;
|
||||
const {edit, showStatus, theme, user, size, testID} = this.props;
|
||||
const {pictureUrl} = this.state;
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
|
|
@ -178,7 +179,10 @@ export default class ProfilePicture extends PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<View style={[style.container, containerStyle]}>
|
||||
<View
|
||||
style={[style.container, containerStyle]}
|
||||
testID={`${testID}.${user.id}`}
|
||||
>
|
||||
{image}
|
||||
{(showStatus || edit) && (user && !user.is_bot) &&
|
||||
<View style={[style.statusWrapper, statusStyle, {borderRadius: this.props.statusSize / 2}]}>
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ export default class UserInfo extends PureComponent {
|
|||
id={i18nId}
|
||||
defaultMessage={defaultMessage}
|
||||
style={style.label}
|
||||
testID={`user_status.label.${status}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ export default class UserInfo extends PureComponent {
|
|||
iconSize={28}
|
||||
showStatus={false}
|
||||
userId={user.id}
|
||||
testID={`${testID}.profile_picture`}
|
||||
/>
|
||||
<View style={style.wrapper}>
|
||||
<View>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ exports[`UserStatus should match snapshot, away status 1`] = `
|
|||
"fontSize": 32,
|
||||
}
|
||||
}
|
||||
testID="user_status.icon.away"
|
||||
/>
|
||||
`;
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ exports[`UserStatus should match snapshot, dnd status 1`] = `
|
|||
"fontSize": 32,
|
||||
}
|
||||
}
|
||||
testID="user_status.icon.dnd"
|
||||
/>
|
||||
`;
|
||||
|
||||
|
|
@ -33,6 +35,7 @@ exports[`UserStatus should match snapshot, online status 1`] = `
|
|||
"fontSize": 32,
|
||||
}
|
||||
}
|
||||
testID="user_status.icon.online"
|
||||
/>
|
||||
`;
|
||||
|
||||
|
|
@ -45,5 +48,6 @@ exports[`UserStatus should match snapshot, should default to offline status 1`]
|
|||
"fontSize": 32,
|
||||
}
|
||||
}
|
||||
testID="user_status.icon.offline"
|
||||
/>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ export default class UserStatus extends PureComponent {
|
|||
<CompassIcon
|
||||
name={iconName}
|
||||
style={{fontSize: size, color: iconColor}}
|
||||
testID={`user_status.icon.${status}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ exports[`edit_profile should match snapshot 1`] = `
|
|||
size={153}
|
||||
statusBorderWidth={6}
|
||||
statusSize={36}
|
||||
testID="edit_profile.profile_picture"
|
||||
/>
|
||||
</View>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -525,6 +525,7 @@ export default class EditProfile extends PureComponent {
|
|||
edit={!profilePictureDisabled}
|
||||
imageUri={uri}
|
||||
profileImageRemove={profileImageRemove}
|
||||
testID='edit_profile.profile_picture'
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ const NotificationIcon = ({fromWebhook, overrideIconUrl, senderId, useUserIcon}:
|
|||
userId={user.id}
|
||||
size={IMAGE_SIZE}
|
||||
iconSize={24}
|
||||
testID='in_app_notification.profile_picture'
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ exports[`Search RecentItem should match snapshot and respond to events 1`] = `
|
|||
"width": 50,
|
||||
}
|
||||
}
|
||||
testID="search.recent_item.test.remove.button"
|
||||
>
|
||||
<CompassIcon
|
||||
color="rgba(61,60,64,0.6)"
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ export default class RecentItem extends PureComponent {
|
|||
<TouchableOpacity
|
||||
onPress={this.handleRemove}
|
||||
style={style.recentRemove}
|
||||
testID={`${testID}.remove.button`}
|
||||
>
|
||||
<CompassIcon
|
||||
name='close-circle-outline'
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ export default class ClockDisplay extends ClockDisplayBase {
|
|||
}),
|
||||
value: 'false',
|
||||
checked: newMilitaryTime === 'false',
|
||||
testID: 'clock_display_settings.normal_clock.action',
|
||||
}, {
|
||||
label: intl.formatMessage({
|
||||
id: 'user.settings.display.militaryClock',
|
||||
|
|
@ -64,6 +65,7 @@ export default class ClockDisplay extends ClockDisplayBase {
|
|||
}),
|
||||
value: 'true',
|
||||
checked: newMilitaryTime === 'true',
|
||||
testID: 'clock_display_settings.military_clock.action',
|
||||
}];
|
||||
|
||||
return (
|
||||
|
|
@ -73,7 +75,10 @@ export default class ClockDisplay extends ClockDisplayBase {
|
|||
visible={showModal}
|
||||
onRequestClose={this.closeModal}
|
||||
>
|
||||
<View style={style.modalOverlay}>
|
||||
<View
|
||||
style={style.modalOverlay}
|
||||
testID='clock_display_settings.clock.modal'
|
||||
>
|
||||
<View style={style.modal}>
|
||||
<View style={style.modalBody}>
|
||||
<View style={style.modalTitleContainer}>
|
||||
|
|
@ -105,6 +110,7 @@ export default class ClockDisplay extends ClockDisplayBase {
|
|||
id='mobile.notification_settings.modal_cancel'
|
||||
defaultMessage='CANCEL'
|
||||
style={style.modalFooterOption}
|
||||
testID='clock_display_settings.clock_modal_cancel.button'
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<View style={style.modalFooterButtonSpacer}/>
|
||||
|
|
@ -116,6 +122,7 @@ export default class ClockDisplay extends ClockDisplayBase {
|
|||
id='mobile.notification_settings.modal_save'
|
||||
defaultMessage='SAVE'
|
||||
style={style.modalFooterOption}
|
||||
testID='clock_display_settings.clock_modal_save.button'
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
|
@ -131,7 +138,10 @@ export default class ClockDisplay extends ClockDisplayBase {
|
|||
const style = getStyleSheet(theme);
|
||||
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<View
|
||||
style={style.container}
|
||||
testID='clock_display_settings.screen'
|
||||
>
|
||||
<StatusBar/>
|
||||
<View style={style.wrapper}>
|
||||
{this.renderClockDisplayModal(style)}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export default class ClockDisplay extends ClockDisplayBase {
|
|||
<SafeAreaView
|
||||
edges={['left', 'right']}
|
||||
style={style.container}
|
||||
testID='clock_display_settings.screen'
|
||||
>
|
||||
<StatusBar/>
|
||||
<View style={style.wrapper}>
|
||||
|
|
@ -46,6 +47,7 @@ export default class ClockDisplay extends ClockDisplayBase {
|
|||
actionType='select'
|
||||
actionValue='false'
|
||||
selected={newMilitaryTime === 'false'}
|
||||
testID='clock_display_settings.normal_clock.action'
|
||||
theme={theme}
|
||||
/>
|
||||
<View style={style.divider}/>
|
||||
|
|
@ -60,6 +62,7 @@ export default class ClockDisplay extends ClockDisplayBase {
|
|||
actionType='select'
|
||||
actionValue='true'
|
||||
selected={newMilitaryTime === 'true'}
|
||||
testID='clock_display_settings.military_clock.action'
|
||||
theme={theme}
|
||||
/>
|
||||
</Section>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ exports[`DisplaySettings should match snapshot 1`] = `
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="display_settings.screen"
|
||||
>
|
||||
<Connect(StatusBar) />
|
||||
<View
|
||||
|
|
@ -42,6 +43,7 @@ exports[`DisplaySettings should match snapshot 1`] = `
|
|||
onPress={[Function]}
|
||||
separator={false}
|
||||
showArrow={true}
|
||||
testID="display_settings.clock_display.action"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
|
|
@ -98,6 +100,7 @@ exports[`DisplaySettings should match snapshot on Tablet devices 1`] = `
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="display_settings.screen"
|
||||
>
|
||||
<Connect(StatusBar) />
|
||||
<View
|
||||
|
|
@ -165,6 +168,7 @@ exports[`DisplaySettings should match snapshot on Tablet devices 1`] = `
|
|||
onPress={[Function]}
|
||||
separator={false}
|
||||
showArrow={true}
|
||||
testID="display_settings.clock_display.action"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ export default class DisplaySettings extends PureComponent {
|
|||
onPress={this.goToTimezoneSettings}
|
||||
separator={false}
|
||||
showArrow={showArrow}
|
||||
testID='display_settings.timezone.action'
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
|
|
@ -124,6 +125,7 @@ export default class DisplaySettings extends PureComponent {
|
|||
<SafeAreaView
|
||||
edges={['left', 'right']}
|
||||
style={style.container}
|
||||
testID='display_settings.screen'
|
||||
>
|
||||
<StatusBar/>
|
||||
<View style={style.wrapper}>
|
||||
|
|
@ -137,6 +139,7 @@ export default class DisplaySettings extends PureComponent {
|
|||
onPress={this.goToThemeSettings}
|
||||
separator={true}
|
||||
showArrow={showArrow}
|
||||
testID='display_settings.theme.action'
|
||||
theme={theme}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -147,6 +150,7 @@ export default class DisplaySettings extends PureComponent {
|
|||
onPress={this.goToClockDisplaySettings}
|
||||
separator={disableClockDisplaySeparator}
|
||||
showArrow={showArrow}
|
||||
testID='display_settings.clock_display.action'
|
||||
theme={theme}
|
||||
/>
|
||||
{timezoneOption}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ exports[`user_profile should match snapshot 1`] = `
|
|||
size={153}
|
||||
statusBorderWidth={6}
|
||||
statusSize={36}
|
||||
testID="user_profile.profile_picture"
|
||||
userId="4hzdnk6mg7gepe7yze6m3domnc"
|
||||
/>
|
||||
<Text
|
||||
|
|
|
|||
|
|
@ -344,6 +344,7 @@ export default class UserProfile extends PureComponent {
|
|||
iconSize={104}
|
||||
statusBorderWidth={6}
|
||||
statusSize={36}
|
||||
testID='user_profile.profile_picture'
|
||||
/>
|
||||
{this.getDisplayName()}
|
||||
<Text style={style.username}>{`@${user.username}`}</Text>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import {getResponseFromError} from './common';
|
|||
* See https://api.mattermost.com/#tag/users/paths/~1users~1login/post
|
||||
* @param {string} user.username - username of a user
|
||||
* @param {string} user.password - password of a user
|
||||
* @return {Object} returns {user, status} on success or {error, status} on error
|
||||
*/
|
||||
export const apiLogin = async (user) => {
|
||||
try {
|
||||
|
|
@ -49,6 +50,7 @@ export const apiLogin = async (user) => {
|
|||
|
||||
/**
|
||||
* Login to Mattermost server as sysadmin.
|
||||
* @return {Object} returns {user, status} on success or {error, status} on error
|
||||
*/
|
||||
export const apiAdminLogin = () => {
|
||||
return apiLogin({
|
||||
|
|
@ -60,6 +62,7 @@ export const apiAdminLogin = () => {
|
|||
/**
|
||||
* Logout from the Mattermost server.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1logout/post
|
||||
* @return {Object} returns data on success
|
||||
*/
|
||||
export const apiLogout = async () => {
|
||||
const response = await client.post('/api/v4/users/logout');
|
||||
|
|
@ -73,6 +76,7 @@ export const apiLogout = async () => {
|
|||
* Create a user.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users/post
|
||||
* @param {Object} user - user object to be created
|
||||
* @return {Object} returns {user} on success or {error, status} on error
|
||||
*/
|
||||
export const apiCreateUser = async ({prefix = 'user', user = null} = {}) => {
|
||||
try {
|
||||
|
|
@ -91,6 +95,7 @@ export const apiCreateUser = async ({prefix = 'user', user = null} = {}) => {
|
|||
|
||||
/**
|
||||
* Get user from a current session.
|
||||
* @return {Object} returns {user} on success or {error, status} on error
|
||||
*/
|
||||
export const apiGetMe = () => {
|
||||
return apiGetUserById('me');
|
||||
|
|
@ -99,7 +104,8 @@ export const apiGetMe = () => {
|
|||
/**
|
||||
* Get a user by ID.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}/get
|
||||
* @param {string} userId
|
||||
* @param {string} userId - the user ID
|
||||
* @return {Object} returns {user} on success or {error, status} on error
|
||||
*/
|
||||
export const apiGetUserById = async (userId) => {
|
||||
try {
|
||||
|
|
@ -114,7 +120,8 @@ export const apiGetUserById = async (userId) => {
|
|||
/**
|
||||
* Get a user by username.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1username~1{username}/get
|
||||
* @param {string} username
|
||||
* @param {string} username - the username
|
||||
* @return {Object} returns {user} on success or {error, status} on error
|
||||
*/
|
||||
export const apiGetUserByUsername = async (username) => {
|
||||
try {
|
||||
|
|
@ -126,6 +133,35 @@ export const apiGetUserByUsername = async (username) => {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Patch user from a current session.
|
||||
* @param {Object} userData - data to partially update a user
|
||||
* @return {Object} returns {user} on success or {error, status} on error
|
||||
*/
|
||||
export const apiPatchMe = (userData) => {
|
||||
return apiPatchUser('me', userData);
|
||||
};
|
||||
|
||||
/**
|
||||
* Patch a user.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1patch/put
|
||||
* @param {string} userId - the user ID
|
||||
* @param {Object} userData - data to partially update a user
|
||||
* @return {Object} returns {user} on success or {error, status} on error
|
||||
*/
|
||||
export const apiPatchUser = async (userId, userData) => {
|
||||
try {
|
||||
const response = await client.put(
|
||||
`/api/v4/users/${userId}/patch`,
|
||||
userData,
|
||||
);
|
||||
|
||||
return {user: response.data};
|
||||
} catch (err) {
|
||||
return getResponseFromError(err);
|
||||
}
|
||||
};
|
||||
|
||||
function generateRandomUser(prefix) {
|
||||
const randomId = getRandomId();
|
||||
|
||||
|
|
@ -147,6 +183,8 @@ export const User = {
|
|||
apiGetMe,
|
||||
apiGetUserById,
|
||||
apiGetUserByUsername,
|
||||
apiPatchMe,
|
||||
apiPatchUser,
|
||||
};
|
||||
|
||||
export default User;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
class Autocomplete {
|
||||
testID = {
|
||||
atMentionItemPrefix: 'autocomplete.at_mention.item.',
|
||||
channelMentionItemPrefix: 'autocomplete.channel_mention.item.',
|
||||
autocomplete: 'autocomplete',
|
||||
atMentionSuggestionList: 'at_mention_suggestion.list',
|
||||
channelMentionSuggestionList: 'channel_mention_suggestion.list',
|
||||
|
|
@ -19,7 +21,11 @@ class Autocomplete {
|
|||
slashSuggestionList = element(by.id(this.testID.slashSuggestionList));
|
||||
|
||||
getAtMentionItem = (userId) => {
|
||||
return element(by.id(`autocomplete.at_mention.item.${userId}`));
|
||||
return element(by.id(`${this.testID.atMentionItemPrefix}${userId}`));
|
||||
}
|
||||
|
||||
getChannelMentionItem = (channelId) => {
|
||||
return element(by.id(`${this.testID.channelMentionItemPrefix}${channelId}`));
|
||||
}
|
||||
|
||||
toBeVisible = async (isVisible = true) => {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,11 @@ class BottomSheet {
|
|||
|
||||
// bottom sheet options
|
||||
archivedChannelsOption = isAndroid() ? element(by.text('Archived Channels')) : element(by.label('Archived Channels')).atIndex(0);
|
||||
awayOption = isAndroid() ? element(by.text('Away')) : element(by.label('Away')).atIndex(0);
|
||||
cancelOption = isAndroid() ? element(by.text('Cancel')) : element(by.label('Cancel')).atIndex(0);
|
||||
doNotDisturbOption = isAndroid() ? element(by.text('Do Not Disturb')) : element(by.label('Do No Disturb')).atIndex(0);
|
||||
offlineOption = isAndroid() ? element(by.text('Offline')) : element(by.label('Offline')).atIndex(0);
|
||||
onlineOption = isAndroid() ? element(by.text('Online')) : element(by.label('Online')).atIndex(0);
|
||||
publicChannelsOption = isAndroid() ? element(by.text('Public Channels')) : element(by.label('Public Channels')).atIndex(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import Post from './post';
|
|||
import PostDraft from './post_draft';
|
||||
import PostList from './post_list';
|
||||
import PostOptions from './post_options';
|
||||
import ProfilePicture from './profile_picture';
|
||||
import RecentItem from './recent_item';
|
||||
import SearchBar from './search_bar';
|
||||
import SendButton from './send_button';
|
||||
|
|
@ -37,6 +38,7 @@ export {
|
|||
PostDraft,
|
||||
PostList,
|
||||
PostOptions,
|
||||
ProfilePicture,
|
||||
RecentItem,
|
||||
SearchBar,
|
||||
SendButton,
|
||||
|
|
|
|||
|
|
@ -1,31 +1,71 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import ProfilePicture from './profile_picture';
|
||||
|
||||
class Post {
|
||||
testID = {
|
||||
postProfilePicturePrefix: 'post_profile_picture.profile_picture.',
|
||||
message: 'markdown_text',
|
||||
postHeaderDateTime: 'post_header.date_time',
|
||||
postHeaderDisplayName: 'post_header.display_name',
|
||||
postHeaderReply: 'post_header.reply',
|
||||
postPreHeaderText: 'post_pre_header.text',
|
||||
markdownText: 'markdown_text',
|
||||
}
|
||||
|
||||
getPost = (postItemSourceTestID, postId, postMessage) => {
|
||||
const postTestID = `${postItemSourceTestID}.${postId}`;
|
||||
const baseMatcher = by.id(postTestID);
|
||||
const postItemMatcher = postMessage ? baseMatcher.withDescendant(by.text(postMessage)) : baseMatcher;
|
||||
const postItemHeaderReplyMatcher = by.id(this.testID.postHeaderReply).withAncestor(postItemMatcher);
|
||||
getPost = (postItemSourceTestID, postId, postMessage, postProfileOptions = {}) => {
|
||||
const postItemMatcher = this.getPostItemMatcher(postItemSourceTestID, postId, postMessage);
|
||||
const postItemMessageMatcher = by.id(this.testID.message).withAncestor(postItemMatcher);
|
||||
const postItemPreHeaderTextMatch = by.id(this.testID.postPreHeaderText).withAncestor(postItemMatcher);
|
||||
const postItemMessageMatcher = by.id(this.testID.markdownText).withAncestor(postItemMatcher);
|
||||
|
||||
return {
|
||||
postItem: element(postItemMatcher),
|
||||
postItemHeaderReply: element(postItemHeaderReplyMatcher),
|
||||
postItemPreHeaderText: element(postItemPreHeaderTextMatch),
|
||||
postItemMessage: element(postItemMessageMatcher),
|
||||
postItemPreHeaderText: element(postItemPreHeaderTextMatch),
|
||||
...this.getPostHeader(postItemMatcher),
|
||||
...this.getPostProfilePicture(postItemMatcher, postProfileOptions),
|
||||
};
|
||||
}
|
||||
|
||||
getPostHeader = (postItemMatcher) => {
|
||||
const postItemHeaderDateTimeMatcher = by.id(this.testID.postHeaderDateTime).withAncestor(postItemMatcher);
|
||||
const postItemHeaderDisplayNameMatcher = by.id(this.testID.postHeaderDisplayName).withAncestor(postItemMatcher);
|
||||
const postItemHeaderReplyMatcher = by.id(this.testID.postHeaderReply).withAncestor(postItemMatcher);
|
||||
|
||||
return {
|
||||
postItemHeaderDateTime: element(postItemHeaderDateTimeMatcher),
|
||||
postItemHeaderDisplayName: element(postItemHeaderDisplayNameMatcher),
|
||||
postItemHeaderReply: element(postItemHeaderReplyMatcher),
|
||||
};
|
||||
}
|
||||
|
||||
getPostItemMatcher = (postItemSourceTestID, postId, postMessage) => {
|
||||
const postTestID = `${postItemSourceTestID}.${postId}`;
|
||||
const baseMatcher = by.id(postTestID);
|
||||
return postMessage ? baseMatcher.withDescendant(by.text(postMessage)) : baseMatcher;
|
||||
}
|
||||
|
||||
getPostMessage = (postItemSourceTestID) => {
|
||||
return element(by.id(this.testID.markdownText).withAncestor(by.id(postItemSourceTestID)));
|
||||
return element(by.id(this.testID.message).withAncestor(by.id(postItemSourceTestID)));
|
||||
}
|
||||
|
||||
getPostProfilePicture = (postItemMatcher, postProfileOptions = {userId: null, userStatus: 'online'}) => {
|
||||
if (Object.keys(postProfileOptions).length === 0 || !postProfileOptions.userId) {
|
||||
return {
|
||||
postItemProfilePicture: null,
|
||||
postItemProfilePictureUserStatus: null,
|
||||
};
|
||||
}
|
||||
|
||||
const profilePictureItemMatcher = ProfilePicture.getProfilePictureItemMatcher(this.testID.postProfilePicturePrefix, postProfileOptions.userId);
|
||||
const profilePictureItemUserStatusMatcher = ProfilePicture.getProfilePictureItemUserStatusMatcher(profilePictureItemMatcher, postProfileOptions.userStatus);
|
||||
const postItemProfilePictureMatcher = profilePictureItemMatcher.withAncestor(postItemMatcher);
|
||||
const postItemProfilePictureUserStatusMatcher = profilePictureItemUserStatusMatcher.withAncestor(postItemMatcher);
|
||||
|
||||
return {
|
||||
postItemProfilePicture: element(postItemProfilePictureMatcher),
|
||||
postItemProfilePictureUserStatus: element(postItemProfilePictureUserStatusMatcher),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,19 +10,27 @@ class PostList {
|
|||
};
|
||||
}
|
||||
|
||||
getPost = (postId, postMessage) => {
|
||||
getPost = (postId, postMessage, postProfileOptions = {}) => {
|
||||
const {
|
||||
postItem,
|
||||
postItemHeaderDateTime,
|
||||
postItemHeaderDisplayName,
|
||||
postItemHeaderReply,
|
||||
postItemPreHeaderText,
|
||||
postItemMessage,
|
||||
} = Post.getPost(this.testID.postListPostItem, postId, postMessage);
|
||||
postItemPreHeaderText,
|
||||
postItemProfilePicture,
|
||||
postItemProfilePictureUserStatus,
|
||||
} = Post.getPost(this.testID.postListPostItem, postId, postMessage, postProfileOptions);
|
||||
|
||||
return {
|
||||
postListPostItem: postItem,
|
||||
postListPostItemHeaderDateTime: postItemHeaderDateTime,
|
||||
postListPostItemHeaderDisplayName: postItemHeaderDisplayName,
|
||||
postListPostItemHeaderReply: postItemHeaderReply,
|
||||
postListPostItemPreHeaderText: postItemPreHeaderText,
|
||||
postListPostItemMessage: postItemMessage,
|
||||
postListPostItemPreHeaderText: postItemPreHeaderText,
|
||||
postListPostItemProfilePicture: postItemProfilePicture,
|
||||
postListPostItemProfilePictureUserStatus: postItemProfilePictureUserStatus,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
21
detox/e2e/support/ui/component/profile_picture.js
Normal file
21
detox/e2e/support/ui/component/profile_picture.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
class ProfilePicture {
|
||||
testID = {
|
||||
userStatusIconPrefix: 'user_status.icon.',
|
||||
}
|
||||
|
||||
getProfilePictureItemMatcher = (profilePictureSourcePrefix, userId) => {
|
||||
const profilePictureTestID = `${profilePictureSourcePrefix}${userId}`;
|
||||
return by.id(profilePictureTestID);
|
||||
}
|
||||
|
||||
getProfilePictureItemUserStatusMatcher(profilePictureItemMatcher, userStatus = 'online') {
|
||||
const userStatusIconTestID = `${this.testID.userStatusIconPrefix}${userStatus}`;
|
||||
return by.id(userStatusIconTestID).withAncestor(profilePictureItemMatcher);
|
||||
}
|
||||
}
|
||||
|
||||
const profilePicture = new ProfilePicture();
|
||||
export default profilePicture;
|
||||
|
|
@ -3,11 +3,18 @@
|
|||
|
||||
class RecentItem {
|
||||
testID = {
|
||||
recentItemPrefix: 'search.recent_item.',
|
||||
recentSearchItemPrefix: 'search.recent_item.',
|
||||
recentSearchItemRemoveButtonSuffix: '.remove.button',
|
||||
}
|
||||
|
||||
getRecentItem = (searchTerms) => {
|
||||
return element(by.id(`${this.testID.recentItemPrefix}${searchTerms}`));
|
||||
getRecentSearchItem = (searchTerms) => {
|
||||
const recentSearchItemTestID = `${this.testID.recentSearchItemPrefix}${searchTerms}`;
|
||||
const recentSearchItemRemoveButtonTestID = `${recentSearchItemTestID}${this.testID.recentSearchItemRemoveButtonSuffix}`;
|
||||
|
||||
return {
|
||||
recentSearchItem: element(by.id(recentSearchItemTestID)),
|
||||
recentSearchItemRemoveButton: element(by.id(recentSearchItemRemoveButtonTestID)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import BottomSheet from './bottom_sheet';
|
||||
|
||||
class SettingsSidebar {
|
||||
testID = {
|
||||
userStatusIconPrefix: 'user_status.icon.',
|
||||
userStatusLabelPrefix: 'user_status.label.',
|
||||
settingsSidebar: 'settings.sidebar',
|
||||
userInfoAction: 'settings.sidebar.user_info.action',
|
||||
statusAction: 'settings.sidebar.status.action',
|
||||
|
|
@ -22,12 +26,55 @@ class SettingsSidebar {
|
|||
settingsAction = element(by.id(this.testID.settingsAction));
|
||||
logoutAction = element(by.id(this.testID.logoutAction));
|
||||
|
||||
getUserStatus(userStatus) {
|
||||
const userStatusIconTestID = `${this.testID.userStatusIconPrefix}${userStatus}`;
|
||||
const userStatusLabelTestID = `${this.testID.userStatusLabelPrefix}${userStatus}`;
|
||||
|
||||
return {
|
||||
userStatusIcon: element(by.id(userStatusIconTestID)),
|
||||
userStatusLabel: element(by.id(userStatusLabelTestID)),
|
||||
};
|
||||
}
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.settingsSidebar).toBeVisible();
|
||||
|
||||
return this.settingsSidebar;
|
||||
}
|
||||
|
||||
setUserStatusTo = async (userStatus) => {
|
||||
const {
|
||||
awayOption,
|
||||
doNotDisturbOption,
|
||||
offlineOption,
|
||||
onlineOption,
|
||||
} = BottomSheet;
|
||||
|
||||
// # Set user status
|
||||
await this.statusAction.tap();
|
||||
switch (userStatus) {
|
||||
case 'online':
|
||||
await onlineOption.tap();
|
||||
break;
|
||||
case 'away':
|
||||
await awayOption.tap();
|
||||
break;
|
||||
case 'dnd':
|
||||
await doNotDisturbOption.tap();
|
||||
break;
|
||||
case 'offline':
|
||||
await offlineOption.tap();
|
||||
break;
|
||||
default:
|
||||
throw new Error('Not a valid user status option: ' + userStatus);
|
||||
}
|
||||
|
||||
// * Verify user status
|
||||
const {userStatusIcon, userStatusLabel} = this.getUserStatus(userStatus);
|
||||
await expect(userStatusIcon).toBeVisible();
|
||||
await expect(userStatusLabel).toBeVisible();
|
||||
}
|
||||
|
||||
tapLogoutAction = async () => {
|
||||
await this.logoutAction.tap();
|
||||
await expect(this.settingsSidebar).not.toBeVisible();
|
||||
|
|
|
|||
|
|
@ -67,16 +67,16 @@ class ChannelScreen {
|
|||
|
||||
postList = new PostList(this.testID.channelScreenPrefix);
|
||||
|
||||
getLongPostItem = (postId, text) => {
|
||||
return LongPostScreen.getPost(postId, text);
|
||||
getLongPostItem = (postId, text, postProfileOptions = {}) => {
|
||||
return LongPostScreen.getPost(postId, text, postProfileOptions);
|
||||
}
|
||||
|
||||
getLongPostMessage = () => {
|
||||
return LongPostScreen.getPostMessage();
|
||||
}
|
||||
|
||||
getPostListPostItem = (postId, text) => {
|
||||
return this.postList.getPost(postId, text);
|
||||
getPostListPostItem = (postId, text, postProfileOptions = {}) => {
|
||||
return this.postList.getPost(postId, text, postProfileOptions);
|
||||
}
|
||||
|
||||
getPostMessageAtIndex = (index) => {
|
||||
|
|
|
|||
65
detox/e2e/support/ui/screen/clock_display_settings.js
Normal file
65
detox/e2e/support/ui/screen/clock_display_settings.js
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {DisplaySettingsScreen} from '@support/ui/screen';
|
||||
import {isAndroid} from '@support/utils';
|
||||
|
||||
class ClockDisplaySettingsScreen {
|
||||
testID = {
|
||||
clockDisplaySettingsScreen: 'clock_display_settings.screen',
|
||||
backButton: 'screen.back.button',
|
||||
militaryClockAction: 'clock_display_settings.military_clock.action',
|
||||
normalClockAction: 'clock_display_settings.normal_clock.action',
|
||||
|
||||
// ANDROID ONLY
|
||||
clockModal: 'clock_display_settings.clock.modal',
|
||||
clockModalCancelButton: 'clock_display_settings.clock_modal_cancel.button',
|
||||
clockModalSaveButton: 'clock_display_settings.clock_modal_save.button',
|
||||
}
|
||||
|
||||
clockDisplaySettingsScreen = element(by.id(this.testID.clockDisplaySettingsScreen));
|
||||
backButton = element(by.id(this.testID.backButton));
|
||||
militaryClockAction = element(by.id(this.testID.militaryClockAction));
|
||||
normalClockAction = element(by.id(this.testID.normalClockAction));
|
||||
|
||||
// ANDROID ONLY
|
||||
clockModal = element(by.id(this.testID.clockModal));
|
||||
clockModalCancelButton = element(by.id(this.testID.clockModalCancelButton));
|
||||
clockModalSaveButton = element(by.id(this.testID.clockModalSaveButton));
|
||||
|
||||
getClockActionFor = (clockKey) => {
|
||||
switch (clockKey) {
|
||||
case 'military':
|
||||
return this.militaryClockAction;
|
||||
case 'normal':
|
||||
return this.normalClockAction;
|
||||
default:
|
||||
throw new Error('Not a valid clock option: ' + clockKey);
|
||||
}
|
||||
}
|
||||
|
||||
toBeVisible = async () => {
|
||||
if (isAndroid()) {
|
||||
await expect(this.clockModal).toBeVisible();
|
||||
return this.clockModal;
|
||||
}
|
||||
|
||||
await expect(this.clockDisplaySettingsScreen).toBeVisible();
|
||||
return this.clockDisplaySettingsScreen;
|
||||
}
|
||||
|
||||
open = async () => {
|
||||
// # Open clock display settings screen
|
||||
await DisplaySettingsScreen.clockDisplayAction.tap();
|
||||
|
||||
return this.toBeVisible();
|
||||
}
|
||||
|
||||
back = async () => {
|
||||
await this.backButton.tap();
|
||||
await expect(this.clockDisplaySettingsScreen).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
const clockDisplaySettingsScreen = new ClockDisplaySettingsScreen();
|
||||
export default clockDisplaySettingsScreen;
|
||||
41
detox/e2e/support/ui/screen/display_settings.js
Normal file
41
detox/e2e/support/ui/screen/display_settings.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {GeneralSettingsScreen} from '@support/ui/screen';
|
||||
|
||||
class DisplaySettingsScreen {
|
||||
testID = {
|
||||
displaySettingsScreen: 'display_settings.screen',
|
||||
backButton: 'screen.back.button',
|
||||
clockDisplayAction: 'display_settings.clock_display.action',
|
||||
themeAction: 'display_settings.theme.action',
|
||||
timezoneAction: 'display_settings.timezone.action',
|
||||
}
|
||||
|
||||
displaySettingsScreen = element(by.id(this.testID.displaySettingsScreen));
|
||||
backButton = element(by.id(this.testID.backButton));
|
||||
clockDisplayAction = element(by.id(this.testID.clockDisplayAction));
|
||||
themeAction = element(by.id(this.testID.themeAction));
|
||||
timezoneAction = element(by.id(this.testID.timezoneAction));
|
||||
|
||||
toBeVisible = async () => {
|
||||
await expect(this.displaySettingsScreen).toBeVisible();
|
||||
|
||||
return this.displaySettingsScreen;
|
||||
}
|
||||
|
||||
open = async () => {
|
||||
// # Open display settings screen
|
||||
await GeneralSettingsScreen.displayAction.tap();
|
||||
|
||||
return this.toBeVisible();
|
||||
}
|
||||
|
||||
back = async () => {
|
||||
await this.backButton.tap();
|
||||
await expect(this.displaySettingsScreen).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
const displaySettingsScreen = new DisplaySettingsScreen();
|
||||
export default displaySettingsScreen;
|
||||
|
|
@ -5,7 +5,9 @@ import AddReactionScreen from './add_reaction';
|
|||
import ChannelInfoScreen from './channel_info';
|
||||
import ChannelNotificationPreferenceScreen from './channel_notification_preference';
|
||||
import ChannelScreen from './channel';
|
||||
import ClockDisplaySettingsScreen from './clock_display_settings';
|
||||
import CreateChannelScreen from './create_channel';
|
||||
import DisplaySettingsScreen from './display_settings';
|
||||
import EditChannelScreen from './edit_channel';
|
||||
import EditPostScreen from './edit_post';
|
||||
import GeneralSettingsScreen from './general_settings';
|
||||
|
|
@ -32,7 +34,9 @@ export {
|
|||
ChannelInfoScreen,
|
||||
ChannelNotificationPreferenceScreen,
|
||||
ChannelScreen,
|
||||
ClockDisplaySettingsScreen,
|
||||
CreateChannelScreen,
|
||||
DisplaySettingsScreen,
|
||||
EditChannelScreen,
|
||||
EditPostScreen,
|
||||
GeneralSettingsScreen,
|
||||
|
|
|
|||
|
|
@ -8,12 +8,25 @@ class LongPostScreen {
|
|||
longPostItem: 'long_post.post',
|
||||
}
|
||||
|
||||
getPost = (postId, postMessage) => {
|
||||
const {postItem, postItemHeaderReply, postItemMessage} = Post.getPost(this.testID.longPostItem, postId, postMessage);
|
||||
getPost = (postId, postMessage, postProfileOptions = {}) => {
|
||||
const {
|
||||
postItem,
|
||||
postItemHeaderDateTime,
|
||||
postItemHeaderDisplayName,
|
||||
postItemHeaderReply,
|
||||
postItemMessage,
|
||||
postItemProfilePicture,
|
||||
postItemProfilePictureUserStatus,
|
||||
} = Post.getPost(this.testID.longPostItem, postId, postMessage, postProfileOptions);
|
||||
|
||||
return {
|
||||
longPostItem: postItem,
|
||||
longPostItemHeaderDateTime: postItemHeaderDateTime,
|
||||
longPostItemHeaderDisplayName: postItemHeaderDisplayName,
|
||||
longPostItemHeaderReply: postItemHeaderReply,
|
||||
longPostItemMessage: postItemMessage,
|
||||
longPostItemProfilePicture: postItemProfilePicture,
|
||||
longPostItemProfilePictureUserStatus: postItemProfilePictureUserStatus,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import {
|
|||
|
||||
class MoreChannelsScreen {
|
||||
testID = {
|
||||
moreChannelsScreen: 'more_channels.screen',
|
||||
moreChannelsScreenPrefix: 'more_channels.',
|
||||
moreChannelsScreen: 'more_channels.screen',
|
||||
closeMoreChannelsButton: 'close.more_channels.button',
|
||||
createButton: 'more_channels.create.button',
|
||||
channelDropdown: 'more_channels.channel.dropdown',
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import {
|
|||
|
||||
class MoreDirectMessagesScreen {
|
||||
testID = {
|
||||
moreDirectMessagesScreenPrefix: 'more_direct_messages.',
|
||||
moreDirectMessagesScreen: 'more_direct_messages.screen',
|
||||
moreDirectMessagesPrefix: 'more_direct_messages.',
|
||||
startButton: 'more_direct_messages.start.button',
|
||||
usersList: 'more_direct_messages.custom_list',
|
||||
userItem: 'more_direct_messages.custom_list.user_item',
|
||||
|
|
@ -21,10 +21,10 @@ class MoreDirectMessagesScreen {
|
|||
usersList = element(by.id(this.testID.usersList));
|
||||
|
||||
// convenience props
|
||||
searchBar = SearchBar.getSearchBar(this.testID.moreDirectMessagesPrefix);
|
||||
searchInput = SearchBar.getSearchInput(this.testID.moreDirectMessagesPrefix);
|
||||
cancelButton = SearchBar.getCancelButton(this.testID.moreDirectMessagesPrefix);
|
||||
clearButton = SearchBar.getClearButton(this.testID.moreDirectMessagesPrefix);
|
||||
searchBar = SearchBar.getSearchBar(this.testID.moreDirectMessagesScreenPrefix);
|
||||
searchInput = SearchBar.getSearchInput(this.testID.moreDirectMessagesScreenPrefix);
|
||||
cancelButton = SearchBar.getCancelButton(this.testID.moreDirectMessagesScreenPrefix);
|
||||
clearButton = SearchBar.getClearButton(this.testID.moreDirectMessagesScreenPrefix);
|
||||
|
||||
getUser = (userId, diplayUsername) => {
|
||||
const userItemTestID = `${this.testID.userItem}.${userId}`;
|
||||
|
|
|
|||
|
|
@ -16,16 +16,16 @@ class PermalinkScreen {
|
|||
|
||||
postList = new PostList(this.testID.permalinkScreenPrefix);
|
||||
|
||||
getLongPostItem = (postId, text) => {
|
||||
return LongPostScreen.getPost(postId, text);
|
||||
getLongPostItem = (postId, text, postProfileOptions = {}) => {
|
||||
return LongPostScreen.getPost(postId, text, postProfileOptions);
|
||||
}
|
||||
|
||||
getLongPostMessage = () => {
|
||||
return LongPostScreen.getPostMessage();
|
||||
}
|
||||
|
||||
getPostListPostItem = (postId, text) => {
|
||||
return this.postList.getPost(postId, text);
|
||||
getPostListPostItem = (postId, text, postProfileOptions = {}) => {
|
||||
return this.postList.getPost(postId, text, postProfileOptions);
|
||||
}
|
||||
|
||||
getPostMessageAtIndex = (index) => {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ class PinnedMessagesScreen {
|
|||
pinnedMessagesScreen = element(by.id(this.testID.pinnedMessagesScreen));
|
||||
backButton = element(by.id(this.testID.backButton));
|
||||
|
||||
getSearchResultPostItem = (postId, text) => {
|
||||
return SearchResultPostScreen.getPost(postId, text);
|
||||
getSearchResultPostItem = (postId, text, postProfileOptions = {}) => {
|
||||
return SearchResultPostScreen.getPost(postId, text, postProfileOptions);
|
||||
}
|
||||
|
||||
toBeVisible = async () => {
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ class RecentMentionsScreen {
|
|||
recentMentionsScreen = element(by.id(this.testID.recentMentionsScreen));
|
||||
closeSettingsButton = element(by.id(this.testID.closeSettingsButton));
|
||||
|
||||
getSearchResultPostItem = (postId, text) => {
|
||||
return SearchResultPostScreen.getPost(postId, text);
|
||||
getSearchResultPostItem = (postId, text, postProfileOptions = {}) => {
|
||||
return SearchResultPostScreen.getPost(postId, text, postProfileOptions);
|
||||
}
|
||||
|
||||
toBeVisible = async () => {
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ class SavedMessagesScreen {
|
|||
savedMessagesScreen = element(by.id(this.testID.savedMessagesScreen));
|
||||
closeSettingsButton = element(by.id(this.testID.closeSettingsButton));
|
||||
|
||||
getSearchResultPostItem = (postId, text) => {
|
||||
return SearchResultPostScreen.getPost(postId, text);
|
||||
getSearchResultPostItem = (postId, text, postProfileOptions = {}) => {
|
||||
return SearchResultPostScreen.getPost(postId, text, postProfileOptions);
|
||||
}
|
||||
|
||||
toBeVisible = async () => {
|
||||
|
|
|
|||
|
|
@ -41,11 +41,11 @@ class SearchScreen {
|
|||
clearButton = SearchBar.getClearButton(this.testID.searchScreenPrefix);
|
||||
|
||||
getRecentSearchItem = (searchTerms) => {
|
||||
return RecentItem.getRecentItem(searchTerms);
|
||||
return RecentItem.getRecentSearchItem(searchTerms);
|
||||
}
|
||||
|
||||
getSearchResultPostItem = (postId, text) => {
|
||||
return SearchResultPostScreen.getPost(postId, text);
|
||||
getSearchResultPostItem = (postId, text, postProfileOptions = {}) => {
|
||||
return SearchResultPostScreen.getPost(postId, text, postProfileOptions);
|
||||
}
|
||||
|
||||
getSearchResultPostMessageAtIndex = (index) => {
|
||||
|
|
|
|||
|
|
@ -8,12 +8,25 @@ class SearchResultPostScreen {
|
|||
searchResultPostItem: 'search_result_post.post',
|
||||
}
|
||||
|
||||
getPost = (postId, postMessage) => {
|
||||
const {postItem, postItemHeaderReply, postItemMessage} = Post.getPost(this.testID.searchResultPostItem, postId, postMessage);
|
||||
getPost = (postId, postMessage, postProfileOptions = {}) => {
|
||||
const {
|
||||
postItem,
|
||||
postItemHeaderDateTime,
|
||||
postItemHeaderDisplayName,
|
||||
postItemHeaderReply,
|
||||
postItemMessage,
|
||||
postItemProfilePicture,
|
||||
postItemProfilePictureUserStatus,
|
||||
} = Post.getPost(this.testID.searchResultPostItem, postId, postMessage, postProfileOptions);
|
||||
|
||||
return {
|
||||
searchResultPostItem: postItem,
|
||||
searchResultPostItemHeaderDateTime: postItemHeaderDateTime,
|
||||
searchResultPostItemHeaderDisplayName: postItemHeaderDisplayName,
|
||||
searchResultPostItemHeaderReply: postItemHeaderReply,
|
||||
searchResultPostItemMessage: postItemMessage,
|
||||
searchResultPostItemProfilePicture: postItemProfilePicture,
|
||||
searchResultPostItemProfilePictureUserStatus: postItemProfilePictureUserStatus,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,16 +44,16 @@ class ThreadScreen {
|
|||
|
||||
postList = new PostList(this.testID.threadScreenPrefix);
|
||||
|
||||
getLongPostItem = (postId, text) => {
|
||||
return LongPostScreen.getPost(postId, text);
|
||||
getLongPostItem = (postId, text, postProfileOptions = {}) => {
|
||||
return LongPostScreen.getPost(postId, text, postProfileOptions);
|
||||
}
|
||||
|
||||
getLongPostMessage = () => {
|
||||
return LongPostScreen.getPostMessage();
|
||||
}
|
||||
|
||||
getPostListPostItem = (postId, text) => {
|
||||
return this.postList.getPost(postId, text);
|
||||
getPostListPostItem = (postId, text, postProfileOptions = {}) => {
|
||||
return this.postList.getPost(postId, text, postProfileOptions);
|
||||
}
|
||||
|
||||
getPostMessageAtIndex = (index) => {
|
||||
|
|
|
|||
112
detox/e2e/test/smoke_test/clock_display.e2e.js
Normal file
112
detox/e2e/test/smoke_test/clock_display.e2e.js
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
// 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 moment from 'moment-timezone';
|
||||
|
||||
import {
|
||||
ChannelScreen,
|
||||
ClockDisplaySettingsScreen,
|
||||
DisplaySettingsScreen,
|
||||
GeneralSettingsScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {
|
||||
Channel,
|
||||
Post,
|
||||
Setup,
|
||||
System,
|
||||
User,
|
||||
} from '@support/server_api';
|
||||
import {isAndroid, isIos} from '@support/utils';
|
||||
|
||||
describe('Clock Display', () => {
|
||||
const testDate = Date.UTC(new Date().getFullYear() + 1, 0, 5, 14, 37); // Jan 5, 2:37pm
|
||||
const testTimezone = 'UTC';
|
||||
const testFullDate = moment(testDate).tz(testTimezone).format();
|
||||
const testMilitaryTime = moment(testDate).tz(testTimezone).format('HH:mm');
|
||||
const testNormalTime = moment(testDate).tz(testTimezone).format('h:mm A');
|
||||
const testMessage = `Hello from ${testFullDate}, ${testTimezone}`;
|
||||
let testChannel;
|
||||
|
||||
beforeAll(async () => {
|
||||
// # Enable timezone
|
||||
await System.apiUpdateConfig({DisplaySettings: {ExperimentalTimezone: true}});
|
||||
|
||||
const {team, user} = await Setup.apiInit();
|
||||
({channel: testChannel} = await Channel.apiGetChannelByName(team.name, 'town-square'));
|
||||
|
||||
// # Set user's timezone
|
||||
await User.apiPatchUser(user.id, {timezone: {automaticTimezone: '', manualTimezone: testTimezone, useAutomaticTimezone: 'false'}});
|
||||
|
||||
// # Post message with a future date as sysadmin
|
||||
await User.apiAdminLogin();
|
||||
await Post.apiCreatePost({
|
||||
channelId: testChannel.id,
|
||||
message: testMessage,
|
||||
createAt: testDate,
|
||||
});
|
||||
|
||||
// # Open channel screen
|
||||
await ChannelScreen.open(user);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3257 should be able to set clock display to 12-hour', async () => {
|
||||
// # Set clock display to normal (12-hour)
|
||||
await setClockDisplayTo('normal');
|
||||
|
||||
// * Verify clock display is normal
|
||||
await verifyClockDisplay(testChannel, testMessage, testNormalTime);
|
||||
});
|
||||
|
||||
it('MM-T3258 should be able to set clock display to 24-hour', async () => {
|
||||
// # Set clock display to military (24-hour)
|
||||
await setClockDisplayTo('military');
|
||||
|
||||
// * Verify clock display is military
|
||||
await verifyClockDisplay(testChannel, testMessage, testMilitaryTime);
|
||||
});
|
||||
});
|
||||
|
||||
async function setClockDisplayTo(clockKey) {
|
||||
const {
|
||||
clockModalSaveButton,
|
||||
getClockActionFor,
|
||||
} = ClockDisplaySettingsScreen;
|
||||
|
||||
// # Open clock display settings screen
|
||||
await ChannelScreen.openSettingsSidebar();
|
||||
await GeneralSettingsScreen.open();
|
||||
await DisplaySettingsScreen.open();
|
||||
await ClockDisplaySettingsScreen.open();
|
||||
|
||||
// # Tap on clock option
|
||||
await getClockActionFor(clockKey).tap();
|
||||
|
||||
// # Tap on Save button if Android
|
||||
if (isAndroid()) {
|
||||
await clockModalSaveButton.tap();
|
||||
}
|
||||
|
||||
// # Go back to channel
|
||||
await ClockDisplaySettingsScreen.back();
|
||||
if (isIos()) {
|
||||
await DisplaySettingsScreen.back();
|
||||
}
|
||||
await GeneralSettingsScreen.close();
|
||||
}
|
||||
|
||||
async function verifyClockDisplay(testChannel, testMessage, clockDisplay) {
|
||||
// * Verify clock display
|
||||
const {post} = await Post.apiGetLastPostInChannel(testChannel.id);
|
||||
const {postListPostItemHeaderDateTime} = await ChannelScreen.getPostListPostItem(post.id, testMessage);
|
||||
await expect(postListPostItemHeaderDateTime).toHaveText(clockDisplay);
|
||||
}
|
||||
|
|
@ -77,11 +77,11 @@ describe('Email Notifications', () => {
|
|||
await navigateBackToChannel();
|
||||
|
||||
// # Post an at-mention message to mentioned user by other user
|
||||
const message = `Mention @${testUser.username} by ${testOtherUser1.username}`;
|
||||
const testMessage = `Mention @${testUser.username} by ${testOtherUser1.username}`;
|
||||
await User.apiLogin(testOtherUser1);
|
||||
await Post.apiCreatePost({
|
||||
channelId: testChannel.id,
|
||||
message,
|
||||
message: testMessage,
|
||||
});
|
||||
|
||||
// * Verify mentioned user receives email notification
|
||||
|
|
@ -93,7 +93,7 @@ describe('Email Notifications', () => {
|
|||
testChannel.display_name,
|
||||
testUser,
|
||||
testOtherUser1,
|
||||
message,
|
||||
testMessage,
|
||||
testConfig.EmailSettings.FeedbackEmail,
|
||||
testConfig.SupportSettings.SupportEmail);
|
||||
});
|
||||
|
|
@ -108,17 +108,17 @@ describe('Email Notifications', () => {
|
|||
await navigateBackToChannel();
|
||||
|
||||
// # Post an at-mention message to mentioned user by other user
|
||||
const message = `Mention @${testUser.username} by ${testOtherUser2.username}`;
|
||||
const testMessage = `Mention @${testUser.username} by ${testOtherUser2.username}`;
|
||||
await User.apiLogin(testOtherUser2);
|
||||
await Post.apiCreatePost({
|
||||
channelId: testChannel.id,
|
||||
message,
|
||||
message: testMessage,
|
||||
});
|
||||
|
||||
// * Verify mentioned user does not receive email notification
|
||||
const {data} = await getRecentEmail(testUser.username);
|
||||
const bodyText = splitEmailBodyText(data.body.text);
|
||||
jestExpect(bodyText[7]).not.toEqual(message);
|
||||
jestExpect(bodyText[7]).not.toEqual(testMessage);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -21,11 +21,15 @@ import {
|
|||
} from '@support/server_api';
|
||||
|
||||
describe('Search', () => {
|
||||
const testMessage = `test ${Date.now().toString()}`;
|
||||
const partialSearchTerm = testMessage.split('-')[0];
|
||||
const {
|
||||
atMentionSuggestionList,
|
||||
channelMentionSuggestionList,
|
||||
} = Autocomplete;
|
||||
let testUser;
|
||||
let testChannel;
|
||||
|
||||
const {atMentionSuggestionList} = Autocomplete;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {team, user} = await Setup.apiInit();
|
||||
testUser = user;
|
||||
|
|
@ -41,11 +45,33 @@ describe('Search', () => {
|
|||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3236 search on sender, select from autocomplete, reply from search results', async () => {
|
||||
const testMessage = Date.now().toString();
|
||||
it('MM-T3235 search on text, jump to result', async () => {
|
||||
// # Post message and search on text
|
||||
await postMessageAndSearchText(testMessage, partialSearchTerm);
|
||||
|
||||
// # Open permalink from search result post item
|
||||
const lastPost = await Post.apiGetLastPostInChannel(testChannel.id);
|
||||
const {searchResultPostItem} = await SearchScreen.getSearchResultPostItem(lastPost.post.id, testMessage);
|
||||
await expect(searchResultPostItem).toBeVisible();
|
||||
await searchResultPostItem.tap();
|
||||
|
||||
// * Verify permalink post list has the message
|
||||
await PermalinkScreen.toBeVisible();
|
||||
const {postListPostItem: permalinkPostItem} = await PermalinkScreen.getPostListPostItem(lastPost.post.id, testMessage);
|
||||
await waitFor(permalinkPostItem).toBeVisible();
|
||||
|
||||
// # Jump to recent messages
|
||||
await PermalinkScreen.jumpToRecentMessages();
|
||||
|
||||
// * Verify user is on channel where message is posted
|
||||
await expect(ChannelScreen.channelNavBarTitle).toHaveText(testChannel.display_name);
|
||||
const {postListPostItem: channelPostItem} = await ChannelScreen.getPostListPostItem(lastPost.post.id, testMessage);
|
||||
await expect(channelPostItem).toBeVisible();
|
||||
});
|
||||
|
||||
it('MM-T3236 search on sender, select from autocomplete, reply from search results', async () => {
|
||||
// # Post message and search on sender
|
||||
await postMessageAndSearchFrom(testMessage, testUser, atMentionSuggestionList);
|
||||
await postMessageAndSearchFrom(testMessage, testUser, atMentionSuggestionList, partialSearchTerm);
|
||||
|
||||
// * Verify search result post has the message
|
||||
const lastPost = await Post.apiGetLastPostInChannel(testChannel.id);
|
||||
|
|
@ -73,35 +99,53 @@ describe('Search', () => {
|
|||
await SearchScreen.cancel();
|
||||
});
|
||||
|
||||
it('MM-T3235 search on text, jump to result', async () => {
|
||||
const testMessage = Date.now().toString();
|
||||
it('MM-T3237 search on channel, select from autocomplete, search in combination with a text string as well', async () => {
|
||||
// # Post message and search in channel
|
||||
await postMessageAndSearchIn(testMessage, testChannel, channelMentionSuggestionList, partialSearchTerm);
|
||||
|
||||
// # Post message and search on text
|
||||
await postMessageAndSearchText(testMessage);
|
||||
|
||||
// # Open permalink from search result post item
|
||||
// * Verify search result post has the message
|
||||
const lastPost = await Post.apiGetLastPostInChannel(testChannel.id);
|
||||
const {searchResultPostItem} = await SearchScreen.getSearchResultPostItem(lastPost.post.id, testMessage);
|
||||
await expect(searchResultPostItem).toBeVisible();
|
||||
await searchResultPostItem.tap();
|
||||
|
||||
// * Verify permalink post list has the message
|
||||
await PermalinkScreen.toBeVisible();
|
||||
const {postListPostItem: permalinkPostItem} = await PermalinkScreen.getPostListPostItem(lastPost.post.id, testMessage);
|
||||
await waitFor(permalinkPostItem).toBeVisible();
|
||||
// # Go back to channel
|
||||
await SearchScreen.cancel();
|
||||
});
|
||||
|
||||
// # Jump to recent messages
|
||||
await PermalinkScreen.jumpToRecentMessages();
|
||||
it('MM-T3238 delete one previous search, tap on another', async () => {
|
||||
const {
|
||||
getRecentSearchItem,
|
||||
searchInModifier,
|
||||
} = SearchScreen;
|
||||
|
||||
// * Verify user is on channel where message is posted
|
||||
await expect(ChannelScreen.channelNavBarTitle).toHaveText(testChannel.display_name);
|
||||
const {postListPostItem: channelPostItem} = await ChannelScreen.getPostListPostItem(lastPost.post.id, testMessage);
|
||||
await expect(channelPostItem).toBeVisible();
|
||||
// # Open search screen
|
||||
await SearchScreen.open();
|
||||
|
||||
// # Delete one previous text search
|
||||
const previousTextSearch = await getRecentSearchItem(testMessage);
|
||||
await previousTextSearch.recentSearchItemRemoveButton.tap();
|
||||
|
||||
// * Verify previous text search is removed
|
||||
await expect(previousTextSearch.recentSearchItem).not.toBeVisible();
|
||||
|
||||
// # Tap on previous in search
|
||||
const inSearchTerms = `${searchInModifier} ${testChannel.name} ${partialSearchTerm}`;
|
||||
const previousInSearch = await getRecentSearchItem(inSearchTerms);
|
||||
await previousInSearch.recentSearchItem.tap();
|
||||
|
||||
// * Verify search result post has the message
|
||||
const lastPost = await Post.apiGetLastPostInChannel(testChannel.id);
|
||||
const {searchResultPostItem} = await SearchScreen.getSearchResultPostItem(lastPost.post.id, testMessage);
|
||||
await expect(searchResultPostItem).toBeVisible();
|
||||
|
||||
// # Go back to channel
|
||||
await SearchScreen.cancel();
|
||||
});
|
||||
});
|
||||
|
||||
async function postMessageAndSearchFrom(testMessage, testUser, atMentionSuggestionList) {
|
||||
async function postMessageAndSearchFrom(testMessage, testUser, atMentionSuggestionList, partialSearchTerm) {
|
||||
const {
|
||||
getRecentSearchItem,
|
||||
searchFromModifier,
|
||||
searchFromSection,
|
||||
searchInput,
|
||||
|
|
@ -126,18 +170,64 @@ async function postMessageAndSearchFrom(testMessage, testUser, atMentionSuggesti
|
|||
const userAtMentionAutocomplete = await Autocomplete.getAtMentionItem(testUser.id);
|
||||
await userAtMentionAutocomplete.tap();
|
||||
|
||||
// # Type end of search term
|
||||
await searchInput.typeText(partialSearchTerm);
|
||||
|
||||
// # Search user
|
||||
await searchInput.tapReturnKey();
|
||||
await expect(atMentionSuggestionList).not.toExist();
|
||||
|
||||
// * Verify recent search item is displayed
|
||||
const searchTerms = `${searchFromModifier} ${testUser.username}`;
|
||||
const recentSearchItem = await SearchScreen.getRecentSearchItem(searchTerms);
|
||||
const searchTerms = `${searchFromModifier} ${testUser.username} ${partialSearchTerm}`;
|
||||
const {recentSearchItem} = await getRecentSearchItem(searchTerms);
|
||||
await expect(recentSearchItem).toBeVisible();
|
||||
}
|
||||
|
||||
async function postMessageAndSearchText(testMessage) {
|
||||
const {searchInput} = SearchScreen;
|
||||
async function postMessageAndSearchIn(testMessage, testChannel, channelMentionSuggestionList, partialSearchTerm) {
|
||||
const {
|
||||
getRecentSearchItem,
|
||||
searchInModifier,
|
||||
searchInSection,
|
||||
searchInput,
|
||||
} = SearchScreen;
|
||||
|
||||
// # Post a message
|
||||
await ChannelScreen.postMessage(testMessage);
|
||||
|
||||
// # Open search screen
|
||||
await SearchScreen.open();
|
||||
|
||||
// # Tap "in:" modifier
|
||||
await searchInput.clearText();
|
||||
await searchInSection.tap();
|
||||
|
||||
// # Type beginning of search term
|
||||
const searchTerm = testChannel.name;
|
||||
await searchInput.typeText(searchTerm);
|
||||
|
||||
// # Select channel from autocomplete
|
||||
await expect(channelMentionSuggestionList).toExist();
|
||||
const channelMentionAutocomplete = await Autocomplete.getChannelMentionItem(testChannel.id);
|
||||
await channelMentionAutocomplete.tap();
|
||||
|
||||
// # Type end of search term
|
||||
await searchInput.typeText(partialSearchTerm);
|
||||
|
||||
// # Search channel
|
||||
await searchInput.tapReturnKey();
|
||||
await expect(channelMentionSuggestionList).not.toExist();
|
||||
|
||||
// * Verify recent search item is displayed
|
||||
const searchTerms = `${searchInModifier} ${testChannel.name} ${partialSearchTerm}`;
|
||||
const {recentSearchItem} = await getRecentSearchItem(searchTerms);
|
||||
await expect(recentSearchItem).toBeVisible();
|
||||
}
|
||||
|
||||
async function postMessageAndSearchText(testMessage, partialSearchTerm) {
|
||||
const {
|
||||
getRecentSearchItem,
|
||||
searchInput,
|
||||
} = SearchScreen;
|
||||
|
||||
// # Post a message
|
||||
await ChannelScreen.postMessage(testMessage);
|
||||
|
|
@ -147,12 +237,12 @@ async function postMessageAndSearchText(testMessage) {
|
|||
|
||||
// # Type beginning of search term
|
||||
await searchInput.clearText();
|
||||
await searchInput.typeText(testMessage);
|
||||
await searchInput.typeText(partialSearchTerm);
|
||||
|
||||
// # Search text
|
||||
await searchInput.tapReturnKey();
|
||||
|
||||
// * Verify recent search item is displayed
|
||||
const recentSearchItem = await SearchScreen.getRecentSearchItem(testMessage);
|
||||
const {recentSearchItem} = await getRecentSearchItem(testMessage);
|
||||
await expect(recentSearchItem).toBeVisible();
|
||||
}
|
||||
|
|
|
|||
75
detox/e2e/test/smoke_test/user_status.e2e.js
Normal file
75
detox/e2e/test/smoke_test/user_status.e2e.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// 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 {
|
||||
MainSidebar,
|
||||
SettingsSidebar,
|
||||
} from '@support/ui/component';
|
||||
import {ChannelScreen} from '@support/ui/screen';
|
||||
import {
|
||||
Channel,
|
||||
Post,
|
||||
Setup,
|
||||
Team,
|
||||
User,
|
||||
} from '@support/server_api';
|
||||
|
||||
describe('User Status', () => {
|
||||
const testMessage = Date.now().toString();
|
||||
let testUser;
|
||||
let testOtherUser;
|
||||
let testChannel;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {user, team} = await Setup.apiInit();
|
||||
testUser = user;
|
||||
|
||||
({user: testOtherUser} = await User.apiCreateUser());
|
||||
await Team.apiAddUserToTeam(testOtherUser.id, team.id);
|
||||
|
||||
({channel: testChannel} = await Channel.apiCreateDirectChannel([testUser.id, testOtherUser.id]));
|
||||
await User.apiLogin(testUser);
|
||||
await Post.apiCreatePost({
|
||||
channelId: testChannel.id,
|
||||
message: testMessage,
|
||||
});
|
||||
|
||||
// # Open channel screen
|
||||
await ChannelScreen.open(testUser);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T3251 should be able to set status', async () => {
|
||||
const {
|
||||
closeSettingsSidebar,
|
||||
getPostListPostItem,
|
||||
openMainSidebar,
|
||||
openSettingsSidebar,
|
||||
} = ChannelScreen;
|
||||
|
||||
// # Set user status to away
|
||||
await openSettingsSidebar();
|
||||
await SettingsSidebar.setUserStatusTo('away');
|
||||
await closeSettingsSidebar();
|
||||
|
||||
// # Login as other user
|
||||
await ChannelScreen.logout();
|
||||
await ChannelScreen.open(testOtherUser);
|
||||
|
||||
// * Verify user's profile has status away as seen by other user
|
||||
await openMainSidebar();
|
||||
await MainSidebar.getChannelByDisplayName(testUser.username).tap();
|
||||
const {post} = await Post.apiGetLastPostInChannel(testChannel.id);
|
||||
const {postListPostItemProfilePictureUserStatus} = await getPostListPostItem(post.id, testMessage, {userId: testUser.id, userStatus: 'away'});
|
||||
await expect(postListPostItemProfilePictureUserStatus).toBeVisible();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue