From 48d4775907d03c3edf2cd7e6610c6f194ee02465 Mon Sep 17 00:00:00 2001 From: Joseph Baylon Date: Wed, 24 Mar 2021 07:13:10 -0700 Subject: [PATCH] MM-30428 Detox/E2E: Add e2e for MM-T3199, MM-T3223, MM-T3224 (#5240) * MM-30428 Detox/E2E: Add e2e for MM-T3199, MM-T3223, MM-T3224 * Updated variables to better names --- app/components/reactions/reaction.js | 8 +- .../__snapshots__/add_reaction.test.js.snap | 1 + app/screens/add_reaction/index.js | 1 + .../channel_info_header.test.js.snap | 12 +++ .../channel_info/channel_info_header.js | 6 +- .../e2e/support/ui/component/post_options.js | 2 +- detox/e2e/support/ui/screen/add_reaction.js | 12 ++- detox/e2e/support/ui/screen/channel_info.js | 12 ++- detox/e2e/test/channel_info/header.e2e.js | 2 +- .../guest_account/guest_experience.e2e.js | 2 +- detox/e2e/test/messaging/permalink.e2e.js | 17 +++- ...ping_channel_url_link_joins_channel.e2e.js | 7 +- detox/e2e/test/smoke_test/add_reaction.e2e.js | 96 +++++++++++++++++++ detox/e2e/test/smoke_test/channels.e2e.js | 1 + .../test/smoke_test/direct_messages.e2e.js | 2 +- detox/e2e/test/smoke_test/edit_channel.e2e.js | 65 +++++++++++++ .../e2e/test/smoke_test/group_messages.e2e.js | 2 +- .../test/smoke_test/message_posting.e2e.js | 4 +- detox/e2e/test/teams/select_team.e2e.js | 1 + 19 files changed, 235 insertions(+), 18 deletions(-) create mode 100644 detox/e2e/test/smoke_test/add_reaction.e2e.js create mode 100644 detox/e2e/test/smoke_test/edit_channel.e2e.js diff --git a/app/components/reactions/reaction.js b/app/components/reactions/reaction.js index ff70889c8e1..9b06e4c0e8c 100644 --- a/app/components/reactions/reaction.js +++ b/app/components/reactions/reaction.js @@ -51,8 +51,14 @@ export default class Reaction extends PureComponent { textStyle={{color: 'black', fontWeight: 'bold'}} customEmojiStyle={{marginHorizontal: 3}} padding={5} + testID={`reaction.emoji.${emojiName}`} /> - {count} + + {count} + ); } diff --git a/app/screens/add_reaction/__snapshots__/add_reaction.test.js.snap b/app/screens/add_reaction/__snapshots__/add_reaction.test.js.snap index 989974027fe..9418dcb1ddd 100644 --- a/app/screens/add_reaction/__snapshots__/add_reaction.test.js.snap +++ b/app/screens/add_reaction/__snapshots__/add_reaction.test.js.snap @@ -12,6 +12,7 @@ exports[`AddReaction should match snapshot 1`] = ` `; diff --git a/app/screens/add_reaction/index.js b/app/screens/add_reaction/index.js index 7d05445d383..5d451d01edc 100644 --- a/app/screens/add_reaction/index.js +++ b/app/screens/add_reaction/index.js @@ -68,6 +68,7 @@ const AddReaction = (props) => { ); diff --git a/app/screens/channel_info/__snapshots__/channel_info_header.test.js.snap b/app/screens/channel_info/__snapshots__/channel_info_header.test.js.snap index 791ebe124e1..53ce7188503 100644 --- a/app/screens/channel_info/__snapshots__/channel_info_header.test.js.snap +++ b/app/screens/channel_info/__snapshots__/channel_info_header.test.js.snap @@ -120,6 +120,7 @@ exports[`channel_info_header should match snapshot 1`] = ` "lineHeight": 20, } } + testID="channel_info.header.purpose" > Purpose string @@ -182,6 +183,7 @@ exports[`channel_info_header should match snapshot 1`] = ` disableGallery={true} onChannelLinkPress={[MockFunction]} onPermalinkPress={[MockFunction]} + testID="channel_info.header.header" textStyles={ Object { "code": Object { @@ -453,6 +455,7 @@ exports[`channel_info_header should match snapshot when DM and hasGuests and is "lineHeight": 20, } } + testID="channel_info.header.purpose" > Purpose string @@ -515,6 +518,7 @@ exports[`channel_info_header should match snapshot when DM and hasGuests and is disableGallery={true} onChannelLinkPress={[MockFunction]} onPermalinkPress={[MockFunction]} + testID="channel_info.header.header" textStyles={ Object { "code": Object { @@ -758,6 +762,7 @@ exports[`channel_info_header should match snapshot when DM and hasGuests but its "lineHeight": 20, } } + testID="channel_info.header.purpose" > Purpose string @@ -820,6 +825,7 @@ exports[`channel_info_header should match snapshot when DM and hasGuests but its disableGallery={true} onChannelLinkPress={[MockFunction]} onPermalinkPress={[MockFunction]} + testID="channel_info.header.header" textStyles={ Object { "code": Object { @@ -1091,6 +1097,7 @@ exports[`channel_info_header should match snapshot when GM and hasGuests 1`] = ` "lineHeight": 20, } } + testID="channel_info.header.purpose" > Purpose string @@ -1153,6 +1160,7 @@ exports[`channel_info_header should match snapshot when GM and hasGuests 1`] = ` disableGallery={true} onChannelLinkPress={[MockFunction]} onPermalinkPress={[MockFunction]} + testID="channel_info.header.header" textStyles={ Object { "code": Object { @@ -1396,6 +1404,7 @@ exports[`channel_info_header should match snapshot when is group constrained 1`] "lineHeight": 20, } } + testID="channel_info.header.purpose" > Purpose string @@ -1458,6 +1467,7 @@ exports[`channel_info_header should match snapshot when is group constrained 1`] disableGallery={true} onChannelLinkPress={[MockFunction]} onPermalinkPress={[MockFunction]} + testID="channel_info.header.header" textStyles={ Object { "code": Object { @@ -1750,6 +1760,7 @@ exports[`channel_info_header should match snapshot when public channel and hasGu "lineHeight": 20, } } + testID="channel_info.header.purpose" > Purpose string @@ -1812,6 +1823,7 @@ exports[`channel_info_header should match snapshot when public channel and hasGu disableGallery={true} onChannelLinkPress={[MockFunction]} onPermalinkPress={[MockFunction]} + testID="channel_info.header.header" textStyles={ Object { "code": Object { diff --git a/app/screens/channel_info/channel_info_header.js b/app/screens/channel_info/channel_info_header.js index 78cccbd4c41..8072ee7e437 100644 --- a/app/screens/channel_info/channel_info_header.js +++ b/app/screens/channel_info/channel_info_header.js @@ -188,7 +188,10 @@ export default class ChannelInfoHeader extends React.PureComponent { id='channel_info.purpose' defaultMessage='Purpose' /> - + {purpose} @@ -216,6 +219,7 @@ export default class ChannelInfoHeader extends React.PureComponent { value={header} onChannelLinkPress={popToRoot} disableAtChannelMentionHighlight={true} + testID={`${testID}.header`} /> diff --git a/detox/e2e/support/ui/component/post_options.js b/detox/e2e/support/ui/component/post_options.js index aeb132cf962..dd1205a31d6 100644 --- a/detox/e2e/support/ui/component/post_options.js +++ b/detox/e2e/support/ui/component/post_options.js @@ -37,7 +37,7 @@ class PostOptions { slideUpPanel = element(by.id(this.testID.slideUpPanel)); toBeVisible = async () => { - await expect(this.postOptions).toBeVisible(); + await expect(this.postOptions).toExist(); return postOptions; } diff --git a/detox/e2e/support/ui/screen/add_reaction.js b/detox/e2e/support/ui/screen/add_reaction.js index e882b9a3720..99bc2efe3cb 100644 --- a/detox/e2e/support/ui/screen/add_reaction.js +++ b/detox/e2e/support/ui/screen/add_reaction.js @@ -1,17 +1,27 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {PostOptions} from '@support/ui/component'; +import { + PostOptions, + SearchBar, +} from '@support/ui/component'; class AddReactionScreen { testID = { addReactionScreen: 'add_reaction.screen', + addReactionEmojiPickerPrefix: 'add_reaction.emoji_picker.', closeAddReactionButton: 'close.add_reaction.button', } addReactionScreen = element(by.id(this.testID.addReactionScreen)); closeAddReactionButton = element(by.id(this.testID.closeAddReactionButton)); + // convenience props + searchBar = SearchBar.getSearchBar(this.testID.addReactionEmojiPickerPrefix); + searchInput = SearchBar.getSearchInput(this.testID.addReactionEmojiPickerPrefix); + cancelButton = SearchBar.getCancelButton(this.testID.addReactionEmojiPickerPrefix); + clearButton = SearchBar.getClearButton(this.testID.addReactionEmojiPickerPrefix); + toBeVisible = async () => { await expect(this.addReactionScreen).toBeVisible(); diff --git a/detox/e2e/support/ui/screen/channel_info.js b/detox/e2e/support/ui/screen/channel_info.js index 119cb5e93b6..f16ea0bfae7 100644 --- a/detox/e2e/support/ui/screen/channel_info.js +++ b/detox/e2e/support/ui/screen/channel_info.js @@ -10,8 +10,10 @@ class ChannelInfoScreen { channelInfoScreen: 'channel_info.screen', channelInfoScrollView: 'channel_info.scroll_view', closeChannelInfoButton: 'close.channel_info.button', - headerChannelIconGMMemberCount: 'channel_info.header.channel_icon.gm_member_count', - headerDisplayName: 'channel_info.header.display_name', + channelIconGMMemberCount: 'channel_info.header.channel_icon.gm_member_count', + channelDisplayName: 'channel_info.header.display_name', + channelHeader: 'channel_info.header.header', + channelPurpose: 'channel_info.header.purpose', favoritePreferenceAction: 'channel_info.favorite.action', favoriteSwitchFalse: 'channel_info.favorite.action.switch.false', favoriteSwitchTrue: 'channel_info.favorite.action.switch.true', @@ -34,8 +36,10 @@ class ChannelInfoScreen { channelInfoScreen = element(by.id(this.testID.channelInfoScreen)); channelInfoScrollView = element(by.id(this.testID.channelInfoScrollView)); closeChannelInfoButton = element(by.id(this.testID.closeChannelInfoButton)); - headerChannelIconGMMemberCount = element(by.id(this.testID.headerChannelIconGMMemberCount)); - headerDisplayName = element(by.id(this.testID.headerDisplayName)); + channelIconGMMemberCount = element(by.id(this.testID.channelIconGMMemberCount)); + channelDisplayName = element(by.id(this.testID.channelDisplayName)); + channelHeader = element(by.id('markdown_text').withAncestor(by.id(this.testID.channelHeader))); + channelPurpose = element(by.id(this.testID.channelPurpose)); favoritePreferenceAction = element(by.id(this.testID.favoritePreferenceAction)); favoriteSwitchFalse = element(by.id(this.testID.favoriteSwitchFalse)); favoriteSwitchTrue = element(by.id(this.testID.favoriteSwitchTrue)); diff --git a/detox/e2e/test/channel_info/header.e2e.js b/detox/e2e/test/channel_info/header.e2e.js index d249dac7c8d..f28e5119d44 100644 --- a/detox/e2e/test/channel_info/header.e2e.js +++ b/detox/e2e/test/channel_info/header.e2e.js @@ -52,7 +52,7 @@ describe('Channel Info Header', () => { await ChannelInfoScreen.open(); // * Verify GM member count is 3 - await expect(ChannelInfoScreen.headerChannelIconGMMemberCount).toHaveText('3'); + await expect(ChannelInfoScreen.channelIconGMMemberCount).toHaveText('3'); // # Close channel info screen await ChannelInfoScreen.close(); diff --git a/detox/e2e/test/guest_account/guest_experience.e2e.js b/detox/e2e/test/guest_account/guest_experience.e2e.js index 209e105b83c..cc6d308bfc5 100644 --- a/detox/e2e/test/guest_account/guest_experience.e2e.js +++ b/detox/e2e/test/guest_account/guest_experience.e2e.js @@ -50,7 +50,7 @@ describe('Guest Experience', () => { await expect(postListPostItemHeaderGuestTag).not.toBeVisible(); }); - it('MM-T1397 Guest tag in search in:', async () => { + xit('MM-T1397 Guest tag in search in:', async () => { // Disabled due to https://mattermost.atlassian.net/browse/MM-33854 const { getSearchResultPostItem, searchInSection, diff --git a/detox/e2e/test/messaging/permalink.e2e.js b/detox/e2e/test/messaging/permalink.e2e.js index f611f33bb30..b2a6f436bc6 100644 --- a/detox/e2e/test/messaging/permalink.e2e.js +++ b/detox/e2e/test/messaging/permalink.e2e.js @@ -7,8 +7,20 @@ // - Use element testID when selecting an element. Create one if none. // ******************************************************************* -import {ChannelScreen, PermalinkScreen} from '@support/ui/screen'; -import {User, Setup, Channel, Post} from '@support/server_api'; +import { + ChannelScreen, + PermalinkScreen, +} from '@support/ui/screen'; +import { + timeouts, + wait, +} from '@support/utils'; +import { + Channel, + Post, + Setup, + User, +} from '@support/server_api'; describe('Permalink', () => { let testUser; @@ -43,6 +55,7 @@ describe('Permalink', () => { // # Tap the channel permalink await element(by.text(permalinkLabel)).tap({x: 5, y: 10}); + await wait(timeouts.ONE_SEC); // * Verify permalink post list has the expected target message await PermalinkScreen.toBeVisible(); diff --git a/detox/e2e/test/messaging/tapping_channel_url_link_joins_channel.e2e.js b/detox/e2e/test/messaging/tapping_channel_url_link_joins_channel.e2e.js index 0872a7389e5..7fc2e7e263a 100644 --- a/detox/e2e/test/messaging/tapping_channel_url_link_joins_channel.e2e.js +++ b/detox/e2e/test/messaging/tapping_channel_url_link_joins_channel.e2e.js @@ -30,6 +30,8 @@ import { import { getAdminAccount, getRandomId, + timeouts, + wait, } from '@support/utils'; describe('Messaging', () => { @@ -63,7 +65,7 @@ describe('Messaging', () => { const channelPermalink = `${serverUrl}/${testTeam.name}/channels/${testChannel.name}`; // # Post the channel permalink to the test channel in Town Square - await postMessage(channelPermalink, {quickReplace: true}); + await postMessage(channelPermalink); await expect(element(by.text(channelPermalink))).toBeVisible(); // # Create another user in the same team, log in and go to town square @@ -114,7 +116,7 @@ describe('Messaging', () => { // # Post Private Channel 2's POST Permalink const message2 = `${serverUrl}/${testTeam.name}/pl/${post.id}`; - await postMessage(message2, {quickReplace: true}); + await postMessage(message2); // * Check that message is successfully posted await expect(element(by.text(message2))).toExist(); @@ -186,4 +188,5 @@ async function joinPrivateChannel() { async function tapLink(message) { const permalinkPost = element(by.text(message)); await permalinkPost.tap({x: 5, y: 10}); + await wait(timeouts.ONE_SEC); } diff --git a/detox/e2e/test/smoke_test/add_reaction.e2e.js b/detox/e2e/test/smoke_test/add_reaction.e2e.js new file mode 100644 index 00000000000..6459e3d5f49 --- /dev/null +++ b/detox/e2e/test/smoke_test/add_reaction.e2e.js @@ -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 { + AddReactionScreen, + ChannelScreen, +} from '@support/ui/screen'; +import { + Channel, + Post, + Setup, + Team, + User, +} from '@support/server_api'; + +describe('Add Reaction', () => { + let testChannel; + let testOtherUser; + + beforeAll(async () => { + const {team, user} = await Setup.apiInit(); + + ({channel: testChannel} = await Channel.apiGetChannelByName(team.name, 'town-square')); + + ({user: testOtherUser} = await User.apiCreateUser()); + await Team.apiAddUserToTeam(testOtherUser.id, team.id); + + // # Open channel screen + await ChannelScreen.open(user); + }); + + afterAll(async () => { + await ChannelScreen.logout(); + }); + + it('MM-T3223 should be able to add a reaction to a post using long press and +:', async () => { + const { + openPostOptionsFor, + postMessage, + } = ChannelScreen; + const {searchInput} = AddReactionScreen; + + // # Post a message + const message = Date.now().toString(); + await postMessage(message); + + // # Add a reaction to the post using long press + const {post} = await Post.apiGetLastPostInChannel(testChannel.id); + await openPostOptionsFor(post.id, message); + await AddReactionScreen.open(); + await searchInput.typeText(':fox_face:'); + await element(by.text('🦊')).tap(); + + // # Add a reaction to the post using +: + await postMessage('+:dog:'); + + // * Verify emojis are added to post + await expect(element(by.text('🦊').withAncestor(by.id(`channel.post_list.post.${post.id}`)))).toExist(); + await expect(element(by.text('🐶').withAncestor(by.id(`channel.post_list.post.${post.id}`)))).toExist(); + + // * Verify emoji exists in recently used section + await openPostOptionsFor(post.id, message); + await AddReactionScreen.open(); + await expect(element(by.text('🦊').withAncestor(by.id('RECENTLY USED')))).toExist(); + await expect(element(by.text('🐶').withAncestor(by.id('RECENTLY USED')))).toExist(); + + // # Close add reaction screen + await AddReactionScreen.close(); + }); + + it('MM-T3224 should be able to remove own reaction and add to another user reaction', async () => { + // # Tap on own reaction to remove + await element(by.text('🦊')).tap(); + + // * Verify own reaction is removed + const {post} = await Post.apiGetLastPostInChannel(testChannel.id); + await expect(element(by.text('🦊').withAncestor(by.id(`channel.post_list.post.${post.id}`)))).not.toExist(); + + // # Login as new user + await ChannelScreen.logout(); + await ChannelScreen.open(testOtherUser); + + // # Add the same existing reaction + await expect(element(by.id('reaction.emoji.dog.count'))).toHaveText('1'); + await element(by.text('🐶')).tap(); + + // * Verify count incremented + await expect(element(by.id('reaction.emoji.dog.count'))).toHaveText('2'); + }); +}); diff --git a/detox/e2e/test/smoke_test/channels.e2e.js b/detox/e2e/test/smoke_test/channels.e2e.js index 181d41a3e12..b5ccf853c79 100644 --- a/detox/e2e/test/smoke_test/channels.e2e.js +++ b/detox/e2e/test/smoke_test/channels.e2e.js @@ -63,6 +63,7 @@ describe('Channels', () => { ({channel: nonJoinedChannel} = await Channel.apiCreateChannel({type: 'O', prefix: '1-non-joined-channel', teamId: team.id})); ({user: dmOtherUser} = await User.apiCreateUser({prefix: 'testchannel-1'})); + await Team.apiAddUserToTeam(dmOtherUser.id, team.id); ({channel: directMessageChannel} = await Channel.apiCreateDirectChannel([user.id, dmOtherUser.id])); await Post.apiCreatePost({ channelId: directMessageChannel.id, diff --git a/detox/e2e/test/smoke_test/direct_messages.e2e.js b/detox/e2e/test/smoke_test/direct_messages.e2e.js index 84806f8cb90..e08b3ef372f 100644 --- a/detox/e2e/test/smoke_test/direct_messages.e2e.js +++ b/detox/e2e/test/smoke_test/direct_messages.e2e.js @@ -66,7 +66,7 @@ describe('Direct Messages', () => { // * Verify DM channel is created await ChannelInfoScreen.open(); - await expect(ChannelInfoScreen.headerDisplayName).toHaveText(testOtherUser.username); + await expect(ChannelInfoScreen.channelDisplayName).toHaveText(testOtherUser.username); await ChannelInfoScreen.close(); await goToChannel(testOtherUser.username); diff --git a/detox/e2e/test/smoke_test/edit_channel.e2e.js b/detox/e2e/test/smoke_test/edit_channel.e2e.js new file mode 100644 index 00000000000..fee298c30a4 --- /dev/null +++ b/detox/e2e/test/smoke_test/edit_channel.e2e.js @@ -0,0 +1,65 @@ +// 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 { + ChannelScreen, + ChannelInfoScreen, + EditChannelScreen, +} from '@support/ui/screen'; +import {Setup} from '@support/server_api'; + +describe('Edit Channel', () => { + beforeAll(async () => { + const {user} = await Setup.apiInit(); + + // # Open channel screen + await ChannelScreen.open(user); + }); + + afterAll(async () => { + await ChannelScreen.logout(); + }); + + it('MM-T3199 should be able to edit public channel', async () => { + const { + editChannelScreen, + headerInput, + nameInput, + purposeInput, + saveButton, + } = EditChannelScreen; + const { + channelDisplayName, + channelPurpose, + } = ChannelInfoScreen; + + // # Open edit channel screen + await ChannelInfoScreen.open(); + await EditChannelScreen.open(); + + // # Edit channel info + await nameInput.typeText(' name'); + await purposeInput.typeText('purpose'); + await editChannelScreen.scrollTo('bottom'); + await headerInput.typeText('header1'); + await headerInput.tapReturnKey(); + await headerInput.typeText('header2'); + + // # Save changes + await saveButton.tap(); + + // * Verify changes have been saved + await expect(channelDisplayName).toHaveText('Town Square name'); + await expect(channelPurpose).toHaveText('purpose'); + await expect(element(by.text('header1\nheader2'))).toBeVisible(); + + // # Close channel info screen + await ChannelInfoScreen.close(); + }); +}); diff --git a/detox/e2e/test/smoke_test/group_messages.e2e.js b/detox/e2e/test/smoke_test/group_messages.e2e.js index 54bba11d5d8..31c567f8e2d 100644 --- a/detox/e2e/test/smoke_test/group_messages.e2e.js +++ b/detox/e2e/test/smoke_test/group_messages.e2e.js @@ -79,7 +79,7 @@ describe('Group Messages', () => { // * Verify GM channel is created await ChannelInfoScreen.open(); - await expect(ChannelInfoScreen.headerDisplayName).toHaveText(`${testOtherUser1.username}, ${testOtherUser2.username}`); + await expect(ChannelInfoScreen.channelDisplayName).toHaveText(`${testOtherUser1.username}, ${testOtherUser2.username}`); await ChannelInfoScreen.close(); // * Verify current user can post message to GM channel diff --git a/detox/e2e/test/smoke_test/message_posting.e2e.js b/detox/e2e/test/smoke_test/message_posting.e2e.js index ffb31365fe9..6f45daf38b5 100644 --- a/detox/e2e/test/smoke_test/message_posting.e2e.js +++ b/detox/e2e/test/smoke_test/message_posting.e2e.js @@ -82,11 +82,11 @@ describe('Message Posting', () => { it('MM-T3225 should be able to post a jumbo emoji', async () => { // # Post a jumbo emoji const message = ':fox_face:'; - await postMessage(message, {quickReplace: true}); + await postMessage(message); // * Verify message is posted const {post} = await Post.apiGetLastPostInChannel(testChannel.id); - const {postListPostItem} = await getPostListPostItem(post.id); + const {postListPostItem} = await getPostListPostItem(post.id, '🦊'); await expect(postListPostItem).toBeVisible(); }); }); diff --git a/detox/e2e/test/teams/select_team.e2e.js b/detox/e2e/test/teams/select_team.e2e.js index a87168acf7f..5a10c89ba66 100644 --- a/detox/e2e/test/teams/select_team.e2e.js +++ b/detox/e2e/test/teams/select_team.e2e.js @@ -41,6 +41,7 @@ describe('Select Team', () => { it('MM-T3619 should be able to select a team', async () => { // # Tap on team to join + await waitFor(SelectTeamScreen.getTeamByDisplayName(testTeam.display_name)).toBeVisible().whileElement(by.id(SelectTeamScreen.testID.teamsList)).scroll(500, 'down'); const team = await SelectTeamScreen.getTeamByDisplayName(testTeam.display_name); await team.tap();