MM-16397 save draft when app state changes (#2899)

* MM-16397 save draft when app state changes

* Unit tests
This commit is contained in:
Elias Nahum 2019-06-22 14:21:57 -04:00 committed by Miguel Alatzar
parent e5f98b5151
commit e6fdef3451
3 changed files with 252 additions and 0 deletions

View file

@ -0,0 +1,149 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PostTextBox should match, full snapshot 1`] = `
<React.Fragment>
<Connect(Typing) />
<View
onLayout={[Function]}
style={
Object {
"alignItems": "flex-end",
"backgroundColor": "#ffffff",
"borderTopColor": "rgba(61,60,64,0.2)",
"borderTopWidth": 1,
"flexDirection": "row",
"paddingVertical": 4,
}
}
>
<AttachmentButton
blurTextBox={[Function]}
browseFileTypes="public.item"
canBrowseFiles={true}
canBrowsePhotoLibrary={true}
canBrowseVideoLibrary={true}
canTakePhoto={true}
canTakeVideo={true}
extraOptions={null}
fileCount={0}
maxFileCount={5}
maxFileSize={1024}
navigator={
Object {
"showModal": [MockFunction],
}
}
onShowFileMaxWarning={[Function]}
onShowFileSizeWarning={[Function]}
theme={
Object {
"awayIndicator": "#ffbc42",
"buttonBg": "#166de0",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3d3c40",
"codeTheme": "github",
"dndIndicator": "#f74343",
"errorTextColor": "#fd5960",
"linkColor": "#2389d7",
"mentionBj": "#ffffff",
"mentionColor": "#145dbf",
"mentionHighlightBg": "#ffe577",
"mentionHighlightLink": "#166de0",
"newMessageSeparator": "#ff8800",
"onlineIndicator": "#06d6a0",
"sidebarBg": "#145dbf",
"sidebarHeaderBg": "#1153ab",
"sidebarHeaderTextColor": "#ffffff",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#579eff",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#4578bf",
"sidebarUnreadText": "#ffffff",
"type": "Mattermost",
}
}
uploadFiles={[Function]}
validMimeTypes={Array []}
/>
<View
style={
Array [
Object {
"alignItems": "stretch",
"backgroundColor": "#fff",
"flex": 1,
"flexDirection": "row",
"marginRight": 10,
},
]
}
>
<TextInput
allowFontScaling={true}
blurOnSubmit={false}
disableFullscreenUI={true}
editable={true}
keyboardType="default"
multiline={true}
onChangeText={[Function]}
onEndEditing={[Function]}
onSelectionChange={[Function]}
placeholder="Write to Test Channel"
placeholderTextColor="rgba(0,0,0,0.5)"
rejectResponderTermination={true}
style={
Object {
"color": "#000",
"flex": 1,
"fontSize": 14,
"maxHeight": 100,
"paddingBottom": 8,
"paddingLeft": 12,
"paddingRight": 12,
"paddingTop": 8,
}
}
underlineColorAndroid="transparent"
value=""
/>
<Fade
visible={false}
>
<SendButton
disabled={false}
handleSendMessage={[Function]}
theme={
Object {
"awayIndicator": "#ffbc42",
"buttonBg": "#166de0",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3d3c40",
"codeTheme": "github",
"dndIndicator": "#f74343",
"errorTextColor": "#fd5960",
"linkColor": "#2389d7",
"mentionBj": "#ffffff",
"mentionColor": "#145dbf",
"mentionHighlightBg": "#ffe577",
"mentionHighlightLink": "#166de0",
"newMessageSeparator": "#ff8800",
"onlineIndicator": "#06d6a0",
"sidebarBg": "#145dbf",
"sidebarHeaderBg": "#1153ab",
"sidebarHeaderTextColor": "#ffffff",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#579eff",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#4578bf",
"sidebarUnreadText": "#ffffff",
"type": "Mattermost",
}
}
/>
</Fade>
</View>
</View>
</React.Fragment>
`;

View file

@ -0,0 +1,90 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {shallowWithIntl} from 'test/intl-test-helper';
import Preferences from 'mattermost-redux/constants/preferences';
import PostTextbox from './post_textbox.ios';
jest.mock('NativeEventEmitter');
describe('PostTextBox', () => {
const baseProps = {
actions: {
addReactionToLatestPost: jest.fn(),
createPost: jest.fn(),
executeCommand: jest.fn(),
handleCommentDraftChanged: jest.fn(),
handlePostDraftChanged: jest.fn(),
handleClearFiles: jest.fn(),
handleClearFailedFiles: jest.fn(),
handleRemoveLastFile: jest.fn(),
initUploadFiles: jest.fn(),
userTyping: jest.fn(),
handleCommentDraftSelectionChanged: jest.fn(),
setStatus: jest.fn(),
selectPenultimateChannel: jest.fn(),
},
canUploadFiles: true,
channelId: 'channel-id',
channelDisplayName: 'Test Channel',
channelTeamId: 'channel-team-id',
channelIsLoading: false,
channelIsReadOnly: false,
currentUserId: 'current-user-id',
deactivatedChannel: false,
files: [],
maxFileSize: 1024,
maxMessageLength: 4000,
navigator: {
showModal: jest.fn(),
},
rootId: '',
theme: Preferences.THEMES.default,
uploadFileRequestStatus: 'NOT_STARTED',
value: '',
userIsOutOfOffice: false,
channelIsArchived: false,
onCloseChannel: jest.fn(),
cursorPositionEvent: '',
valueEvent: '',
};
test('should match, full snapshot', () => {
const wrapper = shallowWithIntl(
<PostTextbox {...baseProps}/>
);
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should emit the event but no text is save to draft', () => {
const wrapper = shallowWithIntl(
<PostTextbox {...baseProps}/>
);
wrapper.setState({value: 'some text'});
const instance = wrapper.instance();
instance.changeDraft = jest.fn();
instance.handleAppStateChange('active');
expect(instance.changeDraft).not.toBeCalled();
});
test('should emit the event and text is save to draft', () => {
const wrapper = shallowWithIntl(
<PostTextbox {...baseProps}/>
);
const instance = wrapper.instance();
const value = 'some text';
wrapper.setState({value});
instance.handleAppStateChange('background');
expect(baseProps.actions.handlePostDraftChanged).toHaveBeenCalledWith(baseProps.channelId, value);
expect(baseProps.actions.handlePostDraftChanged).toHaveBeenCalledTimes(1);
});
});

View file

@ -5,6 +5,7 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Alert,
AppState,
BackHandler,
findNodeHandle,
Keyboard,
@ -99,7 +100,10 @@ export default class PostTextBoxBase extends PureComponent {
componentDidMount() {
const event = this.props.rootId ? INSERT_TO_COMMENT : INSERT_TO_DRAFT;
EventEmitter.on(event, this.handleInsertTextToDraft);
AppState.addEventListener('change', this.handleAppStateChange);
if (Platform.OS === 'android') {
Keyboard.addListener('keyboardDidHide', this.handleAndroidKeyboard);
BackHandler.addEventListener('hardwareBackPress', this.handleAndroidBack);
@ -114,7 +118,10 @@ export default class PostTextBoxBase extends PureComponent {
componentWillUnmount() {
const event = this.props.rootId ? INSERT_TO_COMMENT : INSERT_TO_DRAFT;
EventEmitter.off(event, this.handleInsertTextToDraft);
AppState.removeEventListener('change', this.handleAppStateChange);
if (Platform.OS === 'android') {
Keyboard.removeListener('keyboardDidHide', this.handleAndroidKeyboard);
BackHandler.removeEventListener('hardwareBackPress', this.handleAndroidBack);
@ -248,6 +255,12 @@ export default class PostTextBoxBase extends PureComponent {
return false;
};
handleAppStateChange = (nextAppState) => {
if (nextAppState !== 'active') {
this.changeDraft(this.state.value);
}
};
handleEndEditing = (e) => {
if (e && e.nativeEvent) {
this.changeDraft(e.nativeEvent.text || '');