MM-30286 Detox/E2E: Add e2e test for MM-T3249 and added useful helpers (#4990)
* MM-30286 Detox/E2E: Add e2e test for MM-T3249 and added useful helper functions * Update app/components/sidebars/main/channels_list/channels_list.js Co-authored-by: Elias Nahum <nahumhbl@gmail.com> * Add team icon content helper query * Fixed reset for teams * MM-30286 Detox/E2E: Add e2e test for MM-T3235 (#5003) * MM-30286 Detox/E2E: Add e2e test for MM-T3255 (#5006) * Fix merge issues Co-authored-by: Elias Nahum <nahumhbl@gmail.com> Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
This commit is contained in:
parent
8d9ed361f8
commit
7aebfd0b13
69 changed files with 1403 additions and 162 deletions
|
|
@ -15,6 +15,7 @@ exports[`Badge should match snapshot 1`] = `
|
|||
},
|
||||
]
|
||||
}
|
||||
testID="badge"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
|
|
@ -70,6 +71,7 @@ exports[`Badge should match snapshot 1`] = `
|
|||
},
|
||||
]
|
||||
}
|
||||
testID="badge.unread_count"
|
||||
>
|
||||
99+
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -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 = (
|
||||
<View
|
||||
testID={unreadIndicatorID}
|
||||
style={[styles.text, this.props.countStyle]}
|
||||
onLayout={this.onLayout}
|
||||
/>
|
||||
|
|
@ -127,6 +131,7 @@ export default class Badge extends PureComponent {
|
|||
unreadCount = (
|
||||
<View style={styles.verticalAlign}>
|
||||
<Text
|
||||
testID={unreadCountTestID}
|
||||
style={[styles.text, this.props.countStyle]}
|
||||
onLayout={this.onLayout}
|
||||
>
|
||||
|
|
@ -137,7 +142,10 @@ export default class Badge extends PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<View style={[styles.badgeContainer, containerStyle]}>
|
||||
<View
|
||||
testID={testID}
|
||||
style={[styles.badgeContainer, containerStyle]}
|
||||
>
|
||||
<View
|
||||
ref={this.setBadgeRef}
|
||||
style={[styles.badge, style, {opacity: 0}]}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import Badge from './badge';
|
|||
|
||||
describe('Badge', () => {
|
||||
const baseProps = {
|
||||
testID: 'badge',
|
||||
count: 100,
|
||||
countStyle: {color: '#145dbf', fontSize: 10},
|
||||
style: {backgroundColor: '#ffffff'},
|
||||
|
|
|
|||
|
|
@ -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 <Text>{literal}</Text>;
|
||||
return (
|
||||
<Text testID='markdown_text'>
|
||||
{literal}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
// 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 <Text style={style}>{literal}</Text>;
|
||||
return (
|
||||
<Text
|
||||
testID='markdown_text'
|
||||
style={style}
|
||||
>
|
||||
{literal}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
renderCodeSpan = ({context, literal}) => {
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<View
|
||||
|
|
@ -327,6 +328,7 @@ export default class Post extends PureComponent {
|
|||
style={[style.postStyle, highlighted]}
|
||||
>
|
||||
<TouchableWithFeedback
|
||||
testID={itemTestID}
|
||||
onPress={this.handlePress}
|
||||
onLongPress={this.showPostOptions}
|
||||
delayLongPress={200}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ exports[`renderSystemMessage uses renderer for Channel Display Name update 1`] =
|
|||
],
|
||||
]
|
||||
}
|
||||
testID="markdown_text"
|
||||
>
|
||||
{username} updated the channel display name from: {oldDisplayName} to: {newDisplayName}
|
||||
</Text>
|
||||
|
|
@ -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}
|
||||
</Text>
|
||||
|
|
@ -88,6 +90,7 @@ exports[`renderSystemMessage uses renderer for OLD archived channel without a us
|
|||
],
|
||||
]
|
||||
}
|
||||
testID="markdown_text"
|
||||
>
|
||||
{username} archived the channel
|
||||
</Text>
|
||||
|
|
@ -128,6 +131,7 @@ exports[`renderSystemMessage uses renderer for archived channel 2`] = `
|
|||
],
|
||||
]
|
||||
}
|
||||
testID="markdown_text"
|
||||
>
|
||||
{username} archived the channel
|
||||
</Text>
|
||||
|
|
@ -157,6 +161,7 @@ exports[`renderSystemMessage uses renderer for unarchived channel 1`] = `
|
|||
],
|
||||
]
|
||||
}
|
||||
testID="markdown_text"
|
||||
>
|
||||
{username} unarchived the channel
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<Post
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ export default class Search extends PureComponent {
|
|||
render() {
|
||||
const {testID, backgroundColor, inputHeight, inputStyle, placeholderTextColor, tintColorSearch, cancelButtonStyle, tintColorDelete, titleCancelColor, searchBarRightMargin, containerHeight} = this.props;
|
||||
const searchClearButtonTestID = `${testID}.search.clear.button`;
|
||||
const searchBackButtonTestID = `${testID}.search.back.button`;
|
||||
const searchCancelButtonTestID = `${testID}.search.cancel.button`;
|
||||
const searchInputTestID = `${testID}.search.input`;
|
||||
const searchBarStyle = getSearchBarStyle(
|
||||
backgroundColor,
|
||||
|
|
@ -263,7 +263,7 @@ export default class Search extends PureComponent {
|
|||
(
|
||||
<TouchableWithoutFeedback onPress={this.onCancel}>
|
||||
<CompassIcon
|
||||
testID={searchBackButtonTestID}
|
||||
testID={searchCancelButtonTestID}
|
||||
name='arrow-left'
|
||||
size={this.props.backArrowSize}
|
||||
color={searchBarStyle.clearIconColorAndroid}
|
||||
|
|
@ -281,6 +281,7 @@ export default class Search extends PureComponent {
|
|||
// Making sure the icon won't change depending on whether the input is in focus on Android devices
|
||||
cancelIcon = (
|
||||
<CompassIcon
|
||||
testID={searchCancelButtonTestID}
|
||||
name='arrow-left'
|
||||
size={25}
|
||||
color={searchBarStyle.clearIconColorAndroid}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ exports[`ChannelItem should match snapshot 1`] = `
|
|||
undefined,
|
||||
]
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.channel_id"
|
||||
>
|
||||
<ChannelIcon
|
||||
channelId="channel_id"
|
||||
|
|
@ -144,6 +145,7 @@ exports[`ChannelItem should match snapshot for current user i.e currentUser (you
|
|||
},
|
||||
]
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.channel_id"
|
||||
>
|
||||
<ChannelIcon
|
||||
channelId="channel_id"
|
||||
|
|
@ -257,6 +259,7 @@ exports[`ChannelItem should match snapshot for current user i.e currentUser (you
|
|||
},
|
||||
]
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.channel_id"
|
||||
>
|
||||
<ChannelIcon
|
||||
channelId="channel_id"
|
||||
|
|
@ -370,6 +373,7 @@ exports[`ChannelItem should match snapshot for deactivated user and is currentCh
|
|||
},
|
||||
]
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.channel_id"
|
||||
>
|
||||
<ChannelIcon
|
||||
channelId="channel_id"
|
||||
|
|
@ -472,6 +476,7 @@ exports[`ChannelItem should match snapshot for deactivated user and is searchRes
|
|||
undefined,
|
||||
]
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.channel_id"
|
||||
>
|
||||
<ChannelIcon
|
||||
channelId="channel_id"
|
||||
|
|
@ -575,6 +580,7 @@ exports[`ChannelItem should match snapshot for deactivated user and not searchRe
|
|||
undefined,
|
||||
]
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.channel_id"
|
||||
>
|
||||
<ChannelIcon
|
||||
channelId="channel_id"
|
||||
|
|
@ -678,6 +684,7 @@ exports[`ChannelItem should match snapshot for isManualUnread 1`] = `
|
|||
undefined,
|
||||
]
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.channel_id"
|
||||
>
|
||||
<ChannelIcon
|
||||
channelId="channel_id"
|
||||
|
|
@ -785,6 +792,7 @@ exports[`ChannelItem should match snapshot with draft 1`] = `
|
|||
undefined,
|
||||
]
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.channel_id"
|
||||
>
|
||||
<ChannelIcon
|
||||
channelId="channel_id"
|
||||
|
|
@ -890,6 +898,7 @@ exports[`ChannelItem should match snapshot with mentions and muted 1`] = `
|
|||
undefined,
|
||||
]
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.channel_id"
|
||||
>
|
||||
<ChannelIcon
|
||||
channelId="channel_id"
|
||||
|
|
@ -990,6 +999,7 @@ exports[`ChannelItem should match snapshot with mentions and muted 1`] = `
|
|||
"position": "relative",
|
||||
}
|
||||
}
|
||||
testID="main.sidebar.channels_list.list.channel_item.badge"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -134,8 +134,11 @@ export default class ChannelItem extends PureComponent {
|
|||
|
||||
let badge;
|
||||
if (mentions) {
|
||||
const badgeTestID = `${testID}.badge`;
|
||||
|
||||
badge = (
|
||||
<Badge
|
||||
testID={badgeTestID}
|
||||
containerStyle={style.badgeContainer}
|
||||
style={style.badge}
|
||||
countStyle={style.mention}
|
||||
|
|
@ -167,6 +170,7 @@ export default class ChannelItem extends PureComponent {
|
|||
/>
|
||||
);
|
||||
|
||||
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}
|
||||
<View style={[style.item, extraItemStyle]}>
|
||||
<View
|
||||
testID={itemTestID}
|
||||
style={[style.item, extraItemStyle]}
|
||||
>
|
||||
{icon}
|
||||
<Text
|
||||
testID={displayNameTestID}
|
||||
style={[style.text, extraTextStyle]}
|
||||
ellipsizeMode='tail'
|
||||
numberOfLines={1}
|
||||
testID={displayNameTestID}
|
||||
>
|
||||
{channelDisplayName}
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -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 ? <SwitchTeamsButton onShowTeams={onShowTeams}/> : null;
|
||||
let leftComponent;
|
||||
if (onShowTeams) {
|
||||
leftComponent = (
|
||||
<SwitchTeamsButton
|
||||
testID={switchTeamsButtonTestID}
|
||||
onShowTeams={onShowTeams}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const title = (
|
||||
<View
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SwitchTeamsButton should match snapshot 1`] = `
|
||||
<View
|
||||
testID="main.sidebar.channels_list.switch_teams.button"
|
||||
>
|
||||
<ForwardRef
|
||||
onPress={[Function]}
|
||||
underlayColor="rgba(17,83,171,0.5)"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderRadius": 2,
|
||||
"flexDirection": "row",
|
||||
"height": 36,
|
||||
"justifyContent": "center",
|
||||
"marginRight": 12,
|
||||
"width": 57,
|
||||
}
|
||||
}
|
||||
testID="main.sidebar.channels_list.switch_teams.button.current-team-id"
|
||||
>
|
||||
<CompassIcon
|
||||
name="chevron-left"
|
||||
size={24}
|
||||
style={
|
||||
Object {
|
||||
"color": "#1153ab",
|
||||
"left": -2,
|
||||
"top": 1,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Connect(TeamIcon)
|
||||
styleContainer={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"height": 24,
|
||||
"justifyContent": "center",
|
||||
"width": 24,
|
||||
}
|
||||
}
|
||||
styleImage={
|
||||
Object {
|
||||
"height": 24,
|
||||
"width": 24,
|
||||
}
|
||||
}
|
||||
styleText={
|
||||
Object {
|
||||
"fontFamily": "Open Sans",
|
||||
"fontSize": 14,
|
||||
}
|
||||
}
|
||||
teamId="current-team-id"
|
||||
testID="main.sidebar.channels_list.switch_teams.button.team_icon"
|
||||
/>
|
||||
</View>
|
||||
</ForwardRef>
|
||||
<Badge
|
||||
containerStyle={
|
||||
Object {
|
||||
"borderColor": "#145dbf",
|
||||
"borderRadius": 14,
|
||||
"borderWidth": 2,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": -9,
|
||||
}
|
||||
}
|
||||
count={1}
|
||||
countStyle={
|
||||
Object {
|
||||
"color": "#145dbf",
|
||||
"fontSize": 10,
|
||||
"fontWeight": "bold",
|
||||
}
|
||||
}
|
||||
extraPaddingHorizontal={10}
|
||||
minHeight={20}
|
||||
minWidth={20}
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#ffffff",
|
||||
"height": 20,
|
||||
"padding": 3,
|
||||
}
|
||||
}
|
||||
testID="main.sidebar.channels_list.switch_teams.button.badge"
|
||||
/>
|
||||
</View>
|
||||
`;
|
||||
|
|
@ -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 = (
|
||||
<Badge
|
||||
testID={badgeTestID}
|
||||
containerStyle={containerStyle}
|
||||
style={badgeStyle}
|
||||
countStyle={styles.mention}
|
||||
|
|
@ -60,19 +64,26 @@ export default class SwitchTeamsButton extends React.PureComponent {
|
|||
/>
|
||||
);
|
||||
|
||||
const itemTestID = `${testID}.${currentTeamId}`;
|
||||
const teamIconTestID = `${testID}.team_icon`;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View testID={testID}>
|
||||
<TouchableHighlight
|
||||
onPress={this.showTeams}
|
||||
underlayColor={changeOpacity(theme.sidebarHeaderBg, 0.5)}
|
||||
>
|
||||
<View style={styles.switcherContainer}>
|
||||
<View
|
||||
testID={itemTestID}
|
||||
style={styles.switcherContainer}
|
||||
>
|
||||
<CompassIcon
|
||||
name='chevron-left'
|
||||
size={24}
|
||||
style={styles.switcherArrow}
|
||||
/>
|
||||
<TeamIcon
|
||||
testID={teamIconTestID}
|
||||
teamId={currentTeamId}
|
||||
styleContainer={styles.teamIconContainer}
|
||||
styleText={styles.teamIconText}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
// 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 SwitchTeamsButton from './switch_teams_button';
|
||||
|
||||
describe('SwitchTeamsButton', () => {
|
||||
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(<SwitchTeamsButton {...baseProps}/>);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
@ -217,6 +217,7 @@ export default class MainSidebarBase extends Component {
|
|||
style={style.swiperContent}
|
||||
>
|
||||
<TeamsList
|
||||
testID='main.sidebar.teams_list'
|
||||
closeMainSidebar={this.closeMainSidebar}
|
||||
/>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<TeamsListItem
|
||||
testID={teamsListItemTestID}
|
||||
currentUrl={this.state.serverUrl}
|
||||
selectTeam={this.selectTeam}
|
||||
teamId={item}
|
||||
|
|
@ -134,7 +139,8 @@ export default class TeamsList extends PureComponent {
|
|||
};
|
||||
|
||||
render() {
|
||||
const {hasOtherJoinableTeams, teamIds, theme} = this.props;
|
||||
const {testID, hasOtherJoinableTeams, teamIds, theme} = this.props;
|
||||
const flatListTestID = `${testID}.flat_list`;
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
let moreAction;
|
||||
|
|
@ -156,6 +162,7 @@ export default class TeamsList extends PureComponent {
|
|||
|
||||
return (
|
||||
<SafeAreaView
|
||||
testID={testID}
|
||||
edges={['left']}
|
||||
style={styles.container}
|
||||
>
|
||||
|
|
@ -168,6 +175,7 @@ export default class TeamsList extends PureComponent {
|
|||
{moreAction}
|
||||
</View>
|
||||
<FlatList
|
||||
testID={flatListTestID}
|
||||
extraData={this.state.serverUrl}
|
||||
contentContainerStyle={this.listContentPadding()}
|
||||
data={teamIds}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`TeamsListItem should match snapshot 1`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"marginTop": 10,
|
||||
}
|
||||
}
|
||||
testID="main.sidebar.teams_list.flat_list.teams_list_item"
|
||||
>
|
||||
<ForwardRef
|
||||
onPress={[Function]}
|
||||
underlayColor="rgba(69,120,191,0.5)"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"flex": 1,
|
||||
"flexDirection": "row",
|
||||
"marginHorizontal": 16,
|
||||
"paddingVertical": 10,
|
||||
}
|
||||
}
|
||||
testID="main.sidebar.teams_list.flat_list.teams_list_item.team-id"
|
||||
>
|
||||
<View>
|
||||
<Connect(TeamIcon)
|
||||
styleContainer={
|
||||
Object {
|
||||
"backgroundColor": "#ffffff",
|
||||
"height": 40,
|
||||
"width": 40,
|
||||
}
|
||||
}
|
||||
styleText={
|
||||
Object {
|
||||
"fontSize": 18,
|
||||
}
|
||||
}
|
||||
teamId="team-id"
|
||||
testID="main.sidebar.teams_list.flat_list.teams_list_item.team_icon"
|
||||
/>
|
||||
<Badge
|
||||
containerStyle={
|
||||
Object {
|
||||
"borderColor": "#145dbf",
|
||||
"borderRadius": 14,
|
||||
"borderWidth": 2,
|
||||
"position": "absolute",
|
||||
"right": -12,
|
||||
"top": -10,
|
||||
}
|
||||
}
|
||||
count={1}
|
||||
countStyle={
|
||||
Object {
|
||||
"color": "#145dbf",
|
||||
"fontSize": 10,
|
||||
"fontWeight": "bold",
|
||||
}
|
||||
}
|
||||
extraPaddingHorizontal={10}
|
||||
minHeight={20}
|
||||
minWidth={20}
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#ffffff",
|
||||
"height": 20,
|
||||
"padding": 3,
|
||||
}
|
||||
}
|
||||
testID="main.sidebar.teams_list.flat_list.teams_list_item.badge"
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
"flexDirection": "column",
|
||||
"marginLeft": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
ellipsizeMode="tail"
|
||||
numberOfLines={1}
|
||||
style={
|
||||
Object {
|
||||
"color": "#ffffff",
|
||||
"fontSize": 18,
|
||||
}
|
||||
}
|
||||
testID="main.sidebar.teams_list.flat_list.teams_list_item.display_name"
|
||||
>
|
||||
display-name
|
||||
</Text>
|
||||
<Text
|
||||
ellipsizeMode="tail"
|
||||
numberOfLines={1}
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255,255,255,0.5)",
|
||||
"fontSize": 12,
|
||||
}
|
||||
}
|
||||
>
|
||||
current-url/name
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</ForwardRef>
|
||||
</View>
|
||||
`;
|
||||
|
|
@ -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 = (
|
||||
<Badge
|
||||
testID={badgeTestID}
|
||||
containerStyle={containerStyle}
|
||||
countStyle={styles.mention}
|
||||
count={mentionCount}
|
||||
|
|
@ -60,8 +64,13 @@ export default class TeamsListItem extends React.PureComponent {
|
|||
|
||||
let current;
|
||||
if (teamId === currentTeamId) {
|
||||
const currentTestID = `${testID}.current`;
|
||||
|
||||
current = (
|
||||
<View style={styles.checkmarkContainer}>
|
||||
<View
|
||||
testID={currentTestID}
|
||||
style={styles.checkmarkContainer}
|
||||
>
|
||||
<CompassIcon
|
||||
name='check'
|
||||
style={styles.checkmark}
|
||||
|
|
@ -70,15 +79,26 @@ export default class TeamsListItem extends React.PureComponent {
|
|||
);
|
||||
}
|
||||
|
||||
const itemTestID = `${testID}.${teamId}`;
|
||||
const displayNameTestID = `${testID}.display_name`;
|
||||
const teamIconTestID = `${testID}.team_icon`;
|
||||
|
||||
return (
|
||||
<View style={styles.teamWrapper}>
|
||||
<View
|
||||
testID={testID}
|
||||
style={styles.teamWrapper}
|
||||
>
|
||||
<TouchableHighlight
|
||||
underlayColor={changeOpacity(theme.sidebarTextHoverBg, 0.5)}
|
||||
onPress={this.selectTeam}
|
||||
>
|
||||
<View style={styles.teamContainer}>
|
||||
<View
|
||||
testID={itemTestID}
|
||||
style={styles.teamContainer}
|
||||
>
|
||||
<View>
|
||||
<TeamIcon
|
||||
testID={teamIconTestID}
|
||||
teamId={teamId}
|
||||
styleContainer={styles.teamIconContainer}
|
||||
styleText={styles.teamIconText}
|
||||
|
|
@ -87,6 +107,7 @@ export default class TeamsListItem extends React.PureComponent {
|
|||
</View>
|
||||
<View style={styles.teamNameContainer}>
|
||||
<Text
|
||||
testID={displayNameTestID}
|
||||
numberOfLines={1}
|
||||
ellipsizeMode='tail'
|
||||
style={styles.teamName}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
// 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 TeamsListItem from './teams_list_item';
|
||||
|
||||
describe('TeamsListItem', () => {
|
||||
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(<TeamsListItem {...baseProps}/>);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`TeamIcon should match snapshot 1`] = `
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderRadius": 2,
|
||||
"height": 30,
|
||||
"justifyContent": "center",
|
||||
"width": 30,
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
testID="team_icon"
|
||||
>
|
||||
<FastImage
|
||||
onError={[Function]}
|
||||
source={
|
||||
Object {
|
||||
"uri": "/api/v4/teams/team-id/image?_=1",
|
||||
}
|
||||
}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"borderRadius": 2,
|
||||
"bottom": 0,
|
||||
"left": 0,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
testID="team_icon.content"
|
||||
/>
|
||||
</View>
|
||||
`;
|
||||
|
|
@ -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 = (
|
||||
<Text style={[styles.text, styleText]}>
|
||||
<Text
|
||||
testID={contentTestID}
|
||||
style={[styles.text, styleText]}
|
||||
>
|
||||
{displayName?.substr(0, 2).toUpperCase()}
|
||||
</Text>
|
||||
);
|
||||
} else {
|
||||
teamIconContent = (
|
||||
<FastImage
|
||||
testID={contentTestID}
|
||||
style={[styles.image, styleImage]}
|
||||
source={{uri: Client4.getTeamIconUrl(teamId, lastIconUpdate)}}
|
||||
onError={this.handleImageError}
|
||||
|
|
@ -80,7 +86,10 @@ export default class TeamIcon extends React.PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<View style={[styles.container, styleContainer]}>
|
||||
<View
|
||||
testID={testID}
|
||||
style={[styles.container, styleContainer]}
|
||||
>
|
||||
{teamIconContent}
|
||||
</View>
|
||||
);
|
||||
|
|
|
|||
28
app/components/team_icon/team_icon.test.js
Normal file
28
app/components/team_icon/team_icon.test.js
Normal file
|
|
@ -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(<TeamIcon {...baseProps}/>);
|
||||
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
@ -103,6 +103,7 @@ exports[`MainSidebarDrawerButton should match, full snapshot 2`] = `
|
|||
"padding": 3,
|
||||
}
|
||||
}
|
||||
testID="main_sidebar_drawer.button.badge"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ export default class MainSidebarDrawerButton extends PureComponent {
|
|||
|
||||
badge = (
|
||||
<Badge
|
||||
testID='main_sidebar_drawer.button.badge'
|
||||
containerStyle={containerStyle}
|
||||
style={badgeStyle}
|
||||
countStyle={style.mention}
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ exports[`channelInfo should match snapshot 1`] = `
|
|||
</React.Fragment>
|
||||
<Connect(Pinned)
|
||||
channelId="1234"
|
||||
testID="channel_info.pinned.action"
|
||||
testID="channel_info.pinned_messages.action"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
|
|
@ -841,7 +841,7 @@ exports[`channelInfo should not include NotificationPreference for direct messag
|
|||
</React.Fragment>
|
||||
<Connect(Pinned)
|
||||
channelId="1234"
|
||||
testID="channel_info.pinned.action"
|
||||
testID="channel_info.pinned_messages.action"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
|
|
@ -1200,7 +1200,7 @@ exports[`channelInfo should not include NotificationPreference for direct messag
|
|||
/>
|
||||
<Connect(Pinned)
|
||||
channelId="1234"
|
||||
testID="channel_info.pinned.action"
|
||||
testID="channel_info.pinned_messages.action"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ export default class ChannelInfo extends PureComponent {
|
|||
</>
|
||||
}
|
||||
<Pinned
|
||||
testID='channel_info.pinned.action'
|
||||
testID='channel_info.pinned_messages.action'
|
||||
channelId={currentChannel.id}
|
||||
theme={theme}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ LongPost {
|
|||
shouldRenderReplyButton={false}
|
||||
showAddReaction={false}
|
||||
showLongPost={true}
|
||||
testID="long_post.post.post-id"
|
||||
testID="long_post.post"
|
||||
/>
|
||||
</ScrollView>
|
||||
<View
|
||||
|
|
|
|||
|
|
@ -115,7 +115,6 @@ export default class LongPost extends PureComponent {
|
|||
theme,
|
||||
} = this.props;
|
||||
const style = getStyleSheet(theme);
|
||||
const testID = `long_post.post.${postId}`;
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
|
|
@ -156,7 +155,7 @@ export default class LongPost extends PureComponent {
|
|||
</View>
|
||||
<ScrollView style={style.postList}>
|
||||
<Post
|
||||
testID={testID}
|
||||
testID='long_post.post'
|
||||
postId={postId}
|
||||
shouldRenderReplyButton={false}
|
||||
onPress={this.handlePress}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ exports[`Permalink should match snapshot 1`] = `
|
|||
"marginTop": 20,
|
||||
}
|
||||
}
|
||||
testID="permalink.screen"
|
||||
>
|
||||
<withAnimatable(View)
|
||||
animation="zoomIn"
|
||||
|
|
|
|||
|
|
@ -334,6 +334,7 @@ export default class Permalink extends PureComponent {
|
|||
footerColor='transparent'
|
||||
>
|
||||
<View
|
||||
testID='permalink.screen'
|
||||
style={style.container}
|
||||
>
|
||||
<Animatable.View
|
||||
|
|
@ -380,6 +381,7 @@ export default class Permalink extends PureComponent {
|
|||
onPress={this.handlePress}
|
||||
>
|
||||
<FormattedText
|
||||
testID='permalink.search.jump'
|
||||
id='mobile.search.jump'
|
||||
defautMessage='Jump to recent messages'
|
||||
style={style.jump}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ exports[`PinnedPosts should match snapshot 1`] = `
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="pinned_messages.screen"
|
||||
>
|
||||
<Connect(StatusBar) />
|
||||
<Connect(ChannelLoader)
|
||||
|
|
@ -36,6 +37,7 @@ exports[`PinnedPosts should match snapshot when component waiting for response 1
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="pinned_messages.screen"
|
||||
>
|
||||
<Connect(StatusBar) />
|
||||
<Connect(ChannelLoader)
|
||||
|
|
@ -58,6 +60,7 @@ exports[`PinnedPosts should match snapshot when getPinnedPosts failed 1`] = `
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="pinned_messages.screen"
|
||||
>
|
||||
<Connect(StatusBar) />
|
||||
<Connect(FailedNetworkAction)
|
||||
|
|
|
|||
|
|
@ -224,6 +224,7 @@ export default class PinnedPosts extends PureComponent {
|
|||
|
||||
return (
|
||||
<SafeAreaView
|
||||
testID='pinned_messages.screen'
|
||||
edges={['bottom', 'left', 'right']}
|
||||
style={style.container}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -224,8 +224,8 @@ export default class RecentMentions extends PureComponent {
|
|||
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={style.container}
|
||||
testID='recent_mentions.screen'
|
||||
style={style.container}
|
||||
>
|
||||
<StatusBar/>
|
||||
{component}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ exports[`SavedPosts should match snapshot 1`] = `
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="saved_messages.screen"
|
||||
>
|
||||
<Connect(StatusBar) />
|
||||
<Connect(ChannelLoader)
|
||||
|
|
@ -22,6 +23,7 @@ exports[`SavedPosts should match snapshot when component waiting for response 1`
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="saved_messages.screen"
|
||||
>
|
||||
<Connect(StatusBar) />
|
||||
<Connect(ChannelLoader)
|
||||
|
|
@ -37,6 +39,7 @@ exports[`SavedPosts should match snapshot when getFlaggedPosts failed 1`] = `
|
|||
"flex": 1,
|
||||
}
|
||||
}
|
||||
testID="saved_messages.screen"
|
||||
>
|
||||
<Connect(StatusBar) />
|
||||
<Connect(FailedNetworkAction)
|
||||
|
|
|
|||
|
|
@ -228,7 +228,10 @@ export default class SavedPosts extends PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView style={style.container}>
|
||||
<SafeAreaView
|
||||
testID='saved_messages.screen'
|
||||
style={style.container}
|
||||
>
|
||||
<StatusBar/>
|
||||
{component}
|
||||
</SafeAreaView>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
/>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<Post
|
||||
testID={testID}
|
||||
testID='search_result_post.post'
|
||||
postId={this.props.postId}
|
||||
{...postComponentProps}
|
||||
isSearchResult={true}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export const apiAddUserToChannel = async (userId, channelId) => {
|
|||
* 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);
|
||||
}
|
||||
|
|
|
|||
67
detox/e2e/support/ui/component/channels_list.js
Normal file
67
detox/e2e/support/ui/component/channels_list.js
Normal file
|
|
@ -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;
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
27
detox/e2e/support/ui/component/post_list.js
Normal file
27
detox/e2e/support/ui/component/post_list.js
Normal file
|
|
@ -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;
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
61
detox/e2e/support/ui/component/teams_list.js
Normal file
61
detox/e2e/support/ui/component/teams_list.js
Normal file
|
|
@ -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;
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
61
detox/e2e/support/ui/screen/permalink.js
Normal file
61
detox/e2e/support/ui/screen/permalink.js
Normal file
|
|
@ -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;
|
||||
42
detox/e2e/support/ui/screen/pinned_messages.js
Normal file
42
detox/e2e/support/ui/screen/pinned_messages.js
Normal file
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
52
detox/e2e/support/ui/screen/saved_messages.js
Normal file
52
detox/e2e/support/ui/screen/saved_messages.js
Normal file
|
|
@ -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;
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ describe('Autocomplete', () => {
|
|||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await device.reloadReactNative();
|
||||
await SearchScreen.cancel();
|
||||
await ChannelScreen.logout();
|
||||
});
|
||||
|
||||
|
|
|
|||
92
detox/e2e/test/smoke_test/mention_badges.e2e.js
Normal file
92
detox/e2e/test/smoke_test/mention_badges.e2e.js
Normal file
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
96
detox/e2e/test/smoke_test/teams.e2e.js
Normal file
96
detox/e2e/test/smoke_test/teams.e2e.js
Normal file
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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 () => {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ const ChannelItem = ({onSelect, selected, channel}: ChannelItemProps) => {
|
|||
<View style={styles.item}>
|
||||
{channelTypes[channel.type] || PublicChannel}
|
||||
<Text
|
||||
testID='share_extension.channel_item.display_name'
|
||||
style={[styles.text]}
|
||||
ellipsizeMode='tail'
|
||||
numberOfLines={1}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ const TeamItem = ({onSelect, selected, team}: TeamItemProps) => {
|
|||
<View style={styles.container}>
|
||||
<View style={styles.item}>
|
||||
<TeamIcon
|
||||
testID='share_extension.team_item.team_icon'
|
||||
teamId={team.id}
|
||||
styleContainer={styles.teamIconContainer}
|
||||
styleText={styles.teamIconText}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ const ChannelList = ({intl}: ChannnelListProps) => {
|
|||
);
|
||||
const renderItem = ({item}: SectionListRenderItemInfo<Channel>) => (
|
||||
<ChannelItem
|
||||
testID='share_extension.channel_list.channel_item'
|
||||
channel={item}
|
||||
onSelect={onSelectChannel}
|
||||
selected={item.id === currentChannelId}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ const TeamList = () => {
|
|||
|
||||
return (
|
||||
<FlatList
|
||||
testID='share_extension.team_list.screen'
|
||||
data={teams}
|
||||
ItemSeparatorComponent={renderItemSeparator}
|
||||
renderItem={renderItem}
|
||||
|
|
|
|||
Loading…
Reference in a new issue