diff --git a/app/components/channel_link/__snapshots__/channel_link.test.js.snap b/app/components/channel_link/__snapshots__/channel_link.test.js.snap
new file mode 100644
index 000000000..56727ab3f
--- /dev/null
+++ b/app/components/channel_link/__snapshots__/channel_link.test.js.snap
@@ -0,0 +1,25 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ChannelLink should match snapshot 1`] = `
+
+
+ ~First Channel
+
+
+
+`;
diff --git a/app/components/channel_link/channel_link.js b/app/components/channel_link/channel_link.js
index f06dfc600..839c0330b 100644
--- a/app/components/channel_link/channel_link.js
+++ b/app/components/channel_link/channel_link.js
@@ -5,6 +5,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import {Text} from 'react-native';
+import {getChannelFromChannelName} from './channel_link_utils';
+
import CustomPropTypes from 'app/constants/custom_prop_types';
export default class ChannelLink extends React.PureComponent {
@@ -24,32 +26,14 @@ export default class ChannelLink extends React.PureComponent {
super(props);
this.state = {
- channel: this.getChannelFromChannelName(props),
+ channel: getChannelFromChannelName(props.channelName, props.channelsByName),
};
}
- componentWillReceiveProps(nextProps) {
- if (nextProps.channelName !== this.props.channelName || nextProps.channelsByName !== this.props.channelsByName) {
- this.setState({
- channel: this.getChannelFromChannelName(nextProps),
- });
- }
- }
-
- getChannelFromChannelName(props) {
- let channelName = props.channelName;
-
- while (channelName.length > 0) {
- if (props.channelsByName[channelName]) {
- return props.channelsByName[channelName];
- }
-
- // Repeatedly trim off trailing punctuation in case this is at the end of a sentence
- if ((/[_-]$/).test(channelName)) {
- channelName = channelName.substring(0, channelName.length - 1);
- } else {
- break;
- }
+ static getDerivedStateFromProps(nextProps, prevState) {
+ const nextChannel = getChannelFromChannelName(nextProps.channelName, nextProps.channelsByName);
+ if (nextChannel !== prevState.channel) {
+ return {channel: nextChannel};
}
return null;
diff --git a/app/components/channel_link/channel_link.test.js b/app/components/channel_link/channel_link.test.js
new file mode 100644
index 000000000..7d1732646
--- /dev/null
+++ b/app/components/channel_link/channel_link.test.js
@@ -0,0 +1,75 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import React from 'react';
+import {shallow} from 'enzyme';
+import {Text} from 'react-native';
+
+import ChannelLink from './channel_link';
+
+describe('ChannelLink', () => {
+ const channelsByName = {
+ firstChannel: {id: 'channel_id_1', name: 'firstChannel', display_name: 'First Channel'},
+ secondChannel: {id: 'channel_id_2', name: 'secondChannel', display_name: 'Second Channel'},
+ };
+ const baseProps = {
+ channelName: 'firstChannel',
+ linkStyle: {color: '#2389d7'},
+ onChannelLinkPress: jest.fn(),
+ textStyle: {color: '#3d3c40', fontSize: 15, lineHeight: 20},
+ channelsByName,
+ actions: {
+ handleSelectChannel: jest.fn(),
+ setChannelDisplayName: jest.fn(),
+ },
+ };
+
+ test('should match snapshot', () => {
+ const wrapper = shallow(
+
+ );
+
+ expect(wrapper.getElement()).toMatchSnapshot();
+ expect(wrapper.find(Text).length).toBe(2);
+
+ // inner text with highlight
+ let innerText = wrapper.find(Text).last();
+ expect(innerText.props().onPress).toBeDefined();
+ expect(innerText.props().style.color).toBe('#2389d7');
+ expect(innerText.props().children).toContain(channelsByName.firstChannel.display_name);
+
+ // text for channel name with punctuation
+ const punctuation = '-_';
+ wrapper.setProps({channelName: baseProps.channelName + punctuation});
+ expect(wrapper.find(Text).length).toBe(2);
+ innerText = wrapper.find(Text).last();
+ const outerText = wrapper.find(Text).first();
+ expect(innerText.props().onPress).toBeDefined();
+ expect(innerText.props().children).toContain(channelsByName.firstChannel.display_name);
+ expect(outerText.props().children).toContain(punctuation);
+
+ // text for not found channel
+ const notFoundChannel = 'notFoundChannel';
+ wrapper.setProps({channelName: notFoundChannel});
+ expect(wrapper.find(Text).length).toBe(1);
+ innerText = wrapper.find(Text).first();
+ expect(innerText.props().children).toContain(notFoundChannel);
+ expect(innerText.props().onPress).not.toBeDefined();
+ });
+
+ test('should call props.actions and onChannelLinkPress on handlePress', () => {
+ const wrapper = shallow(
+
+ );
+
+ const channel = channelsByName.firstChannel;
+ wrapper.setState({channel});
+ wrapper.instance().handlePress();
+ expect(baseProps.actions.handleSelectChannel).toHaveBeenCalledTimes(1);
+ expect(baseProps.actions.handleSelectChannel).toBeCalledWith(channel.id);
+ expect(baseProps.actions.setChannelDisplayName).toHaveBeenCalledTimes(1);
+ expect(baseProps.actions.setChannelDisplayName).toBeCalledWith(channel.display_name);
+ expect(baseProps.onChannelLinkPress).toHaveBeenCalledTimes(1);
+ expect(baseProps.onChannelLinkPress).toBeCalledWith(channel);
+ });
+});
diff --git a/app/components/channel_link/channel_link_utils.js b/app/components/channel_link/channel_link_utils.js
new file mode 100644
index 000000000..1d71e57d4
--- /dev/null
+++ b/app/components/channel_link/channel_link_utils.js
@@ -0,0 +1,21 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+export function getChannelFromChannelName(name, channelsByName) {
+ let channelName = name;
+
+ while (channelName.length > 0) {
+ if (channelsByName[channelName]) {
+ return channelsByName[channelName];
+ }
+
+ // Repeatedly trim off trailing punctuation in case this is at the end of a sentence
+ if ((/[_-]$/).test(channelName)) {
+ channelName = channelName.substring(0, channelName.length - 1);
+ } else {
+ break;
+ }
+ }
+
+ return null;
+}
diff --git a/app/components/channel_link/channel_link_utils.test.js b/app/components/channel_link/channel_link_utils.test.js
new file mode 100644
index 000000000..b70a08359
--- /dev/null
+++ b/app/components/channel_link/channel_link_utils.test.js
@@ -0,0 +1,46 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import {getChannelFromChannelName} from './channel_link_utils';
+
+describe('should match return value on getChannelFromChannelName', () => {
+ const channelsByName = {
+ firstChannel: {id: 'channel_id_1', name: 'firstChannel', display_name: 'First Channel'},
+ secondChannel: {id: 'channel_id_2', name: 'secondChannel', display_name: 'Second Channel'},
+ };
+
+ const testCases = [
+ {
+ name: 'regular mention',
+ input: {channelName: 'firstChannel', channelsByName},
+ output: channelsByName.firstChannel,
+ },
+ {
+ name: 'another mention',
+ input: {channelName: 'secondChannel', channelsByName},
+ output: channelsByName.secondChannel,
+ },
+ {
+ name: 'channel mention with trailing punctuation',
+ input: {channelName: 'firstChannel-', channelsByName},
+ output: channelsByName.firstChannel,
+ },
+ {
+ name: 'channel mention with trailing punctuations',
+ input: {channelName: 'firstChannel-_', channelsByName},
+ output: channelsByName.firstChannel,
+ },
+ {
+ name: 'channel mention not found in channelsByName',
+ input: {channelName: 'otherChannel', channelsByName},
+ output: null,
+ },
+ ];
+
+ for (const testCase of testCases) {
+ const {name, input, output} = testCase;
+ test(name, () => {
+ expect(getChannelFromChannelName(input.channelName, input.channelsByName)).toEqual(output);
+ });
+ }
+});