From 09593f7184d11197583adf01363d91434eaab4eb Mon Sep 17 00:00:00 2001 From: Joseph Baylon Date: Tue, 13 Apr 2021 09:28:39 -0700 Subject: [PATCH] MM-30431 Detox/E2E: Added e2e for MM-T3196, MM-T3210, MM-T3211, MM-T3262, MM-T3264 (#5313) * MM-30431 Detox/E2E: Added e2e for MM-T3196, MM-T3210, MM-T3211, MM-T3262, MM-T3264 * Fix snap test --- .../channel_item/channel_item.js | 2 +- app/screens/about/about.js | 53 +++++++++++-- .../advanced_settings/advanced_settings.js | 3 + .../__snapshots__/user_profile.test.js.snap | 9 ++- app/screens/user_profile/user_profile.js | 26 +++++- app/screens/user_profile/user_profile_row.js | 7 +- detox/e2e/support/ui/component/alert.js | 1 + detox/e2e/support/ui/screen/about.js | 79 +++++++++++++++++++ .../support/ui/screen/advanced_settings.js | 62 +++++++++++++++ .../support/ui/screen/channel_add_members.js | 27 ------- detox/e2e/support/ui/screen/index.js | 6 ++ detox/e2e/support/ui/screen/user_profile.js | 49 ++++++++++++ detox/e2e/test/smoke_test/about.e2e.js | 73 +++++++++++++++++ .../test/smoke_test/advanced_settings.e2e.js | 49 ++++++++++++ .../smoke_test/channel_add_members.e2e.js | 49 ++++++++++-- .../test/smoke_test/direct_messages.e2e.js | 64 +++++++++++++++ ios/Podfile.lock | 4 +- 17 files changed, 512 insertions(+), 51 deletions(-) create mode 100644 detox/e2e/support/ui/screen/about.js create mode 100644 detox/e2e/support/ui/screen/advanced_settings.js create mode 100644 detox/e2e/support/ui/screen/user_profile.js create mode 100644 detox/e2e/test/smoke_test/about.e2e.js create mode 100644 detox/e2e/test/smoke_test/advanced_settings.e2e.js diff --git a/app/components/sidebars/main/channels_list/channel_item/channel_item.js b/app/components/sidebars/main/channels_list/channel_item/channel_item.js index 82254c1f8..07a832129 100644 --- a/app/components/sidebars/main/channels_list/channel_item/channel_item.js +++ b/app/components/sidebars/main/channels_list/channel_item/channel_item.js @@ -22,7 +22,7 @@ export default class ChannelItem extends PureComponent { channelId: PropTypes.string.isRequired, channel: PropTypes.object, currentChannelId: PropTypes.string.isRequired, - displayName: PropTypes.string.isRequired, + displayName: PropTypes.string, isArchived: PropTypes.bool, isChannelMuted: PropTypes.bool, isManualUnread: PropTypes.bool, diff --git a/app/screens/about/about.js b/app/screens/about/about.js index 46f71a7d9..5a5793c68 100644 --- a/app/screens/about/about.js +++ b/app/screens/about/about.js @@ -86,6 +86,7 @@ export default class About extends PureComponent { id='about.teamEditiont0' defaultMessage='Team Edition' style={style.title} + testID='about.title' /> ); @@ -94,6 +95,7 @@ export default class About extends PureComponent { id='about.teamEditionSt' defaultMessage='All your team communication in one place, instantly searchable and accessible anywhere.' style={style.subtitle} + testID='about.subtitle' /> ); @@ -103,11 +105,15 @@ export default class About extends PureComponent { id='about.teamEditionLearn' defaultMessage='Join the Mattermost community at ' style={style.learn} + testID='about.learn_more' /> - + {Config.TeamEditionLearnURL} @@ -121,6 +127,7 @@ export default class About extends PureComponent { id='about.teamEditiont1' defaultMessage='Enterprise Edition' style={style.title} + testID='about.title' /> ); @@ -129,6 +136,7 @@ export default class About extends PureComponent { id='about.enterpriseEditionSt' defaultMessage='Modern communication from behind your firewall.' style={style.subtitle} + testID='about.subtitle' /> ); @@ -138,11 +146,15 @@ export default class About extends PureComponent { id='about.enterpriseEditionLearn' defaultMessage='Learn more about Enterprise Edition at ' style={style.learn} + testID='about.learn_more' /> - + {Config.EELearnURL} @@ -155,6 +167,7 @@ export default class About extends PureComponent { id='about.enterpriseEditione1' defaultMessage='Enterprise Edition' style={style.title} + testID='about.title' /> ); @@ -167,6 +180,7 @@ export default class About extends PureComponent { values={{ company: license.Company, }} + testID='about.licensee' /> ); @@ -183,6 +197,7 @@ export default class About extends PureComponent { values={{ version: config.Version, }} + testID='about.server_version' /> ); } else { @@ -195,6 +210,7 @@ export default class About extends PureComponent { version: config.Version, number: config.BuildNumber, }} + testID='about.server_version' /> ); } @@ -207,6 +223,7 @@ export default class About extends PureComponent { defaultMessage='Terms of Service' style={style.noticeLink} onPress={this.handleTermsOfService} + testID='about.terms_of_service' /> ); } @@ -219,6 +236,7 @@ export default class About extends PureComponent { defaultMessage='Privacy Policy' style={style.noticeLink} onPress={this.handlePrivacyPolicy} + testID='about.privacy_policy' /> ); } @@ -236,22 +254,28 @@ export default class About extends PureComponent { - + {`${config.SiteName} `} {title} @@ -265,6 +289,7 @@ export default class About extends PureComponent { version: DeviceInfo.getVersion(), number: DeviceInfo.getBuildNumber(), }} + testID='about.app_version' /> {serverVersion} {licensee} {learnMore} @@ -285,6 +311,7 @@ export default class About extends PureComponent { values={{ site: this.props.config.SiteName, }} + testID='about.powered_by' /> } {termsOfService} @@ -324,6 +352,7 @@ export default class About extends PureComponent { /> ), }} + testID='about.notice_text' /> @@ -333,8 +362,12 @@ export default class About extends PureComponent { id='about.hash' defaultMessage='Build Hash:' style={style.footerTitleText} + testID='about.build_hash.title' /> - + {config.BuildHash} @@ -343,8 +376,12 @@ export default class About extends PureComponent { id='about.hashee' defaultMessage='EE Build Hash:' style={style.footerTitleText} + testID='about.build_hash_enterprise.title' /> - + {config.BuildHashEnterprise} @@ -354,8 +391,12 @@ export default class About extends PureComponent { id='about.date' defaultMessage='Build Date:' style={style.footerTitleText} + testID='about.build_date.title' /> - + {config.BuildDate} diff --git a/app/screens/settings/advanced_settings/advanced_settings.js b/app/screens/settings/advanced_settings/advanced_settings.js index 7cd439e1d..f94d8e8e3 100644 --- a/app/screens/settings/advanced_settings/advanced_settings.js +++ b/app/screens/settings/advanced_settings/advanced_settings.js @@ -145,11 +145,13 @@ class AdvancedSettings extends Component { {this.renderSentryDebugOptions()} diff --git a/app/screens/user_profile/__snapshots__/user_profile.test.js.snap b/app/screens/user_profile/__snapshots__/user_profile.test.js.snap index 0b61dc2f3..0f8eb72a5 100644 --- a/app/screens/user_profile/__snapshots__/user_profile.test.js.snap +++ b/app/screens/user_profile/__snapshots__/user_profile.test.js.snap @@ -7,6 +7,7 @@ exports[`user_profile should match snapshot 1`] = ` "flex": 1, } } + testID="user_profile.screen" > - + nick @@ -110,6 +116,7 @@ exports[`user_profile should match snapshot 1`] = ` icon="send" iconColor="rgba(0, 0, 0, 0.7)" iconSize={24} + testID="user_profile.send_message.action" textColor="#000" textId="mobile.routes.user_profile.send_message" theme={ diff --git a/app/screens/user_profile/user_profile.js b/app/screens/user_profile/user_profile.js index f1840fb1e..ad0fd92ef 100644 --- a/app/screens/user_profile/user_profile.js +++ b/app/screens/user_profile/user_profile.js @@ -160,9 +160,19 @@ export default class UserProfile extends PureComponent { } return ( - - {label} - {user[property]} + + + {label} + + + {user[property]} + ); } @@ -186,12 +196,14 @@ export default class UserProfile extends PureComponent { id='mobile.routes.user_profile.local_time' defaultMessage='LOCAL TIME' style={style.header} + testID='user_profile.timezone_block.local_time.label' /> @@ -287,6 +299,7 @@ export default class UserProfile extends PureComponent { icon={l.icon} theme={this.props.theme} iconSize={l.iconSize} + testID='user_profile.additional_options.action' /> ); }); @@ -331,11 +344,15 @@ export default class UserProfile extends PureComponent { } return ( - + {this.renderAdditionalOptions()} diff --git a/app/screens/user_profile/user_profile_row.js b/app/screens/user_profile/user_profile_row.js index 9912c1053..85f4fdda9 100644 --- a/app/screens/user_profile/user_profile_row.js +++ b/app/screens/user_profile/user_profile_row.js @@ -57,7 +57,7 @@ function createTouchableComponent(children, action) { } function userProfileRow(props) { - const {action, defaultMessage, detail, icon, textId, togglable, theme, iconSize, shouldRender = true} = props; + const {action, defaultMessage, detail, icon, textId, togglable, theme, iconSize, shouldRender = true, testID} = props; if (!shouldRender) { return null; @@ -74,7 +74,10 @@ function userProfileRow(props) { ); const RowComponent = ( - + {iconComponent} { + await expect(this.aboutScreen).toBeVisible(); + + return this.aboutScreen; + } + + open = async () => { + // # Open about screen + await GeneralSettingsScreen.aboutAction.tap(); + + return this.toBeVisible(); + } + + back = async () => { + await this.backButton.tap(); + await expect(this.aboutScreen).not.toBeVisible(); + } +} + +const aboutScreen = new AboutScreen(); +export default aboutScreen; diff --git a/detox/e2e/support/ui/screen/advanced_settings.js b/detox/e2e/support/ui/screen/advanced_settings.js new file mode 100644 index 000000000..51baffa0d --- /dev/null +++ b/detox/e2e/support/ui/screen/advanced_settings.js @@ -0,0 +1,62 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {Alert} from '@support/ui/component'; +import {GeneralSettingsScreen} from '@support/ui/screen'; +import {timeouts, wait} from '@support/utils'; + +class AdvancedSettingsScreen { + testID = { + advancedSettingsScreen: 'advanced_settings.screen', + advancedSettingsScrollView: 'advanced_settings.scroll_view', + backButton: 'screen.back.button', + deleteDocumentsAndDataAction: 'advanced_settings.delete_documents_and_data.action', + } + + advancedSettingsScreen = element(by.id(this.testID.advancedSettingsScreen)); + advancedSettingsScrollView = element(by.id(this.testID.advancedSettingsScrollView)); + backButton = element(by.id(this.testID.backButton)); + deleteDocumentsAndDataAction = element(by.id(this.testID.deleteDocumentsAndDataAction)); + + toBeVisible = async () => { + await expect(this.advancedSettingsScreen).toBeVisible(); + + return this.advancedSettingsScreen; + } + + open = async () => { + // # Open advanced settings screen + await GeneralSettingsScreen.advancedAction.tap(); + + return this.toBeVisible(); + } + + back = async () => { + await this.backButton.tap(); + await expect(this.advancedSettingsScreen).not.toBeVisible(); + } + + deleteDocumentsAndData = async ({confirm = true} = {}) => { + await this.deleteDocumentsAndDataAction.tap(); + const { + deleteDocumentsAndDataTitle, + cancelButton, + deleteButton, + } = Alert; + await expect(deleteDocumentsAndDataTitle).toBeVisible(); + await expect(cancelButton).toBeVisible(); + await expect(deleteButton).toBeVisible(); + if (confirm) { + deleteButton.tap(); + await wait(timeouts.ONE_SEC); + await expect(this.advancedSettingsScreen).not.toBeVisible(); + } else { + cancelButton.tap(); + await wait(timeouts.ONE_SEC); + await expect(this.advancedSettingsScreen).toBeVisible(); + } + } +} + +const advancedSettingsScreen = new AdvancedSettingsScreen(); +export default advancedSettingsScreen; diff --git a/detox/e2e/support/ui/screen/channel_add_members.js b/detox/e2e/support/ui/screen/channel_add_members.js index 41bd47fe4..20337374f 100644 --- a/detox/e2e/support/ui/screen/channel_add_members.js +++ b/detox/e2e/support/ui/screen/channel_add_members.js @@ -2,11 +2,9 @@ // See LICENSE.txt for license information. import { - Alert, MainSidebar, SearchBar, } from '@support/ui/component'; -import {timeouts, wait} from '@support/utils'; class ChannelAddMembersScreen { testID = { @@ -72,31 +70,6 @@ class ChannelAddMembersScreen { await expect(this.channelAddMembersScreen).not.toBeVisible(); } - removeMembers = async (displayUsernameList, {confirm = true} = {}) => { - displayUsernameList.forEach(async (displayUsername) => { - await this.getUserByDisplayUsername(`@${displayUsername}`).tap(); - }); - await wait(timeouts.ONE_SEC); - await this.removeButton.tap(); - const { - removeMembersTitle, - noButton, - yesButton, - } = Alert; - await expect(removeMembersTitle).toBeVisible(); - await expect(noButton).toBeVisible(); - await expect(yesButton).toBeVisible(); - if (confirm) { - yesButton.tap(); - await wait(timeouts.ONE_SEC); - await expect(this.channelAddMembersScreen).not.toBeVisible(); - } else { - noButton.tap(); - await wait(timeouts.ONE_SEC); - await expect(this.channelAddMembersScreen).toBeVisible(); - } - } - hasUserDisplayUsernameAtIndex = async (index, displayUsername) => { await expect( this.getDisplayUsernameAtIndex(index), diff --git a/detox/e2e/support/ui/screen/index.js b/detox/e2e/support/ui/screen/index.js index 0f74ca234..9759397f1 100644 --- a/detox/e2e/support/ui/screen/index.js +++ b/detox/e2e/support/ui/screen/index.js @@ -1,6 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import AboutScreen from './about'; +import AdvancedSettingsScreen from './advanced_settings'; import AddReactionScreen from './add_reaction'; import ChannelInfoScreen from './channel_info'; import ChannelAddMembersScreen from './channel_add_members'; @@ -30,8 +32,11 @@ import SearchScreen from './search'; import SelectServerScreen from './select_server'; import SelectTeamScreen from './select_team'; import ThreadScreen from './thread'; +import UserProfileScreen from './user_profile'; export { + AboutScreen, + AdvancedSettingsScreen, AddReactionScreen, ChannelInfoScreen, ChannelAddMembersScreen, @@ -61,4 +66,5 @@ export { SelectServerScreen, SelectTeamScreen, ThreadScreen, + UserProfileScreen, }; diff --git a/detox/e2e/support/ui/screen/user_profile.js b/detox/e2e/support/ui/screen/user_profile.js new file mode 100644 index 000000000..0f570b865 --- /dev/null +++ b/detox/e2e/support/ui/screen/user_profile.js @@ -0,0 +1,49 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +class UserProfileScreen { + testID = { + userProfileScreen: 'user_profile.screen', + userProfileScrollView: 'user_profile.scroll_view', + emailLabel: 'user_profile.display_block.email.label', + emailValue: 'user_profile.display_block.email.value', + firstNameLabel: 'user_profile.display_block.first_name.label', + firstNameValue: 'user_profile.display_block.first_name.value', + lastNameLabel: 'user_profile.display_block.last_name.label', + lastNameValue: 'user_profile.display_block.last_name.value', + nicknameLabel: 'user_profile.display_block.nickname.label', + nicknameValue: 'user_profile.display_block.nickname.value', + positionLabel: 'user_profile.display_block.position.label', + positionValue: 'user_profile.display_block.position.value', + localTimeLabel: 'user_profile.timezone_block.local_time.label', + localTimeValue: 'user_profile.timezone_block.local_time.value', + additionalOptionsAction: 'user_profile.additional_options.action', + sendMessageAction: 'user_profile.send_message.action', + } + + userProfileScreen = element(by.id(this.testID.userProfileScreen)); + userProfileScrollView = element(by.id(this.testID.userProfileScrollView)); + emailLabel = element(by.id(this.testID.emailLabel)); + emailValue = element(by.id(this.testID.emailValue)); + firstNameLabel = element(by.id(this.testID.firstNameLabel)); + firstNameValue = element(by.id(this.testID.firstNameValue)); + lastNameLabel = element(by.id(this.testID.lastNameLabel)); + lastNameValue = element(by.id(this.testID.lastNameValue)); + nicknameLabel = element(by.id(this.testID.nicknameLabel)); + nicknameValue = element(by.id(this.testID.nicknameValue)); + positionLabel = element(by.id(this.testID.positionLabel)); + positionValue = element(by.id(this.testID.positionValue)); + localTimeLabel = element(by.id(this.testID.localTimeLabel)); + localTimeValue = element(by.id(this.testID.localTimeValue)); + additionalOptionsAction = element(by.id(this.testID.additionalOptionsAction)); + sendMessageAction = element(by.id(this.testID.sendMessageAction)); + + toBeVisible = async () => { + await expect(this.userProfileScreen).toBeVisible(); + + return this.userProfileScreen; + } +} + +const userProfileScreen = new UserProfileScreen(); +export default userProfileScreen; diff --git a/detox/e2e/test/smoke_test/about.e2e.js b/detox/e2e/test/smoke_test/about.e2e.js new file mode 100644 index 000000000..229337e63 --- /dev/null +++ b/detox/e2e/test/smoke_test/about.e2e.js @@ -0,0 +1,73 @@ +// 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 { + AboutScreen, + ChannelScreen, + GeneralSettingsScreen, +} from '@support/ui/screen'; +import {Setup} from '@support/server_api'; + +describe('About', () => { + beforeAll(async () => { + const {user} = await Setup.apiInit(); + + // # Open channel screen + await ChannelScreen.open(user); + }); + + afterAll(async () => { + await ChannelScreen.logout(); + }); + + it('MM-T3264 should be able to display about info', async () => { + const { + aboutAppVersion, + aboutBuildDateTitle, + aboutBuildDateValue, + aboutBuildHashTitle, + aboutBuildHashValue, + aboutBuildHashEnterpriseTitle, + aboutBuildHashEnterpriseValue, + aboutDatabase, + aboutLicensee, + aboutLogo, + aboutScrollView, + aboutServerVersion, + aboutSubtitle, + aboutTitle, + } = AboutScreen; + + // # Open about screen + await ChannelScreen.openSettingsSidebar(); + await GeneralSettingsScreen.open(); + await AboutScreen.open(); + + // * Verify about info + await expect(aboutLogo).toBeVisible(); + await expect(aboutSubtitle).toBeVisible(); + await expect(aboutTitle).toBeVisible(); + await expect(aboutSubtitle).toBeVisible(); + await expect(aboutAppVersion).toBeVisible(); + await expect(aboutServerVersion).toBeVisible(); + await expect(aboutDatabase).toBeVisible(); + await expect(aboutLicensee).toBeVisible(); + await aboutScrollView.scrollTo('bottom'); + await expect(aboutBuildHashTitle).toBeVisible(); + await expect(aboutBuildHashValue).toBeVisible(); + await expect(aboutBuildHashEnterpriseTitle).toBeVisible(); + await expect(aboutBuildHashEnterpriseValue).toBeVisible(); + await expect(aboutBuildDateTitle).toBeVisible(); + await expect(aboutBuildDateValue).toBeVisible(); + + // # Go back to channel + await AboutScreen.back(); + await GeneralSettingsScreen.close(); + }); +}); diff --git a/detox/e2e/test/smoke_test/advanced_settings.e2e.js b/detox/e2e/test/smoke_test/advanced_settings.e2e.js new file mode 100644 index 000000000..b6d904701 --- /dev/null +++ b/detox/e2e/test/smoke_test/advanced_settings.e2e.js @@ -0,0 +1,49 @@ +// 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 { + AdvancedSettingsScreen, + ChannelScreen, + GeneralSettingsScreen, +} from '@support/ui/screen'; +import { + Channel, + Setup, +} from '@support/server_api'; + +describe('Advanced Settings', () => { + let townSquareChannel; + + beforeAll(async () => { + const {team, user} = await Setup.apiInit(); + + ({channel: townSquareChannel} = await Channel.apiGetChannelByName(team.name, 'town-square')); + + // # Open channel screen + await ChannelScreen.open(user); + }); + + afterAll(async () => { + await ChannelScreen.logout(); + }); + + it('MM-T3262 should be able to delete documents and data', async () => { + // # Open advanced settings screen + await ChannelScreen.openSettingsSidebar(); + await GeneralSettingsScreen.open(); + await AdvancedSettingsScreen.open(); + + // # Delete documents and data + await AdvancedSettingsScreen.deleteDocumentsAndData(); + + // * Verify redirects to town square + await ChannelScreen.toBeVisible(); + await expect(ChannelScreen.channelNavBarTitle).toHaveText(townSquareChannel.display_name); + }); +}); diff --git a/detox/e2e/test/smoke_test/channel_add_members.e2e.js b/detox/e2e/test/smoke_test/channel_add_members.e2e.js index 4c6185cc0..aa9465e68 100644 --- a/detox/e2e/test/smoke_test/channel_add_members.e2e.js +++ b/detox/e2e/test/smoke_test/channel_add_members.e2e.js @@ -19,7 +19,21 @@ import { } from '@support/server_api'; describe('Channel Add Members', () => { + const { + goToChannel, + postMessage, + } = ChannelScreen; + const { + addMembersAction, + channelInfoScrollView, + } = ChannelInfoScreen; + const { + addButton, + getUserByDisplayUsername, + searchInput, + } = ChannelAddMembersScreen; let testChannel; + let testAnotherUser; let testLastUser; beforeAll(async () => { @@ -30,7 +44,9 @@ describe('Channel Add Members', () => { const {user: testOtherUser} = await User.apiCreateUser({prefix: `a-${key}-`}); await Team.apiAddUserToTeam(testOtherUser.id, team.id); }); + ({user: testAnotherUser} = await User.apiCreateUser({prefix: 'b-other-'})); ({user: testLastUser} = await User.apiCreateUser({prefix: 'z-'})); + await Team.apiAddUserToTeam(testAnotherUser.id, team.id); await Team.apiAddUserToTeam(testLastUser.id, team.id); // # Open channel screen @@ -41,20 +57,37 @@ describe('Channel Add Members', () => { await ChannelScreen.logout(); }); - it('MM-T3197 should be able load users in long add members list', async () => { - const { - addMembersAction, - channelInfoScrollView, - } = ChannelInfoScreen; - + it('MM-T3196 should be able to add members to channel', async () => { // # Open add members screen - await ChannelScreen.goToChannel(testChannel.display_name); + await goToChannel(testChannel.display_name); + await postMessage('divider'); + await ChannelInfoScreen.open(); + await expect(element(by.id(ChannelInfoScreen.testID.manageMembersAction).withDescendant(by.text('2')))).toBeVisible(); + await channelInfoScrollView.scrollTo('bottom'); + await addMembersAction.tap(); + + // # Add members to channel + await searchInput.typeText('b-other'); + await getUserByDisplayUsername(`@${testAnotherUser.username}`).tap(); + await addButton.tap(); + + // * Verify members are added + await expect(element(by.id(ChannelInfoScreen.testID.manageMembersAction).withDescendant(by.text('3')))).toBeVisible(); + + // * Verify system message + await ChannelInfoScreen.close(); + await expect(element(by.text(`@${testAnotherUser.username} added to the channel by you.`))).toBeVisible(); + }); + + it('MM-T3197 should be able load users in long add members list', async () => { + // # Open add members screen + await goToChannel(testChannel.display_name); await ChannelInfoScreen.open(); await channelInfoScrollView.scrollTo('bottom'); await addMembersAction.tap(); // * Verify user can scroll down multiple times until last user is seen - await waitFor(ChannelAddMembersScreen.getUserByDisplayUsername(`@${testLastUser.username}`)).toBeVisible().whileElement(by.id(ChannelAddMembersScreen.testID.usersList)).scroll(500, 'down'); + await waitFor(getUserByDisplayUsername(`@${testLastUser.username}`)).toBeVisible().whileElement(by.id(ChannelAddMembersScreen.testID.usersList)).scroll(500, 'down'); await ChannelAddMembersScreen.back(); // # Close channel info screen diff --git a/detox/e2e/test/smoke_test/direct_messages.e2e.js b/detox/e2e/test/smoke_test/direct_messages.e2e.js index e08b3ef37..56df981ba 100644 --- a/detox/e2e/test/smoke_test/direct_messages.e2e.js +++ b/detox/e2e/test/smoke_test/direct_messages.e2e.js @@ -12,9 +12,12 @@ import { ChannelInfoScreen, ChannelScreen, MoreDirectMessagesScreen, + ThreadScreen, + UserProfileScreen, } from '@support/ui/screen'; import { Channel, + Post, Setup, Team, User, @@ -26,8 +29,10 @@ describe('Direct Messages', () => { const { channelNavBarTitle, closeMainSidebar, + getPostListPostItem, goToChannel, openMainSidebar, + openReplyThreadFor, } = ChannelScreen; const { getUserAtIndex, @@ -38,6 +43,7 @@ describe('Direct Messages', () => { let testUser; let testOtherUser; let townSquareChannel; + let testMessage; beforeAll(async () => { const {user, team} = await Setup.apiInit(); @@ -48,6 +54,14 @@ describe('Direct Messages', () => { ({channel: townSquareChannel} = await Channel.apiGetChannelByName(team.name, 'town-square')); + // # Post message by other user + testMessage = `Message by ${testOtherUser.username}`; + await User.apiLogin(testOtherUser); + await Post.apiCreatePost({ + channelId: townSquareChannel.id, + message: testMessage, + }); + // # Open channel screen await ChannelScreen.open(testUser); }); @@ -56,6 +70,35 @@ describe('Direct Messages', () => { await ChannelScreen.logout(); }); + it('MM-T3210 should be able to open direct message from profile info in channel', async () => { + // # Open user profile screen from channel + const {post} = await Post.apiGetLastPostInChannel(townSquareChannel.id); + const {postListPostItemProfilePicture} = await getPostListPostItem(post.id, testMessage, {userId: testOtherUser.id}); + await postListPostItemProfilePicture.tap(); + await UserProfileScreen.toBeVisible(); + + // # Open direct message from profile and verify can post message + await openDirectMessageFromProfileAndVerifyCanPostMessage(testOtherUser); + + // # Go back to channel + await goToChannel(townSquareChannel.display_name); + }); + + it('MM-T3211 should be able to open direct message from profile info in reply thread', async () => { + // # Open user profile screen from reply thread + const {post} = await Post.apiGetLastPostInChannel(townSquareChannel.id); + await openReplyThreadFor(post.id, testMessage); + const {postListPostItemProfilePicture} = await ThreadScreen.getPostListPostItem(post.id, testMessage, {userId: testOtherUser.id}); + await postListPostItemProfilePicture.tap(); + await UserProfileScreen.toBeVisible(); + + // # Open direct message from profile and verify can post message + await openDirectMessageFromProfileAndVerifyCanPostMessage(testOtherUser); + + // # Go back to channel + await goToChannel(townSquareChannel.display_name); + }); + it('MM-T3215 should be able to close direct message', async () => { // # Create a DM with the other user await openMainSidebar(); @@ -94,3 +137,24 @@ describe('Direct Messages', () => { await expect(channelNavBarTitle).toHaveText(`${testUser.username} (you) `); }); }); + +async function openDirectMessageFromProfileAndVerifyCanPostMessage(testOtherUser) { + const { + sendMessageAction, + userProfileScrollView, + } = UserProfileScreen; + + // # Open direct message from profile + await userProfileScrollView.scrollTo('bottom'); + await sendMessageAction.tap(); + + // * Verify DM channel is created + await ChannelInfoScreen.open(); + await expect(ChannelInfoScreen.channelDisplayName).toHaveText(testOtherUser.username); + + // * Verify direct message can be posted + const directMessage = Date.now().toString(); + await ChannelInfoScreen.close(); + await ChannelScreen.postMessage(directMessage); + await expect(element(by.text(directMessage))).toBeVisible(); +} diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 6f390dd27..2c28f7f3e 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -651,10 +651,10 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872 - DoubleConversion: cde416483dac037923206447da6e1454df403714 + DoubleConversion: cf9b38bf0b2d048436d9a82ad2abe1404f11e7de FBLazyVector: 49cbe4b43e445b06bf29199b6ad2057649e4c8f5 FBReactNativeSpec: 4862b23f27a9cdb8fdb1710af411fa677dcdd3cf - glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3 + glog: 73c2498ac6884b13ede40eda8228cb1eee9d9d62 jail-monkey: 80c9e34da2cd54023e5ad08bf7051ec75bd43d5b libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3 MMKV: 22e5136f7d00197bc0fc9694b7f71519f0d1ca12