MM-18769 Removed deprecated lifecycles (#4983)

* select_team : updated snapshot and removed deprecated lifecycles

* removed deprecated lifecycle methods

* Added e2e for MM-T3619

* Fix lint issue

Co-authored-by: Joseph Baylon <joseph.baylon@mattermost.com>
This commit is contained in:
A C SREEDHAR REDDY 2020-12-03 02:07:04 +05:30 committed by GitHub
parent 0360ceeb6e
commit 757a673416
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 334 additions and 35 deletions

View file

@ -62,17 +62,21 @@ export default class ClientUpgradeListener extends PureComponent {
}
}
componentWillReceiveProps(nextProps) {
const {forceUpgrade, latestVersion, minVersion} = this.props;
const {latestVersion: nextLatestVersion, minVersion: nextMinVersion, lastUpgradeCheck} = nextProps;
setTop(top) {
this.setState({top});
}
componentDidUpdate(prevProps) {
const {forceUpgrade, latestVersion, minVersion} = prevProps;
const {latestVersion: nextLatestVersion, minVersion: nextMinVersion, lastUpgradeCheck} = this.props;
const versionMismatch = latestVersion !== nextLatestVersion || minVersion !== nextMinVersion;
if (versionMismatch && (forceUpgrade || Date.now() - lastUpgradeCheck > UPDATE_TIMEOUT)) {
this.checkUpgrade(minVersion, latestVersion, nextProps.isLandscape);
} else if (this.props.isLandscape !== nextProps.isLandscape &&
this.checkUpgrade(minVersion, latestVersion, this.props.isLandscape);
} else if (prevProps.isLandscape !== this.props.isLandscape &&
isUpgradeAvailable(this.state.upgradeType) && DeviceTypes.IS_IPHONE_WITH_INSETS) {
const newTop = nextProps.isLandscape ? 45 : 100;
this.setState({top: new Animated.Value(newTop)});
const newTop = this.props.isLandscape ? 45 : 100;
this.setTop(new Animated.Value(newTop));
}
}

View file

@ -42,6 +42,7 @@ exports[`SelectTeam should match snapshot for teams 1`] = `
"flex": 1,
}
}
testID="select_team.screen"
>
<Connect(StatusBar) />
<View
@ -84,7 +85,15 @@ exports[`SelectTeam should match snapshot for teams 1`] = `
</View>
<CustomList
canRefresh={true}
data={Array []}
data={
Array [
Object {
"id": "kemjcpu9bi877yegqjs18ndp4r",
"invite_id": "ojsnudhqzbfzpk6e4n6ip1hwae",
"name": "test",
},
]
}
extraData={false}
listType="flat"
loading={false}
@ -109,6 +118,7 @@ exports[`SelectTeam should match snapshot for teams 1`] = `
renderItem={[Function]}
shouldRenderSeparator={false}
showNoResults={true}
testID="select_team.custom_list"
theme={
Object {
"awayIndicator": "#ffbc42",
@ -149,6 +159,7 @@ exports[`SelectTeam should match snapshot when user is a guest 1`] = `
"flex": 1,
}
}
testID="select_team.screen"
>
<Connect(StatusBar) />
<View
@ -170,6 +181,7 @@ exports[`SelectTeam should match snapshot when user is a guest 1`] = `
"fontSize": 13,
}
}
testID="select_team.guest_cant_join_team"
/>
</View>
</View>

View file

@ -26,6 +26,7 @@ import {resetToChannel, dismissModal} from 'app/actions/navigation';
import {preventDoubleTap} from 'app/utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
import {t} from 'app/utils/i18n';
import memoize from 'memoize-one';
const TEAMS_PER_PAGE = 50;
@ -68,12 +69,6 @@ export default class SelectTeam extends PureComponent {
this.getTeams();
}
componentWillReceiveProps(nextProps) {
if (this.props.teams !== nextProps.teams) {
this.buildData(nextProps);
}
}
navigationButtonPressed({buttonId}) {
const {logout} = this.props.actions;
@ -98,17 +93,15 @@ export default class SelectTeam extends PureComponent {
});
}
buildData = (props) => {
if (props.teams.length) {
this.setState({teams: props.teams});
} else {
const teams = [{
id: t('mobile.select_team.no_teams'),
defaultMessage: 'There are no available teams for you to join.',
}];
this.setState({teams});
memoizedTeams = memoize((teams) => {
if (teams.length) {
return teams;
}
};
return [{
id: t('mobile.select_team.no_teams'),
defaultMessage: 'There are no available teams for you to join.',
}];
})
close = () => {
dismissModal();
@ -164,6 +157,7 @@ export default class SelectTeam extends PureComponent {
<View style={style.teamWrapper}>
<View style={style.teamContainer}>
<FormattedText
testID='select_team.no_teams'
id={item.id}
defaultMessage={item.defaultMessage}
style={style.noTeam}
@ -173,13 +167,25 @@ export default class SelectTeam extends PureComponent {
);
}
const testID = 'select_team.custom_list.team_item';
const itemTestID = `${testID}.${item.id}`;
const teamDisplayNameTestID = `${testID}.display_name`;
const teamIconTestID = `${testID}.team_icon`;
return (
<View style={style.teamWrapper}>
<View
testID={testID}
style={style.teamWrapper}
>
<TouchableOpacity
onPress={preventDoubleTap(() => this.onSelectTeam(item))}
>
<View style={style.teamContainer}>
<View
testID={itemTestID}
style={style.teamContainer}
>
<TeamIcon
testID={teamIconTestID}
teamId={item.id}
styleContainer={style.teamIconContainer}
styleText={style.teamIconText}
@ -187,6 +193,7 @@ export default class SelectTeam extends PureComponent {
/>
<View style={style.teamNameContainer}>
<Text
testID={teamDisplayNameTestID}
numberOfLines={1}
ellipsizeMode='tail'
style={style.teamName}
@ -209,7 +216,7 @@ export default class SelectTeam extends PureComponent {
render() {
const {theme} = this.props;
const {teams} = this.state;
const teams = this.memoizedTeams(this.props.teams);
const style = getStyleFromTheme(theme);
if (this.state.joining) {
@ -229,10 +236,14 @@ export default class SelectTeam extends PureComponent {
if (this.props.currentUserIsGuest) {
return (
<View style={style.container}>
<View
testID='select_team.screen'
style={style.container}
>
<StatusBar/>
<View style={style.headingContainer}>
<FormattedText
testID='select_team.guest_cant_join_team'
id='mobile.select_team.guest_cant_join_team'
defaultMessage='Your guest account has no teams or channels assigned. Please contact an administrator.'
style={style.heading}
@ -243,7 +254,10 @@ export default class SelectTeam extends PureComponent {
}
return (
<SafeAreaView style={style.container}>
<SafeAreaView
testID='select_team.screen'
style={style.container}
>
<StatusBar/>
<View style={style.headingContainer}>
<View style={style.headingWrapper}>
@ -256,6 +270,7 @@ export default class SelectTeam extends PureComponent {
<View style={style.line}/>
</View>
<CustomList
testID='select_team.custom_list'
data={teams}
loading={this.state.loading}
loadingComponent={

View file

@ -77,6 +77,42 @@ export const apiAddUserToChannel = async (userId, channelId) => {
}
};
/**
* Remove user from channel.
* 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
*/
export const apiDeleteUserFromChannel = async (channelId, userId) => {
try {
const response = await client.delete(
`/api/v4/channels/${channelId}/members/${userId}`,
);
return response;
} catch (err) {
return getResponseFromError(err);
}
};
/**
* Get channels for user.
* See https://api.mattermost.com/#tag/channels/paths/~1users~1{user_id}~1teams~1{team_id}~1channels/get
* @param {string} userId - The user ID
* @param {string} teamId - The team ID the user belongs to
* @return {Object} returns {channels} on success or {error, status} on error
*/
export const apiGetChannelsForUser = async (userId, teamId) => {
try {
const response = await client.get(`/api/v4/users/${userId}/teams/${teamId}/channels`);
return {channels: response.data};
} catch (err) {
return getResponseFromError(err);
}
};
function generateRandomChannel(teamId, type, prefix) {
const randomId = getRandomId();
@ -93,7 +129,9 @@ function generateRandomChannel(teamId, type, prefix) {
export const Channel = {
apiAddUserToChannel,
apiCreateChannel,
apiDeleteUserFromChannel,
apiGetChannelByName,
apiGetChannelsForUser,
};
export default Channel;

View file

@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import jestExpect from 'expect';
import {capitalize, getRandomId} from '@support/utils';
import client from './client';
@ -60,12 +61,80 @@ export const apiAddUserToTeam = async (userId, teamId) => {
};
/**
* Get team members for user.
* See https://api.mattermost.com/#tag/teams/paths/~1users~1{user_id}~1teams~1members/get
* @param {string} userId
* Delete a team.
* See https://api.mattermost.com/#tag/teams/paths/~1teams~1{team_id}/delete
* @param {string} teamId - The team ID
* @return {Object} returns {status} on success or {error, status} on error
*/
export const apiDeleteTeam = async (teamId) => {
try {
const response = await client.delete(
`/api/v4/teams/${teamId}`,
);
return {status: response.status};
} catch (err) {
return getResponseFromError(err);
}
};
/**
* Delete teams.
* @param {Array} teams - array of teams
*/
export const apiDeleteTeams = async (teams = []) => {
let teamArray = teams;
if (!teamArray.length > 0) {
({teams: teamArray} = await Team.apiGetTeams());
}
teamArray.forEach(async (team) => {
const {status} = await Team.apiDeleteTeam(team.id);
jestExpect(status).toEqual(200);
});
};
/**
* Remove user from team.
* See https://api.mattermost.com/#tag/teams/paths/~1teams~1{team_id}~1members~1{user_id}/delete
* @param {string} teamId - The team ID
* @param {string} userId - The user ID to be removed from team
* @return {Object} returns {status} on success or {error, status} on error
*/
export const apiDeleteUserFromTeam = async (teamId, userId) => {
try {
const response = await client.delete(
`/api/v4/teams/${teamId}/members/${userId}`,
);
return {status: response.status};
} catch (err) {
return getResponseFromError(err);
}
};
/**
* Get teams.
* See https://api.mattermost.com/#tag/teams/paths/~1teams/get
* @return {Object} returns {teams} on success or {error, status} on error
*/
export const apiGetTeamMembersForUser = async (userId = 'me') => {
export const apiGetTeams = async () => {
try {
const response = await client.get('/api/v4/teams');
return {teams: response.data};
} catch (err) {
return getResponseFromError(err);
}
};
/**
* Get teams for user.
* See https://api.mattermost.com/#tag/teams/paths/~1users~1{user_id}~1teams/get
* @param {string} userId - The user ID
* @return {Object} returns {teams} on success or {error, status} on error
*/
export const apiGetTeamsForUser = async (userId = 'me') => {
try {
const response = await client.get(`/api/v4/users/${userId}/teams`);
@ -75,6 +144,52 @@ export const apiGetTeamMembersForUser = async (userId = 'me') => {
}
};
/**
* Patch a team.
* See https://api.mattermost.com/#tag/teams/paths/~1teams~1{team_id}~1patch/put
* @param {string} teamId - The team ID
* @param {string} patch.display_name - Display name
* @param {string} patch.description - Description
* @param {string} patch.company_name - Company name
* @param {string} patch.allowed_domains - Allowed domains
* @param {boolean} patch.allow_open_invite - Allow open invite
* @param {boolean} patch.group_constrained - Group constrained
* @return {Object} returns {team} on success or {error, status} on error
*/
export const apiPatchTeam = async (teamId, teamData) => {
try {
const response = await client.put(
`/api/v4/teams/${teamId}/patch`,
teamData,
);
return {team: response.data};
} catch (err) {
return getResponseFromError(err);
}
};
/**
* Patch teams.
* @param {string} patch.display_name - Display name
* @param {string} patch.description - Description
* @param {string} patch.company_name - Company name
* @param {string} patch.allowed_domains - Allowed domains
* @param {boolean} patch.allow_open_invite - Allow open invite
* @param {boolean} patch.group_constrained - Group constrained
* @param {Array} teams - array of teams
*/
export const apiPatchTeams = async (teamData, teams = []) => {
let teamArray = teams;
if (!teamArray.length > 0) {
({teams: teamArray} = await Team.apiGetTeams());
}
teamArray.forEach(async (team) => {
await Team.apiPatchTeam(team.id, teamData);
});
};
function generateRandomTeam(type, prefix) {
const randomId = getRandomId();
@ -88,7 +203,13 @@ function generateRandomTeam(type, prefix) {
export const Team = {
apiAddUserToTeam,
apiCreateTeam,
apiGetTeamMembersForUser,
apiDeleteTeam,
apiDeleteTeams,
apiDeleteUserFromTeam,
apiGetTeams,
apiGetTeamsForUser,
apiPatchTeam,
apiPatchTeams,
};
export default Team;

View file

@ -21,6 +21,7 @@ import RecentMentionsScreen from './recent_mentions';
import SearchResultPostScreen from './search_result_post';
import SearchScreen from './search';
import SelectServerScreen from './select_server';
import SelectTeamScreen from './select_team';
import ThreadScreen from './thread';
export {
@ -44,5 +45,6 @@ export {
SearchResultPostScreen,
SearchScreen,
SelectServerScreen,
SelectTeamScreen,
ThreadScreen,
};

View file

@ -0,0 +1,55 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
class SelectTeamScreen {
testID = {
selectTeamScreen: 'select_team.screen',
noTeams: 'select_team.no_teams',
teamsList: 'select_team.custom_list',
teamItem: 'select_team.custom_list.team_item',
teamItemDisplayName: 'select_team.custom_list.team_item.display_name',
teamItemIcon: 'select_team.custom_list.team_item.team_icon',
teamItemIconContent: 'select_team.custom_list.team_item.team_icon.content',
}
selectTeamScreen = element(by.id(this.testID.selectTeamScreen));
noTeams = element(by.id(this.testID.noTeams));
teamsList = element(by.id(this.testID.teamsList));
toBeVisible = async () => {
await expect(this.selectTeamScreen).toBeVisible();
return this.selectTeamScreen;
}
getTeamItem = (teamId, displayName) => {
const teamItemTestID = `${this.testID.teamItem}.${teamId}`;
const baseMatcher = by.id(teamItemTestID);
const teamItemMatcher = displayName ? baseMatcher.withDescendant(by.text(displayName)) : baseMatcher;
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),
teamItemDisplayName: element(teamItemDisplayNameMatcher),
teamItemIcon: element(teamItemIconMatcher),
teamItemIconContent: element(teamItemIconContentMatcher),
};
}
getTeamByDisplayName = (displayName) => {
return element(by.text(displayName).withAncestor(by.id(this.testID.teamsList)));
}
getTeamDisplayNameAtIndex = (index) => {
return element(by.id(this.testID.teamItemDisplayName)).atIndex(index);
}
getTeamIconContentAtIndex = (index) => {
return element(by.id(this.testID.teamItemIconContent)).atIndex(index);
}
}
const selectTeamScreen = new SelectTeamScreen();
export default selectTeamScreen;

View file

@ -65,7 +65,7 @@ async function ensureUserHasTeam(ldapUser) {
// # Login as sysadmin and ensure LDAP user is member of at least one team
await User.apiAdminLogin();
const {user} = await User.apiGetUserByUsername(ldapUser.username);
const {teams} = await Team.apiGetTeamMembersForUser(user.id);
const {teams} = await Team.apiGetTeamsForUser(user.id);
if (!teams?.length) {
const {team} = await Setup.apiInit();

View file

@ -0,0 +1,52 @@
// 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 {
ChannelScreen,
LoginScreen,
SelectTeamScreen,
} from '@support/ui/screen';
import {
Channel,
Team,
User,
} from '@support/server_api';
describe('Select Team', () => {
let testTeam;
beforeAll(async () => {
await Team.apiPatchTeams({allow_open_invite: false});
const {user} = await User.apiCreateUser();
const {team} = await Team.apiCreateTeam();
testTeam = team;
await Team.apiPatchTeam(testTeam.id, {allow_open_invite: true});
// # Open select team screen
await LoginScreen.open();
await LoginScreen.login(user);
await SelectTeamScreen.toBeVisible();
});
afterAll(async () => {
await ChannelScreen.logout();
});
it('MM-T3619 should be able to select a team', async () => {
// # Tap on team to join
const team = await SelectTeamScreen.getTeamByDisplayName(testTeam.display_name);
await team.tap();
// * Verify redirect to default channel of joined team
const {channel} = await Channel.apiGetChannelByName(testTeam.name, 'town-square');
const {channelNavBarTitle} = ChannelScreen;
await ChannelScreen.toBeVisible();
await expect(channelNavBarTitle).toHaveText(channel.display_name);
});
});