MM-30696 Detox/E2E: Add e2e for MM-T3213 (#5147)

* MM-30696 Detox/E2E: Add e2e for MM-T3213

* Add missed file
This commit is contained in:
Joseph Baylon 2021-02-10 13:56:03 -08:00 committed by GitHub
parent b716a9ca8d
commit a49d446b25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 202 additions and 21 deletions

View file

@ -26,6 +26,7 @@ export default class ChannelIcon extends React.PureComponent {
type: PropTypes.string.isRequired,
isArchived: PropTypes.bool.isRequired,
isBot: PropTypes.bool.isRequired,
testID: PropTypes.string,
};
static defaultProps = {
@ -48,6 +49,7 @@ export default class ChannelIcon extends React.PureComponent {
type,
isArchived,
isBot,
testID,
} = this.props;
const style = getStyleSheet(theme);
@ -84,7 +86,7 @@ export default class ChannelIcon extends React.PureComponent {
<CompassIcon
name='archive-outline'
style={[style.icon, unreadIcon, activeIcon, {fontSize: size}]}
testID='channel_icon.archive'
testID={`${testID}.archive`}
/>
);
} else if (isBot) {
@ -92,7 +94,7 @@ export default class ChannelIcon extends React.PureComponent {
<CompassIcon
name='robot-happy'
style={[style.icon, unreadIcon, activeIcon, {fontSize: size, left: -1.5, top: -1}]}
testID='channel_icon.bot'
testID={`${testID}.bot`}
/>
);
} else if (hasDraft) {
@ -100,7 +102,7 @@ export default class ChannelIcon extends React.PureComponent {
<CompassIcon
name='pencil-outline'
style={[style.icon, unreadIcon, activeIcon, {fontSize: size}]}
testID='channel_icon.draft'
testID={`${testID}.draft`}
/>
);
} else if (type === General.OPEN_CHANNEL) {
@ -108,7 +110,7 @@ export default class ChannelIcon extends React.PureComponent {
<CompassIcon
name='globe'
style={[style.icon, unreadIcon, activeIcon, {fontSize: size}]}
testID='channel_icon.public'
testID={`${testID}.public`}
/>
);
} else if (type === General.PRIVATE_CHANNEL) {
@ -116,7 +118,7 @@ export default class ChannelIcon extends React.PureComponent {
<CompassIcon
name='lock-outline'
style={[style.icon, unreadIcon, activeIcon, {fontSize: size, left: 0.5}]}
testID='channel_icon.private'
testID={`${testID}.private`}
/>
);
} else if (type === General.GM_CHANNEL) {
@ -125,7 +127,7 @@ export default class ChannelIcon extends React.PureComponent {
<View style={[style.groupBox, unreadGroupBox, activeGroupBox, {width: size, height: size}]}>
<Text
style={[style.group, unreadGroup, activeGroup, {fontSize}]}
testID='channel_icon.gm_member_count'
testID={`${testID}.gm_member_count`}
>
{membersCount}
</Text>
@ -138,7 +140,7 @@ export default class ChannelIcon extends React.PureComponent {
<CompassIcon
name='clock'
style={[style.icon, unreadIcon, activeIcon, {fontSize: size, color: theme.awayIndicator}]}
testID='channel_icon.away'
testID={`${testID}.away`}
/>
);
break;
@ -147,7 +149,7 @@ export default class ChannelIcon extends React.PureComponent {
<CompassIcon
name='minus-circle'
style={[style.icon, unreadIcon, activeIcon, {fontSize: size, color: theme.dndIndicator}]}
testID='channel_icon.dnd'
testID={`${testID}.dnd`}
/>
);
break;
@ -156,7 +158,7 @@ export default class ChannelIcon extends React.PureComponent {
<CompassIcon
name='check-circle'
style={[style.icon, unreadIcon, activeIcon, {fontSize: size, color: theme.onlineIndicator}]}
testID='channel_icon.online'
testID={`${testID}.online`}
/>
);
break;
@ -165,7 +167,7 @@ export default class ChannelIcon extends React.PureComponent {
<CompassIcon
name='circle-outline'
style={[style.icon, unreadIcon, activeIcon, {fontSize: size, color: offlineColor}]}
testID='channel_icon.offline'
testID={`${testID}.offline`}
/>
);
break;

View file

@ -15,6 +15,7 @@ exports[`UserListRow should match snapshot 1`] = `
enabled={true}
id="21345"
onPress={[Function]}
testID="custom_list.user_item"
>
<View
style={
@ -40,6 +41,7 @@ exports[`UserListRow should match snapshot 1`] = `
"marginLeft": 10,
}
}
testID="custom_list.user_item.21345"
>
<View>
<View
@ -58,6 +60,7 @@ exports[`UserListRow should match snapshot 1`] = `
"fontSize": 15,
}
}
testID="custom_list.user_item.display_username"
>
@user
</Text>
@ -147,6 +150,7 @@ exports[`UserListRow should match snapshot for currentUser with (you) populated
enabled={true}
id="21345"
onPress={[Function]}
testID="custom_list.user_item"
>
<View
style={
@ -172,6 +176,7 @@ exports[`UserListRow should match snapshot for currentUser with (you) populated
"marginLeft": 10,
}
}
testID="custom_list.user_item.21345"
>
<View>
<View
@ -190,6 +195,7 @@ exports[`UserListRow should match snapshot for currentUser with (you) populated
"fontSize": 15,
}
}
testID="custom_list.user_item.display_username"
/>
<BotTag
show={false}
@ -277,6 +283,7 @@ exports[`UserListRow should match snapshot for deactivated user 1`] = `
enabled={true}
id="21345"
onPress={[Function]}
testID="custom_list.user_item"
>
<View
style={
@ -302,6 +309,7 @@ exports[`UserListRow should match snapshot for deactivated user 1`] = `
"marginLeft": 10,
}
}
testID="custom_list.user_item.21345"
>
<View>
<View
@ -320,6 +328,7 @@ exports[`UserListRow should match snapshot for deactivated user 1`] = `
"fontSize": 15,
}
}
testID="custom_list.user_item.display_username"
>
@user
</Text>
@ -420,6 +429,7 @@ exports[`UserListRow should match snapshot for guest user 1`] = `
enabled={true}
id="21345"
onPress={[Function]}
testID="custom_list.user_item"
>
<View
style={
@ -445,6 +455,7 @@ exports[`UserListRow should match snapshot for guest user 1`] = `
"marginLeft": 10,
}
}
testID="custom_list.user_item.21345"
>
<View>
<View
@ -463,6 +474,7 @@ exports[`UserListRow should match snapshot for guest user 1`] = `
"fontSize": 15,
}
}
testID="custom_list.user_item.display_username"
>
@user
</Text>

View file

@ -63,6 +63,9 @@ export default class UserListRow extends React.PureComponent {
const teammateDisplay = displayUsername(user, teammateNameDisplay);
const showTeammateDisplay = teammateDisplay !== username;
const testID = this.props.testID;
const itemTestID = `${testID}.${id}`;
const displayUsernameTestID = `${testID}.display_username`;
return (
<View style={style.container}>
@ -72,7 +75,7 @@ export default class UserListRow extends React.PureComponent {
enabled={enabled}
selectable={selectable}
selected={selected}
testID={this.props.testID}
testID={testID}
>
<View style={style.profileContainer}>
<ProfilePicture
@ -81,13 +84,17 @@ export default class UserListRow extends React.PureComponent {
iconSize={24}
/>
</View>
<View style={style.textContainer}>
<View
style={style.textContainer}
testID={itemTestID}
>
<View>
<View style={style.indicatorContainer}>
<Text
style={style.username}
ellipsizeMode='tail'
numberOfLines={1}
testID={displayUsernameTestID}
>
{usernameDisplay}
</Text>

View file

@ -29,6 +29,7 @@ describe('UserListRow', () => {
},
theme: Preferences.THEMES.default,
teammateNameDisplay: 'test',
testID: 'custom_list.user_item',
};
test('should match snapshot', () => {

View file

@ -43,6 +43,7 @@ exports[`ChannelItem should match snapshot 1`] = `
membersCount={1}
size={16}
status="online"
testID="main.sidebar.channels_list.list.channel_item.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -158,6 +159,7 @@ exports[`ChannelItem should match snapshot for current user i.e currentUser (you
membersCount={1}
size={16}
status="online"
testID="main.sidebar.channels_list.list.channel_item.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -272,6 +274,7 @@ exports[`ChannelItem should match snapshot for current user i.e currentUser (you
membersCount={1}
size={16}
status="online"
testID="main.sidebar.channels_list.list.channel_item.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -386,6 +389,7 @@ exports[`ChannelItem should match snapshot for deactivated user and is currentCh
membersCount={1}
size={16}
status="online"
testID="main.sidebar.channels_list.list.channel_item.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -489,6 +493,7 @@ exports[`ChannelItem should match snapshot for deactivated user and is searchRes
membersCount={1}
size={16}
status="online"
testID="main.sidebar.channels_list.list.channel_item.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -593,6 +598,7 @@ exports[`ChannelItem should match snapshot for deactivated user and not searchRe
membersCount={1}
size={16}
status="online"
testID="main.sidebar.channels_list.list.channel_item.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -697,6 +703,7 @@ exports[`ChannelItem should match snapshot for isManualUnread 1`] = `
membersCount={1}
size={16}
status="online"
testID="main.sidebar.channels_list.list.channel_item.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -805,6 +812,7 @@ exports[`ChannelItem should match snapshot with draft 1`] = `
membersCount={1}
size={16}
status="online"
testID="main.sidebar.channels_list.list.channel_item.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -911,6 +919,7 @@ exports[`ChannelItem should match snapshot with mentions and muted 1`] = `
membersCount={1}
size={16}
status="online"
testID="main.sidebar.channels_list.list.channel_item.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",

View file

@ -167,6 +167,7 @@ export default class ChannelItem extends PureComponent {
type={channel.type}
isArchived={isArchived}
isBot={isBot}
testID={`${testID}.channel_icon`}
/>
);

View file

@ -40,6 +40,7 @@ exports[`channelInfo should match snapshot 1`] = `
onPermalinkPress={[Function]}
purpose="Purpose"
status="status"
testID="channel_info.header"
theme={
Object {
"awayIndicator": "#ffbc42",

View file

@ -35,6 +35,7 @@ exports[`channel_info_header should match snapshot 1`] = `
membersCount={3}
size={24}
status="status"
testID="channel_info.header.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -77,6 +78,7 @@ exports[`channel_info_header should match snapshot 1`] = `
"fontWeight": "600",
}
}
testID="channel_info.header.display_name"
>
Channel name
</Text>
@ -338,6 +340,7 @@ exports[`channel_info_header should match snapshot when DM and hasGuests and is
membersCount={3}
size={24}
status="status"
testID="channel_info.header.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -380,6 +383,7 @@ exports[`channel_info_header should match snapshot when DM and hasGuests and is
"fontWeight": "600",
}
}
testID="channel_info.header.display_name"
>
Channel name
</Text>
@ -669,6 +673,7 @@ exports[`channel_info_header should match snapshot when DM and hasGuests but its
membersCount={3}
size={24}
status="status"
testID="channel_info.header.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -711,6 +716,7 @@ exports[`channel_info_header should match snapshot when DM and hasGuests but its
"fontWeight": "600",
}
}
testID="channel_info.header.display_name"
>
Channel name
</Text>
@ -972,6 +978,7 @@ exports[`channel_info_header should match snapshot when GM and hasGuests 1`] = `
membersCount={3}
size={24}
status="status"
testID="channel_info.header.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -1014,6 +1021,7 @@ exports[`channel_info_header should match snapshot when GM and hasGuests 1`] = `
"fontWeight": "600",
}
}
testID="channel_info.header.display_name"
>
Channel name
</Text>
@ -1303,6 +1311,7 @@ exports[`channel_info_header should match snapshot when is group constrained 1`]
membersCount={3}
size={24}
status="status"
testID="channel_info.header.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -1345,6 +1354,7 @@ exports[`channel_info_header should match snapshot when is group constrained 1`]
"fontWeight": "600",
}
}
testID="channel_info.header.display_name"
>
Channel name
</Text>
@ -1627,6 +1637,7 @@ exports[`channel_info_header should match snapshot when public channel and hasGu
membersCount={3}
size={24}
status="status"
testID="channel_info.header.channel_icon"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -1669,6 +1680,7 @@ exports[`channel_info_header should match snapshot when public channel and hasGu
"fontWeight": "600",
}
}
testID="channel_info.header.display_name"
>
Channel name
</Text>

View file

@ -205,6 +205,7 @@ export default class ChannelInfo extends PureComponent {
isTeammateGuest={isTeammateGuest}
hasGuests={currentChannelGuestCount > 0}
isGroupConstrained={currentChannel.group_constrained}
testID='channel_info.header'
/>
}
<View style={style.rowsContainer}>

View file

@ -42,6 +42,7 @@ export default class ChannelInfoHeader extends React.PureComponent {
isTeammateGuest: PropTypes.bool.isRequired,
hasGuests: PropTypes.bool.isRequired,
isGroupConstrained: PropTypes.bool,
testID: PropTypes.string,
timeZone: PropTypes.string,
};
@ -140,6 +141,7 @@ export default class ChannelInfoHeader extends React.PureComponent {
isArchived,
isBot,
isGroupConstrained,
testID,
timeZone,
} = this.props;
@ -162,11 +164,13 @@ export default class ChannelInfoHeader extends React.PureComponent {
type={type}
isArchived={isArchived}
isBot={isBot}
testID={`${testID}.channel_icon`}
/>
<Text
ellipsizeMode='tail'
numberOfLines={1}
style={style.channelName}
testID={`${testID}.display_name`}
>
{displayName}
</Text>

View file

@ -43,6 +43,7 @@ describe('channel_info_header', () => {
isTeammateGuest: false,
hasGuests: false,
isGroupConstrained: false,
testID: 'channel_info.header',
};
test('should match snapshot', async () => {

View file

@ -364,7 +364,7 @@ export default class MoreDirectMessages extends PureComponent {
selectable={true}
selected={selected}
enabled={true}
testID='more_direct_messages.user'
testID='more_direct_messages.custom_list.user_item'
/>
);
};
@ -516,7 +516,7 @@ export default class MoreDirectMessages extends PureComponent {
onLoadMore={this.getProfiles}
onRowPress={this.handleSelectProfile}
renderItem={this.renderItem}
testID='more_direct_messages.list'
testID='more_direct_messages.custom_list'
theme={theme}
/>
</KeyboardLayout>

View file

@ -10,7 +10,8 @@ class ChannelInfoScreen {
channelInfoScreen: 'channel_info.screen',
channelInfoScrollView: 'channel_info.scroll_view',
closeChannelInfoButton: 'close.channel_info.button',
channelIconGMMemberCount: 'channel_icon.gm_member_count',
headerChannelIconGMMemberCount: 'channel_info.header.channel_icon.gm_member_count',
headerDisplayName: 'channel_info.header.display_name',
favoritePreferenceAction: 'channel_info.favorite.action',
favoriteSwitchFalse: 'channel_info.favorite.action.switch.false',
favoriteSwitchTrue: 'channel_info.favorite.action.switch.true',
@ -33,7 +34,8 @@ class ChannelInfoScreen {
channelInfoScreen = element(by.id(this.testID.channelInfoScreen));
channelInfoScrollView = element(by.id(this.testID.channelInfoScrollView));
closeChannelInfoButton = element(by.id(this.testID.closeChannelInfoButton));
channelIconGMMemberCount = element(by.id(this.testID.channelIconGMMemberCount));
headerChannelIconGMMemberCount = element(by.id(this.testID.headerChannelIconGMMemberCount));
headerDisplayName = element(by.id(this.testID.headerDisplayName));
favoritePreferenceAction = element(by.id(this.testID.favoritePreferenceAction));
favoriteSwitchFalse = element(by.id(this.testID.favoriteSwitchFalse));
favoriteSwitchTrue = element(by.id(this.testID.favoriteSwitchTrue));

View file

@ -1,21 +1,53 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {MainSidebar} from '@support/ui/component';
import {
MainSidebar,
SearchBar,
} from '@support/ui/component';
class MoreDirectMessagesScreen {
testID = {
moreDirectMessagesScreen: 'more_direct_messages.screen',
moreDirectMessagesPrefix: 'more_direct_messages.',
startButton: 'more_direct_messages.start.button',
list: 'more_direct_messages.list',
user: 'more_direct_messages.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));
startButton = element(by.id(this.testID.startButton));
usersList = element(by.id(this.testID.usersList));
// convenience props
searchBar = SearchBar.getSearchBar(this.testID.moreDirectMessagesPrefix);
searchInput = SearchBar.getSearchInput(this.testID.moreDirectMessagesPrefix);
cancelButton = SearchBar.getCancelButton(this.testID.moreDirectMessagesPrefix);
clearButton = SearchBar.getClearButton(this.testID.moreDirectMessagesPrefix);
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);
return {
userItem: element(userItemMatcher),
userItemUsernameDisplay: element(userItemUsernameDisplayMatcher),
};
}
getUserAtIndex = (index) => {
return element(by.id(this.testID.user).withAncestor(by.id(this.testID.list))).atIndex(index);
return element(by.id(this.testID.userItem).withAncestor(by.id(this.testID.usersList))).atIndex(index);
}
getUserByDisplayUsername = (displayUsername) => {
return element(by.text(displayUsername).withAncestor(by.id(this.testID.usersList)));
}
getDisplayUsernameAtIndex = (index) => {
return element(by.id(this.testID.userItemDisplayUsername)).atIndex(index);
}
toBeVisible = async () => {
@ -30,6 +62,12 @@ class MoreDirectMessagesScreen {
return this.toBeVisible();
}
hasUserDisplayUsernameAtIndex = async (index, displayUsername) => {
await expect(
this.getDisplayUsernameAtIndex(index),
).toHaveText(displayUsername);
}
}
const moreDirectMessagesScreen = new MoreDirectMessagesScreen();

View file

@ -52,7 +52,7 @@ describe('Channel Info Header', () => {
await ChannelInfoScreen.open();
// * Verify GM member count is 3
await expect(element(by.id(ChannelInfoScreen.testID.channelIconGMMemberCount)).atIndex(0)).toHaveText('3');
await expect(ChannelInfoScreen.headerChannelIconGMMemberCount).toHaveText('3');
// # Close channel info screen
await ChannelInfoScreen.close();

View file

@ -0,0 +1,90 @@
// 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 {
ChannelInfoScreen,
ChannelScreen,
MoreDirectMessagesScreen,
} from '@support/ui/screen';
import {
User,
Setup,
Team,
} from '@support/server_api';
import {getRandomId} from '@support/utils';
describe('Group Message Channel', () => {
const searchTerm = getRandomId();
let testUser;
let testOtherUser1;
let testOtherUser2;
beforeAll(async () => {
const {user, team} = await Setup.apiInit({userOptions: {prefix: `${searchTerm}-3-`}});
testUser = user;
({user: testOtherUser1} = await User.apiCreateUser({prefix: `${searchTerm}-1-`}));
await Team.apiAddUserToTeam(testOtherUser1.id, team.id);
({user: testOtherUser2} = await User.apiCreateUser({prefix: `${searchTerm}-2-`}));
await Team.apiAddUserToTeam(testOtherUser2.id, team.id);
// # Open channel screen
await ChannelScreen.open(testUser);
});
afterAll(async () => {
await ChannelScreen.logout();
});
it('MM-T3213 should be able to create a GM channel and post a message to the group', async () => {
const {
openMainSidebar,
postMessage,
} = ChannelScreen;
const {
getUserByDisplayUsername,
hasUserDisplayUsernameAtIndex,
getUserAtIndex,
searchInput,
startButton,
} = MoreDirectMessagesScreen;
// # Open more direct messages screen
await openMainSidebar();
await MoreDirectMessagesScreen.open();
// * Verify all 3 users are listed
await searchInput.typeText(searchTerm);
await hasUserDisplayUsernameAtIndex(0, `@${testOtherUser1.username}`);
await hasUserDisplayUsernameAtIndex(1, `@${testOtherUser2.username}`);
await hasUserDisplayUsernameAtIndex(2, `@${testUser.username} - you`);
// # Select profiles of other 2 users
await getUserAtIndex(0).tap();
await searchInput.typeText(searchTerm);
await getUserAtIndex(1).tap();
// * Verify current user is not displayed in the list
await expect(getUserByDisplayUsername(`@${testUser.username} - you`)).not.toBeVisible();
// # Create a GM with selected profiles
await startButton.tap();
// * Verify GM channel is created
await ChannelInfoScreen.open();
await expect(ChannelInfoScreen.headerDisplayName).toHaveText(`${testOtherUser1.username}, ${testOtherUser2.username}`);
await ChannelInfoScreen.close();
// * Verify current user can post message to GM channel
const message = Date.now().toString();
await postMessage(message);
await expect(element(by.text(message))).toBeVisible();
});
});