From 27cafc8288f2747fdd1645948c3682c842a6e376 Mon Sep 17 00:00:00 2001 From: Joseph Baylon Date: Tue, 16 Mar 2021 14:34:13 -0700 Subject: [PATCH] MM-30425 Detox/E2E: Add e2e for MM-T3216, MM-T3217, MM-T3220, MM-T3240, MM-T3269 (#5222) * MM-30425 Detox/E2E: Add e2e for MM-T3216, MM-T3217, MM-T3220, MM-T3240, MM-T3269 * Added/fixed comments * Fix snap test * Stabilize for android Co-authored-by: Mattermod --- .../markdown/markdown_image/markdown_image.js | 5 +- .../show_more_button.test.js.snap | 3 + app/components/show_more_button/index.js | 5 +- detox/e2e/support/ui/component/post.js | 9 ++ detox/e2e/support/ui/component/post_list.js | 6 ++ detox/e2e/support/ui/screen/channel.js | 8 +- detox/e2e/support/ui/screen/long_post.js | 6 ++ detox/e2e/support/ui/screen/search.js | 10 +++ .../support/ui/screen/search_result_post.js | 6 ++ detox/e2e/support/ui/screen/thread.js | 8 +- .../test/smoke_test/direct_messages.e2e.js | 34 +++++--- .../test/smoke_test/message_posting.e2e.js | 63 ++++++++++++++ .../e2e/test/smoke_test/saved_messages.e2e.js | 19 ++++ detox/e2e/test/smoke_test/search.e2e.js | 87 +++++++++++++------ 14 files changed, 224 insertions(+), 45 deletions(-) create mode 100644 detox/e2e/test/smoke_test/message_posting.e2e.js diff --git a/app/components/markdown/markdown_image/markdown_image.js b/app/components/markdown/markdown_image/markdown_image.js index 2bbc585bf..f3634eb6c 100644 --- a/app/components/markdown/markdown_image/markdown_image.js +++ b/app/components/markdown/markdown_image/markdown_image.js @@ -239,7 +239,10 @@ export default class MarkdownImage extends ImageViewPort { } return ( - + {image} ); diff --git a/app/components/show_more_button/__snapshots__/show_more_button.test.js.snap b/app/components/show_more_button/__snapshots__/show_more_button.test.js.snap index 2bc6ff809..d52329f5a 100644 --- a/app/components/show_more_button/__snapshots__/show_more_button.test.js.snap +++ b/app/components/show_more_button/__snapshots__/show_more_button.test.js.snap @@ -3,6 +3,7 @@ exports[`ShowMoreButton should match, button snapshot 1`] = ` + { const postItemMatcher = this.getPostItemMatcher(postItemSourceTestID, postId, postMessage); + const postItemImageMatcher = by.id(this.testID.image).withAncestor(postItemMatcher); const postItemMessageMatcher = by.id(this.testID.message).withAncestor(postItemMatcher); const postItemPreHeaderTextMatch = by.id(this.testID.postPreHeaderText).withAncestor(postItemMatcher); + const postItemShowLessButtonMatcher = by.id(this.testID.showLessButton).withAncestor(postItemMatcher); + const postItemShowMoreButtonMatcher = by.id(this.testID.showMoreButton).withAncestor(postItemMatcher); return { postItem: element(postItemMatcher), + postItemImage: element(postItemImageMatcher), postItemMessage: element(postItemMessageMatcher), postItemPreHeaderText: element(postItemPreHeaderTextMatch), + postItemShowLessButton: element(postItemShowLessButtonMatcher), + postItemShowMoreButton: element(postItemShowMoreButtonMatcher), ...this.getPostHeader(postItemMatcher), ...this.getPostProfilePicture(postItemMatcher, postProfileOptions), }; diff --git a/detox/e2e/support/ui/component/post_list.js b/detox/e2e/support/ui/component/post_list.js index afd26fcee..7e05f25b9 100644 --- a/detox/e2e/support/ui/component/post_list.js +++ b/detox/e2e/support/ui/component/post_list.js @@ -17,10 +17,13 @@ class PostList { postItemHeaderDisplayName, postItemHeaderGuestTag, postItemHeaderReply, + postItemImage, postItemMessage, postItemPreHeaderText, postItemProfilePicture, postItemProfilePictureUserStatus, + postItemShowLessButton, + postItemShowMoreButton, } = Post.getPost(this.testID.postListPostItem, postId, postMessage, postProfileOptions); return { @@ -29,10 +32,13 @@ class PostList { postListPostItemHeaderDisplayName: postItemHeaderDisplayName, postListPostItemHeaderGuestTag: postItemHeaderGuestTag, postListPostItemHeaderReply: postItemHeaderReply, + postListPostItemImage: postItemImage, postListPostItemMessage: postItemMessage, postListPostItemPreHeaderText: postItemPreHeaderText, postListPostItemProfilePicture: postItemProfilePicture, postListPostItemProfilePictureUserStatus: postItemProfilePictureUserStatus, + postListPostItemShowLessButton: postItemShowLessButton, + postListPostItemShowMoreButton: postItemShowMoreButton, }; } diff --git a/detox/e2e/support/ui/screen/channel.js b/detox/e2e/support/ui/screen/channel.js index 65021a983..780cf9a96 100644 --- a/detox/e2e/support/ui/screen/channel.js +++ b/detox/e2e/support/ui/screen/channel.js @@ -175,10 +175,14 @@ class ChannelScreen { await ThreadScreen.toBeVisible(); } - postMessage = async (message) => { + postMessage = async (message, {quickReplace = false} = {}) => { // # Post message await this.postInput.tap(); - await this.postInput.typeText(message); + if (quickReplace) { + await this.postInput.replaceText(message); + } else { + await this.postInput.typeText(message); + } await this.tapSendButton(); } diff --git a/detox/e2e/support/ui/screen/long_post.js b/detox/e2e/support/ui/screen/long_post.js index b37820878..2745db3b0 100644 --- a/detox/e2e/support/ui/screen/long_post.js +++ b/detox/e2e/support/ui/screen/long_post.js @@ -15,9 +15,12 @@ class LongPostScreen { postItemHeaderDisplayName, postItemHeaderGuestTag, postItemHeaderReply, + postItemImage, postItemMessage, postItemProfilePicture, postItemProfilePictureUserStatus, + postItemShowLessButton, + postItemShowMoreButton, } = Post.getPost(this.testID.longPostItem, postId, postMessage, postProfileOptions); return { @@ -26,9 +29,12 @@ class LongPostScreen { longPostItemHeaderDisplayName: postItemHeaderDisplayName, longPostItemHeaderGuestTag: postItemHeaderGuestTag, longPostItemHeaderReply: postItemHeaderReply, + longPostItemImage: postItemImage, longPostItemMessage: postItemMessage, longPostItemProfilePicture: postItemProfilePicture, longPostItemProfilePictureUserStatus: postItemProfilePictureUserStatus, + longPostItemShowLessButton: postItemShowLessButton, + longPostItemShowMoreButton: postItemShowMoreButton, }; } diff --git a/detox/e2e/support/ui/screen/search.js b/detox/e2e/support/ui/screen/search.js index 9169188ab..fb7320992 100644 --- a/detox/e2e/support/ui/screen/search.js +++ b/detox/e2e/support/ui/screen/search.js @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. import { + PostOptions, RecentItem, SearchBar, } from '@support/ui/component'; @@ -75,6 +76,15 @@ class SearchScreen { await expect(this.clearButton).not.toExist(); } + openPostOptionsFor = async (postId, text) => { + const {searchResultPostItem} = await this.getSearchResultPostItem(postId, text); + await expect(searchResultPostItem).toBeVisible(); + + // # Open post options + await searchResultPostItem.longPress(); + await PostOptions.toBeVisible(); + } + hasSearchResultPostMessageAtIndex = async (index, postMessage) => { await expect( this.getSearchResultPostMessageAtIndex(index), diff --git a/detox/e2e/support/ui/screen/search_result_post.js b/detox/e2e/support/ui/screen/search_result_post.js index 5614c1bfb..9acc75463 100644 --- a/detox/e2e/support/ui/screen/search_result_post.js +++ b/detox/e2e/support/ui/screen/search_result_post.js @@ -15,9 +15,12 @@ class SearchResultPostScreen { postItemHeaderDisplayName, postItemHeaderGuestTag, postItemHeaderReply, + postItemImage, postItemMessage, postItemProfilePicture, postItemProfilePictureUserStatus, + postItemShowLessButton, + postItemShowMoreButton, } = Post.getPost(this.testID.searchResultPostItem, postId, postMessage, postProfileOptions); return { @@ -26,9 +29,12 @@ class SearchResultPostScreen { searchResultPostItemHeaderDisplayName: postItemHeaderDisplayName, searchResultPostItemHeaderGuestTag: postItemHeaderGuestTag, searchResultPostItemHeaderReply: postItemHeaderReply, + searchResultPostItemImage: postItemImage, searchResultPostItemMessage: postItemMessage, searchResultPostItemProfilePicture: postItemProfilePicture, searchResultPostItemProfilePictureUserStatus: postItemProfilePictureUserStatus, + searchResultPostItemShowLessButton: postItemShowLessButton, + searchResultPostItemShowMoreButton: postItemShowMoreButton, }; } diff --git a/detox/e2e/support/ui/screen/thread.js b/detox/e2e/support/ui/screen/thread.js index 5010cc010..90a6edee6 100644 --- a/detox/e2e/support/ui/screen/thread.js +++ b/detox/e2e/support/ui/screen/thread.js @@ -93,10 +93,14 @@ class ThreadScreen { await PostOptions.toBeVisible(); } - postMessage = async (message) => { + postMessage = async (message, {quickReplace = false} = {}) => { // # Post message await this.postInput.tap(); - await this.postInput.typeText(message); + if (quickReplace) { + await this.postInput.replaceText(message); + } else { + await this.postInput.typeText(message); + } await this.tapSendButton(); } diff --git a/detox/e2e/test/smoke_test/direct_messages.e2e.js b/detox/e2e/test/smoke_test/direct_messages.e2e.js index 853901d79..1677abd87 100644 --- a/detox/e2e/test/smoke_test/direct_messages.e2e.js +++ b/detox/e2e/test/smoke_test/direct_messages.e2e.js @@ -23,6 +23,17 @@ import {getRandomId} from '@support/utils'; describe('Direct Messages', () => { const searchTerm = getRandomId(); + const { + channelNavBarTitle, + closeMainSidebar, + openMainSidebar, + } = ChannelScreen; + const { + getUserAtIndex, + searchInput, + startButton, + } = MoreDirectMessagesScreen; + const {getChannelByDisplayName} = MainSidebar; let testUser; let testOtherUser; let townSquareChannel; @@ -45,18 +56,6 @@ describe('Direct Messages', () => { }); it('MM-T3215 should be able to close direct message', async () => { - const { - channelNavBarTitle, - closeMainSidebar, - openMainSidebar, - } = ChannelScreen; - const { - getUserAtIndex, - searchInput, - startButton, - } = MoreDirectMessagesScreen; - const {getChannelByDisplayName} = MainSidebar; - // # Create a DM with the other user await openMainSidebar(); await MoreDirectMessagesScreen.open(); @@ -81,4 +80,15 @@ describe('Direct Messages', () => { await expect(getChannelByDisplayName(testOtherUser.username)).not.toBeVisible(); await closeMainSidebar(); }); + + it('MM-T3216 should be able to open direct message with self', async () => { + // # Open a DM with self + await openMainSidebar(); + await MoreDirectMessagesScreen.open(); + await searchInput.typeText(testUser.username); + await getUserAtIndex(0).tap(); + + // * Verify DM channel with self is displayed + await expect(channelNavBarTitle).toHaveText(`${testUser.username} (you) `); + }); }); diff --git a/detox/e2e/test/smoke_test/message_posting.e2e.js b/detox/e2e/test/smoke_test/message_posting.e2e.js new file mode 100644 index 000000000..e1f6c9716 --- /dev/null +++ b/detox/e2e/test/smoke_test/message_posting.e2e.js @@ -0,0 +1,63 @@ +// 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} from '@support/ui/screen'; +import { + Channel, + Post, + Setup, +} from '@support/server_api'; + +describe('Message Posting', () => { + const { + getPostListPostItem, + postMessage, + } = ChannelScreen; + let testChannel; + + beforeAll(async () => { + const {team, user} = await Setup.apiInit(); + + const {channel} = await Channel.apiGetChannelByName(team.name, 'town-square'); + testChannel = channel; + + // # Open channel screen + await ChannelScreen.open(user); + }); + + afterAll(async () => { + await ChannelScreen.logout(); + }); + + it('MM-T3217 should be able to post a long message', async () => { + // # Post a long message + const message = 'The quick brown fox jumps over the lazy dog.'.repeat(30); + await postMessage(message, {quickReplace: true}); + + // * Verify message is posted + const {post} = await Post.apiGetLastPostInChannel(testChannel.id); + const { + postListPostItem, + postListPostItemShowMoreButton, + } = await getPostListPostItem(post.id, message); + await expect(postListPostItem).toExist(); + await expect(postListPostItemShowMoreButton).toExist(); + }); + + it('MM-T3269 should be able to post a markdown image', async () => { + // # Post a markdown image + const message = '![alt text that displays if loading fails](https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png)'; + await postMessage(message, {quickReplace: true}); + + // * Verify message is posted + const {post} = await Post.apiGetLastPostInChannel(testChannel.id); + const {postListPostItemImage} = await getPostListPostItem(post.id); + await expect(postListPostItemImage).toBeVisible(); + }); +}); diff --git a/detox/e2e/test/smoke_test/saved_messages.e2e.js b/detox/e2e/test/smoke_test/saved_messages.e2e.js index f60f8d8b6..f18490962 100644 --- a/detox/e2e/test/smoke_test/saved_messages.e2e.js +++ b/detox/e2e/test/smoke_test/saved_messages.e2e.js @@ -28,6 +28,8 @@ describe('Saved Messages', () => { postMessage, } = ChannelScreen; const { + postOptions, + reactionPickerAction, saveAction, unsaveAction, } = PostOptions; @@ -87,4 +89,21 @@ describe('Saved Messages', () => { // # Close saved messages screen await SavedMessagesScreen.close(); }); + + it('MM-T3220 should not be able to add a reaction on saved messages', async () => { + // # Save message from channel post list + const {post} = await Post.apiGetLastPostInChannel(testChannel.id); + await openPostOptionsFor(post.id, message); + await saveAction.tap(); + + // * Verify add a reaction is not available in post options + await openSettingsSidebar(); + await SavedMessagesScreen.open(); + await SavedMessagesScreen.openPostOptionsFor(post.id, message); + await expect(reactionPickerAction).not.toBeVisible(); + await postOptions.tap(); + + // # Close saved messages screen + await SavedMessagesScreen.close(); + }); }); diff --git a/detox/e2e/test/smoke_test/search.e2e.js b/detox/e2e/test/smoke_test/search.e2e.js index 74b66b369..2681f5715 100644 --- a/detox/e2e/test/smoke_test/search.e2e.js +++ b/detox/e2e/test/smoke_test/search.e2e.js @@ -7,7 +7,10 @@ // - Use element testID when selecting an element. Create one if none. // ******************************************************************* -import {Autocomplete} from '@support/ui/component'; +import { + Autocomplete, + PostOptions, +} from '@support/ui/component'; import { ChannelScreen, PermalinkScreen, @@ -21,12 +24,18 @@ import { } from '@support/server_api'; describe('Search', () => { - const testMessage = `test ${Date.now().toString()}`; - const partialSearchTerm = testMessage.split('-')[0]; const { atMentionSuggestionList, channelMentionSuggestionList, } = Autocomplete; + const { + getRecentSearchItem, + getSearchResultPostItem, + searchFromModifier, + searchInModifier, + } = SearchScreen; + let testMessage; + let testPartialSearchTerm; let testUser; let testChannel; @@ -41,17 +50,22 @@ describe('Search', () => { await ChannelScreen.open(user); }); + beforeEach(async () => { + testPartialSearchTerm = Date.now().toString(); + testMessage = `${testPartialSearchTerm} test`; + }); + afterAll(async () => { await ChannelScreen.logout(); }); it('MM-T3235 search on text, jump to result', async () => { // # Post message and search on text - await postMessageAndSearchText(testMessage, partialSearchTerm); + await postMessageAndSearchText(testMessage, testPartialSearchTerm); // # Open permalink from search result post item const lastPost = await Post.apiGetLastPostInChannel(testChannel.id); - const {searchResultPostItem} = await SearchScreen.getSearchResultPostItem(lastPost.post.id, testMessage); + const {searchResultPostItem} = await getSearchResultPostItem(lastPost.post.id, testMessage); await expect(searchResultPostItem).toBeVisible(); await searchResultPostItem.tap(); @@ -71,14 +85,14 @@ describe('Search', () => { it('MM-T3236 search on sender, select from autocomplete, reply from search results', async () => { // # Post message and search on sender - await postMessageAndSearchFrom(testMessage, testUser, atMentionSuggestionList, partialSearchTerm); + await postMessageAndSearchFrom(testMessage, testUser, atMentionSuggestionList, testPartialSearchTerm); // * Verify search result post has the message const lastPost = await Post.apiGetLastPostInChannel(testChannel.id); const { searchResultPostItem, searchResultPostItemHeaderReply, - } = await SearchScreen.getSearchResultPostItem(lastPost.post.id, testMessage); + } = await getSearchResultPostItem(lastPost.post.id, testMessage); await expect(searchResultPostItem).toBeVisible(); // # Open reply thread from search result post item @@ -101,11 +115,11 @@ describe('Search', () => { it('MM-T3237 search on channel, select from autocomplete, search in combination with a text string as well', async () => { // # Post message and search in channel - await postMessageAndSearchIn(testMessage, testChannel, channelMentionSuggestionList, partialSearchTerm); + await postMessageAndSearchIn(testMessage, testChannel, channelMentionSuggestionList, testPartialSearchTerm); // * Verify search result post has the message const lastPost = await Post.apiGetLastPostInChannel(testChannel.id); - const {searchResultPostItem} = await SearchScreen.getSearchResultPostItem(lastPost.post.id, testMessage); + const {searchResultPostItem} = await getSearchResultPostItem(lastPost.post.id, testMessage); await expect(searchResultPostItem).toBeVisible(); // # Go back to channel @@ -113,37 +127,56 @@ describe('Search', () => { }); it('MM-T3238 delete one previous search, tap on another', async () => { - const { - getRecentSearchItem, - searchInModifier, - } = SearchScreen; + // # Post message and search in channel + await postMessageAndSearchIn(testMessage, testChannel, channelMentionSuggestionList, testPartialSearchTerm); - // # Open search screen - await SearchScreen.open(); + // # Post message and search on sender + await SearchScreen.cancel(); + await postMessageAndSearchFrom(testMessage, testUser, atMentionSuggestionList, testPartialSearchTerm); // # Delete one previous text search - const previousTextSearch = await getRecentSearchItem(testMessage); + const fromSearchTerms = `${searchFromModifier} ${testUser.username} ${testPartialSearchTerm}`; + const previousTextSearch = await getRecentSearchItem(fromSearchTerms); await previousTextSearch.recentSearchItemRemoveButton.tap(); // * Verify previous text search is removed await expect(previousTextSearch.recentSearchItem).not.toBeVisible(); // # Tap on previous in search - const inSearchTerms = `${searchInModifier} ${testChannel.name} ${partialSearchTerm}`; + const inSearchTerms = `${searchInModifier} ${testChannel.name} ${testPartialSearchTerm}`; const previousInSearch = await getRecentSearchItem(inSearchTerms); await previousInSearch.recentSearchItem.tap(); // * Verify search result post has the message const lastPost = await Post.apiGetLastPostInChannel(testChannel.id); - const {searchResultPostItem} = await SearchScreen.getSearchResultPostItem(lastPost.post.id, testMessage); + const {searchResultPostItem} = await getSearchResultPostItem(lastPost.post.id, testMessage); await expect(searchResultPostItem).toBeVisible(); // # Go back to channel await SearchScreen.cancel(); }); + + it('MM-T3240 should not be able to add a reaction on search results', async () => { + const { + postOptions, + reactionPickerAction, + } = PostOptions; + + // # Post message and search on text + await postMessageAndSearchText(testMessage, testPartialSearchTerm); + + // * Verify add a reaction is not visible + const lastPost = await Post.apiGetLastPostInChannel(testChannel.id); + await SearchScreen.openPostOptionsFor(lastPost.post.id, testMessage); + await expect(reactionPickerAction).not.toBeVisible(); + await postOptions.tap(); + + // # Go back to channel + await SearchScreen.cancel(); + }); }); -async function postMessageAndSearchFrom(testMessage, testUser, atMentionSuggestionList, partialSearchTerm) { +async function postMessageAndSearchFrom(testMessage, testUser, atMentionSuggestionList, testPartialSearchTerm) { const { getRecentSearchItem, searchFromModifier, @@ -171,19 +204,19 @@ async function postMessageAndSearchFrom(testMessage, testUser, atMentionSuggesti await userAtMentionAutocomplete.tap(); // # Type end of search term - await searchInput.typeText(partialSearchTerm); + await searchInput.typeText(testPartialSearchTerm); // # Search user await searchInput.tapReturnKey(); await expect(atMentionSuggestionList).not.toExist(); // * Verify recent search item is displayed - const searchTerms = `${searchFromModifier} ${testUser.username} ${partialSearchTerm}`; + const searchTerms = `${searchFromModifier} ${testUser.username} ${testPartialSearchTerm}`; const {recentSearchItem} = await getRecentSearchItem(searchTerms); await expect(recentSearchItem).toBeVisible(); } -async function postMessageAndSearchIn(testMessage, testChannel, channelMentionSuggestionList, partialSearchTerm) { +async function postMessageAndSearchIn(testMessage, testChannel, channelMentionSuggestionList, testPartialSearchTerm) { const { getRecentSearchItem, searchInModifier, @@ -211,19 +244,19 @@ async function postMessageAndSearchIn(testMessage, testChannel, channelMentionSu await channelMentionAutocomplete.tap(); // # Type end of search term - await searchInput.typeText(partialSearchTerm); + await searchInput.typeText(testPartialSearchTerm); // # Search channel await searchInput.tapReturnKey(); await expect(channelMentionSuggestionList).not.toExist(); // * Verify recent search item is displayed - const searchTerms = `${searchInModifier} ${testChannel.name} ${partialSearchTerm}`; + const searchTerms = `${searchInModifier} ${testChannel.name} ${testPartialSearchTerm}`; const {recentSearchItem} = await getRecentSearchItem(searchTerms); await expect(recentSearchItem).toBeVisible(); } -async function postMessageAndSearchText(testMessage, partialSearchTerm) { +async function postMessageAndSearchText(testMessage, testPartialSearchTerm) { const { getRecentSearchItem, searchInput, @@ -237,12 +270,12 @@ async function postMessageAndSearchText(testMessage, partialSearchTerm) { // # Type beginning of search term await searchInput.clearText(); - await searchInput.typeText(partialSearchTerm); + await searchInput.typeText(testPartialSearchTerm); // # Search text await searchInput.tapReturnKey(); // * Verify recent search item is displayed - const {recentSearchItem} = await getRecentSearchItem(testMessage); + const {recentSearchItem} = await getRecentSearchItem(testPartialSearchTerm); await expect(recentSearchItem).toBeVisible(); }