diff --git a/app/components/__snapshots__/badge.test.js.snap b/app/components/__snapshots__/badge.test.js.snap
index 4ba6eb7c7..bf77c93db 100644
--- a/app/components/__snapshots__/badge.test.js.snap
+++ b/app/components/__snapshots__/badge.test.js.snap
@@ -15,6 +15,7 @@ exports[`Badge should match snapshot 1`] = `
},
]
}
+ testID="badge"
>
99+
diff --git a/app/components/badge.js b/app/components/badge.js
index 34064e69a..5b39f6c41 100644
--- a/app/components/badge.js
+++ b/app/components/badge.js
@@ -21,6 +21,7 @@ export default class Badge extends PureComponent {
};
static propTypes = {
+ testID: PropTypes.string,
containerStyle: ViewPropTypes.style,
count: PropTypes.number.isRequired,
extraPaddingHorizontal: PropTypes.number,
@@ -108,12 +109,15 @@ export default class Badge extends PureComponent {
};
renderText = () => {
- const {containerStyle, count, style} = this.props;
+ const {testID, containerStyle, count, style} = this.props;
+ const unreadCountTestID = `${testID}.unread_count`;
+ const unreadIndicatorID = `${testID}.unread_indicator`;
let unreadCount = null;
let unreadIndicator = null;
if (count < 0) {
unreadIndicator = (
@@ -127,6 +131,7 @@ export default class Badge extends PureComponent {
unreadCount = (
@@ -137,7 +142,10 @@ export default class Badge extends PureComponent {
}
return (
-
+
{
const baseProps = {
+ testID: 'badge',
count: 100,
countStyle: {color: '#145dbf', fontSize: 10},
style: {backgroundColor: '#ffffff'},
diff --git a/app/components/markdown/markdown.js b/app/components/markdown/markdown.js
index ee2240d40..5ab9e1442 100644
--- a/app/components/markdown/markdown.js
+++ b/app/components/markdown/markdown.js
@@ -160,13 +160,24 @@ export default class Markdown extends PureComponent {
renderText = ({context, literal}) => {
if (context.indexOf('image') !== -1) {
// If this text is displayed, it will be styled by the image component
- return {literal};
+ return (
+
+ {literal}
+
+ );
}
// Construct the text style based off of the parents of this node since RN's inheritance is limited
const style = this.computeTextStyle(this.props.baseTextStyle, context);
- return {literal};
+ return (
+
+ {literal}
+
+ );
};
renderCodeSpan = ({context, literal}) => {
diff --git a/app/components/post/post.js b/app/components/post/post.js
index 4c972814d..0315ec65c 100644
--- a/app/components/post/post.js
+++ b/app/components/post/post.js
@@ -320,6 +320,7 @@ export default class Post extends PureComponent {
}
const replyBarStyle = this.replyBarStyle();
const rightColumnStyle = [style.rightColumn, (commentedOnPost && isLastReply && style.rightColumnPadding)];
+ const itemTestID = `${testID}.${post.id}`;
return (
{username} updated the channel display name from: {oldDisplayName} to: {newDisplayName}
@@ -51,6 +52,7 @@ exports[`renderSystemMessage uses renderer for Channel Header update 1`] = `
],
]
}
+ testID="markdown_text"
>
{username} updated the channel header from: {oldHeader} to: {newHeader}
@@ -88,6 +90,7 @@ exports[`renderSystemMessage uses renderer for OLD archived channel without a us
],
]
}
+ testID="markdown_text"
>
{username} archived the channel
@@ -128,6 +131,7 @@ exports[`renderSystemMessage uses renderer for archived channel 2`] = `
],
]
}
+ testID="markdown_text"
>
{username} archived the channel
@@ -157,6 +161,7 @@ exports[`renderSystemMessage uses renderer for unarchived channel 1`] = `
],
]
}
+ testID="markdown_text"
>
{username} unarchived the channel
diff --git a/app/components/post_list/post_list.js b/app/components/post_list/post_list.js
index e17c4361f..5d607e411 100644
--- a/app/components/post_list/post_list.js
+++ b/app/components/post_list/post_list.js
@@ -549,7 +549,7 @@ export default class PostList extends PureComponent {
}
function PostComponent({testID, postId, highlightPostId, lastPostIndex, index, ...postProps}) {
- const postTestID = `${testID}.post.${postId}`;
+ const postTestID = `${testID}.post`;
return (
diff --git a/app/components/sidebars/main/channels_list/channel_item/channel_item.js b/app/components/sidebars/main/channels_list/channel_item/channel_item.js
index a2dd6621a..369c063ae 100644
--- a/app/components/sidebars/main/channels_list/channel_item/channel_item.js
+++ b/app/components/sidebars/main/channels_list/channel_item/channel_item.js
@@ -134,8 +134,11 @@ export default class ChannelItem extends PureComponent {
let badge;
if (mentions) {
+ const badgeTestID = `${testID}.badge`;
+
badge = (
);
+ const itemTestID = `${testID}.${channelId}`;
const displayNameTestID = `${testID}.display_name`;
return (
@@ -179,13 +183,16 @@ export default class ChannelItem extends PureComponent {
style={[style.container, mutedStyle]}
>
{extraBorder}
-
+
{icon}
{channelDisplayName}
diff --git a/app/components/sidebars/main/channels_list/channels_list.js b/app/components/sidebars/main/channels_list/channels_list.js
index 15b7c24d8..d0c0dcac5 100644
--- a/app/components/sidebars/main/channels_list/channels_list.js
+++ b/app/components/sidebars/main/channels_list/channels_list.js
@@ -99,6 +99,7 @@ export default class ChannelsList extends PureComponent {
const filteredListTestID = `${testID}.filtered_list`;
const listTestID = `${testID}.list`;
const searchBarTestID = `${testID}.search_bar`;
+ const switchTeamsButtonTestID = `${testID}.switch_teams.button`;
let list;
if (searching) {
@@ -126,7 +127,15 @@ export default class ChannelsList extends PureComponent {
fontSize: 15,
};
- const leftComponent = onShowTeams ? : null;
+ let leftComponent;
+ if (onShowTeams) {
+ leftComponent = (
+
+ );
+ }
const title = (
+
+
+
+
+
+
+
+
+`;
diff --git a/app/components/sidebars/main/channels_list/switch_teams_button/switch_teams_button.js b/app/components/sidebars/main/channels_list/switch_teams_button/switch_teams_button.js
index 268f75dbe..3dbfcfa86 100644
--- a/app/components/sidebars/main/channels_list/switch_teams_button/switch_teams_button.js
+++ b/app/components/sidebars/main/channels_list/switch_teams_button/switch_teams_button.js
@@ -16,6 +16,7 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
export default class SwitchTeamsButton extends React.PureComponent {
static propTypes = {
+ testID: PropTypes.string,
currentTeamId: PropTypes.string,
onShowTeams: PropTypes.func.isRequired,
mentionCount: PropTypes.number.isRequired,
@@ -29,6 +30,7 @@ export default class SwitchTeamsButton extends React.PureComponent {
render() {
const {
+ testID,
currentTeamId,
mentionCount,
teamsCount,
@@ -49,9 +51,11 @@ export default class SwitchTeamsButton extends React.PureComponent {
const minWidth = lowMentionCount ? 8 : 20;
const badgeStyle = lowMentionCount ? styles.smallBadge : styles.badge;
const containerStyle = lowMentionCount ? styles.smallBadgeContainer : styles.badgeContainer;
+ const badgeTestID = `${testID}.badge`;
const badge = (
);
+ const itemTestID = `${testID}.${currentTeamId}`;
+ const teamIconTestID = `${testID}.team_icon`;
+
return (
-
+
-
+
{
+ const baseProps = {
+ onShowTeams: jest.fn(),
+ testID: 'main.sidebar.channels_list.switch_teams.button',
+ currentTeamId: 'current-team-id',
+ mentionCount: 1,
+ teamsCount: 2,
+ theme: Preferences.THEMES.default,
+ };
+
+ test('should match snapshot', () => {
+ const wrapper = shallow();
+
+ expect(wrapper.getElement()).toMatchSnapshot();
+ });
+});
diff --git a/app/components/sidebars/main/main_sidebar_base.js b/app/components/sidebars/main/main_sidebar_base.js
index 935fe42ac..058c8fd62 100644
--- a/app/components/sidebars/main/main_sidebar_base.js
+++ b/app/components/sidebars/main/main_sidebar_base.js
@@ -217,6 +217,7 @@ export default class MainSidebarBase extends Component {
style={style.swiperContent}
>
diff --git a/app/components/sidebars/main/teams_list/teams_list.js b/app/components/sidebars/main/teams_list/teams_list.js
index a5c8e9525..479a26006 100644
--- a/app/components/sidebars/main/teams_list/teams_list.js
+++ b/app/components/sidebars/main/teams_list/teams_list.js
@@ -36,6 +36,7 @@ const VIEWABILITY_CONFIG = {
export default class TeamsList extends PureComponent {
static propTypes = {
+ testID: PropTypes.string,
actions: PropTypes.shape({
handleTeamChange: PropTypes.func.isRequired,
}).isRequired,
@@ -124,8 +125,12 @@ export default class TeamsList extends PureComponent {
};
renderItem = ({item}) => {
+ const {testID} = this.props;
+ const teamsListItemTestID = `${testID}.flat_list.teams_list_item`;
+
return (
@@ -168,6 +175,7 @@ export default class TeamsList extends PureComponent {
{moreAction}
+
+
+
+
+
+
+
+
+ display-name
+
+
+ current-url/name
+
+
+
+
+
+`;
diff --git a/app/components/sidebars/main/teams_list/teams_list_item/teams_list_item.js b/app/components/sidebars/main/teams_list/teams_list_item/teams_list_item.js
index b1856b7a9..3adae01f7 100644
--- a/app/components/sidebars/main/teams_list/teams_list_item/teams_list_item.js
+++ b/app/components/sidebars/main/teams_list/teams_list_item/teams_list_item.js
@@ -17,6 +17,7 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
export default class TeamsListItem extends React.PureComponent {
static propTypes = {
+ testID: PropTypes.string,
currentTeamId: PropTypes.string.isRequired,
currentUrl: PropTypes.string.isRequired,
displayName: PropTypes.string.isRequired,
@@ -33,6 +34,7 @@ export default class TeamsListItem extends React.PureComponent {
render() {
const {
+ testID,
currentTeamId,
currentUrl,
displayName,
@@ -47,9 +49,11 @@ export default class TeamsListItem extends React.PureComponent {
const minWidth = lowMentionCount ? 8 : 20;
const badgeStyle = lowMentionCount ? styles.smallBadge : styles.badge;
const containerStyle = lowMentionCount ? styles.smallBadgeContainer : styles.badgeContainer;
+ const badgeTestID = `${testID}.badge`;
const badge = (
+
+
-
+
{
+ const baseProps = {
+ selectTeam: jest.fn(),
+ testID: 'main.sidebar.teams_list.flat_list.teams_list_item',
+ currentTeamId: 'current-team-id',
+ currentUrl: 'current-url',
+ displayName: 'display-name',
+ mentionCount: 1,
+ name: 'name',
+ teamId: 'team-id',
+ theme: Preferences.THEMES.default,
+ };
+
+ test('should match snapshot', () => {
+ const wrapper = shallow();
+
+ expect(wrapper.getElement()).toMatchSnapshot();
+ });
+});
diff --git a/app/components/team_icon/__snapshots__/team_icon.test.js.snap b/app/components/team_icon/__snapshots__/team_icon.test.js.snap
new file mode 100644
index 000000000..24b21bcbf
--- /dev/null
+++ b/app/components/team_icon/__snapshots__/team_icon.test.js.snap
@@ -0,0 +1,43 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`TeamIcon should match snapshot 1`] = `
+
+
+
+`;
diff --git a/app/components/team_icon/team_icon.js b/app/components/team_icon/team_icon.js
index 529376512..bd0cdde8f 100644
--- a/app/components/team_icon/team_icon.js
+++ b/app/components/team_icon/team_icon.js
@@ -12,6 +12,7 @@ import {makeStyleSheetFromTheme} from 'app/utils/theme';
export default class TeamIcon extends React.PureComponent {
static propTypes = {
+ testID: PropTypes.string,
displayName: PropTypes.string,
lastIconUpdate: PropTypes.number,
teamId: PropTypes.string.isRequired, // eslint-disable-line react/no-unused-prop-types
@@ -51,6 +52,7 @@ export default class TeamIcon extends React.PureComponent {
render() {
const {
+ testID,
displayName,
lastIconUpdate,
teamId,
@@ -59,19 +61,23 @@ export default class TeamIcon extends React.PureComponent {
styleText,
styleImage,
} = this.props;
-
+ const contentTestID = `${testID}.content`;
const styles = getStyleSheet(theme);
let teamIconContent;
if (this.state.imageError || !lastIconUpdate) {
teamIconContent = (
-
+
{displayName?.substr(0, 2).toUpperCase()}
);
} else {
teamIconContent = (
+
{teamIconContent}
);
diff --git a/app/components/team_icon/team_icon.test.js b/app/components/team_icon/team_icon.test.js
new file mode 100644
index 000000000..4c93fffae
--- /dev/null
+++ b/app/components/team_icon/team_icon.test.js
@@ -0,0 +1,28 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import React from 'react';
+import {shallow} from 'enzyme';
+
+import Preferences from '@mm-redux/constants/preferences';
+
+import TeamIcon from './team_icon';
+
+describe('TeamIcon', () => {
+ const baseProps = {
+ testID: 'team_icon',
+ displayName: 'display-name',
+ lastIconUpdate: 1,
+ teamId: 'team-id',
+ styleContainer: {},
+ styleText: {},
+ styleImage: {},
+ theme: Preferences.THEMES.default,
+ };
+
+ test('should match snapshot', () => {
+ const wrapper = shallow();
+
+ expect(wrapper.getElement()).toMatchSnapshot();
+ });
+});
diff --git a/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/__snapshots__/main_sidebar_drawer_button.test.js.snap b/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/__snapshots__/main_sidebar_drawer_button.test.js.snap
index 1905433e6..a6b540e18 100644
--- a/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/__snapshots__/main_sidebar_drawer_button.test.js.snap
+++ b/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/__snapshots__/main_sidebar_drawer_button.test.js.snap
@@ -103,6 +103,7 @@ exports[`MainSidebarDrawerButton should match, full snapshot 2`] = `
"padding": 3,
}
}
+ testID="main_sidebar_drawer.button.badge"
/>
diff --git a/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/main_sidebar_drawer_button.js b/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/main_sidebar_drawer_button.js
index 12d70000d..c04509d7b 100644
--- a/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/main_sidebar_drawer_button.js
+++ b/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/main_sidebar_drawer_button.js
@@ -96,6 +96,7 @@ export default class MainSidebarDrawerButton extends PureComponent {
badge = (
}
diff --git a/app/screens/long_post/__snapshots__/long_post.test.js.snap b/app/screens/long_post/__snapshots__/long_post.test.js.snap
index 40f667de0..c23320656 100644
--- a/app/screens/long_post/__snapshots__/long_post.test.js.snap
+++ b/app/screens/long_post/__snapshots__/long_post.test.js.snap
@@ -327,7 +327,7 @@ LongPost {
shouldRenderReplyButton={false}
showAddReaction={false}
showLongPost={true}
- testID="long_post.post.post-id"
+ testID="long_post.post"
/>
diff --git a/app/screens/recent_mentions/recent_mentions.js b/app/screens/recent_mentions/recent_mentions.js
index 41e0c9e76..831258986 100644
--- a/app/screens/recent_mentions/recent_mentions.js
+++ b/app/screens/recent_mentions/recent_mentions.js
@@ -224,8 +224,8 @@ export default class RecentMentions extends PureComponent {
return (
{component}
diff --git a/app/screens/saved_posts/__snapshots__/saved_posts.test.js.snap b/app/screens/saved_posts/__snapshots__/saved_posts.test.js.snap
index 7de6e8f4f..b0cfa3c64 100644
--- a/app/screens/saved_posts/__snapshots__/saved_posts.test.js.snap
+++ b/app/screens/saved_posts/__snapshots__/saved_posts.test.js.snap
@@ -7,6 +7,7 @@ exports[`SavedPosts should match snapshot 1`] = `
"flex": 1,
}
}
+ testID="saved_messages.screen"
>
+
{component}
diff --git a/app/screens/search/search_result_post/__snapshots__/search_result_post.test.js.snap b/app/screens/search/search_result_post/__snapshots__/search_result_post.test.js.snap
index e71bd7b1d..7e8032c90 100644
--- a/app/screens/search/search_result_post/__snapshots__/search_result_post.test.js.snap
+++ b/app/screens/search/search_result_post/__snapshots__/search_result_post.test.js.snap
@@ -15,6 +15,6 @@ exports[`SearchResultPost should match snapshot 1`] = `
showFullDate={false}
skipFlaggedHeader={false}
skipPinnedHeader={false}
- testID="search_result_post.post.post-id"
+ testID="search_result_post.post"
/>
`;
diff --git a/app/screens/search/search_result_post/search_result_post.js b/app/screens/search/search_result_post/search_result_post.js
index 15c06cf50..373fcf1f9 100644
--- a/app/screens/search/search_result_post/search_result_post.js
+++ b/app/screens/search/search_result_post/search_result_post.js
@@ -42,11 +42,9 @@ export default class SearchResultPost extends PureComponent {
postComponentProps.skipPinnedHeader = this.props.skipPinnedHeader;
}
- const testID = `search_result_post.post.${this.props.postId}`;
-
return (
{
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}~1members~1{user_id}/delete
* @param {string} channelId - The channel ID
* @param {string} userId - The user ID to be removed from channel
- * @return {Object} returns status on success or {error, status} on error
+ * @return {Object} returns {status} on success or {error, status} on error
*/
export const apiDeleteUserFromChannel = async (channelId, userId) => {
try {
@@ -90,7 +90,7 @@ export const apiDeleteUserFromChannel = async (channelId, userId) => {
`/api/v4/channels/${channelId}/members/${userId}`,
);
- return response;
+ return {status: response.status};
} catch (err) {
return getResponseFromError(err);
}
diff --git a/detox/e2e/support/ui/component/channels_list.js b/detox/e2e/support/ui/component/channels_list.js
new file mode 100644
index 000000000..b541f1869
--- /dev/null
+++ b/detox/e2e/support/ui/component/channels_list.js
@@ -0,0 +1,67 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+class ChannelsList {
+ testID = {
+ channelsList: 'main.sidebar.channels_list.list',
+ channelItem: 'main.sidebar.channels_list.list.channel_item',
+ channelItemDisplayName: 'main.sidebar.channels_list.list.channel_item.display_name',
+ filteredChannelsList: 'main.sidebar.channels_list.filtered_list',
+ filteredChannelItem: 'main.sidebar.channels_list.filtered_list.channel_item',
+ filteredChannelItemDisplayName: 'main.sidebar.channels_list.filtered_list.channel_item.display_name',
+ switchTeamsButton: 'main.sidebar.channels_list.switch_teams.button',
+ switchTeamsButtonBadge: 'main.sidebar.channels_list.switch_teams.button.badge',
+ switchTeamsButtonBadgeUnreadCount: 'main.sidebar.channels_list.switch_teams.button.badge.unread_count',
+ switchTeamsButtonBadgeUnreadIndicator: 'main.sidebar.channels_list.switch_teams.button.badge.unread_indicator',
+ }
+
+ channelsList = element(by.id(this.testID.channelsList));
+ filteredChannelsList = element(by.id(this.testID.channelsList));
+ switchTeamsButton = element(by.id(this.testID.switchTeamsButton));
+ switchTeamsButtonBadge = element(by.id(this.testID.switchTeamsButtonBadge));
+ switchTeamsButtonBadgeUnreadCount = element(by.id(this.testID.switchTeamsButtonBadgeUnreadCount));
+ switchTeamsButtonBadgeUnreadIndicator = element(by.id(this.testID.switchTeamsButtonBadgeUnreadIndicator));
+
+ getChannelItem = (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);
+ }
+
+ getFilteredChannelItem = (channelId, displayName) => {
+ const filteredChannelItemTestID = `${this.testID.filteredChannelItem}.${channelId}`;
+ const baseMatcher = by.id(filteredChannelItemTestID);
+ const filteredChannelItemMatcher = displayName ? baseMatcher.withDescendant(by.text(displayName)) : baseMatcher;
+ const filteredChannelItemDisplayNameMatcher = by.id(this.testID.filteredChannelItemDisplayName).withAncestor(filteredChannelItemMatcher);
+
+ return {
+ channelItem: element(filteredChannelItemMatcher),
+ channelItemDisplayName: element(filteredChannelItemDisplayNameMatcher),
+ };
+ }
+
+ getFilteredChannelByDisplayName = (displayName) => {
+ return element(by.text(displayName).withAncestor(by.id(this.testID.filteredChannelsList)));
+ }
+
+ getFilteredChannelDisplayNameAtIndex = (index) => {
+ return element(by.id(this.testID.filteredChannelItemDisplayName)).atIndex(index);
+ }
+}
+
+const channelsList = new ChannelsList();
+export default channelsList;
diff --git a/detox/e2e/support/ui/component/index.js b/detox/e2e/support/ui/component/index.js
index 3e05b638c..6578873fb 100644
--- a/detox/e2e/support/ui/component/index.js
+++ b/detox/e2e/support/ui/component/index.js
@@ -7,9 +7,12 @@ import EditChannelInfo from './edit_channel_info';
import FileQuickAction from './file_quick_action';
import ImageQuickAction from './image_quick_action';
import InputQuickAction from './input_quick_action';
+import ChannelsList from './channels_list';
+import TeamsList from './teams_list';
import MainSidebar from './main_sidebar';
import Post from './post';
import PostDraft from './post_draft';
+import PostList from './post_list';
import PostOptions from './post_options';
import RecentItem from './recent_item';
import SearchBar from './search_bar';
@@ -23,9 +26,12 @@ export {
FileQuickAction,
ImageQuickAction,
InputQuickAction,
+ ChannelsList,
+ TeamsList,
MainSidebar,
Post,
PostDraft,
+ PostList,
PostOptions,
RecentItem,
SearchBar,
diff --git a/detox/e2e/support/ui/component/main_sidebar.js b/detox/e2e/support/ui/component/main_sidebar.js
index c0fb9e98c..cf650be01 100644
--- a/detox/e2e/support/ui/component/main_sidebar.js
+++ b/detox/e2e/support/ui/component/main_sidebar.js
@@ -1,27 +1,73 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
+import ChannelsList from './channels_list';
+import TeamsList from './teams_list';
+
class MainSidebar {
testID = {
mainSidebar: 'main.sidebar',
- channelsList: 'main.sidebar.channels_list',
- channelItemDisplayName: 'main.sidebar.channels_list.list.channel_item.display_name',
- filteredChannelItemDisplayName: 'main.sidebar.channels_list.filtered_list.channel_item.display_name',
openMoreChannelsButton: 'action_button_sidebar.channels',
openCreatePrivateChannelButton: 'action_button_sidebar.pg',
openMoreDirectMessagesButton: 'action_button_sidebar.direct',
}
mainSidebar = element(by.id(this.testID.mainSidebar));
- channelsList = element(by.id(this.testID.channelsList));
- channelItemDisplayName = element(by.id(this.testID.channelItemDisplayName));
- filteredChannelItemDisplayName = element(by.id(this.testID.filteredChannelItemDisplayName));
openMoreChannelsButton = element(by.id(this.testID.openMoreChannelsButton));
openCreatePrivateChannelButton = element(by.id(this.testID.openCreatePrivateChannelButton));
openMoreDirectMessagesButton = element(by.id(this.testID.openMoreDirectMessagesButton));
+ // convenience props
+ channelsList = ChannelsList.channelsList;
+ filteredChannelsList = ChannelsList.filteredChannelsList;
+ switchTeamsButton = ChannelsList.switchTeamsButton;
+ switchTeamsButtonBadge = ChannelsList.switchTeamsButtonBadge;
+ switchTeamsButtonBadgeUnreadCount = ChannelsList.switchTeamsButtonBadgeUnreadCount;
+ switchTeamsButtonBadgeUnreadIndicator = ChannelsList.switchTeamsButtonBadgeUnreadIndicator;
+ teamsList = TeamsList.teamsList;
+
+ getChannel = (channelId, displayName) => {
+ return ChannelsList.getChannelItem(channelId, displayName);
+ }
+
getChannelByDisplayName = (displayName) => {
- return element(by.text(displayName).withAncestor(by.id(this.testID.channelsList)));
+ return ChannelsList.getChannelByDisplayName(displayName);
+ }
+
+ getChannelDisplayNameAtIndex = (index) => {
+ return ChannelsList.getChannelDisplayNameAtIndex(index);
+ }
+
+ getFilteredChannel = (channelId, displayName) => {
+ return ChannelsList.getFilteredChannelItem(channelId, displayName);
+ }
+
+ getFilteredChannelByDisplayName = (displayName) => {
+ return ChannelsList.getFilteredChannelByDisplayName(displayName);
+ }
+
+ getFilteredChannelDisplayNameAtIndex = (index) => {
+ return ChannelsList.getFilteredChannelDisplayNameAtIndex(index);
+ }
+
+ getTeam = (teamId, displayName) => {
+ return TeamsList.getTeamItem(teamId, displayName);
+ }
+
+ getTeamByDisplayName = (displayName) => {
+ return TeamsList.getTeamByDisplayName(displayName);
+ }
+
+ getTeamBadgeUnreadCountAtIndex = (index) => {
+ return TeamsList.getTeamBadgeUnreadCountAtIndex(index);
+ }
+
+ getTeamDisplayNameAtIndex = (index) => {
+ return TeamsList.getTeamDisplayNameAtIndex(index);
+ }
+
+ getTeamIconContentAtIndex = (index) => {
+ return TeamsList.getTeamIconContentAtIndex(index);
}
toBeVisible = async () => {
@@ -30,16 +76,58 @@ class MainSidebar {
return this.mainSidebar;
}
- hasChannelAtIndex = async (index, channelDisplayName) => {
+ closeTeamSidebar = async () => {
+ // # Close team sidebar
+ await this.swipeLeft();
+ await expect(this.teamsList).not.toBeVisible();
+ await expect(this.channelsList).toBeVisible();
+ await this.toBeVisible();
+ }
+
+ openTeamSidebar = async () => {
+ // # Open team sidebar
+ await this.switchTeamsButton.tap();
+ await expect(this.channelsList).not.toBeVisible();
+ await expect(this.teamsList).toBeVisible();
+ await this.toBeVisible();
+ }
+
+ swipeLeft = async () => {
+ await this.mainSidebar.swipe('left');
+ }
+
+ swipeRight = async () => {
+ await this.mainSidebar.swipe('right');
+ }
+
+ hasChannelDisplayNameAtIndex = async (index, channelDisplayName) => {
await expect(
- element(by.id(this.testID.channelItemDisplayName)).atIndex(index),
+ this.getChannelDisplayNameAtIndex(index),
).toHaveText(channelDisplayName);
}
- hasFilteredChannelAtIndex = async (index, filteredChannelItemDisplayName) => {
+ hasFilteredChannelDisplayNameAtIndex = async (index, channelDisplayName) => {
await expect(
- element(by.id(this.testID.filteredChannelItemDisplayName)).atIndex(index),
- ).toHaveText(filteredChannelItemDisplayName);
+ this.getFilteredChannelDisplayNameAtIndex(index),
+ ).toHaveText(channelDisplayName);
+ }
+
+ hasTeamBadgeUnreadCountAtIndex = async (index, teamBadUnreadCount) => {
+ await expect(
+ this.getTeamBadgeUnreadCountAtIndex(index),
+ ).toHaveText(teamBadUnreadCount);
+ }
+
+ hasTeamDisplayNameAtIndex = async (index, teamDisplayName) => {
+ await expect(
+ this.getTeamDisplayNameAtIndex(index),
+ ).toHaveText(teamDisplayName);
+ }
+
+ hasTeamIconContentAtIndex = async (index, teamIconContent) => {
+ await expect(
+ this.getTeamIconContentAtIndex(index),
+ ).toHaveText(teamIconContent);
}
}
diff --git a/detox/e2e/support/ui/component/post.js b/detox/e2e/support/ui/component/post.js
index d78c2ee96..7f809570f 100644
--- a/detox/e2e/support/ui/component/post.js
+++ b/detox/e2e/support/ui/component/post.js
@@ -3,23 +3,27 @@
class Post {
testID = {
- postPrefix: 'post.',
postHeaderReply: 'post_header.reply',
+ markdownText: 'markdown_text',
}
- getPost = (postTypePrefix, postId, text) => {
- const postTestID = `${postTypePrefix}${this.testID.postPrefix}${postId}`;
- if (text) {
- return {
- postItem: element(by.id(postTestID).withDescendant(by.text(text))),
- postItemHeaderReply: element(by.id(this.testID.postHeaderReply).withAncestor(by.id(postTestID).withDescendant(by.text(text)))),
- };
- }
+ getPost = (postItemSourceTestID, postId, postMessage) => {
+ const postTestID = `${postItemSourceTestID}.${postId}`;
+ const baseMatcher = by.id(postTestID);
+ const postItemMatcher = postMessage ? baseMatcher.withDescendant(by.text(postMessage)) : baseMatcher;
+ const postItemHeaderReplyMatcher = by.id(this.testID.postHeaderReply).withAncestor(postItemMatcher);
+ const postItemMessageMatcher = by.id(this.testID.markdownText).withAncestor(postItemMatcher);
+
return {
- postItem: element(by.id(postTestID)),
- postItemHeaderReply: element(by.id(this.testID.postHeaderReply).withAncestor(by.id(postTestID))),
+ postItem: element(postItemMatcher),
+ postItemHeaderReply: element(postItemHeaderReplyMatcher),
+ postItemMessage: element(postItemMessageMatcher),
};
}
+
+ getPostMessage = (postItemSourceTestID) => {
+ return element(by.id(this.testID.markdownText).withAncestor(by.id(postItemSourceTestID)));
+ }
}
const post = new Post();
diff --git a/detox/e2e/support/ui/component/post_list.js b/detox/e2e/support/ui/component/post_list.js
new file mode 100644
index 000000000..f923f1d06
--- /dev/null
+++ b/detox/e2e/support/ui/component/post_list.js
@@ -0,0 +1,27 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import Post from './post';
+
+class PostList {
+ constructor(screenPrefix) {
+ this.testID = {
+ postListPostItem: `${screenPrefix}post_list.post`,
+ };
+ }
+
+ getPost = (postId, postMessage) => {
+ const {postItem, postItemHeaderReply, postItemMessage} = Post.getPost(this.testID.postListPostItem, postId, postMessage);
+ return {
+ postListPostItem: postItem,
+ postListPostItemHeaderReply: postItemHeaderReply,
+ postListPostItemMessage: postItemMessage,
+ };
+ }
+
+ getPostMessageAtIndex = (index) => {
+ return Post.getPostMessage(this.testID.postListPostItem).atIndex(index);
+ }
+}
+
+export default PostList;
diff --git a/detox/e2e/support/ui/component/search_bar.js b/detox/e2e/support/ui/component/search_bar.js
index 90e6b85b5..32e815f5b 100644
--- a/detox/e2e/support/ui/component/search_bar.js
+++ b/detox/e2e/support/ui/component/search_bar.js
@@ -1,11 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
+import {isAndroid} from '@support/utils';
+
class SearchBar {
testID = {
searchBarSuffix: 'search_bar',
searchInputSuffix: 'search_bar.search.input',
- backButtonSuffix: 'search_bar.search.back.button',
+ cancelButtonSuffix: 'search_bar.search.cancel.button',
clearButtonSuffix: 'search_bar.search.clear.button',
}
@@ -17,11 +19,10 @@ class SearchBar {
return element(by.id(`${screenPrefix}${this.testID.searchInputSuffix}`)).atIndex(0);
}
- getBackButton = (screenPrefix) => {
- return element(by.id(`${screenPrefix}${this.testID.backButtonSuffix}`)).atIndex(0);
- }
-
getCancelButton = (screenPrefix) => {
+ if (isAndroid()) {
+ return element(by.id(`${screenPrefix}${this.testID.cancelButtonSuffix}`)).atIndex(0);
+ }
return element(by.text('Cancel').withAncestor(by.id(`${screenPrefix}${this.testID.searchBarSuffix}`))).atIndex(0);
}
diff --git a/detox/e2e/support/ui/component/settings_sidebar.js b/detox/e2e/support/ui/component/settings_sidebar.js
index 8262bf4aa..93b28781d 100644
--- a/detox/e2e/support/ui/component/settings_sidebar.js
+++ b/detox/e2e/support/ui/component/settings_sidebar.js
@@ -27,6 +27,11 @@ class SettingsSidebar {
return this.settingsSidebar;
}
+
+ tapLogoutAction = async () => {
+ await this.logoutAction.tap();
+ await expect(this.settingsSidebar).not.toBeVisible();
+ }
}
const settingsSidebar = new SettingsSidebar();
diff --git a/detox/e2e/support/ui/component/teams_list.js b/detox/e2e/support/ui/component/teams_list.js
new file mode 100644
index 000000000..9f96ac866
--- /dev/null
+++ b/detox/e2e/support/ui/component/teams_list.js
@@ -0,0 +1,61 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+class TeamsList {
+ testID = {
+ teamsList: 'main.sidebar.teams_list',
+ teamItem: 'main.sidebar.teams_list.flat_list.teams_list_item',
+ teamItemBadge: 'main.sidebar.teams_list.flat_list.teams_list_item.badge',
+ teamItemBadgeUnreadCount: 'main.sidebar.teams_list.flat_list.teams_list_item.badge.unread_count',
+ teamItemBadgeUnreadIndicator: 'main.sidebar.teams_list.flat_list.teams_list_item.badge.unread_indicator',
+ teamItemCurrent: 'main.sidebar.teams_list.flat_list.teams_list_item.current',
+ teamItemDisplayName: 'main.sidebar.teams_list.flat_list.teams_list_item.display_name',
+ teamItemIcon: 'main.sidebar.teams_list.flat_list.teams_list_item.team_icon',
+ teamItemIconContent: 'main.sidebar.teams_list.flat_list.teams_list_item.team_icon.content',
+ }
+
+ teamsList = element(by.id(this.testID.teamsList));
+
+ getTeamItem = (teamId, displayName) => {
+ const teamItemTestID = `${this.testID.teamItem}.${teamId}`;
+ const baseMatcher = by.id(teamItemTestID);
+ const teamItemMatcher = displayName ? baseMatcher.withDescendant(by.text(displayName)) : baseMatcher;
+ const teamItemBadgeMatcher = by.id(this.testID.teamItemBadge).withAncestor(teamItemMatcher);
+ const teamItemBadgeUnreadCountMatcher = by.id(this.testID.teamItemBadgeUnreadCount).withAncestor(teamItemMatcher);
+ const teamItemBadgeUnreadIndicatorMatcher = by.id(this.testID.teamItemBadgeUnreadIndicator).withAncestor(teamItemMatcher);
+ const teamItemCurrentMatcher = by.id(this.testID.teamItemCurrent).withAncestor(teamItemMatcher);
+ const teamItemDisplayNameMatcher = by.id(this.testID.teamItemDisplayName).withAncestor(teamItemMatcher);
+ const teamItemIconMatcher = by.id(this.testID.teamItemIcon).withAncestor(teamItemMatcher);
+ const teamItemIconContentMatcher = by.id(this.testID.teamItemIconContent).withAncestor(teamItemMatcher);
+
+ return {
+ teamItem: element(teamItemMatcher),
+ teamItemBadge: element(teamItemBadgeMatcher),
+ teamItemBadgeUnreadCount: element(teamItemBadgeUnreadCountMatcher),
+ teamItemBadgeUnreadIndicator: element(teamItemBadgeUnreadIndicatorMatcher),
+ teamItemCurrent: element(teamItemCurrentMatcher),
+ teamItemDisplayName: element(teamItemDisplayNameMatcher),
+ teamItemIcon: element(teamItemIconMatcher),
+ teamItemIconContent: element(teamItemIconContentMatcher),
+ };
+ }
+
+ getTeamByDisplayName = (displayName) => {
+ return element(by.text(displayName).withAncestor(by.id(this.testID.teamsList)));
+ }
+
+ getTeamBadgeUnreadCountAtIndex = (index) => {
+ return element(by.id(this.testID.teamItemBadgeUnreadCount)).atIndex(index);
+ }
+
+ getTeamDisplayNameAtIndex = (index) => {
+ return element(by.id(this.testID.teamItemDisplayName)).atIndex(index);
+ }
+
+ getTeamIconContentAtIndex = (index) => {
+ return element(by.id(this.testID.teamItemIconContent)).atIndex(index);
+ }
+}
+
+const teamsList = new TeamsList();
+export default teamsList;
diff --git a/detox/e2e/support/ui/screen/channel.js b/detox/e2e/support/ui/screen/channel.js
index 1c3147d86..f488c3560 100644
--- a/detox/e2e/support/ui/screen/channel.js
+++ b/detox/e2e/support/ui/screen/channel.js
@@ -8,6 +8,7 @@ import {
InputQuickAction,
MainSidebar,
PostDraft,
+ PostList,
PostOptions,
SendButton,
SettingsSidebar,
@@ -15,15 +16,18 @@ import {
import {
LoginScreen,
LongPostScreen,
- PostListScreen,
SelectServerScreen,
} from '@support/ui/screen';
+import {isAndroid} from '@support/utils';
class ChannelScreen {
testID = {
channelScreenPrefix: 'channel.',
channelScreen: 'channel.screen',
mainSidebarDrawerButton: 'main_sidebar_drawer.button',
+ mainSidebarDrawerButtonBadge: 'main_sidebar_drawer.button.badge',
+ mainSidebarDrawerButtonBadgeUnreadCount: 'main_sidebar_drawer.button.badge.unread_count',
+ mainSidebarDrawerButtonBadgeUnreadIndicator: 'main_sidebar_drawer.button.badge.unread_indicator',
channelIntro: 'channel_intro.beginning.text',
channelNavBarTitle: 'channel.nav_bar.title',
channelSearchButton: 'channel.search.button',
@@ -33,6 +37,9 @@ class ChannelScreen {
channelScreen = element(by.id(this.testID.channelScreen));
mainSidebarDrawerButton = element(by.id(this.testID.mainSidebarDrawerButton));
+ mainSidebarDrawerButtonBadge = element(by.id(this.testID.mainSidebarDrawerButtonBadge));
+ mainSidebarDrawerButtonBadgeUnreadCount = element(by.id(this.testID.mainSidebarDrawerButtonBadgeUnreadCount));
+ mainSidebarDrawerButtonBadgeUnreadIndicator = element(by.id(this.testID.mainSidebarDrawerButtonBadgeUnreadIndicator));
channelIntro = element(by.id(this.testID.channelIntro));
channelNavBarTitle = element(by.id(this.testID.channelNavBarTitle));
channelSearchButton = element(by.id(this.testID.channelSearchButton));
@@ -57,12 +64,22 @@ class ChannelScreen {
sendButton = SendButton.getSendButton(this.testID.channelScreenPrefix);
sendButtonDisabled = SendButton.getSendButtonDisabled(this.testID.channelScreenPrefix);
- getLongPostPostItem = (postId, text) => {
+ postList = new PostList(this.testID.channelScreenPrefix);
+
+ getLongPostItem = (postId, text) => {
return LongPostScreen.getPost(postId, text);
}
+ getLongPostMessage = () => {
+ return LongPostScreen.getPostMessage();
+ }
+
getPostListPostItem = (postId, text) => {
- return PostListScreen.getPost(this.testID.channelScreenPrefix, postId, text);
+ return this.postList.getPost(postId, text);
+ }
+
+ getPostMessageAtIndex = (index) => {
+ return this.postList.getPostMessageAtIndex(index);
}
toBeVisible = async () => {
@@ -81,13 +98,42 @@ class ChannelScreen {
logout = async () => {
await this.openSettingsSidebar();
- await SettingsSidebar.logoutAction.tap();
+ await SettingsSidebar.tapLogoutAction();
await SelectServerScreen.toBeVisible();
}
+ closeMainSidebar = async () => {
+ if (isAndroid()) {
+ // # Close main sidebar
+ await this.swipeLeft();
+ await this.toBeVisible();
+ } else {
+ // # iOS workaround for now
+ await device.reloadReactNative();
+ }
+ }
+
+ closeSettingsSidebar = async () => {
+ if (isAndroid()) {
+ // # Close settings sidebar
+ await this.swipeRight();
+ await this.toBeVisible();
+ } else {
+ // # iOS workaround for now
+ await device.reloadReactNative();
+ }
+ }
+
+ closeTeamSidebar = async () => {
+ // # Close team sidebar
+ await MainSidebar.closeTeamSidebar();
+ await this.closeMainSidebar();
+ }
+
openMainSidebar = async () => {
// # Open main sidebar
await this.mainSidebarDrawerButton.tap();
+ await expect(MainSidebar.channelsList).toBeVisible();
await MainSidebar.toBeVisible();
}
@@ -97,6 +143,12 @@ class ChannelScreen {
await SettingsSidebar.toBeVisible();
}
+ openTeamSidebar = async () => {
+ // # Open team sidebar
+ await this.openMainSidebar();
+ await MainSidebar.openTeamSidebar();
+ }
+
openPostOptionsFor = async (postId, text) => {
const {postListPostItem} = await this.getPostListPostItem(postId, text);
await expect(postListPostItem).toBeVisible();
@@ -113,12 +165,32 @@ class ChannelScreen {
await this.tapSendButton();
}
+ swipeLeft = async () => {
+ await this.channelScreen.swipe('left');
+ }
+
+ swipeRight = async () => {
+ await this.channelScreen.swipe('right');
+ }
+
tapSendButton = async () => {
// # Tap send button
await this.sendButton.tap();
await expect(this.sendButton).not.toExist();
await expect(this.sendButtonDisabled).toBeVisible();
}
+
+ hasLongPostMessage = async (postMessage) => {
+ await expect(
+ this.getLongPostMessage(),
+ ).toHaveText(postMessage);
+ }
+
+ hasPostMessageAtIndex = async (index, postMessage) => {
+ await expect(
+ this.getPostMessageAtIndex(index),
+ ).toHaveText(postMessage);
+ }
}
const channelScreen = new ChannelScreen();
diff --git a/detox/e2e/support/ui/screen/channel_info.js b/detox/e2e/support/ui/screen/channel_info.js
index d208da170..025094e3d 100644
--- a/detox/e2e/support/ui/screen/channel_info.js
+++ b/detox/e2e/support/ui/screen/channel_info.js
@@ -13,7 +13,7 @@ class ChannelInfoScreen {
mutePreferenceAction: 'channel_info.mute.action',
ignoreMentionsPreferenceAction: 'channel_info.ignore_mentions.action',
notificationPreferenceAction: 'channel_info.notification_preference.action',
- pinnedAction: 'channel_info.pinned.action',
+ pinnedMessagesAction: 'channel_info.pinned_messages.action',
manageMembersAction: 'channel_info.manage_members.action',
addMembersAction: 'channel_info.add_members.action',
convertPrivateAction: 'channel_info.convert_private.action',
@@ -27,7 +27,7 @@ class ChannelInfoScreen {
mutePreferenceAction = element(by.id(this.testID.mutePreferenceAction));
ignoreMentionsPreferenceAction = element(by.id(this.testID.ignoreMentionsPreferenceAction));
notificationPreferenceAction = element(by.id(this.testID.notificationPreferenceAction));
- pinnedAction = element(by.id(this.testID.pinnedAction));
+ pinnedMessagesAction = element(by.id(this.testID.pinnedMessagesAction));
manageMembersAction = element(by.id(this.testID.manageMembersAction));
addMembersAction = element(by.id(this.testID.addMembersAction));
convertPrivateAction = element(by.id(this.testID.convertPrivateAction));
diff --git a/detox/e2e/support/ui/screen/index.js b/detox/e2e/support/ui/screen/index.js
index 9a87f0fd4..7c7f67dee 100644
--- a/detox/e2e/support/ui/screen/index.js
+++ b/detox/e2e/support/ui/screen/index.js
@@ -16,8 +16,10 @@ import MoreDirectMessagesScreen from './more_direct_messages';
import NotificationScreen from './notification';
import NotificationSettingsMobileScreen from './notification_settings_mobile';
import NotificationSettingsScreen from './notification_settings';
-import PostListScreen from './post_list';
+import PermalinkScreen from './permalink';
+import PinnedMessagesScreen from './pinned_messages';
import RecentMentionsScreen from './recent_mentions';
+import SavedMessagesScreen from './saved_messages';
import SearchResultPostScreen from './search_result_post';
import SearchScreen from './search';
import SelectServerScreen from './select_server';
@@ -40,8 +42,10 @@ export {
NotificationScreen,
NotificationSettingsMobileScreen,
NotificationSettingsScreen,
- PostListScreen,
+ PermalinkScreen,
+ PinnedMessagesScreen,
RecentMentionsScreen,
+ SavedMessagesScreen,
SearchResultPostScreen,
SearchScreen,
SelectServerScreen,
diff --git a/detox/e2e/support/ui/screen/long_post.js b/detox/e2e/support/ui/screen/long_post.js
index 7624e9c02..2fc203402 100644
--- a/detox/e2e/support/ui/screen/long_post.js
+++ b/detox/e2e/support/ui/screen/long_post.js
@@ -5,16 +5,21 @@ import {Post} from '@support/ui/component';
class LongPostScreen {
testID = {
- longPostScreenPrefix: 'long_post.',
+ longPostItem: 'long_post.post',
}
- getPost = (postId, text) => {
- const {postItem, postItemHeaderReply} = Post.getPost(this.testID.longPostScreenPrefix, postId, text);
+ getPost = (postId, postMessage) => {
+ const {postItem, postItemHeaderReply, postItemMessage} = Post.getPost(this.testID.longPostItem, postId, postMessage);
return {
longPostItem: postItem,
longPostItemHeaderReply: postItemHeaderReply,
+ longPostItemMessage: postItemMessage,
};
}
+
+ getPostMessage = () => {
+ return Post.getPostMessage(this.testID.longPostItem);
+ }
}
const longPostScreen = new LongPostScreen();
diff --git a/detox/e2e/support/ui/screen/permalink.js b/detox/e2e/support/ui/screen/permalink.js
new file mode 100644
index 000000000..cbf4cce73
--- /dev/null
+++ b/detox/e2e/support/ui/screen/permalink.js
@@ -0,0 +1,61 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import {PostList} from '@support/ui/component';
+import {LongPostScreen} from '@support/ui/screen';
+
+class PermalinkScreen {
+ testID = {
+ permalinkScreenPrefix: 'permalink.',
+ permalinkScreen: 'permalink.screen',
+ searchJump: 'permalink.search.jump',
+ }
+
+ permalinkScreen = element(by.id(this.testID.permalinkScreen));
+ searchJump = element(by.id(this.testID.searchJump));
+
+ postList = new PostList(this.testID.permalinkScreenPrefix);
+
+ getLongPostItem = (postId, text) => {
+ return LongPostScreen.getPost(postId, text);
+ }
+
+ getLongPostMessage = () => {
+ return LongPostScreen.getPostMessage();
+ }
+
+ getPostListPostItem = (postId, text) => {
+ return this.postList.getPost(postId, text);
+ }
+
+ getPostMessageAtIndex = (index) => {
+ return this.postList.getPostMessageAtIndex(index);
+ }
+
+ toBeVisible = async () => {
+ await expect(this.permalinkScreen).toBeVisible();
+
+ return this.permalinkScreen;
+ }
+
+ jumpToRecentMessages = async () => {
+ // # Jump to recent messages
+ await this.searchJump.tap();
+ await expect(this.permalinkScreen).not.toBeVisible();
+ }
+
+ hasLongPostMessage = async (postMessage) => {
+ await expect(
+ this.getLongPostMessage(),
+ ).toHaveText(postMessage);
+ }
+
+ hasPostMessageAtIndex = async (index, postMessage) => {
+ await expect(
+ this.getPostMessageAtIndex(index),
+ ).toHaveText(postMessage);
+ }
+}
+
+const permalinkScreen = new PermalinkScreen();
+export default permalinkScreen;
diff --git a/detox/e2e/support/ui/screen/pinned_messages.js b/detox/e2e/support/ui/screen/pinned_messages.js
new file mode 100644
index 000000000..e83af8ebd
--- /dev/null
+++ b/detox/e2e/support/ui/screen/pinned_messages.js
@@ -0,0 +1,42 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import {
+ ChannelInfoScreen,
+ SearchResultPostScreen,
+} from '@support/ui/screen';
+
+class PinnedMessagesScreen {
+ testID = {
+ pinnedMessagesScreen: 'pinned_messages.screen',
+ backButton: 'screen.back.button',
+ }
+
+ pinnedMessagesScreen = element(by.id(this.testID.pinnedMessagesScreen));
+ backButton = element(by.id(this.testID.backButton));
+
+ getSearchResultPostItem = (postId, text) => {
+ return SearchResultPostScreen.getPost(postId, text);
+ }
+
+ toBeVisible = async () => {
+ await expect(this.pinnedMessagesScreen).toBeVisible();
+
+ return this.pinnedMessagesScreen;
+ }
+
+ open = async () => {
+ // # Open pinned messages screen
+ await ChannelInfoScreen.pinnedMessagesAction.tap();
+
+ return this.toBeVisible();
+ }
+
+ back = async () => {
+ await this.backButton.tap();
+ await expect(this.pinnedMessagesScreen).not.toBeVisible();
+ }
+}
+
+const pinnedMessagesScreen = new PinnedMessagesScreen();
+export default pinnedMessagesScreen;
diff --git a/detox/e2e/support/ui/screen/post_list.js b/detox/e2e/support/ui/screen/post_list.js
deleted file mode 100644
index 4a86a5719..000000000
--- a/detox/e2e/support/ui/screen/post_list.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See LICENSE.txt for license information.
-
-import {Post} from '@support/ui/component';
-
-class PostListScreen {
- testID = {
- postListScreenPrefix: 'post_list.',
- }
-
- getPost = (screenPrefix, postId, text) => {
- const {postItem, postItemHeaderReply} = Post.getPost(`${screenPrefix}${this.testID.postListScreenPrefix}`, postId, text);
- return {
- postListPostItem: postItem,
- postListPostItemHeaderReply: postItemHeaderReply,
- };
- }
-}
-
-const postListScreen = new PostListScreen();
-export default postListScreen;
diff --git a/detox/e2e/support/ui/screen/saved_messages.js b/detox/e2e/support/ui/screen/saved_messages.js
new file mode 100644
index 000000000..b80afeff8
--- /dev/null
+++ b/detox/e2e/support/ui/screen/saved_messages.js
@@ -0,0 +1,52 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import {
+ PostOptions,
+ SettingsSidebar,
+} from '@support/ui/component';
+import {SearchResultPostScreen} from '@support/ui/screen';
+
+class SavedMessagesScreen {
+ testID = {
+ savedMessagesScreen: 'saved_messages.screen',
+ closeSettingsButton: 'close.settings.button',
+ }
+
+ savedMessagesScreen = element(by.id(this.testID.savedMessagesScreen));
+ closeSettingsButton = element(by.id(this.testID.closeSettingsButton));
+
+ getSearchResultPostItem = (postId, text) => {
+ return SearchResultPostScreen.getPost(postId, text);
+ }
+
+ toBeVisible = async () => {
+ await expect(this.savedMessagesScreen).toBeVisible();
+
+ return this.savedMessagesScreen;
+ }
+
+ open = async () => {
+ // # Open saved messages screen
+ await SettingsSidebar.savedMessagesAction.tap();
+
+ return this.toBeVisible();
+ }
+
+ close = async () => {
+ await this.closeSettingsButton.tap();
+ await expect(this.savedMessagesScreen).not.toBeVisible();
+ }
+
+ openPostOptionsFor = async (postId, text) => {
+ const {searchResultPostItem} = await this.getSearchResultPostItem(postId, text);
+ await expect(searchResultPostItem).toBeVisible();
+
+ // # Open post options
+ await searchResultPostItem.longPress();
+ await PostOptions.toBeVisible();
+ }
+}
+
+const savedMessagesScreen = new SavedMessagesScreen();
+export default savedMessagesScreen;
diff --git a/detox/e2e/support/ui/screen/search.js b/detox/e2e/support/ui/screen/search.js
index 7ad9f8ae0..aa3f36df8 100644
--- a/detox/e2e/support/ui/screen/search.js
+++ b/detox/e2e/support/ui/screen/search.js
@@ -9,7 +9,6 @@ import {
ChannelScreen,
SearchResultPostScreen,
} from '@support/ui/screen';
-import {isAndroid} from '@support/utils';
class SearchScreen {
testID = {
@@ -38,7 +37,6 @@ class SearchScreen {
// convenience props
searchBar = SearchBar.getSearchBar(this.testID.searchScreenPrefix);
searchInput = SearchBar.getSearchInput(this.testID.searchScreenPrefix);
- backButton = SearchBar.getBackButton(this.testID.searchScreenPrefix);
cancelButton = SearchBar.getCancelButton(this.testID.searchScreenPrefix);
clearButton = SearchBar.getClearButton(this.testID.searchScreenPrefix);
@@ -50,6 +48,10 @@ class SearchScreen {
return SearchResultPostScreen.getPost(postId, text);
}
+ getSearchResultPostMessageAtIndex = (index) => {
+ return SearchResultPostScreen.getPostMessageAtIndex(index);
+ }
+
toBeVisible = async () => {
await expect(this.searchScreen).toBeVisible();
@@ -63,17 +65,20 @@ class SearchScreen {
return this.toBeVisible();
}
- back = async () => {
- if (isAndroid()) {
- await this.backButton.tap();
- } else {
- await this.cancelButton.tap();
- }
+ cancel = async () => {
+ await this.cancelButton.tap();
await expect(this.searchScreen).not.toBeVisible();
}
clear = async () => {
await this.clearButton.tap();
+ await expect(this.clearButton).not.toExist();
+ }
+
+ hasSearchResultPostMessageAtIndex = async (index, postMessage) => {
+ await expect(
+ this.getSearchResultPostMessageAtIndex(index),
+ ).toHaveText(postMessage);
}
}
diff --git a/detox/e2e/support/ui/screen/search_result_post.js b/detox/e2e/support/ui/screen/search_result_post.js
index 75fb1322d..e07b42ac5 100644
--- a/detox/e2e/support/ui/screen/search_result_post.js
+++ b/detox/e2e/support/ui/screen/search_result_post.js
@@ -5,16 +5,21 @@ import {Post} from '@support/ui/component';
class SearchResultPostScreen {
testID = {
- searchResultPostScreenPrefix: 'search_result_post.',
+ searchResultPostItem: 'search_result_post.post',
}
- getPost = (postId, text) => {
- const {postItem, postItemHeaderReply} = Post.getPost(this.testID.searchResultPostScreenPrefix, postId, text);
+ getPost = (postId, postMessage) => {
+ const {postItem, postItemHeaderReply, postItemMessage} = Post.getPost(this.testID.searchResultPostItem, postId, postMessage);
return {
searchResultPostItem: postItem,
searchResultPostItemHeaderReply: postItemHeaderReply,
+ searchResultPostItemMessage: postItemMessage,
};
}
+
+ getPostMessageAtIndex = (index) => {
+ return Post.getPostMessage(this.testID.searchResultPostItem).atIndex(index);
+ }
}
const searchResultPostScreen = new SearchResultPostScreen();
diff --git a/detox/e2e/support/ui/screen/select_team.js b/detox/e2e/support/ui/screen/select_team.js
index 4ecf32f69..00d8eacde 100644
--- a/detox/e2e/support/ui/screen/select_team.js
+++ b/detox/e2e/support/ui/screen/select_team.js
@@ -49,6 +49,18 @@ class SelectTeamScreen {
getTeamIconContentAtIndex = (index) => {
return element(by.id(this.testID.teamItemIconContent)).atIndex(index);
}
+
+ hasTeamDisplayNameAtIndex = async (index, teamDisplayName) => {
+ await expect(
+ this.getTeamDisplayNameAtIndex(index),
+ ).toHaveText(teamDisplayName);
+ }
+
+ hasTeamIconContentAtIndex = async (index, teamIconContent) => {
+ await expect(
+ this.getTeamIconContentAtIndex(index),
+ ).toHaveText(teamIconContent);
+ }
}
const selectTeamScreen = new SelectTeamScreen();
diff --git a/detox/e2e/support/ui/screen/thread.js b/detox/e2e/support/ui/screen/thread.js
index 5d41e121e..e8781a5a9 100644
--- a/detox/e2e/support/ui/screen/thread.js
+++ b/detox/e2e/support/ui/screen/thread.js
@@ -7,12 +7,10 @@ import {
ImageQuickAction,
InputQuickAction,
PostDraft,
+ PostList,
SendButton,
} from '@support/ui/component';
-import {
- LongPostScreen,
- PostListScreen,
-} from '@support/ui/screen';
+import {LongPostScreen} from '@support/ui/screen';
import {timeouts, wait} from '@support/utils';
class ThreadScreen {
@@ -43,12 +41,22 @@ class ThreadScreen {
sendButton = SendButton.getSendButton(this.testID.threadScreenPrefix);
sendButtonDisabled = SendButton.getSendButtonDisabled(this.testID.threadScreenPrefix);
- getLongPostPostItem = (postId, text) => {
+ postList = new PostList(this.testID.threadScreenPrefix);
+
+ getLongPostItem = (postId, text) => {
return LongPostScreen.getPost(postId, text);
}
+ getLongPostMessage = () => {
+ return LongPostScreen.getPostMessage();
+ }
+
getPostListPostItem = (postId, text) => {
- return PostListScreen.getPost(this.testID.threadScreenPrefix, postId, text);
+ return this.postList.getPost(postId, text);
+ }
+
+ getPostMessageAtIndex = (index) => {
+ return this.postList.getPostMessageAtIndex(index);
}
toBeVisible = async () => {
@@ -76,6 +84,18 @@ class ThreadScreen {
await expect(this.sendButton).not.toExist();
await expect(this.sendButtonDisabled).toBeVisible();
}
+
+ hasLongPostMessage = async (postMessage) => {
+ await expect(
+ this.getLongPostMessage(),
+ ).toHaveText(postMessage);
+ }
+
+ hasPostMessageAtIndex = async (index, postMessage) => {
+ await expect(
+ this.getPostMessageAtIndex(index),
+ ).toHaveText(postMessage);
+ }
}
const threadScreen = new ThreadScreen();
diff --git a/detox/e2e/support/utils.js b/detox/e2e/support/utils.js
index 4218a0f6f..c6009d83e 100644
--- a/detox/e2e/support/utils.js
+++ b/detox/e2e/support/utils.js
@@ -37,6 +37,24 @@ export const capitalize = (text) => {
return text.charAt(0).toUpperCase() + text.slice(1);
};
+/**
+ * @param {map} testIDMap - map of testIDs
+ * @return {map} map of testID matchers
+ */
+export const testIDMatcherMap = (testIDMap) => {
+ const testIDFilter = (k, v) => {
+ const key = k.toLowerCase();
+ if (key.endsWith('prefix') ||
+ key.endsWith('suffix') ||
+ v.startsWith('.') ||
+ v.endsWith('.')) {
+ return false;
+ }
+ return true;
+ };
+ return testIDMap.filter(([k, v]) => testIDFilter(k, v)).map(([k, v]) => [k, by.id(v)]);
+};
+
const SECOND = 1000;
const MINUTE = 60 * 1000;
diff --git a/detox/e2e/test/autocomplete/search.e2e.js b/detox/e2e/test/autocomplete/search.e2e.js
index 5c109b6f2..3d9c81c31 100644
--- a/detox/e2e/test/autocomplete/search.e2e.js
+++ b/detox/e2e/test/autocomplete/search.e2e.js
@@ -34,7 +34,7 @@ describe('Autocomplete', () => {
});
afterAll(async () => {
- await device.reloadReactNative();
+ await SearchScreen.cancel();
await ChannelScreen.logout();
});
diff --git a/detox/e2e/test/smoke_test/mention_badges.e2e.js b/detox/e2e/test/smoke_test/mention_badges.e2e.js
new file mode 100644
index 000000000..675d70662
--- /dev/null
+++ b/detox/e2e/test/smoke_test/mention_badges.e2e.js
@@ -0,0 +1,92 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+// *******************************************************************
+// - [#] indicates a test step (e.g. # Go to a screen)
+// - [*] indicates an assertion (e.g. * Check the title)
+// - Use element testID when selecting an element. Create one if none.
+// *******************************************************************
+
+import {MainSidebar} from '@support/ui/component';
+import {ChannelScreen} from '@support/ui/screen';
+import {
+ Channel,
+ Post,
+ Team,
+ User,
+} from '@support/server_api';
+
+describe('Mention Badges', () => {
+ let testChannel1;
+ let testChannel2;
+ let testTeam1;
+ let testTeam2;
+ let testUser1;
+ let testUser2;
+
+ beforeAll(async () => {
+ ({user: testUser1} = await User.apiCreateUser());
+ ({team: testTeam1} = await Team.apiCreateTeam({prefix: 'team-a'}));
+ ({channel: testChannel1} = await Channel.apiGetChannelByName(testTeam1.name, 'town-square'));
+
+ ({user: testUser2} = await User.apiCreateUser());
+ ({team: testTeam2} = await Team.apiCreateTeam({prefix: 'team-b'}));
+ ({channel: testChannel2} = await Channel.apiGetChannelByName(testTeam2.name, 'town-square'));
+
+ await Team.apiAddUserToTeam(testUser1.id, testTeam1.id);
+ await Team.apiAddUserToTeam(testUser1.id, testTeam2.id);
+ await Team.apiAddUserToTeam(testUser2.id, testTeam1.id);
+ await Team.apiAddUserToTeam(testUser2.id, testTeam2.id);
+
+ // # Open channel screen
+ await ChannelScreen.open(testUser1);
+ });
+
+ afterAll(async () => {
+ await ChannelScreen.logout();
+ });
+
+ it('MM-T3255 should display mention badges after an at-mention', async () => {
+ const {
+ channelNavBarTitle,
+ mainSidebarDrawerButtonBadgeUnreadCount,
+ closeMainSidebar,
+ openTeamSidebar,
+ } = ChannelScreen;
+ const {
+ closeTeamSidebar,
+ switchTeamsButtonBadgeUnreadCount,
+ } = MainSidebar;
+
+ // * Verify team 1 main sidebar drawer button badge does not exist
+ await expect(mainSidebarDrawerButtonBadgeUnreadCount).not.toExist();
+
+ // # Post an at-mention message to user 1 by user 2
+ const testMessage = `Mention @${testUser1.username}`;
+ await User.apiLogin(testUser2);
+ await Post.apiCreatePost({
+ channelId: testChannel2.id,
+ message: testMessage,
+ });
+
+ // * Verify team 1 main sidebar drawer button badge count is 1
+ await expect(channelNavBarTitle).toHaveText(testChannel1.display_name);
+ await expect(mainSidebarDrawerButtonBadgeUnreadCount).toHaveText('1');
+
+ // * Verify team 2 item badge count is 1
+ await openTeamSidebar();
+ const {teamItemBadgeUnreadCount: team2ItemBadgeUnreadCount} = await MainSidebar.getTeam(testTeam2.id);
+ await expect(team2ItemBadgeUnreadCount).toHaveText('1');
+
+ // * Verify team 1 item badge count does not exist
+ const {teamItemBadgeUnreadCount: team1ItemBadgeUnreadCount} = await MainSidebar.getTeam(testTeam1.id);
+ await expect(team1ItemBadgeUnreadCount).not.toExist();
+
+ // * Verify switch teams sidebar button badge count is 1
+ await closeTeamSidebar();
+ await expect(switchTeamsButtonBadgeUnreadCount).toHaveText('1');
+
+ // # Close main sidebar
+ await closeMainSidebar();
+ });
+});
diff --git a/detox/e2e/test/smoke_test/search.e2e.js b/detox/e2e/test/smoke_test/search.e2e.js
index 2d3f2782f..e393793d9 100644
--- a/detox/e2e/test/smoke_test/search.e2e.js
+++ b/detox/e2e/test/smoke_test/search.e2e.js
@@ -10,6 +10,7 @@
import {Autocomplete} from '@support/ui/component';
import {
ChannelScreen,
+ PermalinkScreen,
SearchScreen,
ThreadScreen,
} from '@support/ui/screen';
@@ -42,39 +43,9 @@ describe('Search', () => {
it('MM-T3236 search on sender, select from autocomplete, reply from search results', async () => {
const testMessage = Date.now().toString();
- const {
- searchFromModifier,
- searchFromSection,
- searchInput,
- } = SearchScreen;
- // # Post a message
- await ChannelScreen.postMessage(testMessage);
-
- // # Open search screen
- await SearchScreen.open();
-
- // # Tap "from:" modifier
- await searchInput.clearText();
- await searchFromSection.tap();
-
- // # Type beginning of search term
- const searchTerm = testUser.first_name;
- await searchInput.typeText(searchTerm);
-
- // # Select user from autocomplete
- await expect(atMentionSuggestionList).toExist();
- const userAtMentionAutocomplete = await Autocomplete.getAtMentionItem(testUser.id);
- await userAtMentionAutocomplete.tap();
-
- // # Search user
- await searchInput.tapReturnKey();
- await expect(atMentionSuggestionList).not.toExist();
-
- // * Verify recent search item is displayed
- const searchTerms = `${searchFromModifier} ${testUser.username}`;
- const recentSearchItem = await SearchScreen.getRecentSearchItem(searchTerms);
- await expect(recentSearchItem).toBeVisible();
+ // # Post message and search on sender
+ await postMessageAndSearchFrom(testMessage, testUser, atMentionSuggestionList);
// * Verify search result post has the message
const lastPost = await Post.apiGetLastPostInChannel(testChannel.id);
@@ -86,7 +57,7 @@ describe('Search', () => {
// # Open reply thread from search result post item
const replyTestMessage = `reply-${testMessage}`;
- searchResultPostItemHeaderReply.tap();
+ await searchResultPostItemHeaderReply.tap();
// # Post a reply message
await ThreadScreen.toBeVisible();
@@ -99,6 +70,89 @@ describe('Search', () => {
// # Go back to channel
await ThreadScreen.back();
- await SearchScreen.back();
+ await SearchScreen.cancel();
+ });
+
+ it('MM-T3235 search on text, jump to result', async () => {
+ const testMessage = Date.now().toString();
+
+ // # Post message and search on text
+ await postMessageAndSearchText(testMessage);
+
+ // # Open permalink from search result post item
+ const lastPost = await Post.apiGetLastPostInChannel(testChannel.id);
+ const {searchResultPostItem} = await SearchScreen.getSearchResultPostItem(lastPost.post.id, testMessage);
+ await expect(searchResultPostItem).toBeVisible();
+ await searchResultPostItem.tap();
+
+ // * Verify permalink post list has the message
+ await PermalinkScreen.toBeVisible();
+ const {postListPostItem: permalinkPostItem} = await PermalinkScreen.getPostListPostItem(lastPost.post.id, testMessage);
+ await waitFor(permalinkPostItem).toBeVisible();
+
+ // # Jump to recent messages
+ await PermalinkScreen.jumpToRecentMessages();
+
+ // * Verify user is on channel where message is posted
+ await expect(ChannelScreen.channelNavBarTitle).toHaveText(testChannel.display_name);
+ const {postListPostItem: channelPostItem} = await ChannelScreen.getPostListPostItem(lastPost.post.id, testMessage);
+ await expect(channelPostItem).toBeVisible();
});
});
+
+async function postMessageAndSearchFrom(testMessage, testUser, atMentionSuggestionList) {
+ const {
+ searchFromModifier,
+ searchFromSection,
+ searchInput,
+ } = SearchScreen;
+
+ // # Post a message
+ await ChannelScreen.postMessage(testMessage);
+
+ // # Open search screen
+ await SearchScreen.open();
+
+ // # Tap "from:" modifier
+ await searchInput.clearText();
+ await searchFromSection.tap();
+
+ // # Type beginning of search term
+ const searchTerm = testUser.first_name;
+ await searchInput.typeText(searchTerm);
+
+ // # Select user from autocomplete
+ await expect(atMentionSuggestionList).toExist();
+ const userAtMentionAutocomplete = await Autocomplete.getAtMentionItem(testUser.id);
+ await userAtMentionAutocomplete.tap();
+
+ // # Search user
+ await searchInput.tapReturnKey();
+ await expect(atMentionSuggestionList).not.toExist();
+
+ // * Verify recent search item is displayed
+ const searchTerms = `${searchFromModifier} ${testUser.username}`;
+ const recentSearchItem = await SearchScreen.getRecentSearchItem(searchTerms);
+ await expect(recentSearchItem).toBeVisible();
+}
+
+async function postMessageAndSearchText(testMessage) {
+ const {searchInput} = SearchScreen;
+
+ // # Post a message
+ await ChannelScreen.postMessage(testMessage);
+
+ // # Open search screen
+ await SearchScreen.open();
+
+ // # Type beginning of search term
+ await searchInput.clearText();
+ await searchInput.typeText(testMessage);
+
+ // # Search text
+ await searchInput.tapReturnKey();
+
+ // * Verify recent search item is displayed
+ const recentSearchItem = await SearchScreen.getRecentSearchItem(testMessage);
+ await expect(recentSearchItem).toBeVisible();
+}
diff --git a/detox/e2e/test/smoke_test/teams.e2e.js b/detox/e2e/test/smoke_test/teams.e2e.js
new file mode 100644
index 000000000..c85bf9b3e
--- /dev/null
+++ b/detox/e2e/test/smoke_test/teams.e2e.js
@@ -0,0 +1,96 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+// *******************************************************************
+// - [#] indicates a test step (e.g. # Go to a screen)
+// - [*] indicates an assertion (e.g. * Check the title)
+// - Use element testID when selecting an element. Create one if none.
+// *******************************************************************
+
+import {MainSidebar} from '@support/ui/component';
+import {ChannelScreen} from '@support/ui/screen';
+import {
+ Channel,
+ Setup,
+ Team,
+} from '@support/server_api';
+
+describe('Teams', () => {
+ let testTeam1;
+ let testTeam1Channel;
+ let testTeam2;
+ let testTeam2Channel;
+
+ beforeAll(async () => {
+ const {team, user} = await Setup.apiInit({teamOptions: {prefix: 'team-a'}});
+ testTeam1 = team;
+
+ const {channel} = await Channel.apiGetChannelByName(testTeam1.name, 'town-square');
+ testTeam1Channel = channel;
+
+ ({team: testTeam2} = await Team.apiCreateTeam({prefix: 'team-b'}));
+ await Team.apiAddUserToTeam(user.id, testTeam2.id);
+
+ ({channel: testTeam2Channel} = await Channel.apiGetChannelByName(testTeam2.name, 'town-square'));
+
+ // # Open channel screen
+ await ChannelScreen.open(user);
+ });
+
+ afterAll(async () => {
+ await ChannelScreen.logout();
+ });
+
+ it('MM-T3249 should be able to switch between teams', async () => {
+ const {
+ channelNavBarTitle,
+ closeTeamSidebar,
+ openTeamSidebar,
+ } = ChannelScreen;
+ const {getTeamByDisplayName} = MainSidebar;
+
+ // * Verify user is on team 1 channel
+ await expect(channelNavBarTitle).toHaveText(testTeam1Channel.display_name);
+
+ // * Verify team 1 in team sidebar
+ await openTeamSidebar();
+ await verifyTeamSidebar(testTeam1);
+
+ // # Tap on team 1
+ await getTeamByDisplayName(testTeam1.display_name).tap();
+
+ // * Verify user is on team 1 channel
+ await ChannelScreen.toBeVisible();
+ await expect(channelNavBarTitle).toHaveText(testTeam1Channel.display_name);
+
+ // # Tap on team 2
+ await openTeamSidebar();
+ await getTeamByDisplayName(testTeam2.display_name).tap();
+
+ // * Verify user is on team 2 channel
+ await ChannelScreen.toBeVisible();
+ await expect(channelNavBarTitle).toHaveText(testTeam2Channel.display_name);
+
+ // * Verify team 2 in team sidebar
+ await openTeamSidebar();
+ await verifyTeamSidebar(testTeam2);
+
+ // # Close team sidebar
+ await closeTeamSidebar();
+ });
+});
+
+async function verifyTeamSidebar(testTeam) {
+ const {
+ teamItem,
+ teamItemCurrent,
+ teamItemDisplayName,
+ teamItemIcon,
+ } = await MainSidebar.getTeam(testTeam.id, testTeam.display_name);
+
+ // * Verify team is current
+ await expect(teamItem).toBeVisible();
+ await expect(teamItemCurrent).toBeVisible();
+ await expect(teamItemDisplayName).toBeVisible();
+ await expect(teamItemIcon).toBeVisible();
+}
diff --git a/detox/e2e/test/smoke_test/unread_channels.e2e.js b/detox/e2e/test/smoke_test/unread_channels.e2e.js
index 3c6a88679..2dc7c2f74 100644
--- a/detox/e2e/test/smoke_test/unread_channels.e2e.js
+++ b/detox/e2e/test/smoke_test/unread_channels.e2e.js
@@ -38,31 +38,37 @@ describe('Unread channels', () => {
});
it('MM-T3187 Unread channels sort at top', async () => {
+ const {openMainSidebar} = ChannelScreen;
+ const {
+ getChannelByDisplayName,
+ hasChannelDisplayNameAtIndex,
+ } = MainSidebar;
+
// # Open main sidebar (with at least one unread channel)
- await ChannelScreen.openMainSidebar();
+ await openMainSidebar();
// * Verify unread channel(s) display at top of channel list (with mentions first, if any), in alphabetical order, with title "Unreads"
await expect(element(by.text('UNREADS'))).toBeVisible();
- await MainSidebar.hasChannelAtIndex(0, aChannel.display_name);
- await MainSidebar.hasChannelAtIndex(1, newChannel.display_name);
- await MainSidebar.hasChannelAtIndex(2, zChannel.display_name);
+ await hasChannelDisplayNameAtIndex(0, aChannel.display_name);
+ await hasChannelDisplayNameAtIndex(1, newChannel.display_name);
+ await hasChannelDisplayNameAtIndex(2, zChannel.display_name);
// # Tap an unread channel to view it
- await MainSidebar.getChannelByDisplayName(aChannel.display_name).tap();
- await ChannelScreen.openMainSidebar();
- await MainSidebar.getChannelByDisplayName(newChannel.display_name).tap();
- await ChannelScreen.openMainSidebar();
- await MainSidebar.getChannelByDisplayName(zChannel.display_name).tap();
+ await getChannelByDisplayName(aChannel.display_name).tap();
+ await openMainSidebar();
+ await getChannelByDisplayName(newChannel.display_name).tap();
+ await openMainSidebar();
+ await getChannelByDisplayName(zChannel.display_name).tap();
// * Channel you just read is no longer listed in Unreads
- await ChannelScreen.openMainSidebar();
+ await openMainSidebar();
await expect(element(by.text('UNREADS'))).not.toBeVisible();
await expect(element(by.text('PUBLIC CHANNELS'))).toBeVisible();
- await MainSidebar.hasChannelAtIndex(0, aChannel.display_name);
- await MainSidebar.hasChannelAtIndex(1, newChannel.display_name);
- await MainSidebar.hasChannelAtIndex(2, 'Off-Topic');
- await MainSidebar.hasChannelAtIndex(3, 'Town Square');
- await MainSidebar.hasChannelAtIndex(4, zChannel.display_name);
- await MainSidebar.getChannelByDisplayName(aChannel.display_name).tap();
+ await hasChannelDisplayNameAtIndex(0, aChannel.display_name);
+ await hasChannelDisplayNameAtIndex(1, newChannel.display_name);
+ await hasChannelDisplayNameAtIndex(2, 'Off-Topic');
+ await hasChannelDisplayNameAtIndex(3, 'Town Square');
+ await hasChannelDisplayNameAtIndex(4, zChannel.display_name);
+ await getChannelByDisplayName(aChannel.display_name).tap();
});
});
diff --git a/detox/e2e/test/teams/select_team.e2e.js b/detox/e2e/test/teams/select_team.e2e.js
index 8747dfade..a87168acf 100644
--- a/detox/e2e/test/teams/select_team.e2e.js
+++ b/detox/e2e/test/teams/select_team.e2e.js
@@ -36,6 +36,7 @@ describe('Select Team', () => {
afterAll(async () => {
await ChannelScreen.logout();
+ await Team.apiPatchTeams({allow_open_invite: true});
});
it('MM-T3619 should be able to select a team', async () => {
diff --git a/share_extension/components/channel_item.tsx b/share_extension/components/channel_item.tsx
index 4fa9aebbf..ee32a1776 100644
--- a/share_extension/components/channel_item.tsx
+++ b/share_extension/components/channel_item.tsx
@@ -53,6 +53,7 @@ const ChannelItem = ({onSelect, selected, channel}: ChannelItemProps) => {
{channelTypes[channel.type] || PublicChannel}
{
{
);
const renderItem = ({item}: SectionListRenderItemInfo) => (
{
return (