MM-35679 Detox/E2E: Add e2e for DMs, GMs, main sidebar (#5521)

This commit is contained in:
Joseph Baylon 2021-07-09 03:53:57 -07:00 committed by GitHub
parent 1b5d76712a
commit eed5b41292
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 381 additions and 56 deletions

View file

@ -260,6 +260,7 @@ export default class List extends PureComponent {
leftButtons: [{
id: 'close-dms',
icon: this.closeButton,
testID: 'close.more_direct_messages.button',
}],
},
};

View file

@ -21,6 +21,7 @@ exports[`SelectedUsers should match snapshot 1`] = `
<SelectedUser
onRemove={[MockFunction]}
teammateNameDisplay="full_name"
testID="more_direct_messages.selected_user"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -99,6 +100,7 @@ exports[`SelectedUsers should match snapshot for no warning message 1`] = `
<SelectedUser
onRemove={[MockFunction]}
teammateNameDisplay="full_name"
testID="more_direct_messages.selected_user"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -159,6 +161,7 @@ exports[`SelectedUsers should match snapshot to show warning for ability to add
<SelectedUser
onRemove={[MockFunction]}
teammateNameDisplay="full_name"
testID="more_direct_messages.selected_user"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -197,6 +200,7 @@ exports[`SelectedUsers should match snapshot to show warning for ability to add
<SelectedUser
onRemove={[MockFunction]}
teammateNameDisplay="full_name"
testID="more_direct_messages.selected_user"
theme={
Object {
"awayIndicator": "#ffbc42",

View file

@ -36,6 +36,11 @@ export default class SelectedUser extends React.PureComponent {
* A handler function that will deselect a user when clicked on.
*/
onRemove: PropTypes.func.isRequired,
/**
* The test ID.
*/
testID: PropTypes.string,
};
onRemove = () => {
@ -46,13 +51,20 @@ export default class SelectedUser extends React.PureComponent {
const style = getStyleFromTheme(this.props.theme);
return (
<View style={style.container}>
<Text style={style.text}>
<View
style={style.container}
testID={`${this.props.testID}.${this.props.user.id}`}
>
<Text
style={style.text}
testID={`${this.props.testID}.${this.props.user.id}.display_username`}
>
{displayUsername(this.props.user, this.props.teammateNameDisplay)}
</Text>
<TouchableOpacity
style={style.remove}
onPress={this.onRemove}
testID={`${this.props.testID}.${this.props.user.id}.remove.button`}
>
<CompassIcon
name='close'

View file

@ -63,6 +63,7 @@ export default class SelectedUsers extends React.PureComponent {
theme={this.props.theme}
teammateNameDisplay={this.props.teammateNameDisplay}
onRemove={this.props.onRemove}
testID='more_direct_messages.selected_user'
/>,
);
}

View file

@ -33,6 +33,23 @@ export const apiSaveFavoriteChannelPreference = (userId, channelId) => {
return apiSaveUserPreferences(userId, [preference]);
};
/**
* Save the user's teammate name display preference.
* @param {string} userId - the user ID
* @param {string} nameFormat - one of "username" (default), "nickname_full_name" or "full_name"
* @returns
*/
export const apiSaveTeammateNameDisplayPreference = (userId, nameFormat = 'username') => {
const preference = {
user_id: userId,
category: 'display_settings',
name: 'name_format',
value: nameFormat,
};
return apiSaveUserPreferences(userId, [preference]);
};
/**
* Save the user's teams order preference.
* @param {string} userId - the user ID
@ -72,6 +89,7 @@ export const apiSaveUserPreferences = async (userId, preferences = []) => {
export const Preference = {
apiSaveFavoriteChannelPreference,
apiSaveTeammateNameDisplayPreference,
apiSaveTeamsOrderPreference,
apiSaveUserPreferences,
};

View file

@ -38,7 +38,7 @@ export const apiAdminLogin = () => {
*/
export const apiCreateUser = async ({prefix = 'user', user = null} = {}) => {
try {
const newUser = user || generateRandomUser(prefix);
const newUser = user || generateRandomUser({prefix});
const response = await client.post(
'/api/v4/users',

View file

@ -32,11 +32,11 @@ class ChannelAddMembersScreen {
const userItemTestID = `${this.testID.userItem}.${userId}`;
const baseMatcher = by.id(userItemTestID);
const userItemMatcher = diplayUsername ? baseMatcher.withDescendant(by.text(diplayUsername)) : baseMatcher;
const userItemUsernameDisplayMatcher = by.id(this.testID.userItemDisplayUsername).withAncestor(userItemMatcher);
const userItemDisplayUsernameMatcher = by.id(this.testID.userItemDisplayUsername).withAncestor(userItemMatcher);
return {
userItem: element(userItemMatcher),
userItemUsernameDisplay: element(userItemUsernameDisplayMatcher),
userItemDisplayUsername: element(userItemDisplayUsernameMatcher),
};
}

View file

@ -110,6 +110,12 @@ class ChannelInfoScreen {
}
}
closeDirectOrGroupMessage = async () => {
await this.channelInfoScrollView.scrollTo('bottom');
await this.leaveAction.tap();
await expect(this.channelInfoScreen).not.toBeVisible();
}
leaveChannel = async ({confirm = true, publicChannel = true, description = null} = {}) => {
await this.channelInfoScrollView.scrollTo('bottom');
await this.leaveAction.tap();

View file

@ -34,11 +34,11 @@ class ChannelMembersScreen {
const userItemTestID = `${this.testID.userItem}.${userId}`;
const baseMatcher = by.id(userItemTestID);
const userItemMatcher = diplayUsername ? baseMatcher.withDescendant(by.text(diplayUsername)) : baseMatcher;
const userItemUsernameDisplayMatcher = by.id(this.testID.userItemDisplayUsername).withAncestor(userItemMatcher);
const userItemDisplayUsernameMatcher = by.id(this.testID.userItemDisplayUsername).withAncestor(userItemMatcher);
return {
userItem: element(userItemMatcher),
userItemUsernameDisplay: element(userItemUsernameDisplayMatcher),
userItemDisplayUsername: element(userItemDisplayUsernameMatcher),
};
}

View file

@ -10,13 +10,16 @@ class MoreDirectMessagesScreen {
testID = {
moreDirectMessagesScreenPrefix: 'more_direct_messages.',
moreDirectMessagesScreen: 'more_direct_messages.screen',
closeMoreDirectMessagesButton: 'close.more_direct_messages.button',
startButton: 'more_direct_messages.start.button',
selectedUser: 'more_direct_messages.selected_user',
usersList: 'more_direct_messages.custom_list',
userItem: 'more_direct_messages.custom_list.user_item',
userItemDisplayUsername: 'more_direct_messages.custom_list.user_item.display_username',
}
moreDirectMessagesScreen = element(by.id(this.testID.moreDirectMessagesScreen));
closeMoreDirectMessagesButton = element(by.id(this.testID.closeMoreDirectMessagesButton));
startButton = element(by.id(this.testID.startButton));
usersList = element(by.id(this.testID.usersList));
@ -26,15 +29,28 @@ class MoreDirectMessagesScreen {
cancelButton = SearchBar.getCancelButton(this.testID.moreDirectMessagesScreenPrefix);
clearButton = SearchBar.getClearButton(this.testID.moreDirectMessagesScreenPrefix);
getSelectedUser = (userId) => {
const selectedUserTestID = `${this.testID.selectedUser}.${userId}`;
const selectedUserMatcher = by.id(selectedUserTestID);
const selectedUserDisplayUsernameMatcher = by.id(`${selectedUserTestID}.display_username`).withAncestor(selectedUserMatcher);
const selectedUserRemoveButtonMatcher = by.id(`${selectedUserTestID}.remove.button`).withAncestor(selectedUserMatcher);
return {
selectedUser: element(selectedUserMatcher),
selectedUserDisplayUsername: element(selectedUserDisplayUsernameMatcher),
selectedUserRemoveButton: element(selectedUserRemoveButtonMatcher),
};
}
getUser = (userId, diplayUsername) => {
const userItemTestID = `${this.testID.userItem}.${userId}`;
const baseMatcher = by.id(userItemTestID);
const userItemMatcher = diplayUsername ? baseMatcher.withDescendant(by.text(diplayUsername)) : baseMatcher;
const userItemUsernameDisplayMatcher = by.id(this.testID.userItemDisplayUsername).withAncestor(userItemMatcher);
const userItemDisplayUsernameMatcher = by.id(this.testID.userItemDisplayUsername).withAncestor(userItemMatcher);
return {
userItem: element(userItemMatcher),
userItemUsernameDisplay: element(userItemUsernameDisplayMatcher),
userItemDisplayUsername: element(userItemDisplayUsernameMatcher),
};
}

View file

@ -0,0 +1,100 @@
// 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 {MainSidebar} from '@support/ui/component';
import {
ChannelInfoScreen,
ChannelScreen,
MoreDirectMessagesScreen,
} from '@support/ui/screen';
import {
Preference,
Setup,
Team,
User,
} from '@support/server_api';
describe('Direct Messages', () => {
const {
closeMainSidebar,
goToChannel,
openMainSidebar,
} = ChannelScreen;
const {
closeMoreDirectMessagesButton,
getUserAtIndex,
searchInput,
startButton,
} = MoreDirectMessagesScreen;
const {getChannelByDisplayName} = MainSidebar;
let testUser;
let testOtherUser;
beforeAll(async () => {
const {user, team} = await Setup.apiInit();
testUser = user;
({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-T1800 should remove closed DMs from main sidebar', async () => {
// # Create a DM with the other user
await openMainSidebar();
await MoreDirectMessagesScreen.open();
await searchInput.typeText(testOtherUser.username);
await getUserAtIndex(0).tap();
await startButton.tap();
// # Close DM channel
await goToChannel(testOtherUser.username);
await ChannelInfoScreen.open();
await ChannelInfoScreen.closeDirectOrGroupMessage();
// * Verify DM channel is removed
await openMainSidebar();
await expect(getChannelByDisplayName(testOtherUser.username)).not.toBeVisible();
// # Go back to channel
await closeMainSidebar();
});
it('MM-T442 should display full name / nickname on DM search result', async () => {
// # Set teammate name display to full name
await Preference.apiSaveTeammateNameDisplayPreference(testUser.id, 'full_name');
// # DM search other user
await openMainSidebar();
await MoreDirectMessagesScreen.open();
await searchInput.typeText(testOtherUser.username);
// * Verify search result contains other user's full name
await expect(element(by.text(`${testOtherUser.first_name} ${testOtherUser.last_name}`))).toBeVisible();
// # Set teammate name display to nickname
await Preference.apiSaveTeammateNameDisplayPreference(testUser.id, 'nickname_full_name');
// # DM search other user again
await searchInput.clearText();
await searchInput.typeText(testOtherUser.username);
// * Verify search result contains other user's nickname
await expect(element(by.text(testOtherUser.nickname))).toBeVisible();
// # Go back to channel
await closeMoreDirectMessagesButton.tap();
});
});

View file

@ -0,0 +1,141 @@
// 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,
MoreDirectMessagesScreen,
} from '@support/ui/screen';
import {
Setup,
Team,
User,
} from '@support/server_api';
describe('Group Messages', () => {
const {openMainSidebar} = ChannelScreen;
const {
closeMoreDirectMessagesButton,
getSelectedUser,
getUserAtIndex,
searchInput,
startButton,
} = MoreDirectMessagesScreen;
const testOtherUsers = new Map();
beforeAll(async () => {
const {user, team} = await Setup.apiInit();
[...Array(8).keys()].forEach(async (key) => {
const {user: testOtherUser} = await User.apiCreateUser({prefix: `user-${key}-`});
await Team.apiAddUserToTeam(testOtherUser.id, team.id);
testOtherUsers.set(`user-${key}`, testOtherUser);
});
// # Open channel screen
await ChannelScreen.open(user);
});
afterAll(async () => {
await ChannelScreen.logout();
});
it('MM-T462 should be able to add and remove users while creating new GM', async () => {
const testOtherUser1 = testOtherUsers.get('user-0');
const testOtherUser2 = testOtherUsers.get('user-1');
const testOtherUser3 = testOtherUsers.get('user-2');
const testOtherUser4 = testOtherUsers.get('user-3');
// # Add 4 users
await openMainSidebar();
await MoreDirectMessagesScreen.open();
await searchInput.typeText(testOtherUser1.username);
await getUserAtIndex(0).tap();
await searchInput.clearText();
await searchInput.typeText(testOtherUser2.username);
await getUserAtIndex(0).tap();
await searchInput.clearText();
await searchInput.typeText(testOtherUser3.username);
await getUserAtIndex(0).tap();
await searchInput.clearText();
await searchInput.typeText(testOtherUser4.username);
await getUserAtIndex(0).tap();
// * Verify 4 users are added
const {selectedUserRemoveButton: selectedUserRemoveButton1} = getSelectedUser(testOtherUser1.id);
await expect(selectedUserRemoveButton1).toBeVisible();
const {selectedUserRemoveButton: selectedUserRemoveButton2} = getSelectedUser(testOtherUser2.id);
await expect(selectedUserRemoveButton2).toBeVisible();
const {selectedUserRemoveButton: selectedUserRemoveButton3} = getSelectedUser(testOtherUser3.id);
await expect(selectedUserRemoveButton3).toBeVisible();
const {selectedUserRemoveButton: selectedUserRemoveButton4} = getSelectedUser(testOtherUser4.id);
await expect(selectedUserRemoveButton4).toBeVisible();
// # Remove 2 users
await selectedUserRemoveButton1.tap();
await selectedUserRemoveButton3.tap();
// * Verify 2 users are removed
await expect(selectedUserRemoveButton1).not.toBeVisible();
await expect(selectedUserRemoveButton3).not.toBeVisible();
await expect(selectedUserRemoveButton2).toBeVisible();
await expect(selectedUserRemoveButton4).toBeVisible();
// # Go back to channel
await closeMoreDirectMessagesButton.tap();
});
it('MM-T464 should not be able to add users more than max', async () => {
// # Add 7 users
await openMainSidebar();
await MoreDirectMessagesScreen.open();
await searchInput.typeText(testOtherUsers.get('user-0').username);
await getUserAtIndex(0).tap();
await searchInput.clearText();
await searchInput.typeText(testOtherUsers.get('user-1').username);
await getUserAtIndex(0).tap();
await searchInput.clearText();
await searchInput.typeText(testOtherUsers.get('user-2').username);
await getUserAtIndex(0).tap();
await searchInput.clearText();
await searchInput.typeText(testOtherUsers.get('user-3').username);
await getUserAtIndex(0).tap();
await searchInput.clearText();
await searchInput.typeText(testOtherUsers.get('user-4').username);
await getUserAtIndex(0).tap();
await searchInput.clearText();
await searchInput.typeText(testOtherUsers.get('user-5').username);
await getUserAtIndex(0).tap();
await searchInput.clearText();
await searchInput.typeText(testOtherUsers.get('user-6').username);
await getUserAtIndex(0).tap();
// * Verify message that you cannot more users
await expect(element(by.text('You cannot add more users'))).toBeVisible();
// # Attempt to add one more user
await searchInput.clearText();
await searchInput.typeText(testOtherUsers.get('user-7').username);
await getUserAtIndex(0).tap();
// * Verify last user is not added
const {selectedUser: lastUser} = getSelectedUser(testOtherUsers.get('user-7').id);
await expect(lastUser).not.toBeVisible();
// # Start a GM
await startButton.tap();
// * Verify on GM screen
await ChannelScreen.toBeVisible();
const expectedUsernames = Array.from(testOtherUsers, ([, v]) => (v.username)).sort();
expectedUsernames.pop();
expectedUsernames.forEach(async (username) => {
await expect(element(by.text(username))).toBeVisible();
});
});
});

View file

@ -0,0 +1,73 @@
// 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 {MainSidebar} from '@support/ui/component';
import {ChannelScreen} from '@support/ui/screen';
import {
Setup,
Team,
} from '@support/server_api';
describe('Main Sidebar', () => {
const {
channelNavBarTitle,
closeMainSidebar,
goToChannel,
openMainSidebar,
} = ChannelScreen;
const {
searchInput,
switchTeamsButton,
} = MainSidebar;
let testChannel;
beforeAll(async () => {
const {user, channel} = await Setup.apiInit();
testChannel = channel;
const {team: testOtherTeam} = await Team.apiCreateTeam();
await Team.apiAddUserToTeam(user.id, testOtherTeam.id);
// # Open channel screen
await ChannelScreen.open(user);
});
afterAll(async () => {
await ChannelScreen.logout();
});
it('MM-T3412 should close the sidebar menu when selecting the same channel', async () => {
// # Go to unread channel
await goToChannel(testChannel.display_name);
// # Go to the same channel again
await goToChannel(testChannel.display_name);
// * Verify sidebar menu is not open
await expect(MainSidebar.mainSidebar).not.toBeVisible();
// * Selected channel should remain the same
await expect(channelNavBarTitle).toHaveText(testChannel.display_name);
});
it('MM-T435 should not show switch teams button when jump to search is focused', async () => {
// # Open main sidebar
await openMainSidebar();
// # Tap on search input
await expect(switchTeamsButton).toBeVisible();
await searchInput.tap();
// * Verify switch teams button is not visible
await expect(switchTeamsButton).not.toBeVisible();
// # Go back to channel
await closeMainSidebar();
});
});

View file

@ -1,47 +0,0 @@
// 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 {MainSidebar} from '@support/ui/component';
import {ChannelScreen} from '@support/ui/screen';
import {Setup} from '@support/server_api';
describe('Select channel', () => {
let newChannel;
beforeAll(async () => {
const {user, channel} = await Setup.apiInit();
newChannel = channel;
// # Open channel screen
await ChannelScreen.open(user);
});
afterAll(async () => {
await ChannelScreen.logout();
});
it('MM-T3412 should close the sidebar menu when selecting the same channel', async () => {
const {
channelNavBarTitle,
goToChannel,
} = ChannelScreen;
// # Go to unread channel
await goToChannel(newChannel.display_name);
// # Go to the same channel again
await goToChannel(newChannel.display_name);
// * Verify sidebar menu is not open
await expect(MainSidebar.mainSidebar).not.toBeVisible();
// * Selected channel should remain the same
await expect(channelNavBarTitle).toHaveText(newChannel.display_name);
});
});