diff --git a/app/components/reactions/reaction.js b/app/components/reactions/reaction.js
index ff70889c8..9b06e4c0e 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 989974027..9418dcb1d 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 7d05445d3..5d451d01e 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 791ebe124..53ce71885 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 78cccbd4c..8072ee7e4 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 aeb132cf9..dd1205a31 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 e882b9a37..99bc2efe3 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 119cb5e93..f16ea0bfa 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 d249dac7c..f28e5119d 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 209e105b8..cc6d308bf 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 f611f33bb..b2a6f436b 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 0872a7389..7fc2e7e26 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 000000000..6459e3d5f
--- /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 181d41a3e..b5ccf853c 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 84806f8cb..e08b3ef37 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 000000000..fee298c30
--- /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 54bba11d5..31c567f8e 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 ffb31365f..6f45daf38 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 a87168acf..5a10c89ba 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();