From 267c0e88cc89a2acb22e1962cfb986473d0dc45b Mon Sep 17 00:00:00 2001 From: Joseph Baylon Date: Tue, 27 Apr 2021 16:35:03 -0700 Subject: [PATCH] MM-35073 Detox/E2E: Add e2e for remaining eligible mobile smoke tests (#5352) Co-authored-by: Mattermod --- detox/e2e/support/ui/component/alert.js | 3 + detox/e2e/support/ui/screen/channel_info.js | 36 +++- .../test/smoke_test/direct_messages.e2e.js | 18 ++ .../test/smoke_test/private_channels.e2e.js | 181 ++++++++++++++++++ .../test/smoke_test/public_channels.e2e.js | 115 +++++++++++ package.json | 1 + 6 files changed, 352 insertions(+), 2 deletions(-) create mode 100644 detox/e2e/test/smoke_test/private_channels.e2e.js create mode 100644 detox/e2e/test/smoke_test/public_channels.e2e.js diff --git a/detox/e2e/support/ui/component/alert.js b/detox/e2e/support/ui/component/alert.js index 52fd84932..02caa60c0 100644 --- a/detox/e2e/support/ui/component/alert.js +++ b/detox/e2e/support/ui/component/alert.js @@ -5,10 +5,13 @@ import {isAndroid} from '@support/utils'; class Alert { // alert titles + archivePrivateChannelTitle = isAndroid() ? element(by.text('Archive Private Channel')) : element(by.label('Archive Private Channel')).atIndex(0); archivePublicChannelTitle = isAndroid() ? element(by.text('Archive Public Channel')) : element(by.label('Archive Public Channel')).atIndex(0); deleteDocumentsAndDataTitle = isAndroid() ? element(by.text('Delete Documents & Data')) : element(by.label('Delete Documents & Data')).atIndex(0); deletePostTitle = isAndroid() ? element(by.text('Delete Post')) : element(by.label('Delete Post')).atIndex(0); joinPrivateChannelTitle = isAndroid() ? element(by.text('Join private channel')) : element(by.label('Join private channel')).atIndex(0); + leavePrivateChannelTitle = isAndroid() ? element(by.text('Leave Private Channel')) : element(by.label('Leave Private Channel')).atIndex(0); + leavePublicChannelTitle = isAndroid() ? element(by.text('Leave Public Channel')) : element(by.label('Leave Public Channel')).atIndex(0); removeMembersTitle = isAndroid() ? element(by.text('Remove Members')) : element(by.label('Remove Members')).atIndex(0); // alert buttons diff --git a/detox/e2e/support/ui/screen/channel_info.js b/detox/e2e/support/ui/screen/channel_info.js index 58f4307ed..e27293595 100644 --- a/detox/e2e/support/ui/screen/channel_info.js +++ b/detox/e2e/support/ui/screen/channel_info.js @@ -78,15 +78,47 @@ class ChannelInfoScreen { await expect(this.channelInfoScreen).not.toBeVisible(); } - archiveChannel = async ({confirm = true} = {}) => { + archiveChannel = async ({confirm = true, publicChannel = true} = {}) => { await this.channelInfoScrollView.scrollTo('bottom'); await this.archiveAction.tap(); const { + archivePrivateChannelTitle, archivePublicChannelTitle, noButton, yesButton, } = Alert; - await expect(archivePublicChannelTitle).toBeVisible(); + if (publicChannel) { + await expect(archivePublicChannelTitle).toBeVisible(); + } else { + await expect(archivePrivateChannelTitle).toBeVisible(); + } + await expect(noButton).toBeVisible(); + await expect(yesButton).toBeVisible(); + if (confirm) { + yesButton.tap(); + await wait(timeouts.ONE_SEC); + await expect(this.channelInfoScreen).not.toBeVisible(); + } else { + noButton.tap(); + await wait(timeouts.ONE_SEC); + await expect(this.channelInfoScreen).toBeVisible(); + } + } + + leaveChannel = async ({confirm = true, publicChannel = true} = {}) => { + await this.channelInfoScrollView.scrollTo('bottom'); + await this.leaveAction.tap(); + const { + leavePrivateChannelTitle, + leavePublicChannelTitle, + noButton, + yesButton, + } = Alert; + if (publicChannel) { + await expect(leavePublicChannelTitle).toBeVisible(); + } else { + await expect(leavePrivateChannelTitle).toBeVisible(); + } await expect(noButton).toBeVisible(); await expect(yesButton).toBeVisible(); if (confirm) { diff --git a/detox/e2e/test/smoke_test/direct_messages.e2e.js b/detox/e2e/test/smoke_test/direct_messages.e2e.js index 56df981ba..b04b389f3 100644 --- a/detox/e2e/test/smoke_test/direct_messages.e2e.js +++ b/detox/e2e/test/smoke_test/direct_messages.e2e.js @@ -70,6 +70,24 @@ describe('Direct Messages', () => { await ChannelScreen.logout(); }); + it('MM-T3209 should be able to open direct message from main sidebar', async () => { + // # Create a DM with the other user + await openMainSidebar(); + await MoreDirectMessagesScreen.open(); + await searchInput.typeText(testOtherUser.username); + await getUserAtIndex(0).tap(); + await startButton.tap(); + + // * Verify DM channel is created + await ChannelInfoScreen.open(); + await expect(ChannelInfoScreen.channelDisplayName).toHaveText(testOtherUser.username); + await ChannelInfoScreen.close(); + await goToChannel(testOtherUser.username); + + // # Go back to channel + await goToChannel(townSquareChannel.display_name); + }); + 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); diff --git a/detox/e2e/test/smoke_test/private_channels.e2e.js b/detox/e2e/test/smoke_test/private_channels.e2e.js new file mode 100644 index 000000000..72b26ecd8 --- /dev/null +++ b/detox/e2e/test/smoke_test/private_channels.e2e.js @@ -0,0 +1,181 @@ +// 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} from '@support/ui/component'; +import { + ChannelAddMembersScreen, + ChannelInfoScreen, + ChannelMembersScreen, + ChannelScreen, + CreateChannelScreen, + EditChannelScreen, +} from '@support/ui/screen'; +import { + Channel, + Setup, + Team, + User, +} from '@support/server_api'; +import {getRandomId} from '@support/utils'; + +describe('Private Channels', () => { + const testOtherUserSearchTerm = 'a-other'; + const { + channelNavBarTitle, + closeMainSidebar, + goToChannel, + openMainSidebar, + postMessage, + } = ChannelScreen; + const { + addMembersAction, + channelDisplayName, + channelInfoScrollView, + channelPurpose, + leaveChannel, + manageMembersAction, + } = ChannelInfoScreen; + let testOtherUser; + let testPrivateChannel; + let townSquareChannel; + + beforeAll(async () => { + const {team, user} = await Setup.apiInit(); + + ({user: testOtherUser} = await User.apiCreateUser({prefix: `${testOtherUserSearchTerm}-`})); + await Team.apiAddUserToTeam(testOtherUser.id, team.id); + + ({channel: townSquareChannel} = await Channel.apiGetChannelByName(team.name, 'town-square')); + ({channel: testPrivateChannel} = await Channel.apiCreateChannel({type: 'P', prefix: '1-private-channel', teamId: team.id})); + await Channel.apiAddUserToChannel(user.id, testPrivateChannel.id); + + // # Open channel screen + await ChannelScreen.open(user); + }); + + afterAll(async () => { + await ChannelScreen.logout(); + }); + + it('MM-T3203 should be able to create a private channel', async () => { + const { + createButton, + nameInput, + } = CreateChannelScreen; + const {openCreatePrivateChannelButton} = MainSidebar; + + // # Create a private channel + const privateChannelName = `Channel-${getRandomId()}`; + await openMainSidebar(); + await openCreatePrivateChannelButton.tap(); + await CreateChannelScreen.toBeVisible(); + await expect(element(by.text('New Private Channel'))).toBeVisible(); + await nameInput.typeText(privateChannelName); + await createButton.tap(); + + // * Expect a redirection to the created channel + await expect(ChannelScreen.channelIntro).toHaveText('Beginning of ' + privateChannelName); + }); + + it('MM-T3204 should be able to add user to private channel', async () => { + const { + addButton, + getUserByDisplayUsername, + searchInput, + } = ChannelAddMembersScreen; + + // # Add user to private channel + await goToChannel(testPrivateChannel.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(); + await searchInput.typeText(testOtherUserSearchTerm); + await getUserByDisplayUsername(`@${testOtherUser.username}`).tap(); + await addButton.tap(); + + // * Verify user is added to private + await expect(element(by.id(ChannelInfoScreen.testID.manageMembersAction).withDescendant(by.text('3')))).toBeVisible(); + await ChannelInfoScreen.close(); + await expect(element(by.text(`@${testOtherUser.username} added to the channel by you.`))).toBeVisible(); + }); + + it('MM-T3205 should be able to remove user from private channel', async () => { + const { + removeMembers, + searchInput, + } = ChannelMembersScreen; + + // # Remove user from private channel + await goToChannel(testPrivateChannel.display_name); + await ChannelInfoScreen.open(); + await expect(element(by.id(ChannelInfoScreen.testID.manageMembersAction).withDescendant(by.text('3')))).toBeVisible(); + await manageMembersAction.tap(); + await searchInput.typeText(testOtherUserSearchTerm); + await removeMembers([testOtherUser.username]); + + // * Verify user is removed from private channel + await expect(element(by.id(ChannelInfoScreen.testID.manageMembersAction).withDescendant(by.text('2')))).toBeVisible(); + await manageMembersAction.tap(); + await searchInput.typeText(testOtherUserSearchTerm); + await expect(element(by.text('No Results'))).toBeVisible(); + await ChannelMembersScreen.back(); + + // # Close channel info screen + await ChannelInfoScreen.close(); + }); + + it('MM-T3206 should be able to edit private channel', async () => { + const { + editChannelScreen, + headerInput, + nameInput, + purposeInput, + saveButton, + } = EditChannelScreen; + + // # Edit private channel + await goToChannel(testPrivateChannel.display_name); + await ChannelInfoScreen.open(); + await EditChannelScreen.open(); + await nameInput.typeText(' name'); + await purposeInput.typeText(' purpose'); + await editChannelScreen.scrollTo('bottom'); + await headerInput.tapReturnKey(); + await headerInput.typeText('header1'); + await headerInput.tapReturnKey(); + await headerInput.typeText('header2'); + await saveButton.tap(); + + // * Verify private channel is updated + await channelInfoScrollView.scrollTo('top'); + await expect(channelDisplayName).toHaveText(`${testPrivateChannel.display_name} name`); + await expect(channelPurpose).toHaveText(`Channel purpose: ${testPrivateChannel.display_name.toLowerCase()} purpose`); + await expect(element(by.text(`Channel header: ${testPrivateChannel.display_name.toLowerCase()}\nheader1\nheader2`))).toBeVisible(); + + // # Close channel info screen + await ChannelInfoScreen.close(); + }); + + it('MM-T3207 should be able to leave private channel', async () => { + // # Attempt to leave private channel twice, tap No first, then tap Yes second + await ChannelInfoScreen.open(); + await leaveChannel({confirm: false, publicChannel: false}); + await leaveChannel({confirm: true, publicChannel: false}); + + // * Verify redirected to town square and does not appear in channel list + await expect(channelNavBarTitle).toHaveText(townSquareChannel.display_name); + await openMainSidebar(); + await expect(MainSidebar.getChannelByDisplayName(testPrivateChannel.display_name)).not.toBeVisible(); + + // # Close main sidebar + await closeMainSidebar(); + }); +}); diff --git a/detox/e2e/test/smoke_test/public_channels.e2e.js b/detox/e2e/test/smoke_test/public_channels.e2e.js new file mode 100644 index 000000000..41091be83 --- /dev/null +++ b/detox/e2e/test/smoke_test/public_channels.e2e.js @@ -0,0 +1,115 @@ +// 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} from '@support/ui/component'; +import { + ChannelInfoScreen, + ChannelScreen, + MoreChannelsScreen, +} from '@support/ui/screen'; +import { + Channel, + Setup, + System, +} from '@support/server_api'; + +describe('Public Channels', () => { + const testPublicChannePrefix = '1-public-channel'; + const { + channelNavBarTitle, + closeMainSidebar, + openMainSidebar, + } = ChannelScreen; + const { + archiveChannel, + leaveChannel, + } = ChannelInfoScreen; + const { + hasChannelDisplayNameAtIndex, + showArchivedChannels, + } = MoreChannelsScreen; + const { + getChannelByDisplayName, + getFilteredChannelByDisplayName, + searchInput, + } = MainSidebar; + let testPublicChannel; + let townSquareChannel; + + beforeAll(async () => { + const {team, user} = await Setup.apiInit(); + + ({channel: townSquareChannel} = await Channel.apiGetChannelByName(team.name, 'town-square')); + ({channel: testPublicChannel} = await Channel.apiCreateChannel({type: 'O', prefix: testPublicChannePrefix, teamId: team.id})); + + // # Open channel screen + await ChannelScreen.open(user); + }); + + afterAll(async () => { + await ChannelScreen.logout(); + }); + + it('MM-T3200 should be able to join existing public channel', async () => { + // # Join public channel + await openMainSidebar(); + await searchInput.typeText(testPublicChannePrefix); + await searchInput.tapBackspaceKey(); + await getFilteredChannelByDisplayName(testPublicChannel.display_name).tap(); + + // * Verify user is added to the channel + await expect(element(by.text('You and @sysadmin joined the channel.'))).toBeVisible(); + }); + + it('MM-T3202 should be able to leave public channel', async () => { + // # Attempt to leave public channel twice, tap No first, then tap Yes second + await expect(channelNavBarTitle).toHaveText(testPublicChannel.display_name); + await ChannelInfoScreen.open(); + await leaveChannel({confirm: false}); + await leaveChannel({confirm: true}); + + // * Verify redirected to town square and does not appear in channel list + await expect(channelNavBarTitle).toHaveText(townSquareChannel.display_name); + await openMainSidebar(); + await expect(getChannelByDisplayName(testPublicChannel.display_name)).not.toBeVisible(); + + // # Close main sidebar + await closeMainSidebar(); + }); + + it('MM-T3208 should be able to archive public channel', async () => { + // # Join public channel + await openMainSidebar(); + await searchInput.typeText(testPublicChannePrefix); + await searchInput.tapBackspaceKey(); + await getFilteredChannelByDisplayName(testPublicChannel.display_name).tap(); + + // # Attempt to archive public channel, tap No first, then tap Yes second + await expect(channelNavBarTitle).toHaveText(testPublicChannel.display_name); + await ChannelInfoScreen.open(); + await archiveChannel({confirm: false}); + await archiveChannel({confirm: true}); + + // * Verify redirected to town square and does not appear in channel list + await expect(channelNavBarTitle).toHaveText(townSquareChannel.display_name); + await openMainSidebar(); + await expect(getChannelByDisplayName(testPublicChannel.display_name)).not.toBeVisible(); + + // # Enable experimental view archived channels + await System.apiUpdateConfig({TeamSettings: {ExperimentalViewArchivedChannels: true}}); + + // * Verify public channel is archived + await MoreChannelsScreen.open(); + await showArchivedChannels(); + await hasChannelDisplayNameAtIndex(0, testPublicChannel.display_name); + + // # Close more channels screen + await MoreChannelsScreen.close(); + }); +}); diff --git a/package.json b/package.json index 5084871ef..61e77e7a7 100644 --- a/package.json +++ b/package.json @@ -162,6 +162,7 @@ "android": "react-native run-android", "ios": "react-native run-ios", "start": "react-native start", + "start:reset-cache": "react-native start -- --reset-cache", "check": "npm run lint && npm run tsc", "clean": "./scripts/clean.sh", "ios-gems": "cd ios && bundle install",