MM-35674 Detox/E2E: Add e2e for autocomplete and at-mention (#5404)
* MM-35674 Detox/E2E: Add e2e for autocomplete and at-mention * Uncomment previously commented out line * Fix verification comment
This commit is contained in:
parent
3181c66348
commit
19196170dc
11 changed files with 328 additions and 12 deletions
|
|
@ -123,7 +123,7 @@ const AtMentionItem = (props: AtMentionItemProps) => {
|
|||
size={24}
|
||||
status={null}
|
||||
showStatus={false}
|
||||
testID={`${testID}.profile_picture`}
|
||||
testID='at_mention_item.profile_picture'
|
||||
/>
|
||||
</View>
|
||||
<View style={style.rowInfo}>
|
||||
|
|
@ -139,13 +139,15 @@ const AtMentionItem = (props: AtMentionItemProps) => {
|
|||
<Text
|
||||
style={style.rowFullname}
|
||||
numberOfLines={1}
|
||||
testID='at_mention_item.name'
|
||||
>
|
||||
{name} {name}
|
||||
{name}
|
||||
</Text>
|
||||
}
|
||||
<Text
|
||||
style={style.rowUsername}
|
||||
numberOfLines={1}
|
||||
testID='at_mention_item.username'
|
||||
>
|
||||
{isCurrentUser &&
|
||||
<FormattedText
|
||||
|
|
|
|||
|
|
@ -194,19 +194,19 @@ export const apiPatchUser = async (userId, userData) => {
|
|||
}
|
||||
};
|
||||
|
||||
function generateRandomUser(prefix) {
|
||||
const randomId = getRandomId();
|
||||
export const generateRandomUser = ({prefix = 'user', randomIdLength = 6} = {}) => {
|
||||
const randomId = getRandomId(randomIdLength);
|
||||
|
||||
return {
|
||||
email: `${prefix}${randomId}@sample.mattermost.com`,
|
||||
username: `${prefix}${randomId}`,
|
||||
password: 'passwd',
|
||||
first_name: `First${randomId}`,
|
||||
last_name: `Last${randomId}`,
|
||||
nickname: `Nickname${randomId}`,
|
||||
position: `Position${randomId}`,
|
||||
first_name: `F${randomId}`,
|
||||
last_name: `L${randomId}`,
|
||||
nickname: `N${randomId}`,
|
||||
position: `P${randomId}`,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const User = {
|
||||
apiAdminLogin,
|
||||
|
|
@ -220,6 +220,7 @@ export const User = {
|
|||
apiLogout,
|
||||
apiPatchMe,
|
||||
apiPatchUser,
|
||||
generateRandomUser,
|
||||
};
|
||||
|
||||
export default User;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ class Alert {
|
|||
// alert titles
|
||||
archivePrivateChannelTitle = isAndroid() ? element(by.text('Archive Private Channel')) : element(by.label('Archive Private Channel')).atIndex(0);
|
||||
archivePublicChannelTitle = isAndroid() ? element(by.text('Archive Public Channel')) : element(by.label('Archive Public Channel')).atIndex(0);
|
||||
confirmSendingNotificationsTitle = isAndroid() ? element(by.text('Confirm sending notifications to entire channel')) : element(by.label('Confirm sending notifications to entire channel')).atIndex(0);
|
||||
deleteDocumentsAndDataTitle = isAndroid() ? element(by.text('Delete Documents & Data')) : element(by.label('Delete Documents & Data')).atIndex(0);
|
||||
deletePostTitle = isAndroid() ? element(by.text('Delete Post')) : element(by.label('Delete Post')).atIndex(0);
|
||||
joinPrivateChannelTitle = isAndroid() ? element(by.text('Join private channel')) : element(by.label('Join private channel')).atIndex(0);
|
||||
|
|
@ -16,6 +17,7 @@ class Alert {
|
|||
|
||||
// alert buttons
|
||||
cancelButton = isAndroid() ? element(by.text('CANCEL')) : element(by.label('Cancel')).atIndex(1);
|
||||
confirmButton = isAndroid() ? element(by.text('CONFIRM')) : element(by.label('Confirm')).atIndex(1);
|
||||
deleteButton = isAndroid() ? element(by.text('DELETE')) : element(by.label('Delete')).atIndex(0);
|
||||
joinButton = isAndroid() ? element(by.text('JOIN')) : element(by.label('Join')).atIndex(0);
|
||||
okButton = isAndroid() ? element(by.text('OK')) : element(by.label('OK')).atIndex(1);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ class Autocomplete {
|
|||
atMentionItemPrefix: 'autocomplete.at_mention.item.',
|
||||
channelMentionItemPrefix: 'autocomplete.channel_mention.item.',
|
||||
autocomplete: 'autocomplete',
|
||||
atMentionItemName: 'at_mention_item.name',
|
||||
atMentionItemProfilePicture: 'at_mention_item.profile_picture',
|
||||
atMentionItemUsername: 'at_mention_item.username',
|
||||
atMentionSuggestionList: 'at_mention_suggestion.list',
|
||||
channelMentionSuggestionList: 'channel_mention_suggestion.list',
|
||||
dateSuggestion: 'autocomplete.date_suggestion',
|
||||
|
|
@ -21,7 +24,17 @@ class Autocomplete {
|
|||
slashSuggestionList = element(by.id(this.testID.slashSuggestionList));
|
||||
|
||||
getAtMentionItem = (userId) => {
|
||||
return element(by.id(`${this.testID.atMentionItemPrefix}${userId}`));
|
||||
const atMentionItemMatcher = by.id(`${this.testID.atMentionItemPrefix}${userId}`);
|
||||
const atMentionItemNameMatcher = by.id(this.testID.atMentionItemName).withAncestor(atMentionItemMatcher);
|
||||
const atMentionItemProfilePictureMatcher = by.id(this.testID.atMentionItemProfilePicture).withAncestor(atMentionItemMatcher);
|
||||
const atMentionItemUsernameMatcher = by.id(this.testID.atMentionItemUsername).withAncestor(atMentionItemMatcher);
|
||||
|
||||
return {
|
||||
atMentionItem: element(atMentionItemMatcher),
|
||||
atMentionItemName: element(atMentionItemNameMatcher),
|
||||
atMentionItemProfilePicture: element(atMentionItemProfilePictureMatcher),
|
||||
atMentionItemUsername: element(atMentionItemUsernameMatcher),
|
||||
};
|
||||
}
|
||||
|
||||
getChannelMentionItem = (channelId) => {
|
||||
|
|
|
|||
|
|
@ -224,6 +224,11 @@ class ChannelScreen {
|
|||
).toHaveText(postMessage);
|
||||
}
|
||||
|
||||
hasPostMessage = async (postId, postMessage) => {
|
||||
const {postListPostItem} = this.getPostListPostItem(postId, postMessage);
|
||||
await expect(postListPostItem).toBeVisible();
|
||||
}
|
||||
|
||||
hasPostMessageAtIndex = async (index, postMessage) => {
|
||||
await expect(
|
||||
this.getPostMessageAtIndex(index),
|
||||
|
|
|
|||
|
|
@ -52,6 +52,11 @@ class PermalinkScreen {
|
|||
).toHaveText(postMessage);
|
||||
}
|
||||
|
||||
hasPostMessage = async (postId, postMessage) => {
|
||||
const {postListPostItem} = this.getPostListPostItem(postId, postMessage);
|
||||
await expect(postListPostItem).toBeVisible();
|
||||
}
|
||||
|
||||
hasPostMessageAtIndex = async (index, postMessage) => {
|
||||
await expect(
|
||||
this.getPostMessageAtIndex(index),
|
||||
|
|
|
|||
|
|
@ -119,6 +119,11 @@ class ThreadScreen {
|
|||
).toHaveText(postMessage);
|
||||
}
|
||||
|
||||
hasPostMessage = async (postId, postMessage) => {
|
||||
const {postListPostItem} = this.getPostListPostItem(postId, postMessage);
|
||||
await expect(postListPostItem).toBeVisible();
|
||||
}
|
||||
|
||||
hasPostMessageAtIndex = async (index, postMessage) => {
|
||||
await expect(
|
||||
this.getPostMessageAtIndex(index),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ describe('Autocomplete', () => {
|
|||
|
||||
beforeAll(async () => {
|
||||
({user} = await Setup.apiInit());
|
||||
userAtMentionAutocomplete = Autocomplete.getAtMentionItem(user.id);
|
||||
({atMentionItem: userAtMentionAutocomplete} = Autocomplete.getAtMentionItem(user.id));
|
||||
|
||||
// # Open channel screen
|
||||
await ChannelScreen.open(user);
|
||||
|
|
|
|||
186
detox/e2e/test/autocomplete/autocomplete.e2e.js
Normal file
186
detox/e2e/test/autocomplete/autocomplete.e2e.js
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
// 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 {Autocomplete} from '@support/ui/component';
|
||||
import {
|
||||
ChannelScreen,
|
||||
SearchScreen,
|
||||
ThreadScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {
|
||||
Channel,
|
||||
Post,
|
||||
Setup,
|
||||
Team,
|
||||
User,
|
||||
} from '@support/server_api';
|
||||
|
||||
describe('Autocomplete', () => {
|
||||
const {
|
||||
goToChannel,
|
||||
openReplyThreadFor,
|
||||
postInput,
|
||||
postMessage,
|
||||
} = ChannelScreen;
|
||||
const {
|
||||
atMentionSuggestionList,
|
||||
emojiSuggestionList,
|
||||
slashSuggestionList,
|
||||
} = Autocomplete;
|
||||
let testUser;
|
||||
let testOtherUser;
|
||||
let testChannel;
|
||||
let townSquareChannel;
|
||||
|
||||
beforeAll(async () => {
|
||||
const currentUser = User.generateRandomUser();
|
||||
delete currentUser.nickname;
|
||||
const {channel, team, user} = await Setup.apiInit({userOptions: {user: currentUser}});
|
||||
testChannel = channel;
|
||||
testUser = user;
|
||||
|
||||
({user: testOtherUser} = await User.apiCreateUser());
|
||||
await Team.apiAddUserToTeam(testOtherUser.id, team.id);
|
||||
|
||||
({channel: townSquareChannel} = await Channel.apiGetChannelByName(team.id, 'town-square'));
|
||||
|
||||
// # Open channel screen
|
||||
await ChannelScreen.open(testUser);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
// # Clear text and verify that Autocomplete disappeared
|
||||
await postInput.clearText();
|
||||
await Autocomplete.toBeVisible(false);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T168 should have autocomplete items available from input boxes', async () => {
|
||||
// # Type ":ta" to activate emoji autocomplete
|
||||
await postInput.typeText(':ta');
|
||||
|
||||
// * Verify emoji autocomplete is displayed
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(emojiSuggestionList).toExist();
|
||||
|
||||
// # Type space to close emoji autocomplete
|
||||
await postInput.typeText(' ');
|
||||
|
||||
// * Verify emoji autocomplete is not displayed
|
||||
await expect(emojiSuggestionList).not.toExist();
|
||||
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await postInput.typeText('@');
|
||||
|
||||
// * Verify at mention autocomplete is displayed
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
|
||||
// # Post message, open reply thread, and type "/" to activate slash autocomplete
|
||||
const message = Date.now().toString();
|
||||
await postMessage(message, {quickReplace: true});
|
||||
const {post} = await Post.apiGetLastPostInChannel(townSquareChannel.id);
|
||||
await openReplyThreadFor(post.id, message);
|
||||
await ThreadScreen.postInput.typeText('/');
|
||||
|
||||
// * Verify slash autocomplete is displayed
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(slashSuggestionList).toExist();
|
||||
|
||||
// # Go back to channel
|
||||
await ThreadScreen.postInput.clearText();
|
||||
await ThreadScreen.back();
|
||||
});
|
||||
|
||||
it('MM-T171 should have at-mention autocomplete available out of channel members', async () => {
|
||||
// # Go to test channel
|
||||
await goToChannel(testChannel.display_name);
|
||||
|
||||
// # Activate at mention autocomplete for other user
|
||||
await postInput.typeText(`@${testOtherUser.username}`);
|
||||
|
||||
// * Verify at mention autocomplete with other user is displayed
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
const {atMentionItem: testOtherUserAutocomplete} = Autocomplete.getAtMentionItem(testOtherUser.id);
|
||||
await expect(testOtherUserAutocomplete).toExist();
|
||||
});
|
||||
|
||||
it('MM-T1798 should include self in user autocomplete', async () => {
|
||||
// # Activate at mention autocomplete for current user
|
||||
await postInput.typeText(`@${testUser.username}`);
|
||||
|
||||
// * Verify at mention autocomplete with current user is displayed
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
const {
|
||||
atMentionItem,
|
||||
atMentionItemName,
|
||||
atMentionItemUsername,
|
||||
} = Autocomplete.getAtMentionItem(testUser.id);
|
||||
await expect(atMentionItem).toExist();
|
||||
await expect(atMentionItemName).toHaveText(`${testUser.first_name} ${testUser.last_name}`);
|
||||
await expect(atMentionItemUsername).toHaveText(`(you) @${testUser.username}`);
|
||||
});
|
||||
|
||||
it('MM-T2349 should have autocomplete using nickname', async () => {
|
||||
// # Activate at mention autocomplete for other user using nickname
|
||||
await postInput.typeText(`@${testOtherUser.nickname}`);
|
||||
|
||||
// * Verify at mention autocomplete with other user is displayed
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
const {
|
||||
atMentionItem,
|
||||
atMentionItemName,
|
||||
atMentionItemUsername,
|
||||
} = Autocomplete.getAtMentionItem(testOtherUser.id);
|
||||
await expect(atMentionItem).toExist();
|
||||
await expect(atMentionItemName).toHaveText(`${testOtherUser.first_name} ${testOtherUser.last_name} (${testOtherUser.nickname})`);
|
||||
await expect(atMentionItemUsername).toHaveText(` @${testOtherUser.username}`);
|
||||
});
|
||||
|
||||
it('MM-T170 should be able to search usernames as case insensitive', async () => {
|
||||
const {
|
||||
searchInput,
|
||||
searchFromSection,
|
||||
} = SearchScreen;
|
||||
|
||||
// # Search user using lowercase username
|
||||
await SearchScreen.open();
|
||||
await searchInput.clearText();
|
||||
await searchFromSection.tap();
|
||||
const lowerCaseSearchTerm = testUser.username;
|
||||
await searchInput.typeText(lowerCaseSearchTerm);
|
||||
|
||||
// * Verify user is displayed using lowercase search term
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
const {atMentionItem: lowerCaseAtMention} = await Autocomplete.getAtMentionItem(testUser.id);
|
||||
await expect(lowerCaseAtMention).toBeVisible();
|
||||
|
||||
// # Search user using uppercase username
|
||||
await searchInput.clearText();
|
||||
await searchFromSection.tap();
|
||||
const upperCaseSearchTerm = testUser.username.toUpperCase();
|
||||
await searchInput.typeText(upperCaseSearchTerm);
|
||||
|
||||
// * Verify user is displayed using uppercase search term
|
||||
await Autocomplete.toBeVisible();
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
const {atMentionItem: upperCaseAtMention} = await Autocomplete.getAtMentionItem(testUser.id);
|
||||
await expect(upperCaseAtMention).toBeVisible();
|
||||
|
||||
// # Go back to channel
|
||||
await SearchScreen.cancel();
|
||||
});
|
||||
});
|
||||
97
detox/e2e/test/messaging/at_mention.e2e.js
Normal file
97
detox/e2e/test/messaging/at_mention.e2e.js
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// 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 {Alert} from '@support/ui/component';
|
||||
import {ChannelScreen} from '@support/ui/screen';
|
||||
import {
|
||||
Channel,
|
||||
Post,
|
||||
Setup,
|
||||
Team,
|
||||
User,
|
||||
} from '@support/server_api';
|
||||
|
||||
describe('At Mention', () => {
|
||||
const {
|
||||
hasPostMessage,
|
||||
postInput,
|
||||
postMessage,
|
||||
sendButton,
|
||||
} = ChannelScreen;
|
||||
let testUser;
|
||||
let testOtherUser;
|
||||
let townSquareChannel;
|
||||
let testTeam;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {team, user} = await Setup.apiInit();
|
||||
testTeam = team;
|
||||
testUser = user;
|
||||
|
||||
({user: testOtherUser} = await User.apiCreateUser());
|
||||
await Team.apiAddUserToTeam(testOtherUser.id, testTeam.id);
|
||||
|
||||
({channel: townSquareChannel} = await Channel.apiGetChannelByName(testTeam.id, 'town-square'));
|
||||
|
||||
// # Open channel screen
|
||||
await ChannelScreen.open(testUser);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-T169 should post at-mentions as lowercase', async () => {
|
||||
// # Post lowercase at-mention
|
||||
const lowerCaseMessage = `@${testUser.username}`;
|
||||
await postMessage(lowerCaseMessage);
|
||||
|
||||
// * Verify at-mention is posted as lowercase
|
||||
const {post: lowerCasePost} = await Post.apiGetLastPostInChannel(townSquareChannel.id);
|
||||
await hasPostMessage(lowerCasePost.id, lowerCaseMessage);
|
||||
|
||||
// # Post uppercase at-mention
|
||||
const upperCaseMessage = `@${testOtherUser.username.toUpperCase()}`;
|
||||
await postMessage(upperCaseMessage);
|
||||
|
||||
// * Verify at-mention is posted as lowercase
|
||||
const {post: upperCasePost} = await Post.apiGetLastPostInChannel(townSquareChannel.id);
|
||||
await hasPostMessage(upperCasePost.id, upperCaseMessage.toLowerCase());
|
||||
});
|
||||
|
||||
it('MM-T172 should display confirmation dialog when posting @all and @channel', async () => {
|
||||
const {
|
||||
cancelButton,
|
||||
confirmSendingNotificationsTitle,
|
||||
} = Alert;
|
||||
|
||||
// # Create 20 more users
|
||||
[...Array(20).keys()].forEach(async (key) => {
|
||||
const {user} = await User.apiCreateUser({prefix: `a-${key}-`});
|
||||
await Team.apiAddUserToTeam(user.id, testTeam.id);
|
||||
});
|
||||
|
||||
// # Post @all
|
||||
await postInput.typeText('@all');
|
||||
await sendButton.tap();
|
||||
|
||||
// * Verify confirmation dialog is displayed
|
||||
await expect(confirmSendingNotificationsTitle).toBeVisible();
|
||||
await cancelButton.tap();
|
||||
|
||||
// # Post @channel
|
||||
await postInput.clearText();
|
||||
await postInput.typeText('@channel');
|
||||
await sendButton.tap();
|
||||
|
||||
// * Verify confirmation dialog is displayed
|
||||
await expect(confirmSendingNotificationsTitle).toBeVisible();
|
||||
await cancelButton.tap();
|
||||
});
|
||||
});
|
||||
|
|
@ -226,7 +226,7 @@ async function postMessageAndSearchFrom(testMessage, testUser, atMentionSuggesti
|
|||
|
||||
// # Select user from autocomplete
|
||||
await expect(atMentionSuggestionList).toExist();
|
||||
const userAtMentionAutocomplete = await Autocomplete.getAtMentionItem(testUser.id);
|
||||
const {atMentionItem: userAtMentionAutocomplete} = await Autocomplete.getAtMentionItem(testUser.id);
|
||||
await userAtMentionAutocomplete.tap();
|
||||
|
||||
// # Type end of search term
|
||||
|
|
|
|||
Loading…
Reference in a new issue