MM-31256 Detox/E2E: Add e2e for MM-T3618 (#5144)

This commit is contained in:
Joseph Baylon 2021-02-10 13:55:43 -08:00 committed by GitHub
parent f495e1e48d
commit b716a9ca8d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 245 additions and 15 deletions

View file

@ -41,6 +41,10 @@ export default class ChannelListRow extends React.PureComponent {
);
}
const testID = this.props.testID;
const itemTestID = `${testID}.${this.props.id}`;
const channelDisplayNameTestID = `${testID}.display_name`;
return (
<CustomListRow
id={this.props.id}
@ -48,14 +52,21 @@ export default class ChannelListRow extends React.PureComponent {
enabled={this.props.enabled}
selectable={this.props.selectable}
selected={this.props.selected}
testID={testID}
>
<View style={style.container}>
<View
style={style.container}
testID={itemTestID}
>
<View style={style.titleContainer}>
<CompassIcon
name={this.props.isArchived ? 'archive-outline' : 'globe'}
style={style.icon}
/>
<Text style={style.displayName}>
<Text
style={style.displayName}
testID={channelDisplayNameTestID}
>
{this.props.channel.display_name}
</Text>
</View>

View file

@ -24,6 +24,7 @@ exports[`channelInfo should match snapshot 1`] = `
"flex": 1,
}
}
testID="channel_info.scroll_view"
>
<ChannelInfoHeader
createAt={123}
@ -512,6 +513,7 @@ exports[`channelInfo should match snapshot 1`] = `
>
<Connect(Leave)
close={[Function]}
testID="channel_info.leave.action"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -544,6 +546,7 @@ exports[`channelInfo should match snapshot 1`] = `
/>
<Connect(Archive)
close={[Function]}
testID="channel_info.archive.action"
theme={
Object {
"awayIndicator": "#ffbc42",

View file

@ -27,6 +27,7 @@ interface ArchiveProps {
unarchiveChannel: (channelId: string) => Promise<ActionResult>;
selectPenultimateChannel: (channelId: string) => Promise<ActionResult>;
teamId: string;
testID?: string;
theme: Theme;
viewArchivedChannels: boolean;
}
@ -129,7 +130,7 @@ export default class Archive extends PureComponent<ArchiveProps> {
});
render() {
const {canArchive, canUnarchive, theme} = this.props;
const {canArchive, canUnarchive, testID, theme} = this.props;
if (!canArchive && !canUnarchive) {
return null;
@ -142,9 +143,10 @@ export default class Archive extends PureComponent<ArchiveProps> {
action={this.handleUnarchive}
defaultMessage='Unarchive Channel'
icon='archive-arrow-up-outline'
rightArrow={false}
testID={testID}
textId={t('mobile.routes.channelInfo.unarchive_channel')}
theme={theme}
rightArrow={false}
/>
);
} else {
@ -154,10 +156,11 @@ export default class Archive extends PureComponent<ArchiveProps> {
defaultMessage='Archive Channel'
iconColor='#CA3B27'
icon='archive-outline'
rightArrow={false}
testID={testID}
textId={t('mobile.routes.channelInfo.delete_channel')}
textColor='#CA3B27'
theme={theme}
rightArrow={false}
/>
);
}

View file

@ -186,6 +186,7 @@ export default class ChannelInfo extends PureComponent {
<StatusBar/>
<ScrollView
style={style.scrollView}
testID='channel_info.scroll_view'
>
{Boolean(currentChannel?.id) &&
<ChannelInfoHeader
@ -212,10 +213,12 @@ export default class ChannelInfo extends PureComponent {
<View style={style.footer}>
<Leave
close={this.close}
testID='channel_info.leave.action'
theme={theme}
/>
<Archive
close={this.close}
testID='channel_info.archive.action'
theme={theme}
/>
</View>

View file

@ -26,6 +26,7 @@ interface LeaveProps {
isFavorite: boolean;
isGroupMessage: boolean;
isPublic: boolean;
testID?: string;
theme: Theme;
}
@ -91,7 +92,7 @@ export default class Leave extends PureComponent<LeaveProps> {
});
render() {
const {canLeave, isDirectMessage, isGroupMessage, theme} = this.props;
const {canLeave, isDirectMessage, isGroupMessage, testID, theme} = this.props;
if (!canLeave && !isDirectMessage && !isGroupMessage) {
return null;
@ -115,10 +116,11 @@ export default class Leave extends PureComponent<LeaveProps> {
defaultMessage={defaultMessage}
icon='close'
iconColor='#CA3B27'
rightArrow={false}
testID={testID}
textColor='#CA3B27'
textId={i18nId}
theme={theme}
rightArrow={false}
/>
);
} else {
@ -128,10 +130,11 @@ export default class Leave extends PureComponent<LeaveProps> {
defaultMessage='Leave Channel'
icon='exit-to-app'
iconColor='#CA3B27'
rightArrow={false}
testID={testID}
textColor='#CA3B27'
textId={t('navbar.leave')}
theme={theme}
rightArrow={false}
/>
);
}

View file

@ -57,7 +57,9 @@ exports[`MoreChannels should match snapshot 1`] = `
value=""
/>
</View>
<View>
<View
testID="more_channels.channel.dropdown"
>
<Text
accessibilityRole="button"
onPress={[Function]}
@ -70,6 +72,7 @@ exports[`MoreChannels should match snapshot 1`] = `
"marginTop": 20,
}
}
testID="more_channels.channel.dropdown.public"
>
<CompassIcon
@ -119,6 +122,7 @@ exports[`MoreChannels should match snapshot 1`] = `
renderItem={[Function]}
shouldRenderSeparator={true}
showNoResults={true}
testID="more_channels.custom_list"
theme={
Object {
"awayIndicator": "#ffbc42",

View file

@ -82,12 +82,13 @@ export default class MoreChannels extends PureComponent {
id: 'create-pub-channel',
text: context.intl.formatMessage({id: 'mobile.create_channel', defaultMessage: 'Create'}),
showAsAction: 'always',
testID: 'public_channel.create.button',
testID: 'more_channels.create.button',
};
this.leftButton = {
id: 'close-more-channels',
icon: props.closeButton,
testID: 'close.more_channels.button',
};
}
@ -348,6 +349,7 @@ export default class MoreChannels extends PureComponent {
<ChannelListRow
{...props}
isArchived={this.state.typeOfChannels === 'archived'}
testID='more_channels.custom_list.channel_item'
/>
);
}
@ -438,11 +440,15 @@ export default class MoreChannels extends PureComponent {
let channelDropdown;
if (canShowArchivedChannels) {
channelDropdown = (
<View style={style.titleContainer}>
<View
style={style.titleContainer}
testID='more_channels.channel.dropdown'
>
<Text
accessibilityRole={'button'}
style={style.channelDropdown}
onPress={this.handleDropdownClick}
testID={`more_channels.channel.dropdown.${typeOfChannels}`}
>
{typeOfChannels === 'public' ? publicChannelsText : archivedChannelsText}
{' '}
@ -492,6 +498,7 @@ export default class MoreChannels extends PureComponent {
onLoadMore={more}
onRowPress={this.onSelectChannel}
renderItem={this.renderItem}
testID='more_channels.custom_list'
theme={theme}
/>
</>

View file

@ -5,11 +5,14 @@ import {isAndroid} from '@support/utils';
class Alert {
// alert titles
archivePublicChannelTitle = isAndroid() ? element(by.text('Archive Public Channel')) : element(by.label('Archive Public Channel')).atIndex(0);
deletePostTitle = isAndroid() ? element(by.text('Delete Post')) : element(by.label('Delete Post')).atIndex(0);
// alert buttons
cancelButton = isAndroid() ? element(by.text('CANCEL')) : element(by.label('Cancel')).atIndex(0);
deleteButton = isAndroid() ? element(by.text('DELETE')) : element(by.label('Delete')).atIndex(0);
noButton = isAndroid() ? element(by.text('NO')) : element(by.label('No')).atIndex(0);
yesButton = isAndroid() ? element(by.text('YES')) : element(by.label('Yes')).atIndex(0);
}
const alert = new Alert();

View file

@ -0,0 +1,17 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {isAndroid} from '@support/utils';
class BottomSheet {
// bottom sheet titles
showTitle = isAndroid() ? element(by.text('Show')) : element(by.label('Show')).atIndex(0);
// bottom sheet options
archivedChannelsOption = isAndroid() ? element(by.text('Archived Channels')) : element(by.label('Archived Channels')).atIndex(0);
cancelOption = isAndroid() ? element(by.text('Cancel')) : element(by.label('Cancel')).atIndex(0);
publicChannelsOption = isAndroid() ? element(by.text('Public Channels')) : element(by.label('Public Channels')).atIndex(0);
}
const bottomSheet = new BottomSheet();
export default bottomSheet;

View file

@ -3,6 +3,7 @@
import Alert from './alert';
import Autocomplete from './autocomplete';
import BottomSheet from './bottom_sheet';
import CameraQuickAction from './camera_quick_action';
import EditChannelInfo from './edit_channel_info';
import FileQuickAction from './file_quick_action';
@ -23,6 +24,7 @@ import SettingsSidebar from './settings_sidebar';
export {
Alert,
Autocomplete,
BottomSheet,
CameraQuickAction,
EditChannelInfo,
FileQuickAction,

View file

@ -1,12 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Alert} from '@support/ui/component';
import {ChannelScreen} from '@support/ui/screen';
import {timeouts, wait} from '@support/utils';
class ChannelInfoScreen {
testID = {
channelInfoScreen: 'channel_info.screen',
channelInfoScrollView: 'channel_info.scroll_view',
closeChannelInfoButton: 'close.channel_info.button',
channelIconGMMemberCount: 'channel_icon.gm_member_count',
favoritePreferenceAction: 'channel_info.favorite.action',
@ -24,9 +26,12 @@ class ChannelInfoScreen {
addMembersAction: 'channel_info.add_members.action',
convertPrivateAction: 'channel_info.convert_private.action',
editChannelAction: 'channel_info.edit_channel.action',
leaveAction: 'channel_info.leave.action',
archiveAction: 'channel_info.archive.action',
}
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));
favoritePreferenceAction = element(by.id(this.testID.favoritePreferenceAction));
@ -44,6 +49,8 @@ class ChannelInfoScreen {
addMembersAction = element(by.id(this.testID.addMembersAction));
convertPrivateAction = element(by.id(this.testID.convertPrivateAction));
editChannelAction = element(by.id(this.testID.editChannelAction));
leaveAction = element(by.id(this.testID.leaveAction));
archiveAction = element(by.id(this.testID.archiveAction));
toBeVisible = async () => {
await wait(timeouts.TWO_SEC);
@ -64,6 +71,24 @@ class ChannelInfoScreen {
await this.closeChannelInfoButton.tap();
await expect(this.channelInfoScreen).not.toBeVisible();
}
archiveChannel = async (confirm = true) => {
await this.channelInfoScrollView.scrollTo('bottom');
await this.archiveAction.tap();
const {
archivePublicChannelTitle,
noButton,
yesButton,
} = Alert;
await expect(archivePublicChannelTitle).toBeVisible();
if (confirm) {
yesButton.tap();
} else {
noButton.tap();
}
await wait(timeouts.ONE_SEC);
await expect(this.channelInfoScreen).not.toBeVisible();
}
}
const channelInfoScreen = new ChannelInfoScreen();

View file

@ -1,16 +1,59 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {MainSidebar} from '@support/ui/component';
import {
BottomSheet,
MainSidebar,
SearchBar,
} from '@support/ui/component';
class MoreChannelsScreen {
testID = {
moreChannelsScreen: 'more_channels.screen',
publicChannelCreateButton: 'public_channel.create.button',
moreChannelsScreenPrefix: 'more_channels.',
closeMoreChannelsButton: 'close.more_channels.button',
createButton: 'more_channels.create.button',
channelDropdown: 'more_channels.channel.dropdown',
channelDropdownArchived: 'more_channels.channel.dropdown.archived',
channelDropdownPublic: 'more_channels.channel.dropdown.public',
channelsList: 'more_channels.custom_list',
channelItem: 'more_channels.custom_list.channel_item',
channelItemDisplayName: 'more_channels.custom_list.channel_item.display_name',
}
moreChannelsScreen = element(by.id(this.testID.moreChannelsScreen));
publicChannelCreateButton = element(by.id(this.testID.publicChannelCreateButton));
closeMoreChannelsButton = element(by.id(this.testID.closeMoreChannelsButton));
createButton = element(by.id(this.testID.createButton));
channelDropdown = element(by.id(this.testID.channelDropdown));
channelDropdownArchived = element(by.id(this.testID.channelDropdownArchived));
channelDropdownPublic = element(by.id(this.testID.channelDropdownPublic));
channelsList = element(by.id(this.testID.channelsList));
// convenience props
searchBar = SearchBar.getSearchBar(this.testID.moreChannelsScreenPrefix);
searchInput = SearchBar.getSearchInput(this.testID.moreChannelsScreenPrefix);
cancelButton = SearchBar.getCancelButton(this.testID.moreChannelsScreenPrefix);
clearButton = SearchBar.getClearButton(this.testID.moreChannelsScreenPrefix);
getChannel = (channelId, displayName) => {
const channelItemTestID = `${this.testID.channelItem}.${channelId}`;
const baseMatcher = by.id(channelItemTestID);
const channelItemMatcher = displayName ? baseMatcher.withDescendant(by.text(displayName)) : baseMatcher;
const channelItemDisplayNameMatcher = by.id(this.testID.channelItemDisplayName).withAncestor(channelItemMatcher);
return {
channelItem: element(channelItemMatcher),
channelItemDisplayName: element(channelItemDisplayNameMatcher),
};
}
getChannelByDisplayName = (displayName) => {
return element(by.text(displayName).withAncestor(by.id(this.testID.channelsList)));
}
getChannelDisplayNameAtIndex = (index) => {
return element(by.id(this.testID.channelItemDisplayName)).atIndex(index);
}
toBeVisible = async () => {
await expect(this.moreChannelsScreen).toBeVisible();
@ -24,6 +67,29 @@ class MoreChannelsScreen {
return this.toBeVisible();
}
close = async () => {
await this.closeMoreChannelsButton.tap();
await expect(this.moreChannelsScreen).not.toBeVisible();
}
showArchivedChannels = async () => {
await this.channelDropdown.tap();
await BottomSheet.archivedChannelsOption.tap();
await expect(this.channelDropdownArchived).toBeVisible();
}
showPublicChannels = async () => {
await this.channelDropdown.tap();
await BottomSheet.publicChannelsOption.tap();
await expect(this.channelDropdownPublic).toBeVisible();
}
hasChannelDisplayNameAtIndex = async (index, channelDisplayName) => {
await expect(
this.getChannelDisplayNameAtIndex(index),
).toHaveText(channelDisplayName);
}
}
const moreChannelsScreen = new MoreChannelsScreen();

View file

@ -0,0 +1,83 @@
// 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,
ChannelInfoScreen,
MoreChannelsScreen,
} from '@support/ui/screen';
import {
Channel,
Setup,
System,
} from '@support/server_api';
describe('Archived Channels', () => {
let archivedChannel;
let nonArchivedChannel;
beforeAll(async () => {
// # Enable experimental view archived channels
await System.apiUpdateConfig({TeamSettings: {ExperimentalViewArchivedChannels: true}});
const {channel, team, user} = await Setup.apiInit();
archivedChannel = channel;
({channel: nonArchivedChannel} = await Channel.apiCreateChannel({type: 'O', prefix: 'non-archived-channel', teamId: team.id}));
// # Open channel screen
await ChannelScreen.open(user);
});
afterAll(async () => {
await ChannelScreen.logout();
});
it('MM-T3618 should display archived channels list', async () => {
const {openMainSidebar} = ChannelScreen;
const {
getChannelByDisplayName,
hasChannelDisplayNameAtIndex,
searchInput,
showArchivedChannels,
showPublicChannels,
} = MoreChannelsScreen;
// # Archive channel
await openMainSidebar();
await MainSidebar.getChannelByDisplayName(archivedChannel.display_name).tap();
await ChannelInfoScreen.open();
await ChannelInfoScreen.archiveChannel();
// # Open more channels screen
await openMainSidebar();
await MoreChannelsScreen.open();
// * Verify only non archived channels are displayed in public channels list
await showPublicChannels();
await hasChannelDisplayNameAtIndex(0, nonArchivedChannel.display_name);
await expect(getChannelByDisplayName(archivedChannel.display_name)).not.toBeVisible();
await searchInput.typeText(nonArchivedChannel.display_name);
await hasChannelDisplayNameAtIndex(0, nonArchivedChannel.display_name);
await expect(getChannelByDisplayName(archivedChannel.display_name)).not.toBeVisible();
// * Verify only archived channels are displayed in archived channels list
await searchInput.clearText();
await showArchivedChannels();
await hasChannelDisplayNameAtIndex(0, archivedChannel.display_name);
await expect(getChannelByDisplayName(nonArchivedChannel.display_name)).not.toBeVisible();
await searchInput.typeText(archivedChannel.display_name);
await hasChannelDisplayNameAtIndex(0, archivedChannel.display_name);
await expect(getChannelByDisplayName(nonArchivedChannel.display_name)).not.toBeVisible();
// # Close more channels screen
await MoreChannelsScreen.close();
});
});

View file

@ -39,7 +39,7 @@ describe('Channels', () => {
await expect(element(by.text('No more channels to join'))).toBeVisible();
// # Tap to create new channel
await MoreChannelsScreen.publicChannelCreateButton.tap();
await MoreChannelsScreen.createButton.tap();
// * Expect a new screen to create a new public channel
const createChannelScreen = await CreateChannelScreen.toBeVisible();