Detox/E2E: Channel Info and Quick Actions e2e tests in Gekidou (#6487)

* Detox/E2E: Channel Info and Quick Actions e2e tests in Gekidou

* Detox/E2E: Fix broken iOS e2e tests in Gekidou (#6488)
This commit is contained in:
Joseph Baylon
2022-07-21 14:18:56 -07:00
committed by GitHub
parent 3abaf8893d
commit c460c485a7
39 changed files with 934 additions and 177 deletions

View File

@@ -46,13 +46,13 @@ const ChannelActions = ({channelId, channelType, inModal = false, testID}: Props
<FavoriteBox
channelId={channelId}
showSnackBar={!inModal}
testID={`${testID}.favorite.action`}
testID={testID}
/>
<View style={styles.separator}/>
<MutedBox
channelId={channelId}
showSnackBar={!inModal}
testID={`${testID}.mute.action`}
testID={testID}
/>
<View style={styles.separator}/>
{channelType && DIRECT_CHANNELS.includes(channelType) &&

View File

@@ -27,6 +27,8 @@ const FavoriteBox = ({channelId, containerStyle, isFavorited, showSnackBar = fal
toggleFavoriteChannel(serverUrl, channelId, showSnackBar);
}, [serverUrl, channelId, showSnackBar]);
const favoriteActionTestId = isFavorited ? `${testID}.unfavorite.action` : `${testID}.favorite.action`;
return (
<OptionBox
activeIconName='star'
@@ -35,7 +37,7 @@ const FavoriteBox = ({channelId, containerStyle, isFavorited, showSnackBar = fal
iconName='star-outline'
isActive={isFavorited}
onPress={handleOnPress}
testID={testID}
testID={favoriteActionTestId}
text={intl.formatMessage({id: 'channel_info.favorite', defaultMessage: 'Favorite'})}
/>
);

View File

@@ -27,6 +27,8 @@ const MutedBox = ({channelId, containerStyle, isMuted, showSnackBar = false, tes
toggleMuteChannel(serverUrl, channelId, showSnackBar);
}, [channelId, isMuted, serverUrl, showSnackBar]);
const muteActionTestId = isMuted ? `${testID}.unmute.action` : `${testID}.mute.action`;
return (
<OptionBox
activeIconName='bell-off-outline'
@@ -35,7 +37,7 @@ const MutedBox = ({channelId, containerStyle, isMuted, showSnackBar = false, tes
iconName='bell-outline'
isActive={isMuted}
onPress={handleOnPress}
testID={testID}
testID={muteActionTestId}
text={intl.formatMessage({id: 'channel_info.muted', defaultMessage: 'Mute'})}
/>
);

View File

@@ -95,6 +95,7 @@ export default function Archived({
<Button
containerStyle={style.closeButton}
onPress={onCloseChannelPress}
testID={`${testID}.close_channel.button`}
>
<FormattedText
id='center_panel.archived.closeChannel'

View File

@@ -73,7 +73,12 @@ const Toast = ({animatedStyle, children, style, iconName, message, textStyle}: T
}
{Boolean(message) &&
<View style={styles.flex}>
<Text style={[styles.text, textStyle]}>{message}</Text>
<Text
style={[styles.text, textStyle]}
testID='toast.message'
>
{message}
</Text>
</View>
}
{children}

View File

@@ -46,27 +46,27 @@ const IntroOptions = ({channelId, header, favorite, people}: Props) => {
<AddPeopleBox
channelId={channelId}
containerStyle={[styles.item, styles.margin]}
testID='channel_post_list.intro_options.add_people.option'
testID='channel_post_list.intro_options.add_people.action'
/>
}
{header &&
<SetHeaderBox
channelId={channelId}
containerStyle={[styles.item, styles.margin]}
testID='channel_post_list.intro_options.set_header.option'
testID='channel_post_list.intro_options.set_header.action'
/>
}
{favorite &&
<FavoriteBox
channelId={channelId}
containerStyle={[styles.item, styles.margin]}
testID='channel_post_list.intro_options.favorite.option'
testID='channel_post_list.intro_options'
/>
}
<InfoBox
channelId={channelId}
containerStyle={styles.item}
testID='channel_post_list.intro_options.channel_details.option'
testID='channel_post_list.intro_options.channel_info.action'
/>
</View>
);

View File

@@ -154,6 +154,7 @@ const ChannelHeader = ({
iconName: Platform.select({android: 'dots-vertical', default: 'dots-horizontal'}),
onPress: onChannelQuickAction,
buttonType: 'opacity',
testID: 'channel_header.channel_quick_actions.button',
}]), [isTablet, searchTerm, onChannelQuickAction]);
let title = displayName;

View File

@@ -47,6 +47,7 @@ const ChannelQuickAction = ({channelId}: Props) => {
<InfoBox
channelId={channelId}
showAsLabel={true}
testID='channel.quick_actions.channel_info.action'
/>
<View style={styles.line}/>
<LeaveChannelLabel

View File

@@ -119,6 +119,7 @@ const Archive = ({
icon='archive-arrow-up-outline'
destructive={true}
type='default'
testID='channel_info.options.unarchive_channel.option'
/>
);
}

View File

@@ -73,6 +73,7 @@
"ExperimentalGroupUnreadChannels": "disabled",
"ExperimentalChannelOrganization": false,
"ExperimentalChannelSidebarOrganization": "disabled",
"EnableAPIChannelDeletion": true,
"EnableAPITeamDeletion": true,
"ExperimentalEnableHardenedMode": false,
"DisableLegacyMFA": true,
@@ -81,7 +82,9 @@
"DisableBotsWhenOwnerIsDeactivated": true,
"EnableBotAccountCreation": true,
"EnableSVGs": true,
"EnableLatex": false
"EnableLatex": true,
"EnableInlineLatex": true,
"CollapsedThreads": "always_on"
},
"TeamSettings": {
"SiteName": "Mattermost",
@@ -110,7 +113,7 @@
"MaxNotificationsPerChannel": 1000,
"EnableConfirmNotificationsToChannel": true,
"TeammateNameDisplay": "username",
"ExperimentalViewArchivedChannels": false,
"ExperimentalViewArchivedChannels": true,
"ExperimentalEnableAutomaticReplies": false,
"ExperimentalHideTownSquareinLHS": false,
"ExperimentalTownSquareIsReadOnly": false,

View File

@@ -6,7 +6,10 @@ import {isAndroid} from '@support/utils';
class Alert {
// alert titles
confirmSendingNotificationsTitle = isAndroid() ? element(by.text('Confirm sending notifications to entire channel')) : element(by.label('Confirm sending notifications to entire channel')).atIndex(0);
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);
deletePostTitle = isAndroid() ? element(by.text('Delete Post')) : element(by.label('Delete Post')).atIndex(0);
leaveChannelTitle = isAndroid() ? element(by.text('Leave channel')) : element(by.label('Leave channel')).atIndex(0);
logoutTitle = (serverDisplayName: string) => {
const title = `Are you sure you want to log out of ${serverDisplayName}?`;
@@ -19,15 +22,20 @@ class Alert {
return isAndroid() ? element(by.text(title)) : element(by.label(title)).atIndex(0);
};
unarchivePrivateChannelTitle = isAndroid() ? element(by.text('Unarchive Private Channel')) : element(by.label('Unarchive Private Channel')).atIndex(0);
unarchivePublicChannelTitle = isAndroid() ? element(by.text('Unarchive Public Channel')) : element(by.label('Unarchive Public Channel')).atIndex(0);
// 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);
leaveButton = isAndroid() ? element(by.text('LEAVE')) : element(by.label('Leave')).atIndex(0);
logoutButton = isAndroid() ? element(by.text('LOG OUT')) : element(by.label('Log out')).atIndex(1);
markReadButton = isAndroid() ? element(by.text('MARK READ')) : element(by.label('Mark read')).atIndex(1);
noButton = isAndroid() ? element(by.text('NO')) : element(by.label('No')).atIndex(1);
okButton = isAndroid() ? element(by.text('OK')) : element(by.label('OK')).atIndex(1);
removeButton = isAndroid() ? element(by.text('REMOVE')) : element(by.label('Remove')).atIndex(1);
yesButton = isAndroid() ? element(by.text('YES')) : element(by.label('Yes')).atIndex(1);
}
const alert = new Alert();

View File

@@ -17,6 +17,10 @@ class PostDraft {
return element(by.id(`${screenPrefix}${this.testID.postDraftArchivedSuffix}`));
};
getPostDraftArchivedCloseChannelButton = (screenPrefix: string) => {
return element(by.id(`${screenPrefix}${this.testID.postDraftArchivedSuffix}.close_channel.button`));
};
getPostDraftReadOnly = (screenPrefix: string) => {
return element(by.id(`${screenPrefix}${this.testID.postDraftReadOnlySuffix}`));
};

View File

@@ -2,6 +2,7 @@
// See LICENSE.txt for license information.
import {
Alert,
CameraQuickAction,
FileQuickAction,
ImageQuickAction,
@@ -23,19 +24,43 @@ class ChannelScreen {
testID = {
channelScreenPrefix: 'channel.',
channelScreen: 'channel.screen',
channelQuickActionsButton: 'channel_header.channel_quick_actions.button',
favoriteQuickAction: 'channel.quick_actions.favorite.action',
unfavoriteQuickAction: 'channel.quick_actions.unfavorite.action',
muteQuickAction: 'channel.quick_actions.mute.action',
unmuteQuickAction: 'channel.quick_actions.unmute.action',
setHeaderQuickAction: 'channel.quick_actions.set_header.action',
addPeopleQuickAction: 'channel.quick_actions.add_people.action',
copyChannelLinkQuickAction: 'channel.quick_actions.copy_channel_link.action',
channelInfoQuickAction: 'channel.quick_actions.channel_info.action',
leaveChannelQuickAction: 'channel.quick_actions.leave_channel.action',
introDisplayName: 'channel_post_list.intro.display_name',
introAddPeopleOption: 'channel_post_list.intro_options.add_people.option',
introSetHeaderOption: 'channel_post_list.intro_options.set_header.option',
introFavoriteOption: 'channel_post_list.intro_options.set_header.option',
introChannelDetailsOption: 'channel_post_list.intro_options.channel_details.option',
introAddPeopleAction: 'channel_post_list.intro_options.add_people.action',
introSetHeaderAction: 'channel_post_list.intro_options.set_header.action',
introFavoriteAction: 'channel_post_list.intro_options.favorite.action',
introUnfavoriteAction: 'channel_post_list.intro_options.unfavorite.action',
introChannelInfoAction: 'channel_post_list.intro_options.channel_info.action',
toastMessage: 'toast.message',
};
channelScreen = element(by.id(this.testID.channelScreen));
channelQuickActionsButton = element(by.id(this.testID.channelQuickActionsButton));
favoriteQuickAction = element(by.id(this.testID.favoriteQuickAction));
unfavoriteQuickAction = element(by.id(this.testID.unfavoriteQuickAction));
muteQuickAction = element(by.id(this.testID.muteQuickAction));
unmuteQuickAction = element(by.id(this.testID.unmuteQuickAction));
setHeaderQuickAction = element(by.id(this.testID.setHeaderQuickAction));
addPeopleQuickAction = element(by.id(this.testID.addPeopleQuickAction));
copyChannelLinkQuickAction = element(by.id(this.testID.copyChannelLinkQuickAction));
channelInfoQuickAction = element(by.id(this.testID.channelInfoQuickAction));
leaveChannelQuickAction = element(by.id(this.testID.leaveChannelQuickAction));
introDisplayName = element(by.id(this.testID.introDisplayName));
introAddPeopleOption = element(by.id(this.testID.introAddPeopleOption));
introSetHeaderOption = element(by.id(this.testID.introSetHeaderOption));
introFavoriteOption = element(by.id(this.testID.introFavoriteOption));
introChannelDetailsOption = element(by.id(this.testID.introChannelDetailsOption));
introAddPeopleAction = element(by.id(this.testID.introAddPeopleAction));
introSetHeaderAction = element(by.id(this.testID.introSetHeaderAction));
introFavoriteAction = element(by.id(this.testID.introFavoriteAction));
introUnfavoriteAction = element(by.id(this.testID.introUnfavoriteAction));
introChannelInfoAction = element(by.id(this.testID.introChannelInfoAction));
toastMessage = element(by.id(this.testID.toastMessage));
// convenience props
backButton = NavigationHeader.backButton;
@@ -52,6 +77,7 @@ class ChannelScreen {
cameraQuickActionDisabled = CameraQuickAction.getCameraQuickActionDisabled(this.testID.channelScreenPrefix);
postDraft = PostDraft.getPostDraft(this.testID.channelScreenPrefix);
postDraftArchived = PostDraft.getPostDraftArchived(this.testID.channelScreenPrefix);
postDraftArchivedCloseChannelButton = PostDraft.getPostDraftArchivedCloseChannelButton(this.testID.channelScreenPrefix);
postDraftReadOnly = PostDraft.getPostDraftReadOnly(this.testID.channelScreenPrefix);
postInput = PostDraft.getPostInput(this.testID.channelScreenPrefix);
sendButton = SendButton.getSendButton(this.testID.channelScreenPrefix);
@@ -101,6 +127,28 @@ class ChannelScreen {
await expect(this.channelScreen).not.toBeVisible();
};
leaveChannel = async ({confirm = true} = {}) => {
await waitFor(this.leaveChannelQuickAction).toExist().withTimeout(timeouts.TWO_SEC);
await this.leaveChannelQuickAction.tap({x: 1, y: 1});
const {
leaveChannelTitle,
cancelButton,
leaveButton,
} = Alert;
await expect(leaveChannelTitle).toBeVisible();
await expect(cancelButton).toBeVisible();
await expect(leaveButton).toBeVisible();
if (confirm) {
await leaveButton.tap();
await wait(timeouts.ONE_SEC);
await expect(this.channelScreen).not.toExist();
} else {
await cancelButton.tap();
await wait(timeouts.ONE_SEC);
await expect(this.leaveChannelQuickAction).toExist();
}
};
openPostOptionsFor = async (postId: string, text: string) => {
const {postListPostItem} = this.getPostListPostItem(postId, text);
await expect(postListPostItem).toBeVisible();

View File

@@ -1,9 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {ProfilePicture} from '@support/ui/component';
import {
Alert,
ProfilePicture,
} from '@support/ui/component';
import {ChannelScreen} from '@support/ui/screen';
import {timeouts} from '@support/utils';
import {timeouts, wait} from '@support/utils';
import {expect} from 'detox';
class ChannelInfoScreen {
@@ -16,7 +19,9 @@ class ChannelInfoScreen {
publicPrivateTitleDisplayName: 'channel_info.title.public_private.display_name',
publicPrivateTitlePurpose: 'channel_info.title.public_private.purpose',
favoriteAction: 'channel_info.channel_actions.favorite.action',
unfavoriteAction: 'channel_info.channel_actions.unfavorite.action',
muteAction: 'channel_info.channel_actions.mute.action',
unmuteAction: 'channel_info.channel_actions.unmute.action',
setHeaderAction: 'channel_info.channel_actions.set_header.action',
addPeopleAction: 'channel_info.channel_actions.add_people.action',
copyChannelLinkAction: 'channel_info.channel_actions.copy_channel_link.action',
@@ -32,6 +37,7 @@ class ChannelInfoScreen {
convertPrivateOption: 'channel_info.options.convert_private.option',
leaveChannelOption: 'channel_info.options.leave_channel.option',
archiveChannelOption: 'channel_info.options.archive_channel.option',
unarchiveChannelOption: 'channel_info.options.unarchive_channel.option',
};
channelInfoScreen = element(by.id(this.testID.channelInfoScreen));
@@ -41,7 +47,9 @@ class ChannelInfoScreen {
publicPrivateTitleDisplayName = element(by.id(this.testID.publicPrivateTitleDisplayName));
publicPrivateTitlePurpose = element(by.id(this.testID.publicPrivateTitlePurpose));
favoriteAction = element(by.id(this.testID.favoriteAction));
unfavoriteAction = element(by.id(this.testID.unfavoriteAction));
muteAction = element(by.id(this.testID.muteAction));
unmuteAction = element(by.id(this.testID.unmuteAction));
setHeaderAction = element(by.id(this.testID.setHeaderAction));
addPeopleAction = element(by.id(this.testID.addPeopleAction));
copyChannelLinkAction = element(by.id(this.testID.copyChannelLinkAction));
@@ -57,6 +65,7 @@ class ChannelInfoScreen {
convertPrivateOption = element(by.id(this.testID.convertPrivateOption));
leaveChannelOption = element(by.id(this.testID.leaveChannelOption));
archiveChannelOption = element(by.id(this.testID.archiveChannelOption));
unarchiveChannelOption = element(by.id(this.testID.unarchiveChannelOption));
getDirectMessageTitle = async (userId: string) => {
const directMessageTitleTestId = `${this.testID.directMessageTitlePrefix}${userId}`;
@@ -95,6 +104,59 @@ class ChannelInfoScreen {
await expect(this.channelInfoScreen).not.toBeVisible();
};
archiveChannel = async (alertArchiveChannelTitle: Detox.NativeElement, {confirm = true} = {}) => {
await this.scrollView.scrollTo('bottom');
await waitFor(this.archiveChannelOption).toExist().withTimeout(timeouts.TWO_SEC);
await this.archiveChannelOption.tap({x: 1, y: 1});
const {
noButton,
yesButton,
} = Alert;
await expect(alertArchiveChannelTitle).toBeVisible();
await expect(noButton).toBeVisible();
await expect(yesButton).toBeVisible();
if (confirm) {
await yesButton.tap();
await wait(timeouts.ONE_SEC);
await expect(this.channelInfoScreen).not.toExist();
} else {
await noButton.tap();
await wait(timeouts.ONE_SEC);
await expect(this.channelInfoScreen).toExist();
}
};
archivePrivateChannel = async ({confirm = true} = {}) => {
await this.archiveChannel(Alert.archivePrivateChannelTitle, {confirm});
};
archivePublicChannel = async ({confirm = true} = {}) => {
await this.archiveChannel(Alert.archivePublicChannelTitle, {confirm});
};
leaveChannel = async ({confirm = true} = {}) => {
await this.scrollView.scrollTo('bottom');
await waitFor(this.leaveChannelOption).toExist().withTimeout(timeouts.TWO_SEC);
await this.leaveChannelOption.tap({x: 1, y: 1});
const {
leaveChannelTitle,
cancelButton,
leaveButton,
} = Alert;
await expect(leaveChannelTitle).toBeVisible();
await expect(cancelButton).toBeVisible();
await expect(leaveButton).toBeVisible();
if (confirm) {
await leaveButton.tap();
await wait(timeouts.ONE_SEC);
await expect(this.channelInfoScreen).not.toExist();
} else {
await cancelButton.tap();
await wait(timeouts.ONE_SEC);
await expect(this.channelInfoScreen).toExist();
}
};
toggleIgnoreMentionsOptionOn = async () => {
await this.ignoreMentionsOptionToggledOff.tap();
await expect(this.ignoreMentionsOptionToggledOn).toBeVisible();
@@ -104,6 +166,36 @@ class ChannelInfoScreen {
await this.ignoreMentionsOptionToggledOn.tap();
await expect(this.ignoreMentionsOptionToggledOff).toBeVisible();
};
unarchiveChannel = async (alertUnarchiveChannelTitle: Detox.NativeElement, {confirm = true} = {}) => {
await this.scrollView.scrollTo('bottom');
await waitFor(this.unarchiveChannelOption).toExist().withTimeout(timeouts.TWO_SEC);
await this.unarchiveChannelOption.tap({x: 1, y: 1});
const {
noButton,
yesButton,
} = Alert;
await expect(alertUnarchiveChannelTitle).toBeVisible();
await expect(noButton).toBeVisible();
await expect(yesButton).toBeVisible();
if (confirm) {
await yesButton.tap();
await wait(timeouts.ONE_SEC);
await expect(this.channelInfoScreen).not.toExist();
} else {
await noButton.tap();
await wait(timeouts.ONE_SEC);
await expect(this.channelInfoScreen).toExist();
}
};
unarchivePrivateChannel = async ({confirm = true} = {}) => {
await this.unarchiveChannel(Alert.unarchivePrivateChannelTitle, {confirm});
};
unarchivePublicChannel = async ({confirm = true} = {}) => {
await this.unarchiveChannel(Alert.unarchivePublicChannelTitle, {confirm});
};
}
const channelInfoScreen = new ChannelInfoScreen();

View File

@@ -68,7 +68,7 @@ class CreateOrEditChannelScreen {
if (fromChannelInfo) {
await ChannelInfoScreen.setHeaderAction.tap();
} else {
await ChannelScreen.introSetHeaderOption.tap();
await ChannelScreen.introSetHeaderAction.tap();
}
return this.toBeVisible();

View File

@@ -10,7 +10,6 @@
import {
Channel,
Setup,
System,
Team,
} from '@support/server_api';
import {
@@ -38,12 +37,6 @@ describe('Autocomplete - Channel Mention', () => {
let otherChannelMentionAutocomplete: any;
beforeAll(async () => {
System.apiUpdateConfig(siteOneUrl, {
ServiceSettings: {
EnableAPIChannelDeletion: true,
},
});
const {channel, team, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;
testTeam = team;
@@ -197,7 +190,7 @@ describe('Autocomplete - Channel Mention', () => {
await expect(Autocomplete.sectionChannelMentionList).toBeVisible();
});
it('MM-T4879_8 - should not be able to autocomplete archived channel', async () => {
it('MM-T4879_8 - should be able to autocomplete archived channel', async () => {
// # Archive another team channel and type in "~" to activate channel mention autocomplete
await Channel.apiDeleteChannel(siteOneUrl, testOtherChannel.id);
await ChannelScreen.postInput.typeText('~');
@@ -209,8 +202,8 @@ describe('Autocomplete - Channel Mention', () => {
// # Type in channel name of archived channel
await ChannelScreen.postInput.typeText(testOtherChannel.name);
// * Verify channel mention autocomplete does not contain associated channel suggestion
await expect(otherChannelMentionAutocomplete).not.toBeVisible();
// * Verify channel mention autocomplete contains associated channel suggestion
await expect(otherChannelMentionAutocomplete).toBeVisible();
// # Unarchive channel, clear post input, and type in "~" to activate channel mention list
await Channel.apiRestoreChannel(siteOneUrl, testOtherChannel.id);

View File

@@ -0,0 +1,128 @@
// 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 {
Channel,
Setup,
} from '@support/server_api';
import {
serverOneUrl,
siteOneUrl,
} from '@support/test_config';
import {
BrowseChannelsScreen,
ChannelDropdownMenuScreen,
ChannelScreen,
ChannelListScreen,
HomeScreen,
LoginScreen,
ServerScreen,
ChannelInfoScreen,
} from '@support/ui/screen';
import {expect} from 'detox';
describe('Channels - Archive Channel', () => {
const serverOneDisplayName = 'Server 1';
const channelsCategory = 'channels';
let testTeam: any;
let testUser: any;
beforeAll(async () => {
const {team, user} = await Setup.apiInit(siteOneUrl);
testTeam = team;
testUser = user;
// # Log in to server
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
await LoginScreen.login(testUser);
});
beforeEach(async () => {
// * Verify on channel list screen
await ChannelListScreen.toBeVisible();
});
afterAll(async () => {
// # Log out
await HomeScreen.logout();
});
it('MM-T4932_1 - should be able to archive a public channel and confirm', async () => {
// # Open a public channel screen, open channel info screen, and tap on archive channel option and confirm
const {channel: publicChannel} = await Channel.apiCreateChannel(siteOneUrl, {type: 'O', teamId: testTeam.id});
await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, publicChannel.id);
await device.reloadReactNative();
await ChannelScreen.open(channelsCategory, publicChannel.name);
await ChannelInfoScreen.open();
await ChannelInfoScreen.archivePublicChannel({confirm: true});
// * Verify on channel screen and post draft archived message is displayed
await ChannelScreen.toBeVisible();
await expect(ChannelScreen.postDraftArchived).toBeVisible();
await expect(element(by.text('You are viewing an archived channel. New messages cannot be posted.'))).toBeVisible();
// # Tap on close channel button, open browse channels screen, tap on channel dropdown, tap on archived channels menu item, and search for the archived public channel
await ChannelScreen.postDraftArchivedCloseChannelButton.tap();
await BrowseChannelsScreen.open();
await BrowseChannelsScreen.channelDropdownTextPublic.tap();
await ChannelDropdownMenuScreen.archivedChannelsItem.tap();
await BrowseChannelsScreen.searchInput.replaceText(publicChannel.name);
// * Verify search returns the archived public channel item
await expect(BrowseChannelsScreen.getChannelItemDisplayName(publicChannel.name)).toHaveText(publicChannel.display_name);
// # Go back to channel list screen
await BrowseChannelsScreen.close();
});
it('MM-T4932_2 - should be able to archive a public channel and cancel', async () => {
// # Open a public channel screen, open channel info screen, and tap on archive channel option and cancel
const {channel: publicChannel} = await Channel.apiCreateChannel(siteOneUrl, {type: 'O', teamId: testTeam.id});
await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, publicChannel.id);
await device.reloadReactNative();
await ChannelScreen.open(channelsCategory, publicChannel.name);
await ChannelInfoScreen.open();
await ChannelInfoScreen.archivePublicChannel({confirm: false});
// * Verify still on channel info screen
await ChannelInfoScreen.toBeVisible();
// # Go back to channel list screen
await ChannelInfoScreen.close();
await ChannelScreen.back();
});
it('MM-T4932_3 - should be able to archive a private channel and confirm', async () => {
// # Open a private channel screen, open channel info screen, and tap on archive channel option and confirm
const {channel: privateChannel} = await Channel.apiCreateChannel(siteOneUrl, {type: 'P', teamId: testTeam.id});
await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, privateChannel.id);
await device.reloadReactNative();
await ChannelScreen.open(channelsCategory, privateChannel.name);
await ChannelInfoScreen.open();
await ChannelInfoScreen.archivePrivateChannel({confirm: true});
// * Verify on channel screen and post draft archived message is displayed
await ChannelScreen.toBeVisible();
await expect(ChannelScreen.postDraftArchived).toBeVisible();
await expect(element(by.text('You are viewing an archived channel. New messages cannot be posted.'))).toBeVisible();
// # Tap on close channel button, open browse channels screen, tap on channel dropdown, tap on archived channels menu item, and search for the archived private channel
await ChannelScreen.postDraftArchivedCloseChannelButton.tap();
await BrowseChannelsScreen.open();
await BrowseChannelsScreen.channelDropdownTextPublic.tap();
await ChannelDropdownMenuScreen.archivedChannelsItem.tap();
await BrowseChannelsScreen.searchInput.replaceText(privateChannel.name);
// * Verify search returns the archived private channel item
await expect(BrowseChannelsScreen.getChannelItemDisplayName(privateChannel.name)).toHaveText(privateChannel.display_name);
// # Go back to channel list screen
await BrowseChannelsScreen.close();
});
});

View File

@@ -10,7 +10,6 @@
import {
Channel,
Setup,
System,
Team,
User,
} from '@support/server_api';
@@ -36,15 +35,6 @@ describe('Channels - Browse Channels', () => {
let testUser: any;
beforeAll(async () => {
System.apiUpdateConfig(siteOneUrl, {
ServiceSettings: {
EnableAPIChannelDeletion: true,
},
TeamSettings: {
ExperimentalViewArchivedChannels: true,
},
});
const {team, user} = await Setup.apiInit(siteOneUrl);
testTeam = team;
testUser = user;
@@ -77,24 +67,24 @@ describe('Channels - Browse Channels', () => {
await BrowseChannelsScreen.close();
});
it('MM-T4729_2 - should be able to browse and join a channel', async () => {
// # As admin, create a new channel so that user can join
it('MM-T4729_2 - should be able to browse and join an unjoined public channel', async () => {
// # As admin, create a new public channel so that user can join
const {channel} = await Channel.apiCreateChannel(siteOneUrl, {teamId: testTeam.id});
// * Verify new channel does not appear on channel list screen
// * Verify new public channel does not appear on channel list screen
await expect(ChannelListScreen.getChannelItemDisplayName(channelsCategory, channel.display_name)).not.toExist();
// # Open browse channels screen and search for the new channel name to join
// # Open browse channels screen and search for the new public channel name to join
await BrowseChannelsScreen.open();
await BrowseChannelsScreen.searchInput.replaceText(channel.name);
// * Verify search returns the new channel item
// * Verify search returns the new public channel item
await expect(BrowseChannelsScreen.getChannelItemDisplayName(channel.name)).toHaveText(channel.display_name);
// # Tap on the new channel item
// # Tap on the new public channel item
await BrowseChannelsScreen.getChannelItem(channel.name).multiTap(2);
// * Verify on newly joined channel screen
// * Verify on newly joined public channel screen
await ChannelScreen.toBeVisible();
await expect(ChannelScreen.headerTitle).toHaveText(channel.display_name);
await expect(ChannelScreen.introDisplayName).toHaveText(channel.display_name);
@@ -103,7 +93,7 @@ describe('Channels - Browse Channels', () => {
await ChannelScreen.back();
await ChannelListScreen.toBeVisible();
// * Verify newly joined channel is added to channel list
// * Verify newly joined public channel is added to channel list
await expect(ChannelListScreen.getChannelItemDisplayName(channelsCategory, channel.name)).toBeVisible();
});
@@ -114,7 +104,7 @@ describe('Channels - Browse Channels', () => {
await BrowseChannelsScreen.searchInput.replaceText(searchTerm);
// * Verify empty search state for browse channels
await expect(element(by.text(`No results for “${searchTerm}`))).toBeVisible();
await expect(element(by.text(`No matches found for “${searchTerm}`))).toBeVisible();
await expect(element(by.text('Check the spelling or try another search.'))).toBeVisible();
// # Go back to channel list screen
@@ -133,13 +123,13 @@ describe('Channels - Browse Channels', () => {
await BrowseChannelsScreen.searchInput.replaceText(testOtherUser1.username);
// * Verify empty search state for browse channels
await expect(element(by.text(`No results for “${testOtherUser1.username}`))).toBeVisible();
await expect(element(by.text(`No matches found for “${testOtherUser1.username}`))).toBeVisible();
// # Search for the group message channel
await BrowseChannelsScreen.searchInput.replaceText(testOtherUser2.username);
// * Verify empty search state for browse channels
await expect(element(by.text(`No results for “${testOtherUser2.username}`))).toBeVisible();
await expect(element(by.text(`No matches found for “${testOtherUser2.username}`))).toBeVisible();
// # Go back to channel list screen
await BrowseChannelsScreen.close();
@@ -161,4 +151,39 @@ describe('Channels - Browse Channels', () => {
// # Go back to channel list screen
await BrowseChannelsScreen.close();
});
it('MM-T4729_6 - should not be able to browse a joined public channel', async () => {
// # Open browse channels screen and search for a joined public channel
const {channel: joinedPublicChannel} = await Channel.apiCreateChannel(siteOneUrl, {type: 'O', teamId: testTeam.id});
await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, joinedPublicChannel.id);
await BrowseChannelsScreen.open();
await BrowseChannelsScreen.searchInput.replaceText(joinedPublicChannel.name);
// * Verify empty search state for browse channels
await expect(element(by.text(`No matches found for “${joinedPublicChannel.name}`))).toBeVisible();
// # Go back to channel list screen
await BrowseChannelsScreen.close();
});
it('MM-T4729_7 - should not be able to browse joined and unjoined private channel', async () => {
// # As admin, create joined and unjoined private channels, open browse channels screen, and search for the joined private channel
const {channel: joinedPrivateChannel} = await Channel.apiCreateChannel(siteOneUrl, {type: 'P', teamId: testTeam.id});
const {channel: unjoinedPrivateChannel} = await Channel.apiCreateChannel(siteOneUrl, {type: 'P', teamId: testTeam.id});
await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, joinedPrivateChannel.id);
await BrowseChannelsScreen.open();
await BrowseChannelsScreen.searchInput.replaceText(joinedPrivateChannel.name);
// * Verify empty search state for browse channels
await expect(element(by.text(`No matches found for “${joinedPrivateChannel.name}`))).toBeVisible();
// # Search for the unjoined private channel
await BrowseChannelsScreen.searchInput.replaceText(unjoinedPrivateChannel.name);
// * Verify empty search state for browse channels
await expect(element(by.text(`No matches found for “${unjoinedPrivateChannel.name}`))).toBeVisible();
// # Go back to channel list screen
await BrowseChannelsScreen.close();
});
});

View File

@@ -0,0 +1,102 @@
// 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 {Setup} from '@support/server_api';
import {
serverOneUrl,
siteOneUrl,
} from '@support/test_config';
import {
ChannelScreen,
ChannelListScreen,
HomeScreen,
LoginScreen,
ServerScreen,
ChannelInfoScreen,
} from '@support/ui/screen';
import {expect} from 'detox';
describe('Channels - Channel Info', () => {
const serverOneDisplayName = 'Server 1';
const channelsCategory = 'channels';
let testChannel: any;
beforeAll(async () => {
const {channel, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;
// # Log in to server
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
await LoginScreen.login(user);
});
beforeEach(async () => {
// * Verify on channel list screen
await ChannelListScreen.toBeVisible();
});
afterAll(async () => {
// # Log out
await HomeScreen.logout();
});
it('MM-T4928_1 - should match elements on channel info screen', async () => {
// # Open a channel screen and open channel info screen
await ChannelScreen.open(channelsCategory, testChannel.name);
await ChannelInfoScreen.open();
// * Verify basic elements on channel info screen
await expect(ChannelInfoScreen.closeButton).toBeVisible();
await expect(ChannelInfoScreen.publicPrivateTitleDisplayName).toHaveText(testChannel.display_name);
await expect(ChannelInfoScreen.publicPrivateTitlePurpose).toHaveText(`Channel purpose: ${testChannel.display_name.toLowerCase()}`);
await expect(element(by.text(`Channel header: ${testChannel.display_name.toLowerCase()}`))).toBeVisible();
await expect(ChannelInfoScreen.favoriteAction).toBeVisible();
await expect(ChannelInfoScreen.muteAction).toBeVisible();
await expect(ChannelInfoScreen.addPeopleAction).toBeVisible();
await expect(ChannelInfoScreen.copyChannelLinkAction).toBeVisible();
await expect(ChannelInfoScreen.ignoreMentionsOptionToggledOff).toBeVisible();
await expect(ChannelInfoScreen.notificationPreferenceOption).toBeVisible();
await expect(ChannelInfoScreen.pinnedMessagesOption).toBeVisible();
await expect(ChannelInfoScreen.membersOption).toBeVisible();
await expect(ChannelInfoScreen.editChannelOption).toBeVisible();
await expect(ChannelInfoScreen.leaveChannelOption).toBeVisible();
await expect(ChannelInfoScreen.archiveChannelOption).toBeVisible();
// # Go back to channel list screen
await ChannelInfoScreen.close();
await ChannelScreen.back();
});
it('MM-T4928_2 - should be able to view channel info by tapping intro channel info action', async () => {
// # Open a channel screen and tap on intro channel info action
await ChannelScreen.open(channelsCategory, testChannel.name);
await ChannelScreen.introChannelInfoAction.tap();
// * Verify on channel info screen
await ChannelInfoScreen.toBeVisible();
// # Go back to channel list screen
await ChannelInfoScreen.close();
await ChannelScreen.back();
});
it('MM-T4928_3 - should be able to view channel info from channel quick actions', async () => {
// # Open a channel screen, tap on channel quick actions button, and tap on channel info action
await ChannelScreen.open(channelsCategory, testChannel.name);
await ChannelScreen.channelQuickActionsButton.tap();
await ChannelScreen.channelInfoQuickAction.tap();
// * Verify on channel info screen
await ChannelInfoScreen.toBeVisible();
// # Go back to channel list screen
await ChannelInfoScreen.close();
await ChannelScreen.back();
});
});

View File

@@ -9,7 +9,6 @@
import {
Setup,
System,
Team,
} from '@support/server_api';
import {
@@ -41,12 +40,6 @@ describe('Channels - Channel List', () => {
let testUser: any;
beforeAll(async () => {
System.apiUpdateConfig(siteOneUrl, {
ServiceSettings: {
CollapsedThreads: 'default_on',
},
});
const {channel, team, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;
testTeam = team;

View File

@@ -57,9 +57,9 @@ describe('Channels - Channel Post List', () => {
await expect(ChannelScreen.backButton).toBeVisible();
await expect(ChannelScreen.headerTitle).toHaveText(testChannel.display_name);
await expect(ChannelScreen.introDisplayName).toHaveText(testChannel.display_name);
await expect(ChannelScreen.introAddPeopleOption).toBeVisible();
await expect(ChannelScreen.introSetHeaderOption).toBeVisible();
await expect(ChannelScreen.introChannelDetailsOption).toBeVisible();
await expect(ChannelScreen.introAddPeopleAction).toBeVisible();
await expect(ChannelScreen.introSetHeaderAction).toBeVisible();
await expect(ChannelScreen.introChannelInfoAction).toBeVisible();
await expect(ChannelScreen.postList.getFlatList()).toBeVisible();
await expect(ChannelScreen.postDraft).toBeVisible();
await expect(ChannelScreen.postInput).toBeVisible();

View File

@@ -81,8 +81,8 @@ describe('Channels - Create Channel and Edit Channel Header', () => {
await expect(ChannelScreen.headerTitle).toHaveText(displayName);
await expect(ChannelScreen.introDisplayName).toHaveText(displayName);
// # Tap on set header option to edit the channel header
await ChannelScreen.introSetHeaderOption.tap();
// # Tap on set header action to edit the channel header
await ChannelScreen.introSetHeaderAction.tap();
// * Verify channel header is correct
await expect(CreateOrEditChannelScreen.headerInput).toHaveValue(header);
@@ -118,8 +118,8 @@ describe('Channels - Create Channel and Edit Channel Header', () => {
await expect(ChannelScreen.headerTitle).toHaveText(displayName);
await expect(ChannelScreen.introDisplayName).toHaveText(displayName);
// # Tap on set header option to edit the channel header
await ChannelScreen.introSetHeaderOption.tap();
// # Tap on set header action to edit the channel header
await ChannelScreen.introSetHeaderAction.tap();
// * Verify channel header is correct
await expect(CreateOrEditChannelScreen.headerInput).toHaveValue(header);

View File

@@ -160,7 +160,7 @@ describe('Channels - Create Direct Message', () => {
await CreateDirectMessageScreen.searchInput.replaceText(searchTerm);
// * Verify empty search state for create direct message
await expect(element(by.text(`No results for “${searchTerm}`))).toBeVisible();
await expect(element(by.text(`No matches found for “${searchTerm}`))).toBeVisible();
await expect(element(by.text('Check the spelling or try another search.'))).toBeVisible();
// # Go back to channel list screen

View File

@@ -0,0 +1,136 @@
// 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 {
Channel,
Setup,
Team,
User,
} from '@support/server_api';
import {
serverOneUrl,
siteOneUrl,
} from '@support/test_config';
import {
ChannelScreen,
ChannelListScreen,
HomeScreen,
LoginScreen,
ServerScreen,
ChannelInfoScreen,
} from '@support/ui/screen';
import {expect} from 'detox';
describe('Channels - Favorite and Unfavorite Channel', () => {
const serverOneDisplayName = 'Server 1';
const channelsCategory = 'channels';
const favoritesCategory = 'favorites';
const directMessagesCategory = 'direct_messages';
let testChannel: any;
let testTeam: any;
let testUser: any;
beforeAll(async () => {
const {channel, team, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;
testTeam = team;
testUser = user;
// # Log in to server
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
await LoginScreen.login(testUser);
});
beforeEach(async () => {
// * Verify on channel list screen
await ChannelListScreen.toBeVisible();
});
afterAll(async () => {
// # Log out
await HomeScreen.logout();
});
it('MM-T4929_1 - should be able to favorite/unfavorite a channel from channel quick actions', async () => {
// # Open a channel screen, tap on channel quick actions button, and tap on favorite quick action to favorite the channel
await ChannelScreen.open(channelsCategory, testChannel.name);
await ChannelScreen.channelQuickActionsButton.tap();
await ChannelScreen.favoriteQuickAction.tap();
// * Verify favorited toast message appears
await expect(ChannelScreen.toastMessage).toHaveText('This channel was favorited');
// # Go back to channel list screen
await ChannelScreen.back();
// * Verify channel is listed under favorites category
await expect(ChannelListScreen.getChannelItemDisplayName(favoritesCategory, testChannel.name)).toBeVisible();
// # Go back to the favorited channel, tap on channel quick actions button, and tap on favorited quick action to unfavorite the channel
await ChannelScreen.open(favoritesCategory, testChannel.name);
await ChannelScreen.channelQuickActionsButton.tap();
await ChannelScreen.unfavoriteQuickAction.tap();
// * Verify unfavorited toast message appears
await expect(ChannelScreen.toastMessage).toHaveText('This channel was unfavorited');
// # Go back to channel list screen
await ChannelScreen.back();
// * Verify channel is not listed anymore under favorites category and is back under channels category
await expect(ChannelListScreen.getChannelItemDisplayName(favoritesCategory, testChannel.name)).not.toBeVisible();
await expect(ChannelListScreen.getChannelItemDisplayName(channelsCategory, testChannel.name)).toBeVisible();
});
it('MM-T4929_2 - should be able to favorite/unfavorite a channel from channel info screen', async () => {
// # Open a channel screen, open channel info screen, tap on favorite action to favorite the channel, and go back to channel list screen
await ChannelScreen.open(channelsCategory, testChannel.name);
await ChannelInfoScreen.open();
await ChannelInfoScreen.favoriteAction.tap();
await ChannelInfoScreen.close();
await ChannelScreen.back();
// * Verify channel is listed under favorites category
await expect(ChannelListScreen.getChannelItemDisplayName(favoritesCategory, testChannel.name)).toBeVisible();
// # Go back to the favorited channel, open channel info screen, tap on favorited action to unfavorite the channel, and go back to channel list screen
await ChannelScreen.open(favoritesCategory, testChannel.name);
await ChannelInfoScreen.open();
await ChannelInfoScreen.unfavoriteAction.tap();
await ChannelInfoScreen.close();
await ChannelScreen.back();
// * Verify channel is not listed anymore under favorites category and is back under channels category
await expect(ChannelListScreen.getChannelItemDisplayName(favoritesCategory, testChannel.name)).not.toBeVisible();
await expect(ChannelListScreen.getChannelItemDisplayName(channelsCategory, testChannel.name)).toBeVisible();
});
it('MM-T4929_3 - should be able to favorite/unfavorite a direct message channel from channel intro', async () => {
// # Open a direct message channel screen, tap on intro favorite action to favorite the channel, and go back to channel list screen
const {user: newUser} = await User.apiCreateUser(siteOneUrl);
await Team.apiAddUserToTeam(siteOneUrl, newUser.id, testTeam.id);
const {channel: directMessageChannel} = await Channel.apiCreateDirectChannel(siteOneUrl, [testUser.id, newUser.id]);
await device.reloadReactNative();
await ChannelScreen.open(directMessagesCategory, directMessageChannel.name);
await ChannelScreen.introFavoriteAction.tap();
await ChannelScreen.back();
// * Verify direct message channel is listed under favorites category
await expect(ChannelListScreen.getChannelItemDisplayName(favoritesCategory, directMessageChannel.name)).toBeVisible();
// # Go back to the favorited direct message channel, tap on intro favorited action to unfavorite the direct message channel, and go back to channel list screen
await ChannelScreen.open(favoritesCategory, directMessageChannel.name);
await ChannelScreen.introUnfavoriteAction.tap();
await ChannelScreen.back();
// * Verify direct message channel is not listed anymore under favorites category and is back under direct messages category
await expect(ChannelListScreen.getChannelItemDisplayName(favoritesCategory, directMessageChannel.name)).not.toBeVisible();
await expect(ChannelListScreen.getChannelItemDisplayName(directMessagesCategory, directMessageChannel.name)).toBeVisible();
});
});

View File

@@ -10,7 +10,6 @@
import {
Channel,
Setup,
System,
Team,
User,
} from '@support/server_api';
@@ -35,15 +34,6 @@ describe('Channels - Find Channels', () => {
let testUser: any;
beforeAll(async () => {
System.apiUpdateConfig(siteOneUrl, {
ServiceSettings: {
EnableAPIChannelDeletion: true,
},
TeamSettings: {
ExperimentalViewArchivedChannels: true,
},
});
const {channel, team, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;
testTeam = team;
@@ -77,18 +67,18 @@ describe('Channels - Find Channels', () => {
await FindChannelsScreen.close();
});
it('MM-T4907_2 - should be able to find and navigate to a channel', async () => {
// # Open find channels screen and search for the channel to navigate to
it('MM-T4907_2 - should be able to find and navigate to a public channel', async () => {
// # Open find channels screen and search for a public channel to navigate to
await FindChannelsScreen.open();
await FindChannelsScreen.searchInput.replaceText(testChannel.name);
// * Verify search returns the target channel item
// * Verify search returns the target public channel item
await expect(FindChannelsScreen.getFilteredChannelItemDisplayName(testChannel.name)).toHaveText(testChannel.display_name);
// # Tap on the target channel item
// # Tap on the target public channel item
await FindChannelsScreen.getFilteredChannelItem(testChannel.name).tap();
// * Verify on target channel screen
// * Verify on target public channel screen
await ChannelScreen.toBeVisible();
await expect(ChannelScreen.headerTitle).toHaveText(testChannel.display_name);
await expect(ChannelScreen.introDisplayName).toHaveText(testChannel.display_name);
@@ -104,7 +94,7 @@ describe('Channels - Find Channels', () => {
await FindChannelsScreen.searchInput.replaceText(searchTerm);
// * Verify empty search state for find channels
await expect(element(by.text(`No results for “${searchTerm}`))).toBeVisible();
await expect(element(by.text(`No matches found for “${searchTerm}`))).toBeVisible();
await expect(element(by.text('Check the spelling or try another search.'))).toBeVisible();
// # Go back to channel list screen
@@ -135,7 +125,7 @@ describe('Channels - Find Channels', () => {
await FindChannelsScreen.close();
});
it('MM-T4907_5 - should be able to find archived channel', async () => {
it('MM-T4907_5 - should be able to find an archived channel', async () => {
// # Archive a channel, open find channels screen, and search for the archived channel
const {channel: archivedChannel} = await Channel.apiCreateChannel(siteOneUrl, {teamId: testTeam.id});
await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, archivedChannel.id);
@@ -149,4 +139,25 @@ describe('Channels - Find Channels', () => {
// # Go back to channel list screen
await FindChannelsScreen.close();
});
it('MM-T4907_6 - should be able to find a joined private channel and not find an unjoined private channel', async () => {
// # Open find channels screen and search for a joined private channel
const {channel: joinedPrivateChannel} = await Channel.apiCreateChannel(siteOneUrl, {type: 'P', teamId: testTeam.id});
const {channel: unjoinedPrivateChannel} = await Channel.apiCreateChannel(siteOneUrl, {type: 'P', teamId: testTeam.id});
await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, joinedPrivateChannel.id);
await FindChannelsScreen.open();
await FindChannelsScreen.searchInput.replaceText(joinedPrivateChannel.name);
// * Verify search returns the target joined private channel item
await expect(FindChannelsScreen.getFilteredChannelItemDisplayName(joinedPrivateChannel.name)).toHaveText(joinedPrivateChannel.display_name);
// # Search for an unjoined private channel
await FindChannelsScreen.searchInput.replaceText(unjoinedPrivateChannel.name);
// * Verify empty search state for find channels
await expect(element(by.text(`No matches found for “${unjoinedPrivateChannel.name}`))).toBeVisible();
// # Go back to channel list screen
await FindChannelsScreen.close();
});
});

View File

@@ -0,0 +1,98 @@
// 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 {
Channel,
Setup,
} from '@support/server_api';
import {
serverOneUrl,
siteOneUrl,
} from '@support/test_config';
import {
ChannelScreen,
ChannelListScreen,
HomeScreen,
LoginScreen,
ServerScreen,
ChannelInfoScreen,
} from '@support/ui/screen';
import {expect} from 'detox';
describe('Channels - Leave Channel', () => {
const serverOneDisplayName = 'Server 1';
const channelsCategory = 'channels';
let testTeam: any;
let testUser: any;
beforeAll(async () => {
const {team, user} = await Setup.apiInit(siteOneUrl);
testTeam = team;
testUser = user;
// # Log in to server
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
await LoginScreen.login(testUser);
});
beforeEach(async () => {
// * Verify on channel list screen
await ChannelListScreen.toBeVisible();
});
afterAll(async () => {
// # Log out
await HomeScreen.logout();
});
it('MM-T4931_1 - should be able to leave a channel from channel info screen and confirm', async () => {
// # Open a channel screen, open channel info screen, and tap on leave channel option and confirm
const {channel} = await Channel.apiCreateChannel(siteOneUrl, {teamId: testTeam.id});
await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, channel.id);
await device.reloadReactNative();
await ChannelScreen.open(channelsCategory, channel.name);
await ChannelInfoScreen.open();
await ChannelInfoScreen.leaveChannel({confirm: true});
// * Verify on channel list screen and the channel left by the user does not appear on the list
await ChannelListScreen.toBeVisible();
await expect(ChannelListScreen.getChannelItem(channelsCategory, channel.name)).not.toExist();
});
it('MM-T4931_2 - should be able to leave a channel from channel info screen and cancel', async () => {
// # Open a channel screen, open channel info screen, and tap on leave channel option and cancel
const {channel} = await Channel.apiCreateChannel(siteOneUrl, {teamId: testTeam.id});
await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, channel.id);
await device.reloadReactNative();
await ChannelScreen.open(channelsCategory, channel.name);
await ChannelInfoScreen.open();
await ChannelInfoScreen.leaveChannel({confirm: false});
// * Verify still on channel info screen
await ChannelInfoScreen.toBeVisible();
// # Go back to channel list screen
await ChannelInfoScreen.close();
await ChannelScreen.back();
});
it('MM-T4931_3 - should be able to leave a channel from channel quick actions', async () => {
// # Open a channel screen, tap on channel quick actions button, and tap on leave channel option and confirm
const {channel} = await Channel.apiCreateChannel(siteOneUrl, {teamId: testTeam.id});
await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, channel.id);
await device.reloadReactNative();
await ChannelScreen.open(channelsCategory, channel.name);
await ChannelScreen.channelQuickActionsButton.tap();
await ChannelScreen.leaveChannel({confirm: true});
// * Verify on channel list screen and the channel left by the user does not appear on the list
await ChannelListScreen.toBeVisible();
await expect(ChannelListScreen.getChannelItem(channelsCategory, channel.name)).not.toExist();
});
});

View File

@@ -0,0 +1,88 @@
// 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 {Setup} from '@support/server_api';
import {
serverOneUrl,
siteOneUrl,
} from '@support/test_config';
import {
ChannelScreen,
ChannelListScreen,
HomeScreen,
LoginScreen,
ServerScreen,
ChannelInfoScreen,
} from '@support/ui/screen';
import {expect} from 'detox';
describe('Channels - Mute and Unmute Channel', () => {
const serverOneDisplayName = 'Server 1';
const channelsCategory = 'channels';
let testChannel: any;
beforeAll(async () => {
const {channel, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;
// # Log in to server
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
await LoginScreen.login(user);
});
beforeEach(async () => {
// * Verify on channel list screen
await ChannelListScreen.toBeVisible();
});
afterAll(async () => {
// # Log out
await HomeScreen.logout();
});
it('MM-T4930_1 - should be able to mute/unmute a channel from channel quick actions', async () => {
// # Open a channel screen, tap on channel quick actions button, and tap on mute quick action to mute the channel
await ChannelScreen.open(channelsCategory, testChannel.name);
await ChannelScreen.channelQuickActionsButton.tap();
await ChannelScreen.muteQuickAction.tap();
// * Verify muted toast message appears
await expect(ChannelScreen.toastMessage).toHaveText('This channel was muted');
// # Tap on channel quick actions button and tap on muted quick action to unmute the channel
await ChannelScreen.channelQuickActionsButton.tap();
await ChannelScreen.unmuteQuickAction.tap();
// * Verify unmuted toast message appears
await expect(ChannelScreen.toastMessage).toHaveText('This channel was unmuted');
// # Go back to channel list screen
await ChannelScreen.back();
});
it('MM-T4930_2 - should be able to mute/unmute a channel from channel info screen', async () => {
// # Open a channel screen, open channel info screen, and tap on mute action to mute the channel
await ChannelScreen.open(channelsCategory, testChannel.name);
await ChannelInfoScreen.open();
await ChannelInfoScreen.muteAction.tap();
// * Verify channel is muted
await expect(ChannelInfoScreen.unmuteAction).toBeVisible();
// # Tap on muted action to unmute the channel
await ChannelInfoScreen.unmuteAction.tap();
// * Verify channel is unmuted
await expect(ChannelInfoScreen.muteAction).toBeVisible();
// # Go back to channel list screen
await ChannelInfoScreen.close();
await ChannelScreen.back();
});
});

View File

@@ -171,7 +171,7 @@ describe('Messaging - Emojis and Reactions', () => {
await EmojiPickerScreen.searchInput.replaceText(searchTerm);
// * Verify empty search state for emoji picker
await expect(element(by.text(`No results for “${searchTerm}`))).toBeVisible();
await expect(element(by.text(`No matches found for “${searchTerm}`))).toBeVisible();
await expect(element(by.text('Check the spelling or try another search.'))).toBeVisible();
// # Go back to channel list screen

View File

@@ -10,7 +10,6 @@
import {
Post,
Setup,
System,
} from '@support/server_api';
import {
serverOneUrl,
@@ -31,13 +30,6 @@ describe('Messaging - Markdown Latex', () => {
let testChannel: any;
beforeAll(async () => {
System.apiUpdateConfig(siteOneUrl, {
ServiceSettings: {
EnableLatex: true,
EnableInlineLatex: true,
},
});
const {channel, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;

View File

@@ -212,25 +212,23 @@ describe('Server Login - Server List', () => {
// * Verify on channel list screen of the first server
await expect(ChannelListScreen.headerServerDisplayName).toHaveText(serverOneDisplayName);
// # Open server list screen, swipe left on first server and tap on logout option
// # Open server list screen, swipe left on third server and tap on logout option
await ServerListScreen.open();
await ServerListScreen.getServerItemActive(serverOneDisplayName).swipe('left');
await ServerListScreen.getServerItemLogoutOption(serverOneDisplayName).tap();
await ServerListScreen.getServerItemInactive(serverThreeDisplayName).swipe('left');
await ServerListScreen.getServerItemLogoutOption(serverThreeDisplayName).tap();
// * Verify logout server alert is displayed
await expect(Alert.logoutTitle(serverOneDisplayName)).toBeVisible();
await expect(Alert.logoutTitle(serverThreeDisplayName)).toBeVisible();
// # Tap on logout button and go back to server list screen
// # Tap on logout button
await Alert.logoutButton.tap();
await ServerListScreen.open();
// * Verify first server is logged out
await ServerListScreen.getServerItemInactive(serverOneDisplayName).swipe('left');
await expect(ServerListScreen.getServerItemLoginOption(serverOneDisplayName)).toBeVisible();
// * Verify third server is logged out
await ServerListScreen.getServerItemInactive(serverThreeDisplayName).swipe('left');
await expect(ServerListScreen.getServerItemLoginOption(serverThreeDisplayName)).toBeVisible();
// # Log back in to first server
await ServerListScreen.getServerItemLoginOption(serverOneDisplayName).tap();
await LoginScreen.login(serverOneUser);
// # Go back to first server
await ServerListScreen.getServerItemActive(serverOneDisplayName).tap();
});
it('MM-T4691_7 - should not be able to add server for an already existing server', async () => {
@@ -257,7 +255,12 @@ describe('Server Login - Server List', () => {
// * Verify same name server error
await expect(ServerScreen.serverDisplayNameInputError).toHaveText(sameNameServerError);
// # Close server screen to go back to first server
// # Close server screen, open server list screen, log out of second server, and go back to first server
await ServerScreen.close();
await ServerListScreen.open();
await ServerListScreen.getServerItemInactive(serverTwoDisplayName).swipe('left');
await ServerListScreen.getServerItemLogoutOption(serverTwoDisplayName).tap();
await Alert.logoutButton.tap();
await ServerListScreen.getServerItemActive(serverOneDisplayName).tap();
});
});

View File

@@ -38,15 +38,17 @@ describe('Smoke Test - Channels', () => {
const channelsCategory = 'channels';
let testChannel: any;
let testTeam: any;
let testUser: any;
beforeAll(async () => {
const {channel, team, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;
testTeam = team;
testUser = user;
// # Log in to server
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
await LoginScreen.login(user);
await LoginScreen.login(testUser);
});
beforeEach(async () => {
@@ -158,4 +160,51 @@ describe('Smoke Test - Channels', () => {
await ChannelInfoScreen.close();
await ChannelScreen.back();
});
it('MM-T4774_5 - should be able to favorite and mute a channel', async () => {
// # Open a channel screen, open channel info screen, tap on favorite action to favorite the channel, and tap on mute action to mute the channel
await ChannelScreen.open(channelsCategory, testChannel.name);
await ChannelInfoScreen.open();
await ChannelInfoScreen.favoriteAction.tap();
await ChannelInfoScreen.muteAction.tap();
// * Verify channel is favorited and muted
await expect(ChannelInfoScreen.unfavoriteAction).toBeVisible();
await expect(ChannelInfoScreen.unmuteAction).toBeVisible();
// # Tap on favorited action to unfavorite the channel and tap on muted action to unmute the channel
await ChannelInfoScreen.unfavoriteAction.tap();
await ChannelInfoScreen.unmuteAction.tap();
// * Verify channel is unfavorited and unmuted
await expect(ChannelInfoScreen.favoriteAction).toBeVisible();
await expect(ChannelInfoScreen.muteAction).toBeVisible();
// # Go back to channel list screen
await ChannelInfoScreen.close();
await ChannelScreen.back();
});
it('MM-T4774_6 - should be able to archive and leave a channel', async () => {
// # Open a channel screen, open channel info screen, and tap on archive channel option and confirm
const {channel} = await Channel.apiCreateChannel(siteOneUrl, {teamId: testTeam.id});
await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, channel.id);
await device.reloadReactNative();
await ChannelScreen.open(channelsCategory, channel.name);
await ChannelInfoScreen.open();
await ChannelInfoScreen.archivePublicChannel({confirm: true});
// * Verify on channel screen and post draft archived message is displayed
await ChannelScreen.toBeVisible();
await expect(ChannelScreen.postDraftArchived).toBeVisible();
await expect(element(by.text('You are viewing an archived channel. New messages cannot be posted.'))).toBeVisible();
// # Open channel info screen, and tap on leave channel option and confirm
await ChannelInfoScreen.open();
await ChannelInfoScreen.leaveChannel({confirm: true});
// * Verify on channel list screen and the channel left by the user does not appear on the list
await ChannelListScreen.toBeVisible();
await expect(ChannelListScreen.getChannelItem(channelsCategory, channel.name)).not.toExist();
});
});

View File

@@ -17,6 +17,7 @@ import {
serverTwoUrl,
siteTwoUrl,
} from '@support/test_config';
import {Alert} from '@support/ui/component';
import {
ChannelListScreen,
HomeScreen,
@@ -55,7 +56,7 @@ describe('Smoke Test - Server Login', () => {
await expect(ChannelListScreen.headerServerDisplayName).toHaveText(serverOneDisplayName);
});
it('MM-T4675_2 - should be able to add a new server and log in to the new server', async () => {
it('MM-T4675_2 - should be able to add a new server and log-in-to/log-out-from the new server', async () => {
// # Open server list screen
await ServerListScreen.open();
@@ -75,8 +76,24 @@ describe('Smoke Test - Server Login', () => {
await device.reloadReactNative();
await expect(ChannelListScreen.headerServerDisplayName).toHaveText(serverTwoDisplayName);
// # Go back to first server
// # Go back to first server, open server list screen, swipe left on second server and tap on logout option
await ServerListScreen.open();
await ServerListScreen.getServerItemInactive(serverOneDisplayName).tap();
await ServerListScreen.open();
await ServerListScreen.getServerItemInactive(serverTwoDisplayName).swipe('left');
await ServerListScreen.getServerItemLogoutOption(serverTwoDisplayName).tap();
// * Verify logout server alert is displayed
await expect(Alert.logoutTitle(serverTwoDisplayName)).toBeVisible();
// # Tap on logout button
await Alert.logoutButton.tap();
// * Verify second server is logged out
await ServerListScreen.getServerItemInactive(serverTwoDisplayName).swipe('left');
await expect(ServerListScreen.getServerItemLoginOption(serverTwoDisplayName)).toBeVisible();
// # Go back to first server
await ServerListScreen.getServerItemActive(serverOneDisplayName).tap();
});
});

View File

@@ -10,7 +10,6 @@
import {
Post,
Setup,
System,
} from '@support/server_api';
import {
serverOneUrl,
@@ -37,12 +36,6 @@ describe('Smoke Test - Threads', () => {
let testChannel: any;
beforeAll(async () => {
System.apiUpdateConfig(siteOneUrl, {
ServiceSettings: {
CollapsedThreads: 'default_on',
},
});
const {channel, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;

View File

@@ -10,7 +10,6 @@
import {
Post,
Setup,
System,
} from '@support/server_api';
import {
serverOneUrl,
@@ -36,12 +35,6 @@ describe('Threads - Follow and Unfollow Thread', () => {
let testChannel: any;
beforeAll(async () => {
System.apiUpdateConfig(siteOneUrl, {
ServiceSettings: {
CollapsedThreads: 'default_on',
},
});
const {channel, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;

View File

@@ -10,7 +10,6 @@
import {
Post,
Setup,
System,
} from '@support/server_api';
import {
serverOneUrl,
@@ -35,12 +34,6 @@ describe('Threads - Global Threads', () => {
let testUser: any;
beforeAll(async () => {
System.apiUpdateConfig(siteOneUrl, {
ServiceSettings: {
CollapsedThreads: 'default_on',
},
});
const {channel, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;
testUser = user;
@@ -75,7 +68,7 @@ describe('Threads - Global Threads', () => {
});
it('MM-T4805_2 - should be able to go to a thread a user started and followed', async () => {
// # Create a thread started by the current user
// # Create a thread started by the current user which current user replied to
const parentMessage = `Message ${getRandomId()}`;
await ChannelScreen.open(channelsCategory, testChannel.name);
await ChannelScreen.postMessage(parentMessage);
@@ -100,7 +93,7 @@ describe('Threads - Global Threads', () => {
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
await expect(GlobalThreadsScreen.getThreadItemThreadStarterUserDisplayName(parentPost.id)).toHaveText(testUser.username);
await expect(GlobalThreadsScreen.getThreadItemThreadStarterChannelDisplayName(parentPost.id)).toHaveText(testChannel.display_name.toUpperCase());
await expect(GlobalThreadsScreen.getThreadItemFooterUnreadReplies(parentPost.id)).toHaveText('1 new reply');
await expect(GlobalThreadsScreen.getThreadItemFooterReplyCount(parentPost.id)).toHaveText('1 reply');
// # Tap on the thread
await GlobalThreadsScreen.getThreadItem(parentPost.id).tap();
@@ -168,7 +161,7 @@ describe('Threads - Global Threads', () => {
await expect(GlobalThreadsScreen.getThreadItem(parentPost.id)).toBeVisible();
await expect(GlobalThreadsScreen.getThreadItemThreadStarterUserDisplayName(parentPost.id)).toHaveText('sysadmin');
await expect(GlobalThreadsScreen.getThreadItemThreadStarterChannelDisplayName(parentPost.id)).toHaveText(testChannel.display_name.toUpperCase());
await expect(GlobalThreadsScreen.getThreadItemFooterUnreadReplies(parentPost.id)).toHaveText('1 new reply');
await expect(GlobalThreadsScreen.getThreadItemFooterReplyCount(parentPost.id)).toHaveText('1 reply');
// # Tap on the thread
await GlobalThreadsScreen.getThreadItem(parentPost.id).tap();

View File

@@ -10,7 +10,6 @@
import {
Post,
Setup,
System,
} from '@support/server_api';
import {
serverOneUrl,
@@ -36,12 +35,6 @@ describe('Threads - Mark Thread as Read and Unread', () => {
let testChannel: any;
beforeAll(async () => {
System.apiUpdateConfig(siteOneUrl, {
ServiceSettings: {
CollapsedThreads: 'default_on',
},
});
const {channel, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;
@@ -61,15 +54,16 @@ describe('Threads - Mark Thread as Read and Unread', () => {
});
it('MM-T4807_1 - should be able to mark a thread as read by opening thread', async () => {
// # Create a thread, go back to channel list screen, then go to global threads screen, and tap on unread threads button
// # Create a thread started by the current user which another user replied to, go back to channel list screen, then go to global threads screen, and tap on unread threads button
const parentMessage = `Message ${getRandomId()}`;
await ChannelScreen.open(channelsCategory, testChannel.name);
await ChannelScreen.postMessage(parentMessage);
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
const replyMessage = `${parentMessage} reply`;
await ThreadScreen.postMessage(replyMessage);
await ThreadScreen.back();
await Post.apiCreatePost(siteOneUrl, {
channelId: testChannel.id,
message: `${parentMessage} reply`,
rootId: parentPost.id,
});
await ChannelScreen.back();
await device.reloadReactNative();
await GlobalThreadsScreen.open();
@@ -100,15 +94,16 @@ describe('Threads - Mark Thread as Read and Unread', () => {
});
it('MM-T4807_2 - should be able to mark a thread as read/unread via thread options', async () => {
// # Create a thread, go back to channel list screen, then go to global threads screen, and tap on unread threads button
// # Create a thread started by the current user which another user replied to, go back to channel list screen, then go to global threads screen, and tap on unread threads button
const parentMessage = `Message ${getRandomId()}`;
await ChannelScreen.open(channelsCategory, testChannel.name);
await ChannelScreen.postMessage(parentMessage);
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
const replyMessage = `${parentMessage} reply`;
await ThreadScreen.postMessage(replyMessage);
await ThreadScreen.back();
await Post.apiCreatePost(siteOneUrl, {
channelId: testChannel.id,
message: `${parentMessage} reply`,
rootId: parentPost.id,
});
await ChannelScreen.back();
await device.reloadReactNative();
await GlobalThreadsScreen.open();
@@ -148,15 +143,16 @@ describe('Threads - Mark Thread as Read and Unread', () => {
});
it('MM-T4807_3 - should be able to mark all threads as read', async () => {
// # Create a thread, go back to channel list screen, then go to global threads screen, and tap on unread threads button
// # Create a thread started by the current user which another user replied to, go back to channel list screen, then go to global threads screen, and tap on unread threads button
const parentMessage = `Message ${getRandomId()}`;
await ChannelScreen.open(channelsCategory, testChannel.name);
await ChannelScreen.postMessage(parentMessage);
const {post: parentPost} = await Post.apiGetLastPostInChannel(siteOneUrl, testChannel.id);
await ChannelScreen.openReplyThreadFor(parentPost.id, parentMessage);
const replyMessage = `${parentMessage} reply`;
await ThreadScreen.postMessage(replyMessage);
await ThreadScreen.back();
await Post.apiCreatePost(siteOneUrl, {
channelId: testChannel.id,
message: `${parentMessage} reply`,
rootId: parentPost.id,
});
await ChannelScreen.back();
await device.reloadReactNative();
await GlobalThreadsScreen.open();

View File

@@ -10,7 +10,6 @@
import {
Post,
Setup,
System,
} from '@support/server_api';
import {
serverOneUrl,
@@ -36,12 +35,6 @@ describe('Threads - Open Thread in Channel', () => {
let testChannel: any;
beforeAll(async () => {
System.apiUpdateConfig(siteOneUrl, {
ServiceSettings: {
CollapsedThreads: 'default_on',
},
});
const {channel, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;

View File

@@ -10,7 +10,6 @@
import {
Post,
Setup,
System,
} from '@support/server_api';
import {
serverOneUrl,
@@ -35,12 +34,6 @@ describe('Threads - Reply to Thread', () => {
let testChannel: any;
beforeAll(async () => {
System.apiUpdateConfig(siteOneUrl, {
ServiceSettings: {
CollapsedThreads: 'default_on',
},
});
const {channel, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;

View File

@@ -10,7 +10,6 @@
import {
Post,
Setup,
System,
} from '@support/server_api';
import {
serverOneUrl,
@@ -36,12 +35,6 @@ describe('Threads - Save and Unsave Thread', () => {
let testChannel: any;
beforeAll(async () => {
System.apiUpdateConfig(siteOneUrl, {
ServiceSettings: {
CollapsedThreads: 'default_on',
},
});
const {channel, user} = await Setup.apiInit(siteOneUrl);
testChannel = channel;