diff --git a/app/components/failed_network_action/index.js b/app/components/failed_network_action/index.js index f2f262f37..9126258f8 100644 --- a/app/components/failed_network_action/index.js +++ b/app/components/failed_network_action/index.js @@ -14,6 +14,19 @@ export default class FailedNetworkAction extends PureComponent { static propTypes = { onRetry: PropTypes.func, theme: PropTypes.object.isRequired, + errorTitle: PropTypes.object, + errorDescription: PropTypes.object, + }; + + static defaultProps = { + errorTitle: { + id: 'mobile.failed_network_action.title', + defaultMessage: 'No internet connection', + }, + errorDescription: { + id: 'mobile.failed_network_action.description', + defaultMessage: 'There seems to be a problem with your internet connection. Make sure you have an active connection and try again.', + }, }; render() { @@ -28,13 +41,13 @@ export default class FailedNetworkAction extends PureComponent { width={76} /> {onRetry && diff --git a/app/screens/select_team/__snapshots__/select_team.test.js.snap b/app/screens/select_team/__snapshots__/select_team.test.js.snap new file mode 100644 index 000000000..792a26e69 --- /dev/null +++ b/app/screens/select_team/__snapshots__/select_team.test.js.snap @@ -0,0 +1,609 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SelectTeam should match snapshot for fail of teams 1`] = ` +ShallowWrapper { + "length": 1, + Symbol(enzyme.__root__): [Circular], + Symbol(enzyme.__unrendered__): , + Symbol(enzyme.__renderer__): Object { + "batchedUpdates": [Function], + "getNode": [Function], + "render": [Function], + "simulateEvent": [Function], + "unmount": [Function], + }, + Symbol(enzyme.__node__): Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "errorDescription": Object { + "defaultMessage": "Make sure you have an active connection and try again.", + "id": "mobile.failed_network_action.shortDescription", + }, + "errorTitle": Object { + "defaultMessage": "Team Not Found", + "id": "error.team_not_found.title", + }, + "onRetry": [Function], + "theme": Object {}, + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + Symbol(enzyme.__nodes__): Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "errorDescription": Object { + "defaultMessage": "Make sure you have an active connection and try again.", + "id": "mobile.failed_network_action.shortDescription", + }, + "errorTitle": Object { + "defaultMessage": "Team Not Found", + "id": "error.team_not_found.title", + }, + "onRetry": [Function], + "theme": Object {}, + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + ], + Symbol(enzyme.__options__): Object { + "adapter": ReactSixteenAdapter { + "options": Object { + "enableComponentDidUpdateOnSetState": true, + }, + }, + }, +} +`; + +exports[`SelectTeam should match snapshot for teams 1`] = ` +ShallowWrapper { + "length": 1, + Symbol(enzyme.__root__): [Circular], + Symbol(enzyme.__unrendered__): , + Symbol(enzyme.__renderer__): Object { + "batchedUpdates": [Function], + "getNode": [Function], + "render": [Function], + "simulateEvent": [Function], + "unmount": [Function], + }, + Symbol(enzyme.__node__): Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "children": Array [ + , + + + + + + , + , + ], + "style": Object { + "backgroundColor": undefined, + "flex": 1, + }, + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object {}, + "ref": null, + "rendered": null, + "type": [Function], + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "children": Array [ + + + , + , + ], + "style": Object { + "alignItems": "center", + "flexDirection": "row", + "marginHorizontal": 16, + "marginTop": 20, + }, + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "children": , + "style": Object { + "marginRight": 15, + }, + }, + "ref": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "defaultMessage": "Open teams you can join", + "id": "mobile.select_team.join_open", + "style": Object { + "color": undefined, + "fontSize": 13, + }, + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + "type": [Function], + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "style": Object { + "backgroundColor": undefined, + "height": 1, + "width": "100%", + }, + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + ], + "type": [Function], + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "data": Array [ + Object { + "id": "kemjcpu9bi877yegqjs18ndp4r", + "invite_id": "ojsnudhqzbfzpk6e4n6ip1hwae", + "name": "test", + }, + ], + "disableVirtualization": false, + "horizontal": false, + "initialNumToRender": 10, + "keyExtractor": [Function], + "maxToRenderPerBatch": 10, + "numColumns": 1, + "onEndReachedThreshold": 2, + "renderItem": [Function], + "scrollEventThrottle": 50, + "updateCellsBatchingPeriod": 50, + "viewabilityConfig": Object { + "viewAreaCoveragePercentThreshold": 3, + "waitForInteraction": false, + }, + "windowSize": 21, + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + ], + "type": [Function], + }, + Symbol(enzyme.__nodes__): Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "children": Array [ + , + + + + + + , + , + ], + "style": Object { + "backgroundColor": undefined, + "flex": 1, + }, + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object {}, + "ref": null, + "rendered": null, + "type": [Function], + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "children": Array [ + + + , + , + ], + "style": Object { + "alignItems": "center", + "flexDirection": "row", + "marginHorizontal": 16, + "marginTop": 20, + }, + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "children": , + "style": Object { + "marginRight": 15, + }, + }, + "ref": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "defaultMessage": "Open teams you can join", + "id": "mobile.select_team.join_open", + "style": Object { + "color": undefined, + "fontSize": 13, + }, + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + "type": [Function], + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "style": Object { + "backgroundColor": undefined, + "height": 1, + "width": "100%", + }, + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + ], + "type": [Function], + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "data": Array [ + Object { + "id": "kemjcpu9bi877yegqjs18ndp4r", + "invite_id": "ojsnudhqzbfzpk6e4n6ip1hwae", + "name": "test", + }, + ], + "disableVirtualization": false, + "horizontal": false, + "initialNumToRender": 10, + "keyExtractor": [Function], + "maxToRenderPerBatch": 10, + "numColumns": 1, + "onEndReachedThreshold": 2, + "renderItem": [Function], + "scrollEventThrottle": 50, + "updateCellsBatchingPeriod": 50, + "viewabilityConfig": Object { + "viewAreaCoveragePercentThreshold": 3, + "waitForInteraction": false, + }, + "windowSize": 21, + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + ], + "type": [Function], + }, + ], + Symbol(enzyme.__options__): Object { + "adapter": ReactSixteenAdapter { + "options": Object { + "enableComponentDidUpdateOnSetState": true, + }, + }, + }, +} +`; diff --git a/app/screens/select_team/index.js b/app/screens/select_team/index.js index 91c6843da..8978cd48d 100644 --- a/app/screens/select_team/index.js +++ b/app/screens/select_team/index.js @@ -28,7 +28,7 @@ function mapStateToProps(state) { } return { - teamsRequest: state.requests.teams.getMyTeams, + teamsRequest: state.requests.teams.getTeams, teams: Object.values(getJoinableTeams(state)).sort(sortTeams), currentChannelId: getCurrentChannelId(state), joinTeamRequest: state.requests.teams.joinTeam, diff --git a/app/screens/select_team/select_team.js b/app/screens/select_team/select_team.js index 82d369cce..5a5f9e2db 100644 --- a/app/screens/select_team/select_team.js +++ b/app/screens/select_team/select_team.js @@ -15,6 +15,7 @@ import { import {RequestStatus} from 'mattermost-redux/constants'; import EventEmitter from 'mattermost-redux/utils/event_emitter'; +import FailedNetworkAction from 'app/components/failed_network_action'; import FormattedText from 'app/components/formatted_text'; import Loading from 'app/components/loading'; import StatusBar from 'app/components/status_bar'; @@ -28,6 +29,16 @@ const VIEWABILITY_CONFIG = ListTypes.VISIBILITY_CONFIG_DEFAULTS; const TEAMS_PER_PAGE = 200; +const errorTitle = { + id: 'error.team_not_found.title', + defaultMessage: 'Team Not Found', +}; + +const errorDescription = { + id: 'mobile.failed_network_action.shortDescription', + defaultMessage: 'Make sure you have an active connection and try again.', +}; + export default class SelectTeam extends PureComponent { static propTypes = { actions: PropTypes.shape({ @@ -44,6 +55,7 @@ export default class SelectTeam extends PureComponent { userWithoutTeams: PropTypes.bool, teams: PropTypes.array.isRequired, theme: PropTypes.object, + teamsRequest: PropTypes.object.isRequired, }; constructor(props) { @@ -57,9 +69,7 @@ export default class SelectTeam extends PureComponent { } componentDidMount() { - this.props.actions.getTeams(0, TEAMS_PER_PAGE).then(() => { - this.buildData(this.props); - }); + this.getTeams(); } componentWillReceiveProps(nextProps) { @@ -77,6 +87,14 @@ export default class SelectTeam extends PureComponent { } } + getTeams = () => { + this.setState({loading: true}); + this.props.actions.getTeams(0, TEAMS_PER_PAGE).then(() => { + this.setState({loading: false}); + this.buildData(this.props); + }); + } + buildData = (props) => { if (props.teams.length) { this.setState({teams: props.teams}); @@ -213,10 +231,21 @@ export default class SelectTeam extends PureComponent { const {teams} = this.state; const styles = getStyleSheet(theme); - if (this.state.joining) { + if (this.state.joining || this.state.loading) { return ; } + if (this.props.teamsRequest.status === RequestStatus.FAILURE) { + return ( + + ); + } + return ( diff --git a/app/screens/select_team/select_team.test.js b/app/screens/select_team/select_team.test.js new file mode 100644 index 000000000..90f7ec1f8 --- /dev/null +++ b/app/screens/select_team/select_team.test.js @@ -0,0 +1,97 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. +import React from 'react'; +import {configure, shallow} from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +import {RequestStatus} from 'mattermost-redux/constants'; +configure({adapter: new Adapter()}); + +import SelectTeam from './select_team.js'; + +jest.mock('rn-fetch-blob', () => ({ + fs: { + dirs: { + DocumentDir: () => jest.fn(), + CacheDir: () => jest.fn(), + }, + }, +})); + +jest.mock('rn-fetch-blob/fs', () => ({ + dirs: { + DocumentDir: () => jest.fn(), + CacheDir: () => jest.fn(), + }, +})); + +jest.mock('app/utils/theme', () => { + const original = require.requireActual('app/utils/theme'); + return { + ...original, + changeOpacity: jest.fn(), + }; +}); + +const getTeams = async () => { + return { + error: {}, + }; +}; + +describe('SelectTeam', () => { + const actions = { + getTeams, + handleTeamChange: jest.fn(), + joinTeam: jest.fn(), + logout: jest.fn(), + markChannelAsRead: jest.fn(), + }; + + const baseProps = { + actions, + currentChannelId: 'someId', + currentUrl: 'test', + joinTeamRequest: {}, + navigator: { + setOnNavigatorEvent: jest.fn(), + }, + userWithoutTeams: false, + teams: [], + theme: {}, + teamsRequest: { + status: RequestStatus.FAILURE, + }, + }; + + test('should match snapshot for fail of teams', async () => { + const wrapper = shallow( + , + ); + expect(wrapper.state('loading')).toEqual(true); + await getTeams(); + expect(wrapper.state('loading')).toEqual(false); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + }); + + test('should match snapshot for teams', async () => { + const props = { + ...baseProps, + teams: [{ + id: 'kemjcpu9bi877yegqjs18ndp4r', + invite_id: 'ojsnudhqzbfzpk6e4n6ip1hwae', + name: 'test', + }], + teamsRequest: { + status: RequestStatus.SUCCESS, + }, + }; + + const wrapper = shallow( + , + ); + await getTeams(); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 09d63872d..b7dc7a1c0 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -2455,6 +2455,7 @@ "mobile.failed_network_action.description": "There seems to be a problem with your internet connection. Make sure you have an active connection and try again.", "mobile.failed_network_action.retry": "Try Again", "mobile.failed_network_action.title": "No internet connection", + "mobile.failed_network_action.shortDescription": "Make sure you have an active connection and try again.", "mobile.file_upload.browse": "Browse Files", "mobile.file_upload.camera": "Take Photo or Video", "mobile.file_upload.library": "Photo Library",