From c0ce5e349042d28f67c43ca0064f35abda979cd5 Mon Sep 17 00:00:00 2001 From: Joseph Baylon Date: Wed, 6 Jul 2022 11:15:45 -0700 Subject: [PATCH] Detox/E2E: Find channels, Edit channel, etc e2e tests in Gekidou --- app/screens/channel_info/extra/extra.tsx | 3 + .../unfiltered_list/unfiltered_list.tsx | 2 +- .../ui/screen/channel_dropdown_menu.ts | 4 +- detox/e2e/support/ui/screen/channel_info.ts | 33 ++++ .../ui/screen/create_or_edit_channel.ts | 8 +- ...draft.e2e.ts => channel_post_draft.e2e.ts} | 2 +- .../test/autocomplete/create_channel.e2e.ts | 96 ++++++++++ .../autocomplete/thread_post_draft.e2e.ts | 106 +++++++++++ .../e2e/test/channels/browse_channels.e2e.ts | 62 ++++++- ...te_channel_and_edit_channel_header.e2e.ts} | 0 detox/e2e/test/channels/edit_channel.e2e.ts | 175 ++++++++++++++++++ detox/e2e/test/channels/find_channels.e2e.ts | 152 +++++++++++++++ detox/e2e/test/smoke_test/channels.e2e.ts | 30 +++ 13 files changed, 664 insertions(+), 9 deletions(-) rename detox/e2e/test/autocomplete/{post_draft.e2e.ts => channel_post_draft.e2e.ts} (98%) create mode 100644 detox/e2e/test/autocomplete/create_channel.e2e.ts create mode 100644 detox/e2e/test/autocomplete/thread_post_draft.e2e.ts rename detox/e2e/test/channels/{create_and_edit_header.e2e.ts => create_channel_and_edit_channel_header.e2e.ts} (100%) create mode 100644 detox/e2e/test/channels/edit_channel.e2e.ts create mode 100644 detox/e2e/test/channels/find_channels.e2e.ts diff --git a/app/screens/channel_info/extra/extra.tsx b/app/screens/channel_info/extra/extra.tsx index 2857390811..c740c496dd 100644 --- a/app/screens/channel_info/extra/extra.tsx +++ b/app/screens/channel_info/extra/extra.tsx @@ -123,6 +123,7 @@ const Extra = ({channelId, createdAt, createdBy, customStatus, header}: Props) = id='channel_info.header' defaultMessage='Header:' style={styles.extraHeading} + testID='channel_info.extra.header' /> } @@ -160,6 +162,7 @@ const Extra = ({channelId, createdAt, createdBy, customStatus, header}: Props) = defaultMessage='Created on {date}' style={styles.created} values={created} + testID='channel_info.extra.created_on' /> } diff --git a/app/screens/find_channels/unfiltered_list/unfiltered_list.tsx b/app/screens/find_channels/unfiltered_list/unfiltered_list.tsx index 23073e0f98..5cbacda519 100644 --- a/app/screens/find_channels/unfiltered_list/unfiltered_list.tsx +++ b/app/screens/find_channels/unfiltered_list/unfiltered_list.tsx @@ -80,7 +80,7 @@ const UnfilteredList = ({close, keyboardHeight, recentChannels, showTeamName, un isInfo={true} onPress={onPress} showTeamName={showTeamName} - testID='find_channels.unfiltered_list.channel_item' + testID={`${testID}.channel_item`} /> ); }, [onPress, showTeamName]); diff --git a/detox/e2e/support/ui/screen/channel_dropdown_menu.ts b/detox/e2e/support/ui/screen/channel_dropdown_menu.ts index 2003dee1ee..c2a8264a71 100644 --- a/detox/e2e/support/ui/screen/channel_dropdown_menu.ts +++ b/detox/e2e/support/ui/screen/channel_dropdown_menu.ts @@ -9,8 +9,8 @@ class ChannelDropdownMenuScreen { testID = { channelDropdownMenuScreen: 'browse_channels.dropdown_slideup.screen', publicChannelsItem: 'browse_channels.dropdown_slideup_item.public_channels', - archivedChannelsItem: 'browse_channels.dropdown_slideup_item.public_channels', - sharedChannelsItem: 'browse_channels.dropdown_slideup_item.public_channels', + archivedChannelsItem: 'browse_channels.dropdown_slideup_item.archived_channels', + sharedChannelsItem: 'browse_channels.dropdown_slideup_item.shared_channels', }; channelDropdownMenuScreen = element(by.id(this.testID.channelDropdownMenuScreen)); diff --git a/detox/e2e/support/ui/screen/channel_info.ts b/detox/e2e/support/ui/screen/channel_info.ts index 2d5931383e..588c7c7782 100644 --- a/detox/e2e/support/ui/screen/channel_info.ts +++ b/detox/e2e/support/ui/screen/channel_info.ts @@ -1,20 +1,28 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import {ProfilePicture} from '@support/ui/component'; import {ChannelScreen} from '@support/ui/screen'; import {timeouts} from '@support/utils'; import {expect} from 'detox'; class ChannelInfoScreen { testID = { + directMessageTitlePrefix: 'channel_info.title.direct_message.', channelInfoScreen: 'channel_info.screen', closeButton: 'close.channel_info.button', scrollView: 'channel_info.scrollview', + groupMessageTitleDisplayName: 'channel_info.title.group_message.display_name', + publicPrivateTitleDisplayName: 'channel_info.title.public_private.display_name', + publicPrivateTitlePurpose: 'channel_info.title.public_private.purpose', favoriteAction: 'channel_info.channel_actions.favorite.action', muteAction: 'channel_info.channel_actions.mute.action', setHeaderAction: 'channel_info.channel_actions.set_header.action', addPeopleAction: 'channel_info.channel_actions.add_people.action', copyChannelLinkAction: 'channel_info.channel_actions.copy_channel_link.action', + extraHeader: 'channel_info.extra.header', + extraCreatedBy: 'channel_info.extra.created_by', + extraCreatedOn: 'channel_info.extra.created_on', ignoreMentionsOptionToggledOff: 'channel_info.options.ignore_mentions.option.toggled.false', ignoreMentionsOptionToggledOn: 'channel_info.options.ignore_mentions.option.toggled.true', notificationPreferenceOption: 'channel_info.options.notification_preference.option', @@ -29,11 +37,17 @@ class ChannelInfoScreen { channelInfoScreen = element(by.id(this.testID.channelInfoScreen)); closeButton = element(by.id(this.testID.closeButton)); scrollView = element(by.id(this.testID.scrollView)); + groupMessageTitleDisplayName = element(by.id(this.testID.groupMessageTitleDisplayName)); + publicPrivateTitleDisplayName = element(by.id(this.testID.publicPrivateTitleDisplayName)); + publicPrivateTitlePurpose = element(by.id(this.testID.publicPrivateTitlePurpose)); favoriteAction = element(by.id(this.testID.favoriteAction)); muteAction = element(by.id(this.testID.muteAction)); setHeaderAction = element(by.id(this.testID.setHeaderAction)); addPeopleAction = element(by.id(this.testID.addPeopleAction)); copyChannelLinkAction = element(by.id(this.testID.copyChannelLinkAction)); + extraHeader = element(by.id(this.testID.extraHeader)); + extraCreatedBy = element(by.id(this.testID.extraCreatedBy)); + extraCreatedOn = element(by.id(this.testID.extraCreatedOn)); ignoreMentionsOptionToggledOff = element(by.id(this.testID.ignoreMentionsOptionToggledOff)); ignoreMentionsOptionToggledOn = element(by.id(this.testID.ignoreMentionsOptionToggledOn)); notificationPreferenceOption = element(by.id(this.testID.notificationPreferenceOption)); @@ -44,6 +58,25 @@ class ChannelInfoScreen { leaveChannelOption = element(by.id(this.testID.leaveChannelOption)); archiveChannelOption = element(by.id(this.testID.archiveChannelOption)); + getDirectMessageTitle = async (userId: string) => { + const directMessageTitleTestId = `${this.testID.directMessageTitlePrefix}${userId}`; + const directMessageTitleProfilePictureMatcher = ProfilePicture.getProfilePictureItemMatcher(this.testID.directMessageTitlePrefix, userId); + const directMessageTitleUserDisplayNameMatcher = by.id(`${directMessageTitleTestId}.display_name`); + const directMessageTitleGuestTagMatcher = by.id(`${directMessageTitleTestId}.guest.tag`); + const directMessageTitleBotTagMatcher = by.id(`${directMessageTitleTestId}.bot.tag`); + const directMessageTitlePositionMatcher = by.id(`${directMessageTitleTestId}.position`); + const directMessageTitleBotDescriptionMatcher = by.id(`${directMessageTitleTestId}.bot_description`); + + return { + directMessageTitleProfilePicture: element(directMessageTitleProfilePictureMatcher), + directMessageTitleUserDisplayName: element(directMessageTitleUserDisplayNameMatcher), + directMessageTitleGuestTag: element(directMessageTitleGuestTagMatcher), + directMessageTitleBotTag: element(directMessageTitleBotTagMatcher), + directMessageTitlePosition: element(directMessageTitlePositionMatcher), + directMessageTitleBotDescription: element(directMessageTitleBotDescriptionMatcher), + }; + }; + toBeVisible = async () => { await waitFor(this.channelInfoScreen).toExist().withTimeout(timeouts.TEN_SEC); diff --git a/detox/e2e/support/ui/screen/create_or_edit_channel.ts b/detox/e2e/support/ui/screen/create_or_edit_channel.ts index 1a04b3ac98..b03ea3f7f9 100644 --- a/detox/e2e/support/ui/screen/create_or_edit_channel.ts +++ b/detox/e2e/support/ui/screen/create_or_edit_channel.ts @@ -63,9 +63,13 @@ class CreateOrEditChannelScreen { return this.toBeVisible(); }; - openEditChannelHeader = async () => { + openEditChannelHeader = async ({fromChannelInfo = false} = {}) => { // # Open edit channel header screen - await ChannelScreen.introSetHeaderOption.tap(); + if (fromChannelInfo) { + await ChannelInfoScreen.setHeaderAction.tap(); + } else { + await ChannelScreen.introSetHeaderOption.tap(); + } return this.toBeVisible(); }; diff --git a/detox/e2e/test/autocomplete/post_draft.e2e.ts b/detox/e2e/test/autocomplete/channel_post_draft.e2e.ts similarity index 98% rename from detox/e2e/test/autocomplete/post_draft.e2e.ts rename to detox/e2e/test/autocomplete/channel_post_draft.e2e.ts index f441aa1cd0..79bda76e4f 100644 --- a/detox/e2e/test/autocomplete/post_draft.e2e.ts +++ b/detox/e2e/test/autocomplete/channel_post_draft.e2e.ts @@ -22,7 +22,7 @@ import { } from '@support/ui/screen'; import {expect} from 'detox'; -describe('Autocomplete - Post Draft', () => { +describe('Autocomplete - Channel Post Draft', () => { const serverOneDisplayName = 'Server 1'; const channelsCategory = 'channels'; diff --git a/detox/e2e/test/autocomplete/create_channel.e2e.ts b/detox/e2e/test/autocomplete/create_channel.e2e.ts new file mode 100644 index 0000000000..661c257ddc --- /dev/null +++ b/detox/e2e/test/autocomplete/create_channel.e2e.ts @@ -0,0 +1,96 @@ +// 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 {Autocomplete} from '@support/ui/component'; +import { + ChannelListScreen, + CreateOrEditChannelScreen, + HomeScreen, + LoginScreen, + ServerScreen, +} from '@support/ui/screen'; +import {expect} from 'detox'; + +describe('Autocomplete - Create Channel', () => { + const serverOneDisplayName = 'Server 1'; + + beforeAll(async () => { + const {user} = await Setup.apiInit(siteOneUrl); + + // # Log in to server + await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName); + await LoginScreen.login(user); + + // * Verify on channel list screen + await ChannelListScreen.toBeVisible(); + + // # Open create channel screen + await CreateOrEditChannelScreen.openCreateChannel(); + }); + + beforeEach(async () => { + // # Clear header input + await CreateOrEditChannelScreen.headerInput.clearText(); + }); + + afterAll(async () => { + // # Log out + await CreateOrEditChannelScreen.close(); + await HomeScreen.logout(); + }); + + it('MM-T4904_1 - should render at-mention autocomplete in header input', async () => { + // * Verify at-mention list is not displayed + await expect(Autocomplete.sectionAtMentionList).not.toBeVisible(); + + // # Type in "@" to activate at-mention autocomplete + await CreateOrEditChannelScreen.headerInput.typeText('@'); + + // * Verify at-mention list is displayed + await expect(Autocomplete.sectionAtMentionList).toBeVisible(); + }); + + it('MM-T4904_2 - should render channel mention autocomplete in header input', async () => { + // * Verify channel mention list is not displayed + await expect(Autocomplete.sectionChannelMentionList).not.toBeVisible(); + + // # Type in "~" to activate channel mention autocomplete + await CreateOrEditChannelScreen.headerInput.typeText('~'); + + // * Verify channel mention list is displayed + await expect(Autocomplete.sectionChannelMentionList).toBeVisible(); + }); + + it('MM-T4904_3 - should render emoji suggestion autocomplete in header input', async () => { + // * Verify emoji suggestion list is not displayed + await expect(Autocomplete.flatEmojiSuggestionList).not.toBeVisible(); + + // # Type in ":" followed by 2 characters to activate emoji suggestion autocomplete + await CreateOrEditChannelScreen.headerInput.typeText(':sm'); + + // * Verify emoji suggestion list is displayed + await expect(Autocomplete.flatEmojiSuggestionList).toBeVisible(); + }); + + it('MM-T4904_4 - should not render slash suggestion autocomplete in header input', async () => { + // * Verify slash suggestion list is not displayed + await expect(Autocomplete.flatEmojiSuggestionList).not.toBeVisible(); + + // # Type in "/" to activate slash suggestion autocomplete + await CreateOrEditChannelScreen.headerInput.typeText('/'); + + // * Verify slash suggestion list is still not displayed + await expect(Autocomplete.flatEmojiSuggestionList).not.toBeVisible(); + }); +}); diff --git a/detox/e2e/test/autocomplete/thread_post_draft.e2e.ts b/detox/e2e/test/autocomplete/thread_post_draft.e2e.ts new file mode 100644 index 0000000000..1341813bf6 --- /dev/null +++ b/detox/e2e/test/autocomplete/thread_post_draft.e2e.ts @@ -0,0 +1,106 @@ +// 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 {Autocomplete} from '@support/ui/component'; +import { + ChannelListScreen, + ChannelScreen, + HomeScreen, + LoginScreen, + ServerScreen, + ThreadScreen, +} from '@support/ui/screen'; +import {getRandomId} from '@support/utils'; +import {expect} from 'detox'; + +describe('Autocomplete - Thread Post Draft', () => { + const serverOneDisplayName = 'Server 1'; + const channelsCategory = 'channels'; + + beforeAll(async () => { + const {channel, user} = await Setup.apiInit(siteOneUrl); + + // # Log in to server + await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName); + await LoginScreen.login(user); + + // * Verify on channel list screen + await ChannelListScreen.toBeVisible(); + + // # Open a channel screen, post a message, and tap on post to open reply thread + const message = `Message ${getRandomId()}`; + await ChannelScreen.open(channelsCategory, channel.name); + await ChannelScreen.postMessage(message); + await element(by.text(message)).tap(); + }); + + beforeEach(async () => { + // # Clear post input + await ThreadScreen.postInput.clearText(); + + // * Verify autocomplete is not displayed + await Autocomplete.toBeVisible(false); + }); + + afterAll(async () => { + // # Log out + await ThreadScreen.back(); + await ChannelScreen.back(); + await HomeScreen.logout(); + }); + + it('MM-T4905_1 - should render at-mention autocomplete in post input', async () => { + // * Verify at-mention list is not displayed + await expect(Autocomplete.sectionAtMentionList).not.toBeVisible(); + + // # Type in "@" to activate at-mention autocomplete + await ThreadScreen.postInput.typeText('@'); + + // * Verify at-mention list is displayed + await expect(Autocomplete.sectionAtMentionList).toBeVisible(); + }); + + it('MM-T4905_2 - should render channel mention autocomplete in post input', async () => { + // * Verify channel mention list is not displayed + await expect(Autocomplete.sectionChannelMentionList).not.toBeVisible(); + + // # Type in "~" to activate channel mention autocomplete + await ThreadScreen.postInput.typeText('~'); + + // * Verify channel mention list is displayed + await expect(Autocomplete.sectionChannelMentionList).toBeVisible(); + }); + + it('MM-T4905_3 - should render emoji suggestion autocomplete in post input', async () => { + // * Verify emoji suggestion list is not displayed + await expect(Autocomplete.flatEmojiSuggestionList).not.toBeVisible(); + + // # Type in ":" followed by 2 characters to activate emoji suggestion autocomplete + await ThreadScreen.postInput.typeText(':sm'); + + // * Verify emoji suggestion list is displayed + await expect(Autocomplete.flatEmojiSuggestionList).toBeVisible(); + }); + + it('MM-T4905_4 - should render slash suggestion autocomplete in post input', async () => { + // * Verify slash suggestion list is not displayed + await expect(Autocomplete.flatSlashSuggestionList).not.toBeVisible(); + + // # Type in "/" to activate slash suggestion autocomplete + await ThreadScreen.postInput.typeText('/'); + + // * Verify slash suggestion list is displayed + await expect(Autocomplete.flatSlashSuggestionList).toBeVisible(); + }); +}); diff --git a/detox/e2e/test/channels/browse_channels.e2e.ts b/detox/e2e/test/channels/browse_channels.e2e.ts index 4b49f6adf5..50b2ec84ee 100644 --- a/detox/e2e/test/channels/browse_channels.e2e.ts +++ b/detox/e2e/test/channels/browse_channels.e2e.ts @@ -10,6 +10,9 @@ import { Channel, Setup, + System, + Team, + User, } from '@support/server_api'; import { serverOneUrl, @@ -17,6 +20,7 @@ import { } from '@support/test_config'; import { BrowseChannelsScreen, + ChannelDropdownMenuScreen, ChannelScreen, ChannelListScreen, HomeScreen, @@ -29,14 +33,25 @@ describe('Channels - Browse Channels', () => { const serverOneDisplayName = 'Server 1'; const channelsCategory = 'channels'; let testTeam: any; + let testUser: any; beforeAll(async () => { + System.apiUpdateConfig(siteOneUrl, { + ServiceSettings: { + EnableAPIChannelDeletion: true, + }, + TeamSettings: { + ExperimentalViewArchivedChannels: true, + }, + }); + const {team, user} = await Setup.apiInit(siteOneUrl); testTeam = team; + testUser = user; // # Log in to server await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName); - await LoginScreen.login(user); + await LoginScreen.login(testUser); }); beforeEach(async () => { @@ -62,7 +77,7 @@ describe('Channels - Browse Channels', () => { await BrowseChannelsScreen.close(); }); - it('MM-T4729_2 - should be able to browse and join channels', async () => { + it('MM-T4729_2 - should be able to browse and join a channel', async () => { // # As admin, create a new channel so that user can join const {channel} = await Channel.apiCreateChannel(siteOneUrl, {teamId: testTeam.id}); @@ -79,7 +94,7 @@ describe('Channels - Browse Channels', () => { // # Tap on the new channel item await BrowseChannelsScreen.getChannelItem(channel.name).multiTap(2); - // * Verify on newly joined channel screen + // * Verify on newly joined channel screen await ChannelScreen.toBeVisible(); await expect(ChannelScreen.headerTitle).toHaveText(channel.display_name); await expect(ChannelScreen.introDisplayName).toHaveText(channel.display_name); @@ -105,4 +120,45 @@ describe('Channels - Browse Channels', () => { // # Go back to channel list screen await BrowseChannelsScreen.close(); }); + + it('MM-T4729_4 - should not be able to browse direct and group message channels', async () => { + // # Create direct and group message channels, open browse channels screen, and search for the direct message channel + const {user: testOtherUser1} = await User.apiCreateUser(siteOneUrl, {prefix: 'a'}); + await Team.apiAddUserToTeam(siteOneUrl, testOtherUser1.id, testTeam.id); + const {user: testOtherUser2} = await User.apiCreateUser(siteOneUrl, {prefix: 'b'}); + await Team.apiAddUserToTeam(siteOneUrl, testOtherUser2.id, testTeam.id); + await Channel.apiCreateDirectChannel(siteOneUrl, [testUser.id, testOtherUser1.id]); + await Channel.apiCreateGroupChannel(siteOneUrl, [testUser.id, testOtherUser1.id, testOtherUser2.id]); + await BrowseChannelsScreen.open(); + await BrowseChannelsScreen.searchInput.replaceText(testOtherUser1.username); + + // * Verify empty search state for browse channels + await expect(element(by.text(`No results for “${testOtherUser1.username}”`))).toBeVisible(); + + // # Search for the group message channel + await BrowseChannelsScreen.searchInput.replaceText(testOtherUser2.username); + + // * Verify empty search state for browse channels + await expect(element(by.text(`No results for “${testOtherUser2.username}”`))).toBeVisible(); + + // # Go back to channel list screen + await BrowseChannelsScreen.close(); + }); + + it('MM-T4729_5 - should be able to browse an archived channel', async () => { + // # Archive a channel, open browse channels screen, tap on channel dropdown, tap on archived channels menu item, and search for the archived channel + const {channel: archivedChannel} = await Channel.apiCreateChannel(siteOneUrl, {teamId: testTeam.id}); + await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, archivedChannel.id); + await Channel.apiDeleteChannel(siteOneUrl, archivedChannel.id); + await BrowseChannelsScreen.open(); + await BrowseChannelsScreen.channelDropdownTextPublic.tap(); + await ChannelDropdownMenuScreen.archivedChannelsItem.tap(); + await BrowseChannelsScreen.searchInput.replaceText(archivedChannel.name); + + // * Verify search returns the archived channel item + await expect(BrowseChannelsScreen.getChannelItemDisplayName(archivedChannel.name)).toHaveText(archivedChannel.display_name); + + // # Go back to channel list screen + await BrowseChannelsScreen.close(); + }); }); diff --git a/detox/e2e/test/channels/create_and_edit_header.e2e.ts b/detox/e2e/test/channels/create_channel_and_edit_channel_header.e2e.ts similarity index 100% rename from detox/e2e/test/channels/create_and_edit_header.e2e.ts rename to detox/e2e/test/channels/create_channel_and_edit_channel_header.e2e.ts diff --git a/detox/e2e/test/channels/edit_channel.e2e.ts b/detox/e2e/test/channels/edit_channel.e2e.ts new file mode 100644 index 0000000000..026db4606c --- /dev/null +++ b/detox/e2e/test/channels/edit_channel.e2e.ts @@ -0,0 +1,175 @@ +// 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, + Team, + User, +} from '@support/server_api'; +import { + serverOneUrl, + siteOneUrl, +} from '@support/test_config'; +import { + ChannelScreen, + ChannelInfoScreen, + ChannelListScreen, + CreateDirectMessageScreen, + CreateOrEditChannelScreen, + HomeScreen, + LoginScreen, + ServerScreen, +} from '@support/ui/screen'; +import {expect} from 'detox'; + +describe('Channels - Edit Channel', () => { + const serverOneDisplayName = 'Server 1'; + const channelsCategory = 'channels'; + let testOtherUser1: any; + let testOtherUser2: any; + let testChannel: any; + + beforeAll(async () => { + const {channel, team, user} = await Setup.apiInit(siteOneUrl); + testChannel = channel; + + ({user: testOtherUser1} = await User.apiCreateUser(siteOneUrl, {prefix: 'a'})); + await Team.apiAddUserToTeam(siteOneUrl, testOtherUser1.id, team.id); + ({user: testOtherUser2} = await User.apiCreateUser(siteOneUrl, {prefix: 'b'})); + await Team.apiAddUserToTeam(siteOneUrl, testOtherUser2.id, team.id); + + // # Log in to server + await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName); + await LoginScreen.login(user); + + // * Verify on channel list screen + await ChannelListScreen.toBeVisible(); + + // # Open a channel screen + await ChannelScreen.open(channelsCategory, testChannel.name); + }); + + beforeEach(async () => { + // * Verify on channel screen + await ChannelScreen.toBeVisible(); + }); + + afterAll(async () => { + // # Log out + await ChannelScreen.back(); + await HomeScreen.logout(); + }); + + it('MM-T4906_1 - should match elements on edit channel screen', async () => { + // # Open channel info screen and open edit channel screen + await ChannelInfoScreen.open(); + await CreateOrEditChannelScreen.openEditChannel(); + + // * Verify basic elements on edit channel screen + await expect(CreateOrEditChannelScreen.backButton).toBeVisible(); + await expect(CreateOrEditChannelScreen.saveButton).toBeVisible(); + await expect(CreateOrEditChannelScreen.displayNameInput).toBeVisible(); + await expect(CreateOrEditChannelScreen.purposeInput).toBeVisible(); + await expect(CreateOrEditChannelScreen.purposeDescription).toHaveText('Describe how this channel should be used.'); + await expect(CreateOrEditChannelScreen.headerInput).toBeVisible(); + await expect(CreateOrEditChannelScreen.headerDescription).toHaveText('Specify text to appear in the channel header beside the channel name. For example, include frequently used links by typing link text [Link Title](http://example.com).'); + + // # Go back to channel screen + await CreateOrEditChannelScreen.back(); + await ChannelInfoScreen.close(); + }); + + it('MM-T4906_2 - should be able to edit public channel', async () => { + // # Open channel info screen and open edit channel screen + await ChannelInfoScreen.open(); + await CreateOrEditChannelScreen.openEditChannel(); + + // * Verify current values of fields + await expect(CreateOrEditChannelScreen.displayNameInput).toHaveValue(testChannel.display_name); + await expect(CreateOrEditChannelScreen.purposeInput).toHaveValue(`Channel purpose: ${testChannel.display_name.toLowerCase()}`); + await expect(CreateOrEditChannelScreen.headerInput).toHaveValue(`Channel header: ${testChannel.display_name.toLowerCase()}`); + + // # Edit channel info and save changes + await CreateOrEditChannelScreen.displayNameInput.typeText(' name'); + await CreateOrEditChannelScreen.purposeInput.typeText(' purpose'); + await CreateOrEditChannelScreen.headerInput.tapReturnKey(); + await CreateOrEditChannelScreen.headerInput.typeText('header1'); + await CreateOrEditChannelScreen.headerInput.tapReturnKey(); + await CreateOrEditChannelScreen.headerInput.typeText('header2'); + await CreateOrEditChannelScreen.saveButton.tap(); + + // * Verify on channel info screen and changes have been saved + await ChannelInfoScreen.toBeVisible(); + await expect(ChannelInfoScreen.publicPrivateTitleDisplayName).toHaveText(`${testChannel.display_name} name`); + await expect(ChannelInfoScreen.publicPrivateTitlePurpose).toHaveText(`Channel purpose: ${testChannel.display_name.toLowerCase()} purpose`); + await expect(element(by.text(`Channel header: ${testChannel.display_name.toLowerCase()}\nheader1\nheader2`))).toBeVisible(); + + // # Go back to channel screen + await ChannelInfoScreen.close(); + }); + + it('MM-T4906_3 - should be able edit direct message channel', async () => { + // # Create a direct message with another user + await ChannelScreen.back(); + await CreateDirectMessageScreen.open(); + await CreateDirectMessageScreen.closeTutorial(); + await CreateDirectMessageScreen.searchInput.replaceText(testOtherUser1.username); + await CreateDirectMessageScreen.getUserItem(testOtherUser1.id).tap(); + await CreateDirectMessageScreen.startButton.tap(); + + // * Verify on direct message channel screen + await ChannelScreen.toBeVisible(); + await expect(ChannelScreen.headerTitle).toHaveText(testOtherUser1.username); + + // # Open channel info screen, open edit channel header screen, edit channel info, and save changes + await ChannelInfoScreen.open(); + await CreateOrEditChannelScreen.openEditChannelHeader({fromChannelInfo: true}); + await CreateOrEditChannelScreen.headerInput.typeText('header1'); + await CreateOrEditChannelScreen.headerInput.tapReturnKey(); + await CreateOrEditChannelScreen.headerInput.typeText('header2'); + await CreateOrEditChannelScreen.saveButton.tap(); + + // * Verify on channel info screen and changes have been saved + await ChannelInfoScreen.toBeVisible(); + await expect(element(by.text('header1\nheader2'))).toBeVisible(); + + // # Go back to channel screen + await ChannelInfoScreen.close(); + }); + + it('MM-T4906_4 - should be able edit group message channel', async () => { + // # Create a group message with two other users + await ChannelScreen.back(); + await CreateDirectMessageScreen.open(); + await CreateDirectMessageScreen.searchInput.replaceText(testOtherUser1.username); + await CreateDirectMessageScreen.getUserItem(testOtherUser1.id).tap(); + await CreateDirectMessageScreen.searchInput.replaceText(testOtherUser2.username); + await CreateDirectMessageScreen.getUserItem(testOtherUser2.id).tap(); + await CreateDirectMessageScreen.startButton.tap(); + + // * Verify on group message channel screen + await ChannelScreen.toBeVisible(); + await expect(ChannelScreen.headerTitle).toHaveText(`${testOtherUser1.username}, ${testOtherUser2.username}`); + + // # Open channel info screen, open edit channel header screen, edit channel info, and save changes + await ChannelInfoScreen.open(); + await CreateOrEditChannelScreen.openEditChannelHeader({fromChannelInfo: true}); + await CreateOrEditChannelScreen.headerInput.typeText('header1'); + await CreateOrEditChannelScreen.headerInput.tapReturnKey(); + await CreateOrEditChannelScreen.headerInput.typeText('header2'); + await CreateOrEditChannelScreen.saveButton.tap(); + + // * Verify on channel info screen and changes have been saved + await ChannelInfoScreen.toBeVisible(); + await expect(element(by.text('header1\nheader2'))).toBeVisible(); + + // # Go back to channel screen + await ChannelInfoScreen.close(); + }); +}); diff --git a/detox/e2e/test/channels/find_channels.e2e.ts b/detox/e2e/test/channels/find_channels.e2e.ts new file mode 100644 index 0000000000..8dd1609f71 --- /dev/null +++ b/detox/e2e/test/channels/find_channels.e2e.ts @@ -0,0 +1,152 @@ +// 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 { + Channel, + Setup, + System, + Team, + User, +} from '@support/server_api'; +import { + serverOneUrl, + siteOneUrl, +} from '@support/test_config'; +import { + ChannelScreen, + ChannelListScreen, + FindChannelsScreen, + HomeScreen, + LoginScreen, + ServerScreen, +} from '@support/ui/screen'; +import {expect} from 'detox'; + +describe('Channels - Find Channels', () => { + const serverOneDisplayName = 'Server 1'; + let testChannel: any; + let testTeam: any; + let testUser: any; + + beforeAll(async () => { + System.apiUpdateConfig(siteOneUrl, { + ServiceSettings: { + EnableAPIChannelDeletion: true, + }, + TeamSettings: { + ExperimentalViewArchivedChannels: true, + }, + }); + + const {channel, team, user} = await Setup.apiInit(siteOneUrl); + testChannel = channel; + testTeam = team; + testUser = user; + + // # Log in to server + await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName); + await LoginScreen.login(testUser); + }); + + beforeEach(async () => { + // * Verify on channel list screen + await ChannelListScreen.toBeVisible(); + }); + + afterAll(async () => { + // # Log out + await HomeScreen.logout(); + }); + + it('MM-T4907_1 - should match elements on find channels screen', async () => { + // # Open find channels screen + await FindChannelsScreen.open(); + + // * Verify basic elements on find channels screen + await expect(FindChannelsScreen.closeButton).toBeVisible(); + await expect(FindChannelsScreen.searchInput).toBeVisible(); + await expect(FindChannelsScreen.sectionUnfilteredChannelList).toExist(); + + // # Go back to channel list screen + await FindChannelsScreen.close(); + }); + + it('MM-T4907_2 - should be able to find and navigate to a channel', async () => { + // # Open find channels screen and search for the channel to navigate to + await FindChannelsScreen.open(); + await FindChannelsScreen.searchInput.replaceText(testChannel.name); + + // * Verify search returns the target channel item + await expect(FindChannelsScreen.getFilteredChannelItemDisplayName(testChannel.name)).toHaveText(testChannel.display_name); + + // # Tap on the target channel item + await FindChannelsScreen.getFilteredChannelItem(testChannel.name).tap(); + + // * Verify on target channel screen + await ChannelScreen.toBeVisible(); + await expect(ChannelScreen.headerTitle).toHaveText(testChannel.display_name); + await expect(ChannelScreen.introDisplayName).toHaveText(testChannel.display_name); + + // # Go back to channel list screen + await ChannelScreen.back(); + }); + + it('MM-T4907_3 - should display empty search state for find channels', async () => { + // # Open find channels screen and search for a non-existent channel + const searchTerm = 'blahblahblahblah'; + await FindChannelsScreen.open(); + await FindChannelsScreen.searchInput.replaceText(searchTerm); + + // * Verify empty search state for find channels + await expect(element(by.text(`No results for “${searchTerm}”`))).toBeVisible(); + await expect(element(by.text('Check the spelling or try another search.'))).toBeVisible(); + + // # Go back to channel list screen + await FindChannelsScreen.close(); + }); + + it('MM-T4907_4 - should be able to find direct and group message channels', async () => { + // # Create direct and group message channels, open find channels screen, and search for the direct message channel + const {user: testOtherUser1} = await User.apiCreateUser(siteOneUrl, {prefix: 'a'}); + await Team.apiAddUserToTeam(siteOneUrl, testOtherUser1.id, testTeam.id); + const {user: testOtherUser2} = await User.apiCreateUser(siteOneUrl, {prefix: 'b'}); + await Team.apiAddUserToTeam(siteOneUrl, testOtherUser2.id, testTeam.id); + const {channel: directMessageChannel} = await Channel.apiCreateDirectChannel(siteOneUrl, [testUser.id, testOtherUser1.id]); + const {channel: groupMessageChannel} = await Channel.apiCreateGroupChannel(siteOneUrl, [testUser.id, testOtherUser1.id, testOtherUser2.id]); + await FindChannelsScreen.open(); + await FindChannelsScreen.searchInput.replaceText(testOtherUser1.username); + + // * Verify search returns the target direct message channel item + await expect(FindChannelsScreen.getFilteredChannelItemDisplayName(directMessageChannel.name)).toHaveText(testOtherUser1.username); + + // # Search for the group message channel + await FindChannelsScreen.searchInput.replaceText(testOtherUser2.username); + + // * Verify search returns the target group message channel item + await expect(FindChannelsScreen.getFilteredChannelItemDisplayName(groupMessageChannel.name)).toHaveText(`${testOtherUser1.username}, ${testOtherUser2.username}, sysadmin`); + + // # Go back to channel list screen + await FindChannelsScreen.close(); + }); + + it('MM-T4907_5 - should be able to find archived channel', async () => { + // # Archive a channel, open find channels screen, and search for the archived channel + const {channel: archivedChannel} = await Channel.apiCreateChannel(siteOneUrl, {teamId: testTeam.id}); + await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, archivedChannel.id); + await Channel.apiDeleteChannel(siteOneUrl, archivedChannel.id); + await FindChannelsScreen.open(); + await FindChannelsScreen.searchInput.replaceText(archivedChannel.name); + + // * Verify search returns the target archived channel item + await expect(FindChannelsScreen.getFilteredChannelItemDisplayName(archivedChannel.name)).toHaveText(archivedChannel.display_name); + + // # Go back to channel list screen + await FindChannelsScreen.close(); + }); +}); diff --git a/detox/e2e/test/smoke_test/channels.e2e.ts b/detox/e2e/test/smoke_test/channels.e2e.ts index 289c8c945e..56ebe5c7aa 100644 --- a/detox/e2e/test/smoke_test/channels.e2e.ts +++ b/detox/e2e/test/smoke_test/channels.e2e.ts @@ -21,9 +21,11 @@ import { import { BrowseChannelsScreen, ChannelScreen, + ChannelInfoScreen, ChannelListScreen, CreateDirectMessageScreen, CreateOrEditChannelScreen, + FindChannelsScreen, HomeScreen, LoginScreen, ServerScreen, @@ -128,4 +130,32 @@ describe('Smoke Test - Channels', () => { // # Go back to channel list screen await ChannelScreen.back(); }); + + it('MM-T4774_4 - should be able to find and edit a channel', async () => { + // # Open find channels screen, search for the channel to navigate to, and tap on the target channel item + await FindChannelsScreen.open(); + await FindChannelsScreen.searchInput.replaceText(testChannel.name); + await FindChannelsScreen.getFilteredChannelItem(testChannel.name).tap(); + + // * Verify on target channel screen + await ChannelScreen.toBeVisible(); + await expect(ChannelScreen.headerTitle).toHaveText(testChannel.display_name); + + // # Open channel info screen, open edit channel screen, edit channel info, and save changes + await ChannelInfoScreen.open(); + await CreateOrEditChannelScreen.openEditChannel(); + await CreateOrEditChannelScreen.headerInput.tapReturnKey(); + await CreateOrEditChannelScreen.headerInput.typeText('header1'); + await CreateOrEditChannelScreen.headerInput.tapReturnKey(); + await CreateOrEditChannelScreen.headerInput.typeText('header2'); + await CreateOrEditChannelScreen.saveButton.tap(); + + // * Verify on channel info screen and changes have been saved + await ChannelInfoScreen.toBeVisible(); + await expect(element(by.text(`Channel header: ${testChannel.display_name.toLowerCase()}\nheader1\nheader2`))).toBeVisible(); + + // # Go back to channel list screen + await ChannelInfoScreen.close(); + await ChannelScreen.back(); + }); });