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:
Joseph Baylon 2021-06-01 07:37:34 -07:00 committed by GitHub
parent 3181c66348
commit 19196170dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 328 additions and 12 deletions

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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) => {

View file

@ -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),

View file

@ -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),

View file

@ -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),

View file

@ -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);

View 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();
});
});

View 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();
});
});

View file

@ -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