diff --git a/webapp/channels/src/components/post/post_component.test.tsx b/webapp/channels/src/components/post/post_component.test.tsx
index 1285cf6d66f..88dbad2b073 100644
--- a/webapp/channels/src/components/post/post_component.test.tsx
+++ b/webapp/channels/src/components/post/post_component.test.tsx
@@ -5,30 +5,39 @@ import React from 'react';
import {DeepPartial} from '@mattermost/types/utilities';
-import {renderWithFullContext, screen} from 'tests/react_testing_utils';
+import mergeObjects from 'packages/mattermost-redux/test/merge_objects';
+
+import {renderWithFullContext, screen, userEvent} from 'tests/react_testing_utils';
import {GlobalState} from 'types/store';
+import {getHistory} from 'utils/browser_history';
import {Locations} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
-import PostComponent from './post_component';
-import mergeObjects from 'packages/mattermost-redux/test/merge_objects';
+import PostComponent, {Props} from './post_component';
describe('PostComponent', () => {
- const baseProps = {
+ const currentTeam = TestHelper.getTeamMock();
+ const channel = TestHelper.getChannelMock({team_id: currentTeam.id});
+
+ const baseProps: Props = {
center: false,
- currentTeam: TestHelper.getTeamMock(),
+ currentTeam,
currentUserId: 'currentUserId',
displayName: '',
+ hasReplies: false,
isBot: false,
+ isCollapsedThreadsEnabled: true,
isFlagged: false,
isMobileView: false,
isPostAcknowledgementsEnabled: false,
isPostPriorityEnabled: false,
location: Locations.CENTER,
- post: TestHelper.getPostMock(),
+ post: TestHelper.getPostMock({channel_id: channel.id}),
recentEmojis: [],
+ replyCount: 0,
+ team: currentTeam,
actions: {
markPostAsUnread: jest.fn(),
emitShortcutReactToLastPostFrom: jest.fn(),
@@ -56,12 +65,7 @@ describe('PostComponent', () => {
};
test('should show reactions in the center channel', () => {
- renderWithFullContext(
- ,
- baseState,
- );
+ renderWithFullContext(, baseState);
expect(screen.getByLabelText('reactions')).toBeInTheDocument();
});
@@ -75,56 +79,250 @@ describe('PostComponent', () => {
},
});
- const {rerender} = renderWithFullContext(
- ,
- state,
- );
+ let props: Props = {
+ ...baseProps,
+ location: Locations.RHS_ROOT,
+ };
+ const {rerender} = renderWithFullContext(, state);
expect(screen.getByLabelText('reactions')).toBeInTheDocument();
- rerender(
- ,
- );
+ props = {
+ ...baseProps,
+ location: Locations.RHS_COMMENT,
+ };
+ rerender();
expect(screen.getByLabelText('reactions')).toBeInTheDocument();
});
test('should show only show reactions in search results with pinned/saved posts visible', () => {
- const {rerender} = renderWithFullContext(
- ,
- baseState,
- );
+ let props = {
+ ...baseProps,
+ location: Locations.SEARCH,
+ };
+ const {rerender} = renderWithFullContext(, baseState);
expect(screen.queryByLabelText('reactions')).not.toBeInTheDocument();
- rerender(
- ,
- );
+ props = {
+ ...baseProps,
+ location: Locations.SEARCH,
+ isPinnedPosts: true,
+ };
+ rerender();
expect(screen.getByLabelText('reactions')).toBeInTheDocument();
- rerender(
- ,
- );
+ props = {
+ ...baseProps,
+ location: Locations.SEARCH,
+ isFlaggedPosts: true,
+ };
+ rerender();
expect(screen.getByLabelText('reactions')).toBeInTheDocument();
});
});
+
+ describe('thread footer', () => {
+ test('should never show thread footer for a post that isn\'t part of a thread', () => {
+ let props: Props = baseProps;
+ const {rerender} = renderWithFullContext();
+
+ expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument();
+
+ props = {
+ ...baseProps,
+ location: Locations.SEARCH,
+ };
+ rerender();
+
+ expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument();
+ });
+
+ // This probably shouldn't appear in the search results https://mattermost.atlassian.net/browse/MM-53078
+ test('should only show thread footer for a root post in the center channel and search results', () => {
+ const rootPost = TestHelper.getPostMock({
+ id: 'rootPost',
+ channel_id: channel.id,
+ reply_count: 1,
+ });
+ const state: DeepPartial = {
+ entities: {
+ posts: {
+ posts: {
+ rootPost,
+ },
+ },
+ },
+ };
+
+ let props = {
+ ...baseProps,
+ hasReplies: true,
+ post: rootPost,
+ replyCount: 1,
+ };
+ const {rerender} = renderWithFullContext(, state);
+
+ expect(screen.queryByText(/Follow|Following/)).toBeInTheDocument();
+
+ props = {
+ ...props,
+ location: Locations.RHS_ROOT,
+ };
+ rerender();
+
+ expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument();
+
+ props = {
+ ...props,
+ location: Locations.SEARCH,
+ };
+ rerender();
+
+ expect(screen.queryByText(/Follow|Following/)).toBeInTheDocument();
+ });
+
+ test('should never show thread footer for a comment', () => {
+ let props = {
+ ...baseProps,
+ hasReplies: true,
+ post: {
+ ...baseProps.post,
+ root_id: 'some_other_post_id',
+ },
+ };
+ const {rerender} = renderWithFullContext();
+
+ expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument();
+
+ props = {
+ ...props,
+ location: Locations.RHS_COMMENT,
+ };
+ rerender();
+
+ expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument();
+
+ props = {
+ ...props,
+ location: Locations.SEARCH,
+ };
+ rerender();
+
+ expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument();
+ });
+
+ test('should not show thread footer with CRT disabled', () => {
+ const rootPost = TestHelper.getPostMock({
+ id: 'rootPost',
+ channel_id: channel.id,
+ reply_count: 1,
+ });
+ const state: DeepPartial = {
+ entities: {
+ posts: {
+ posts: {
+ rootPost,
+ },
+ },
+ },
+ };
+
+ let props = {
+ ...baseProps,
+ hasReplies: true,
+ isCollapsedThreadsEnabled: false,
+ post: rootPost,
+ replyCount: 1,
+ };
+ const {rerender} = renderWithFullContext(, state);
+
+ expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument();
+
+ props = {
+ ...props,
+ location: Locations.SEARCH,
+ };
+ rerender();
+
+ expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument();
+ });
+
+ describe('reply/X replies link', () => {
+ const rootPost = TestHelper.getPostMock({
+ id: 'rootPost',
+ channel_id: channel.id,
+ reply_count: 1,
+ });
+ const state: DeepPartial = {
+ entities: {
+ posts: {
+ posts: {
+ rootPost,
+ },
+ },
+ },
+ };
+
+ const propsForRootPost = {
+ ...baseProps,
+ hasReplies: true,
+ post: rootPost,
+ replyCount: 1,
+ };
+
+ test('should select post in RHS when clicked in center channel', () => {
+ renderWithFullContext(, state);
+
+ userEvent.click(screen.getByText('1 reply'));
+
+ // Yes, this action has a different name than the one you'd expect
+ expect(propsForRootPost.actions.selectPostFromRightHandSideSearch).toHaveBeenCalledWith(rootPost);
+ });
+
+ test('should select post in RHS when clicked in center channel in a DM/GM', () => {
+ const props = {
+ ...propsForRootPost,
+ team: undefined,
+ };
+ renderWithFullContext(, state);
+
+ userEvent.click(screen.getByText('1 reply'));
+
+ // Yes, this action has a different name than the one you'd expect
+ expect(propsForRootPost.actions.selectPostFromRightHandSideSearch).toHaveBeenCalledWith(rootPost);
+ expect(getHistory().push).not.toHaveBeenCalled();
+ });
+
+ test('should select post in RHS when clicked in a search result on the current team', () => {
+ const props = {
+ ...propsForRootPost,
+ location: Locations.SEARCH,
+ };
+ renderWithFullContext(, state);
+
+ userEvent.click(screen.getByText('1 reply'));
+
+ expect(propsForRootPost.actions.selectPostFromRightHandSideSearch).toHaveBeenCalledWith(rootPost);
+ expect(getHistory().push).not.toHaveBeenCalled();
+ });
+
+ test('should jump to post when clicked in a search result on another team', () => {
+ const props = {
+ ...propsForRootPost,
+ location: Locations.SEARCH,
+ team: TestHelper.getTeamMock({id: 'another_team'}),
+ };
+ renderWithFullContext(, state);
+
+ userEvent.click(screen.getByText('1 reply'));
+
+ expect(propsForRootPost.actions.selectPostFromRightHandSideSearch).not.toHaveBeenCalled();
+ expect(getHistory().push).toHaveBeenCalled();
+ });
+ });
+ });
});
diff --git a/webapp/channels/src/components/post/post_component.tsx b/webapp/channels/src/components/post/post_component.tsx
index ace78e7bf4f..2ae035d3831 100644
--- a/webapp/channels/src/components/post/post_component.tsx
+++ b/webapp/channels/src/components/post/post_component.tsx
@@ -82,7 +82,7 @@ export type Props = {
channelType?: string;
a11yIndex?: number;
isBot: boolean;
- hasReplies?: boolean;
+ hasReplies: boolean;
isFirstReply?: boolean;
previousPostIsComment?: boolean;
matches?: string[];