Detox/E2E: Account e2e tests in Gekidou (#6584)

* Detox/E2E: Account e2e tests in Gekidou

* Fix suite title

* Changed ldap port to number

* Fix testIDs for settings

* Added zephyr test case keys
This commit is contained in:
Joseph Baylon
2022-08-18 03:18:46 -07:00
committed by GitHub
parent 1fa248b5a7
commit 25ae8fdb88
43 changed files with 453 additions and 55 deletions

View File

@@ -65,7 +65,12 @@ const TabletTitle = ({action, enabled = true, onPress, testID, title}: Props) =>
<>
<View style={styles.container}>
<View style={styles.titleContainer}>
<Text style={styles.title}>{title}</Text>
<Text
style={styles.title}
testID={`${testID}.title`}
>
{title}
</Text>
</View>
{Boolean(action) &&
<View style={styles.actionContainer}>
@@ -73,7 +78,7 @@ const TabletTitle = ({action, enabled = true, onPress, testID, title}: Props) =>
disabled={!enabled}
onPress={onPress}
type={Platform.select({android: 'native', ios: 'opacity'})}
testID={testID}
testID={`${testID}.${action?.toLocaleLowerCase()}.button`}
underlayColor={changeOpacity(theme.centerChannelColor, 0.1)}
>
<Text style={textStyle}>{action}</Text>

View File

@@ -9,7 +9,7 @@ exports[`UserStatus should match snapshot, away status 1`] = `
"fontSize": 32,
}
}
testID="user_status.icon.away"
testID="user_status.indicator.away"
/>
`;
@@ -22,7 +22,7 @@ exports[`UserStatus should match snapshot, dnd status 1`] = `
"fontSize": 32,
}
}
testID="user_status.icon.dnd"
testID="user_status.indicator.dnd"
/>
`;
@@ -35,7 +35,7 @@ exports[`UserStatus should match snapshot, online status 1`] = `
"fontSize": 32,
}
}
testID="user_status.icon.online"
testID="user_status.indicator.online"
/>
`;
@@ -48,6 +48,6 @@ exports[`UserStatus should match snapshot, should default to offline status 1`]
"fontSize": 32,
}
}
testID="user_status.icon.offline"
testID="user_status.indicator.offline"
/>
`;

View File

@@ -40,7 +40,7 @@ const UserStatus = ({size = 6, status = General.OFFLINE}: UserStatusProps) => {
<CompassIcon
name={iconName}
style={{fontSize: size, color: iconColor}}
testID={`user_status.icon.${status}`}
testID={`user_status.indicator.${status}`}
/>
);
};

View File

@@ -70,7 +70,7 @@ const ChannelInfo = ({
bounces={true}
alwaysBounceVertical={false}
contentContainerStyle={styles.content}
testID='channel_info.scrollview'
testID='channel_info.scroll_view'
>
<Title
channelId={channelId}

View File

@@ -276,7 +276,7 @@ export default function ChannelInfoForm({
ref={mainView}
>
<KeyboardAwareScrollView
testID={'create_or_edit_channel.scrollview'}
testID={'create_or_edit_channel.scroll_view'}
ref={scrollViewRef}
keyboardShouldPersistTaps={'always'}
enableAutomaticScroll={!keyboardVisible}

View File

@@ -333,7 +333,7 @@ class CustomStatusModal extends NavigationComponent<Props, State> {
<TabletTitle
action={intl.formatMessage({id: 'mobile.custom_status.modal_confirm', defaultMessage: 'Done'})}
onPress={this.handleSetStatus}
testID='custom_status.done.button'
testID='custom_status'
title={intl.formatMessage({id: 'mobile.routes.custom_status', defaultMessage: 'Set a Status'})}
/>
}
@@ -352,6 +352,7 @@ class CustomStatusModal extends NavigationComponent<Props, State> {
bounces={false}
keyboardDismissMode='none'
keyboardShouldPersistTaps='always'
testID='custom_status.scroll_view'
>
<View style={style.scrollView}>
<View style={style.block}>

View File

@@ -103,7 +103,7 @@ const EditProfilePicture = ({user, onUpdateProfilePicture}: ChangeProfilePicture
return (
<View
style={styles.container}
testID={`${EditProfilePicture}.${user.id}`}
testID={`edit_profile.${user.id}.profile_picture`}
>
<ProfileImage
size={SIZE}

View File

@@ -85,13 +85,18 @@ const EmailField = ({
onFocusNextField={onFocusNextField}
onTextChange={onChange}
returnKeyType='next'
testID='edit_profile.text_setting.email'
testID='edit_profile_form.email'
value={email}
/>
<View
style={descContainer}
>
<Text style={style.text}>{fieldDescription}</Text>
<Text
style={style.text}
testID='edit_profile_form.email.description'
>
{fieldDescription}
</Text>
</View>
</>

View File

@@ -72,6 +72,7 @@ const Field = ({
const textInputStyle = isDisabled ? style.disabledStyle : undefined;
const subContainer = [style.viewContainer, {paddingHorizontal: isTablet ? 42 : 20}];
const fieldInputTestId = isDisabled ? `${testID}.input.disabled` : `${testID}.input`;
return (
<View
@@ -88,7 +89,7 @@ const Field = ({
label={formattedLabel}
maxLength={maxLength}
onChangeText={onChangeText}
testID={`${testID}.input`}
testID={fieldInputTestId}
theme={theme}
value={value}
ref={fieldRef}

View File

@@ -169,7 +169,7 @@ const ProfileForm = ({
fieldRef={firstNameRef}
isDisabled={userProfileFields.firstName.isDisabled}
label={formatMessage(FIELDS.firstName)}
testID='edit_profile.text_setting.firstName'
testID='edit_profile_form.first_name'
value={userInfo.firstName}
{...fieldConfig}
/>
@@ -179,7 +179,7 @@ const ProfileForm = ({
fieldRef={lastNameRef}
isDisabled={userProfileFields.lastName.isDisabled}
label={formatMessage(FIELDS.lastName)}
testID='edit_profile.text_setting.lastName'
testID='edit_profile_form.last_name'
value={userInfo.lastName}
{...fieldConfig}
/>
@@ -190,7 +190,7 @@ const ProfileForm = ({
isDisabled={userProfileFields.username.isDisabled}
label={formatMessage(FIELDS.username)}
maxLength={22}
testID='edit_profile.text_setting.username'
testID='edit_profile_form.username'
value={userInfo.username}
{...fieldConfig}
/>
@@ -215,7 +215,7 @@ const ProfileForm = ({
isDisabled={userProfileFields.nickname.isDisabled}
label={formatMessage(FIELDS.nickname)}
maxLength={22}
testID='edit_profile.text_setting.nickname'
testID='edit_profile_form.nickname'
value={userInfo.nickname}
{...fieldConfig}
/>
@@ -229,7 +229,7 @@ const ProfileForm = ({
maxLength={128}
{...fieldConfig}
returnKeyType='done'
testID='edit_profile.text_setting.position'
testID='edit_profile_form.position'
value={userInfo.position}
/>
<View style={styles.footer}/>

View File

@@ -24,6 +24,7 @@ const UserProfilePicture = ({currentUser, lockedPicture, onUpdateProfilePicture}
author={currentUser}
size={USER_PROFILE_PICTURE_SIZE}
showStatus={false}
testID={`edit_profile.${currentUser.id}.profile_picture`}
/>
);
}

View File

@@ -81,7 +81,7 @@ const EditProfile = ({
return isTablet ? null : {
id: CLOSE_BUTTON_ID,
icon: CompassIcon.getImageSourceSync('close', 24, theme.centerChannelColor),
testID: CLOSE_BUTTON_ID,
testID: 'close.edit_profile.button',
};
}, [isTablet, theme.centerChannelColor]);
@@ -193,7 +193,7 @@ const EditProfile = ({
action={buttonText}
enabled={canSave}
onPress={submitUser}
testID='custom_status.done.button'
testID='edit_profile'
title={intl.formatMessage({id: 'mobile.screen.your_profile', defaultMessage: 'Your Profile'})}
/>
}

View File

@@ -87,6 +87,7 @@ const CustomStatus = ({isCustomStatusExpirySupported, isTablet, currentUser}: Cu
return (
<TouchableOpacity
onPress={goToCustomStatusScreen}
testID='account.custom_status.option'
>
<View style={styles.body}>
<CustomStatusEmoji

View File

@@ -41,7 +41,7 @@ const LogOut = () => {
icon='exit-to-app'
label={intl.formatMessage({id: 'account.logout', defaultMessage: 'Log out'})}
optionDescriptionTextStyle={styles.desc}
testID='account.logout.action'
testID='account.logout.option'
type='default'
/>
);

View File

@@ -24,7 +24,7 @@ const Settings = () => {
action={openSettings}
icon='settings-outline'
label={intl.formatMessage({id: 'account.settings', defaultMessage: 'Settings'})}
testID='account.settings.action'
testID='account.settings.option'
type='default'
/>
);

View File

@@ -60,7 +60,7 @@ const UserStatus = ({currentUser}: Props) => {
icon='check-circle'
imageStyles={{color: theme.onlineIndicator}}
onPress={() => setUserStatus(ONLINE)}
testID='user_status.bottom_sheet.online'
testID='user_status.online.option'
text={intl.formatMessage({
id: 'mobile.set_status.online',
defaultMessage: 'Online',
@@ -71,7 +71,7 @@ const UserStatus = ({currentUser}: Props) => {
icon='clock'
imageStyles={{color: theme.awayIndicator}}
onPress={() => setUserStatus(AWAY)}
testID='user_status.bottom_sheet.away'
testID='user_status.away.option'
text={intl.formatMessage({
id: 'mobile.set_status.away',
defaultMessage: 'Away',
@@ -82,7 +82,7 @@ const UserStatus = ({currentUser}: Props) => {
icon='minus-circle'
imageStyles={{color: theme.dndIndicator}}
onPress={() => setUserStatus(DND)}
testID='user_status.bottom_sheet.dnd'
testID='user_status.dnd.option'
text={intl.formatMessage({
id: 'mobile.set_status.dnd',
defaultMessage: 'Do Not Disturb',
@@ -93,7 +93,7 @@ const UserStatus = ({currentUser}: Props) => {
icon='circle-outline'
imageStyles={{color: changeOpacity('#B8B8B8', 0.64)}}
onPress={() => setUserStatus(OFFLINE)}
testID='user_status.bottom_sheet.offline'
testID='user_status.offline.option'
text={intl.formatMessage({
id: 'mobile.set_status.offline',
defaultMessage: 'Offline',
@@ -139,6 +139,7 @@ const UserStatus = ({currentUser}: Props) => {
return (
<TouchableOpacity
onPress={handleSetStatus}
testID='account.user_presence.option'
>
<View style={styles.body}>
<UserStatusIndicator

View File

@@ -33,7 +33,7 @@ const YourProfile = ({isTablet, theme}: Props) => {
<OptionItem
icon={ACCOUNT_OUTLINE_IMAGE}
label={intl.formatMessage({id: 'account.your_profile', defaultMessage: 'Your Profile'})}
testID='account.your_profile.action'
testID='account.your_profile.option'
type='default'
action={openProfile}
/>

View File

@@ -52,7 +52,7 @@ const AccountUserInfo = ({user, showFullName, theme}: Props) => {
const nickName = user.nickname ? ` (${user.nickname})` : '';
const title = `${user.firstName} ${user.lastName}${nickName}`;
const userName = `@${user.username}`;
const accountUserInfoTestId = `account_user_info.${user.id}`;
const accountUserInfoTestId = `account.user_info.${user.id}`;
return (
<View style={styles.container}>
@@ -65,7 +65,14 @@ const AccountUserInfo = ({user, showFullName, theme}: Props) => {
statusSize={24}
testID={`${accountUserInfoTestId}.profile_picture`}
/>
{showFullName && <Text style={styles.textFullName}>{title}</Text>}
{showFullName &&
<Text
style={styles.textFullName}
testID={`${accountUserInfoTestId}.display_name`}
>
{title}
</Text>
}
<Text
style={showFullName ? styles.textUserName : styles.textFullName}
testID={`${accountUserInfoTestId}.username`}

View File

@@ -167,7 +167,7 @@ const About = ({config, license}: AboutProps) => {
}, [config]);
return (
<SettingContainer>
<SettingContainer testID='about'>
<View style={styles.logoContainer}>
<CompassIcon
color={theme.centerChannelColor}

View File

@@ -68,7 +68,7 @@ const AdvancedSettings = ({componentId}: AdvancedSettingsProps) => {
const hasData = Boolean(dataSize && (dataSize > 0));
return (
<SettingContainer>
<SettingContainer testID='advanced_settings'>
<TouchableOpacity
onPress={onPressDeleteData}
disabled={!hasData}
@@ -80,6 +80,7 @@ const AdvancedSettings = ({componentId}: AdvancedSettingsProps) => {
icon='trash-can-outline'
info={getFormattedFileSize(dataSize || 0)}
label={intl.formatMessage({id: 'advanced_settings.delete_data', defaultMessage: 'Delete Documents & Data'})}
testID='advanced_settings.delete_data.option'
type='none'
/>
<SettingSeparator/>

View File

@@ -70,24 +70,27 @@ const Display = ({currentUser, hasMilitaryTimeFormat, isThemeSwitchingEnabled, i
});
return (
<SettingContainer>
<SettingContainer testID='display_settings'>
{isThemeSwitchingEnabled && (
<SettingItem
optionName='theme'
onPress={goToThemeSettings}
info={theme.type!}
testID='display_settings.theme.option'
/>
)}
<SettingItem
optionName='clock'
onPress={goToClockDisplaySettings}
info={intl.formatMessage(hasMilitaryTimeFormat ? TIME_FORMAT[1] : TIME_FORMAT[0])}
testID='display_settings.clock_display.option'
/>
{isTimezoneEnabled && (
<SettingItem
optionName='timezone'
onPress={goToTimezoneSettings}
info={intl.formatMessage(timezone.useAutomaticTimezone ? TIMEZONE_FORMAT[0] : TIMEZONE_FORMAT[1])}
testID='display_settings.timezone.option'
/>
)}
</SettingContainer>

View File

@@ -70,7 +70,7 @@ const DisplayClock = ({componentId, currentUserId, hasMilitaryTimeFormat}: Displ
useNavButtonPressed(SAVE_CLOCK_BUTTON_ID, componentId, saveClockDisplayPreference, [isMilitaryTimeFormat]);
return (
<SettingContainer>
<SettingContainer testID='display_clock'>
<SettingBlock
disableHeader={true}
>

View File

@@ -68,7 +68,7 @@ const DisplayTheme = ({allowedThemeKeys, componentId, currentTeamId, currentUser
useAndroidHardwareBackHandler(componentId, close);
return (
<SettingContainer>
<SettingContainer testID='display_theme'>
<ThemeTiles
allowedThemeKeys={allowedThemeKeys}
onThemeChange={setDisplayTheme}

View File

@@ -106,7 +106,7 @@ const DisplayTimezone = ({currentUser, componentId}: DisplayTimezoneProps) => {
}, [userTimezone.useAutomaticTimezone]);
return (
<SettingContainer>
<SettingContainer testID='display_timezone'>
<SettingOption
action={updateAutomaticTimezone}
description={toggleDesc}

View File

@@ -108,7 +108,7 @@ const NotificationAutoResponder = ({currentUser, componentId}: NotificationAutoR
useAndroidHardwareBackHandler(componentId, close);
return (
<SettingContainer>
<SettingContainer testID='notification_auto_responder'>
<SettingOption
label={intl.formatMessage({id: 'notification_settings.auto_responder.to.enable', defaultMessage: 'Enable automatic replies'})}
action={setAutoResponderActive}

View File

@@ -124,7 +124,7 @@ const NotificationEmail = ({componentId, currentUser, emailInterval, enableEmail
useNavButtonPressed(SAVE_EMAIL_BUTTON_ID, componentId, saveEmail, [saveEmail]);
return (
<SettingContainer>
<SettingContainer testID='notification_email'>
<SettingBlock
disableFooter={!sendEmailNotifications}
footerText={emailFooterText}

View File

@@ -17,7 +17,7 @@ type NotificationMentionProps = {
}
const NotificationMention = ({componentId, currentUser, isCRTEnabled}: NotificationMentionProps) => {
return (
<SettingContainer>
<SettingContainer testID='notification_mention'>
<MentionSettings
currentUser={currentUser}
componentId={componentId}

View File

@@ -84,7 +84,7 @@ const NotificationPush = ({componentId, currentUser, isCRTEnabled, sendPushNotif
useAndroidHardwareBackHandler(componentId, close);
return (
<SettingContainer>
<SettingContainer testID='notification_push'>
<MobileSendPush
pushStatus={pushSend}
sendPushNotifications={sendPushNotifications}

View File

@@ -88,7 +88,7 @@ const Notifications = ({
}, []);
return (
<SettingContainer>
<SettingContainer testID='notification_settings'>
<SettingItem
onPress={goToNotificationSettingsMentions}
optionName='mentions'
@@ -96,21 +96,25 @@ const Notifications = ({
id: isCRTEnabled ? mentionTexts.crtOn.id : mentionTexts.crtOff.id,
defaultMessage: isCRTEnabled ? mentionTexts.crtOn.defaultMessage : mentionTexts.crtOff.defaultMessage,
})}
testID='notification_settings.mentions.option'
/>
<SettingItem
optionName='push_notification'
onPress={goToNotificationSettingsPush}
testID='notification_settings.push_notifications.option'
/>
<SettingItem
optionName='email'
onPress={goToEmailSettings}
info={intl.formatMessage(getEmailIntervalTexts(emailIntervalPref))}
testID='notification_settings.email_notifications.option'
/>
{enableAutoResponder && (
<SettingItem
onPress={goToNotificationAutoResponder}
optionName='automatic_dm_replies'
info={currentUser.status === General.OUT_OF_OFFICE && notifyProps.auto_responder_active === 'true' ? 'On' : 'Off'}
testID='notification_settings.automatic_replies.option'
/>
)}
</SettingContainer>

View File

@@ -24,8 +24,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
type SettingContainerProps = {
children: React.ReactNode;
testID?: string;
}
const SettingContainer = ({children}: SettingContainerProps) => {
const SettingContainer = ({children, testID}: SettingContainerProps) => {
const theme = useTheme();
const styles = getStyleSheet(theme);
@@ -33,10 +34,12 @@ const SettingContainer = ({children}: SettingContainerProps) => {
<SafeAreaView
edges={edges}
style={styles.container}
testID={`${testID}.screen`}
>
<ScrollView
contentContainerStyle={styles.contentContainerStyle}
alwaysBounceVertical={false}
testID={`${testID}.scroll_view`}
>
{children}
</ScrollView>

View File

@@ -59,7 +59,7 @@ const Settings = ({componentId, helpLink, showHelp, siteName}: SettingsProps) =>
return {
id: CLOSE_BUTTON_ID,
icon: CompassIcon.getImageSourceSync('close', 24, theme.centerChannelColor),
testID: CLOSE_BUTTON_ID,
testID: 'close.settings.button',
};
}, [theme.centerChannelColor]);
@@ -121,25 +121,28 @@ const Settings = ({componentId, helpLink, showHelp, siteName}: SettingsProps) =>
});
return (
<SettingContainer>
<SettingContainer testID='settings'>
<SettingItem
onPress={goToNotifications}
optionName='notification'
testID='settings.notifications.option'
/>
<SettingItem
onPress={goToDisplaySettings}
optionName='display'
testID='settings.display.option'
/>
<SettingItem
onPress={goToAdvancedSettings}
optionName='advanced_settings'
testID='settings.advanced_settings.option'
/>
<SettingItem
icon='information-outline'
label={intl.formatMessage({id: 'settings.about', defaultMessage: 'About {appTitle}'}, {appTitle: serverName})}
onPress={goToAbout}
optionName='about'
testID='general_settings.about'
testID='settings.about.option'
/>
{Platform.OS === 'android' && <View style={styles.helpGroup}/>}
{showHelp &&
@@ -148,6 +151,7 @@ const Settings = ({componentId, helpLink, showHelp, siteName}: SettingsProps) =>
onPress={openHelp}
optionName='help'
separator={false}
testID='settings.help.option'
type='default'
/>
}

View File

@@ -3,10 +3,32 @@
import fs from 'fs';
import {AxiosRequestConfig} from 'axios';
import FormData from 'form-data';
import client from './client';
export const getCookiesFromConfig = (config: AxiosRequestConfig<any>) => {
let mmAuthToken = '';
let mmUserId = '';
let mmCsrf = '';
config.jar?.toJSON().cookies.forEach((cookie: any) => {
if (cookie.key === 'MMAUTHTOKEN') {
mmAuthToken = cookie.value;
} else if (cookie.key === 'MMUSERID') {
mmUserId = cookie.value;
} else if (cookie.key === 'MMCSRF') {
mmCsrf = cookie.value;
}
});
return {
mmAuthToken,
mmUserId,
mmCsrf,
};
};
export const getResponseFromError = (err: any) => {
const {response} = err;
if (!response) {

View File

@@ -93,7 +93,7 @@
"EnableUserCreation": true,
"EnableOpenServer": true,
"EnableUserDeactivation": false,
"EnableCustomUserStatuses": false,
"EnableCustomUserStatuses": true,
"RestrictCreationToDomains": "",
"EnableCustomBrand": false,
"CustomBrandText": "",

View File

@@ -12,4 +12,4 @@ export const adminEmail = process.env.ADMIN_EMAIL || 'sysadmin@sample.mattermost
export const adminUsername = process.env.ADMIN_USERNAME || 'sysadmin';
export const adminPassword = process.env.ADMIN_PASSWORD || 'Sys@dmin-sample1';
export const ldapServer = process.env.LDAP_SERVER || '127.0.0.1';
export const ldapPort = process.env.LDAP_PORT || '389';
export const ldapPort = process.env.LDAP_PORT || 389;

View File

@@ -1,19 +1,60 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Alert} from '@support/ui/component';
import {
Alert,
ProfilePicture,
} from '@support/ui/component';
import {HomeScreen} from '@support/ui/screen';
import {timeouts} from '@support/utils';
import {expect} from 'detox';
class AccountScreen {
testID = {
userInfoPrefix: 'account.user_info.',
accountScreen: 'account.screen',
logoutAction: 'account.logout.action',
userPresenceOption: 'account.user_presence.option',
setStatusOption: 'account.custom_status.option',
yourProfileOption: 'account.your_profile.option',
settingsOption: 'account.settings.option',
logoutOption: 'account.logout.option',
onlineUserStatusOption: 'user_status.online.option',
awayUserStatusOption: 'user_status.away.option',
dndUserStatusOption: 'user_status.dnd.option',
offlineUserStatusOption: 'user_status.offline.option',
};
accountScreen = element(by.id(this.testID.accountScreen));
logoutAction = element(by.id(this.testID.logoutAction));
userPresenceOption = element(by.id(this.testID.userPresenceOption));
setStatusOption = element(by.id(this.testID.setStatusOption));
yourProfileOption = element(by.id(this.testID.yourProfileOption));
settingsOption = element(by.id(this.testID.settingsOption));
logoutOption = element(by.id(this.testID.logoutOption));
onlineUserStatusOption = element(by.id(this.testID.onlineUserStatusOption));
awayUserStatusOption = element(by.id(this.testID.awayUserStatusOption));
dndUserStatusOption = element(by.id(this.testID.dndUserStatusOption));
offlineUserStatusOption = element(by.id(this.testID.offlineUserStatusOption));
getUserInfo = (userId: string) => {
const userInfoTestId = `${this.testID.userInfoPrefix}${userId}`;
const userInfoProfilePictureMatcher = ProfilePicture.getProfilePictureItemMatcher(this.testID.userInfoPrefix, userId);
const userInfoUserDisplayNameMatcher = by.id(`${userInfoTestId}.display_name`);
const userInfoUsernameMatcher = by.id(`${userInfoTestId}.username`);
return {
userInfoProfilePicture: element(userInfoProfilePictureMatcher),
userInfoUserDisplayName: element(userInfoUserDisplayNameMatcher),
userInfoUsername: element(userInfoUsernameMatcher),
};
};
getUserPresenceIndicator = (status: string) => {
return element(by.id(`user_status.indicator.${status}`)).atIndex(0);
};
getUserPresenceLabel = (status: string) => {
return element(by.id(`user_status.label.${status}`)).atIndex(0);
};
toBeVisible = async () => {
await waitFor(this.accountScreen).toExist().withTimeout(timeouts.TEN_SEC);
@@ -29,7 +70,7 @@ class AccountScreen {
};
logout = async (serverDisplayName: string | null = null) => {
await this.logoutAction.tap();
await this.logoutOption.tap();
if (serverDisplayName) {
await expect(Alert.logoutTitle(serverDisplayName)).toBeVisible();
}

View File

@@ -14,7 +14,7 @@ class ChannelInfoScreen {
directMessageTitlePrefix: 'channel_info.title.direct_message.',
channelInfoScreen: 'channel_info.screen',
closeButton: 'close.channel_info.button',
scrollView: 'channel_info.scrollview',
scrollView: 'channel_info.scroll_view',
groupMessageTitleDisplayName: 'channel_info.title.group_message.display_name',
publicPrivateTitleDisplayName: 'channel_info.title.public_private.display_name',
publicPrivateTitlePurpose: 'channel_info.title.public_private.purpose',
@@ -67,7 +67,7 @@ class ChannelInfoScreen {
archiveChannelOption = element(by.id(this.testID.archiveChannelOption));
unarchiveChannelOption = element(by.id(this.testID.unarchiveChannelOption));
getDirectMessageTitle = async (userId: string) => {
getDirectMessageTitle = (userId: string) => {
const directMessageTitleTestId = `${this.testID.directMessageTitlePrefix}${userId}`;
const directMessageTitleProfilePictureMatcher = ProfilePicture.getProfilePictureItemMatcher(this.testID.directMessageTitlePrefix, userId);
const directMessageTitleUserDisplayNameMatcher = by.id(`${directMessageTitleTestId}.display_name`);

View File

@@ -16,7 +16,7 @@ class CreateOrEditChannelScreen {
backButton: 'screen.back.button',
createButton: 'create_or_edit_channel.create.button',
saveButton: 'create_or_edit_channel.save.button',
scrollView: 'create_or_edit_channel.scrollview',
scrollView: 'create_or_edit_channel.scroll_view',
makePrivateToggledOff: 'channel_info_form.make_private.toggled.false',
makePrivateToggledOn: 'channel_info_form.make_private.toggled.true',
makePrivateDescription: 'channel_info_form.make_private.description',

View File

@@ -0,0 +1,37 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {AccountScreen} from '@support/ui/screen';
import {timeouts} from '@support/utils';
import {expect} from 'detox';
class CustomStatusScreen {
testID = {
customStatusScreen: 'custom_status.screen',
doneButton: 'custom_status.done.button',
};
customStatusScreen = element(by.id(this.testID.customStatusScreen));
doneButton = element(by.id(this.testID.doneButton));
toBeVisible = async () => {
await waitFor(this.customStatusScreen).toExist().withTimeout(timeouts.TEN_SEC);
return this.customStatusScreen;
};
open = async () => {
// # Open custom status screen
await AccountScreen.setStatusOption.tap();
return this.toBeVisible();
};
close = async () => {
await this.doneButton.tap();
await expect(this.customStatusScreen).not.toBeVisible();
};
}
const customStatusScreen = new CustomStatusScreen();
export default customStatusScreen;

View File

@@ -0,0 +1,73 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {ProfilePicture} from '@support/ui/component';
import {AccountScreen} from '@support/ui/screen';
import {timeouts} from '@support/utils';
import {expect} from 'detox';
class EditProfileScreen {
testID = {
editProfileScreen: 'edit_profile.screen',
editProfilePrefix: 'edit_profile.',
closeButton: 'close.edit_profile.button',
saveButton: 'edit_profile.save.button',
scrollView: 'edit_profile.scroll_view',
firstNameInput: 'edit_profile_form.first_name.input',
firstNameInputDisabled: 'edit_profile_form.first_name.input.disabled',
lastNameInput: 'edit_profile_form.last_name.input',
lastNameInputDisabled: 'edit_profile_form.last_name.input.disabled',
usernameInput: 'edit_profile_form.username.input',
usernameInputDisabled: 'edit_profile_form.username.input.disabled',
emailInput: 'edit_profile_form.email.input',
emailInputDisabled: 'edit_profile_form.email.input.disabled',
emailInputDescription: 'edit_profile_form.email.input.description',
nicknameInput: 'edit_profile_form.nickname.input',
nicknameInputDisabled: 'edit_profile_form.nickname.input.disabled',
positionInput: 'edit_profile_form.position.input',
positionInputDisabled: 'edit_profile_form.position.input.disabled',
};
editProfileScreen = element(by.id(this.testID.editProfileScreen));
closeButton = element(by.id(this.testID.closeButton));
saveButton = element(by.id(this.testID.saveButton));
scrollView = element(by.id(this.testID.scrollView));
firstNameInput = element(by.id(this.testID.firstNameInput));
firstNameInputDisabled = element(by.id(this.testID.firstNameInputDisabled));
lastNameInput = element(by.id(this.testID.lastNameInput));
lastNameInputDisabled = element(by.id(this.testID.lastNameInputDisabled));
usernameInput = element(by.id(this.testID.usernameInput));
usernameInputDisabled = element(by.id(this.testID.usernameInputDisabled));
emailInput = element(by.id(this.testID.emailInput));
emailInputDisabled = element(by.id(this.testID.emailInputDisabled));
emailInputDescription = element(by.id(this.testID.emailInputDescription));
nicknameInput = element(by.id(this.testID.nicknameInput));
nicknameInputDisabled = element(by.id(this.testID.nicknameInputDisabled));
positionInput = element(by.id(this.testID.positionInput));
positionInputDisabled = element(by.id(this.testID.positionInputDisabled));
getEditProfilePicture = (userId: string) => {
return element(ProfilePicture.getProfilePictureItemMatcher(this.testID.editProfilePrefix, userId));
};
toBeVisible = async () => {
await waitFor(this.editProfileScreen).toExist().withTimeout(timeouts.TEN_SEC);
return this.editProfileScreen;
};
open = async () => {
// # Open edit profile screen
await AccountScreen.yourProfileOption.tap();
return this.toBeVisible();
};
close = async () => {
await this.closeButton.tap();
await expect(this.editProfileScreen).not.toBeVisible();
};
}
const editProfileScreen = new EditProfileScreen();
export default editProfileScreen;

View File

@@ -9,7 +9,9 @@ import ChannelInfoScreen from './channel_info';
import ChannelListScreen from './channel_list';
import CreateDirectMessageScreen from './create_direct_message';
import CreateOrEditChannelScreen from './create_or_edit_channel';
import CustomStatusScreen from './custom_status';
import EditPostScreen from './edit_post';
import EditProfileScreen from './edit_profile';
import EditServerScreen from './edit_server';
import EmojiPickerScreen from './emoji_picker';
import FindChannelsScreen from './find_channels';
@@ -24,6 +26,7 @@ import RecentMentionsScreen from './recent_mentions';
import SavedMessagesScreen from './saved_messages';
import ServerScreen from './server';
import ServerListScreen from './server_list';
import SettingsScreen from './settings';
import TableScreen from './table';
import ThreadScreen from './thread';
import ThreadOptionsScreen from './thread_options';
@@ -38,7 +41,9 @@ export {
ChannelListScreen,
CreateDirectMessageScreen,
CreateOrEditChannelScreen,
CustomStatusScreen,
EditPostScreen,
EditProfileScreen,
EditServerScreen,
EmojiPickerScreen,
FindChannelsScreen,
@@ -53,6 +58,7 @@ export {
SavedMessagesScreen,
ServerScreen,
ServerListScreen,
SettingsScreen,
TableScreen,
ThreadScreen,
ThreadOptionsScreen,

View File

@@ -0,0 +1,49 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {AccountScreen} from '@support/ui/screen';
import {timeouts} from '@support/utils';
import {expect} from 'detox';
class SettingsScreen {
testID = {
settingsScreen: 'settings.screen',
closeButton: 'close.settings.button',
scrollView: 'settings.scroll_view',
notificationsOption: 'settings.notifications.option',
displayOption: 'settings.display.option',
advancedSettingsOption: 'settings.advanced_settings.option',
aboutOption: 'settings.about.option',
helpOption: 'settings.help.option',
};
settingsScreen = element(by.id(this.testID.settingsScreen));
closeButton = element(by.id(this.testID.closeButton));
scrollView = element(by.id(this.testID.scrollView));
notificationsOption = element(by.id(this.testID.notificationsOption));
displayOption = element(by.id(this.testID.displayOption));
advancedSettingsOption = element(by.id(this.testID.advancedSettingsOption));
aboutOption = element(by.id(this.testID.aboutOption));
helpOption = element(by.id(this.testID.helpOption));
toBeVisible = async () => {
await waitFor(this.settingsScreen).toExist().withTimeout(timeouts.TEN_SEC);
return this.settingsScreen;
};
open = async () => {
// # Open settings screen
await AccountScreen.settingsOption.tap();
return this.toBeVisible();
};
close = async () => {
await this.closeButton.tap();
await expect(this.settingsScreen).not.toBeVisible();
};
}
const settingsScreen = new SettingsScreen();
export default settingsScreen;

View File

@@ -0,0 +1,133 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// *******************************************************************
// - [#] indicates a test step (e.g. # Go to a screen)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element testID when selecting an element. Create one if none.
// *******************************************************************
import {Setup} from '@support/server_api';
import {
serverOneUrl,
siteOneUrl,
} from '@support/test_config';
import {
AccountScreen,
CustomStatusScreen,
EditProfileScreen,
HomeScreen,
LoginScreen,
ServerScreen,
SettingsScreen,
} from '@support/ui/screen';
import {expect} from 'detox';
describe('Account - Account Menu', () => {
const serverOneDisplayName = 'Server 1';
let testUser: any;
beforeAll(async () => {
const {user} = await Setup.apiInit(siteOneUrl);
testUser = user;
// # Log in to server and go to account screen
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
await LoginScreen.login(testUser);
await AccountScreen.open();
});
beforeEach(async () => {
// * Verify on account screen
await AccountScreen.toBeVisible();
});
afterAll(async () => {
// # Log out
await HomeScreen.logout();
});
it('MM-T4988_1 - should match elements on account screen', async () => {
// * Verify basic elements on account screen
const {userInfoProfilePicture, userInfoUserDisplayName, userInfoUsername} = AccountScreen.getUserInfo(testUser.id);
await expect(userInfoProfilePicture).toBeVisible();
await expect(userInfoUserDisplayName).toHaveText(`${testUser.first_name} ${testUser.last_name} (${testUser.nickname})`);
await expect(userInfoUsername).toHaveText(`@${testUser.username}`);
await expect(AccountScreen.userPresenceOption).toBeVisible();
await expect(AccountScreen.setStatusOption).toBeVisible();
await expect(AccountScreen.yourProfileOption).toBeVisible();
await expect(AccountScreen.settingsOption).toBeVisible();
await expect(AccountScreen.logoutOption).toBeVisible();
});
it('MM-T4988_2 - should be able to set user presence', async () => {
// # Tap on user presence option and tap on offline user status option
await AccountScreen.userPresenceOption.tap();
await AccountScreen.offlineUserStatusOption.tap();
// * Verify on account screen and verify user presence icon and label are for offline user status
await AccountScreen.toBeVisible();
await expect(AccountScreen.getUserPresenceIndicator('offline')).toBeVisible();
await expect(AccountScreen.getUserPresenceLabel('offline')).toHaveText('Offline');
// # Tap on user presence option and tap on do not disturb user status option
await AccountScreen.userPresenceOption.tap();
await AccountScreen.dndUserStatusOption.tap();
// * Verify on account screen and verify user presence icon and label are for do no disturb user status
await AccountScreen.toBeVisible();
await expect(AccountScreen.getUserPresenceIndicator('dnd')).toBeVisible();
await expect(AccountScreen.getUserPresenceLabel('dnd')).toHaveText('Do Not Disturb');
// # Tap on user presence option and tap on away user status option
await AccountScreen.userPresenceOption.tap();
await AccountScreen.awayUserStatusOption.tap();
// * Verify on account screen and verify user presence icon and label are for away user status
await AccountScreen.toBeVisible();
await expect(AccountScreen.getUserPresenceIndicator('away')).toBeVisible();
await expect(AccountScreen.getUserPresenceLabel('away')).toHaveText('Away');
// # Tap on user presence option and tap on online user status option
await AccountScreen.userPresenceOption.tap();
await AccountScreen.onlineUserStatusOption.tap();
// * Verify on account screen and verify user presence icon and label are for online user status
await AccountScreen.toBeVisible();
await expect(AccountScreen.getUserPresenceIndicator('online')).toBeVisible();
await expect(AccountScreen.getUserPresenceLabel('online')).toHaveText('Online');
});
it('MM-T4988_3 - should be able to go to custom status screen', async () => {
// # Tap on set status option
await AccountScreen.setStatusOption.tap();
// * Verify on custom status screen
await CustomStatusScreen.toBeVisible();
// # Go back to account screen
await CustomStatusScreen.close();
});
it('MM-T4988_4 - should be able to go to edit profile screen', async () => {
// # Tap on your profile option
await AccountScreen.yourProfileOption.tap();
// * Verify on edit profile screen
await EditProfileScreen.toBeVisible();
// # Go back to account screen
await EditProfileScreen.close();
});
it('MM-T4988_5 - should be able to go to settings screen', async () => {
// # Tap on settings option
await AccountScreen.settingsOption.tap();
// * Verify on settings screen
await SettingsScreen.toBeVisible();
// # Go back to account screen
await SettingsScreen.close();
});
});

View File

@@ -25,7 +25,7 @@ import {
} from '@support/ui/screen';
import {expect} from 'detox';
describe('Autocomplete - At-Mention', () => {
describe('Smoke Test - Autocomplete', () => {
const serverOneDisplayName = 'Server 1';
const channelsCategory = 'channels';
let testChannel: any;