diff --git a/src/discussions/comments/CommentsView.jsx b/src/discussions/comments/CommentsView.jsx index a9b2f4f2..f2e0acab 100644 --- a/src/discussions/comments/CommentsView.jsx +++ b/src/discussions/comments/CommentsView.jsx @@ -139,7 +139,7 @@ function DiscussionCommentsView({ <> {handleDefinition(messages.endorsedResponseCount, endorsedComments.length)} {endorsed === EndorsementStatus.DISCUSSION - ? handleComments(endorsedComments, false, false) + ? handleComments(endorsedComments, true, false) : handleComments(endorsedComments, false, false)} )} @@ -147,7 +147,7 @@ function DiscussionCommentsView({ <> {handleDefinition(messages.responseCount, unEndorsedComments.length)} {unEndorsedComments.length === 0 &&
} - {handleComments(unEndorsedComments, true)} + {handleComments(unEndorsedComments, false, true)} {(userCanAddThreadInBlackoutDate && !!unEndorsedComments.length && !isClosed) && (
{!addingResponse && ( @@ -216,7 +216,13 @@ function CommentsView({ intl }) { ); } return ( - +
+ +
); } diff --git a/src/discussions/comments/CommentsView.test.jsx b/src/discussions/comments/CommentsView.test.jsx index 861ec88c..70ee2d5c 100644 --- a/src/discussions/comments/CommentsView.test.jsx +++ b/src/discussions/comments/CommentsView.test.jsx @@ -155,577 +155,600 @@ describe('CommentsView', () => { mockAxiosReturnPagedCommentsResponses(); }); - // describe('for all post types', () => { - // function assertLastUpdateData(data) { - // expect(JSON.parse(axiosMock.history.patch[axiosMock.history.patch.length - 1].data)).toMatchObject(data); - // } + describe('for all post types', () => { + function assertLastUpdateData(data) { + expect(JSON.parse(axiosMock.history.patch[axiosMock.history.patch.length - 1].data)).toMatchObject(data); + } - // it('should show and hide the editor', async () => { - // renderComponent(discussionPostId); - // await waitFor(() => screen.findByText('comment number 1', { exact: false })); - // const addResponseButtons = screen.getAllByRole('button', { name: /add a response/i }); - // await act(async () => { - // fireEvent.click( - // addResponseButtons[0], - // ); - // }); - // expect(screen.queryByTestId('tinymce-editor')).toBeInTheDocument(); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /cancel/i })); - // }); - // expect(screen.queryByTestId('tinymce-editor')).not.toBeInTheDocument(); - // }); + it('should show and hide the editor', async () => { + renderComponent(discussionPostId); + await waitFor(() => screen.findByText('comment number 1', { exact: false })); + const addResponseButtons = screen.getAllByRole('button', { name: /add a response/i }); + await act(async () => { + fireEvent.click( + addResponseButtons[0], + ); + }); + expect(screen.queryByTestId('tinymce-editor')).toBeInTheDocument(); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /cancel/i })); + }); + expect(screen.queryByTestId('tinymce-editor')).not.toBeInTheDocument(); + }); - // it('should allow posting a response', async () => { - // renderComponent(discussionPostId); - // await waitFor(() => screen.findByText('comment number 1', { exact: false })); - // const responseButtons = screen.getAllByRole('button', { name: /add a response/i }); - // await act(async () => { - // fireEvent.click( - // responseButtons[0], - // ); - // }); - // await act(() => { - // fireEvent.change(screen.getByTestId('tinymce-editor'), { target: { value: 'testing123' } }); - // }); + it('should allow posting a response', async () => { + renderComponent(discussionPostId); + await waitFor(() => screen.findByText('comment number 1', { exact: false })); + const responseButtons = screen.getAllByRole('button', { name: /add a response/i }); + await act(async () => { + fireEvent.click( + responseButtons[0], + ); + }); + await act(() => { + fireEvent.change(screen.getByTestId('tinymce-editor'), { target: { value: 'testing123' } }); + }); - // await act(async () => { - // fireEvent.click( - // screen.getByText(/submit/i), - // ); - // }); - // expect(screen.queryByTestId('tinymce-editor')).not.toBeInTheDocument(); - // await waitFor(async () => expect(await screen.findByText('testing123', { exact: false })).toBeInTheDocument()); - // }); + await act(async () => { + fireEvent.click( + screen.getByText(/submit/i), + ); + }); + expect(screen.queryByTestId('tinymce-editor')).not.toBeInTheDocument(); + await waitFor(async () => expect(await screen.findByText('testing123', { exact: false })).toBeInTheDocument()); + }); - // it('should not allow posting a response on a closed post', async () => { - // renderComponent(closedPostId); - // await waitFor(() => screen.findByText('Thread-2', { exact: false })); - // expect(screen.queryByRole('button', { name: /add a response/i })).not.toBeInTheDocument(); - // }); + it('should not allow posting a response on a closed post', async () => { + renderComponent(closedPostId); + await waitFor(() => screen.findByText('Thread-2', { exact: false })); + expect(screen.queryByRole('button', { name: /add response/i })).not.toBeInTheDocument(); + }); - // it('should allow posting a comment', async () => { - // renderComponent(discussionPostId); - // await waitFor(() => screen.findByText('comment number 1', { exact: false })); - // await act(async () => { - // fireEvent.click( - // screen.getAllByRole('button', { name: /add a comment/i })[0], - // ); - // }); - // act(() => { - // fireEvent.change(screen.getByTestId('tinymce-editor'), { target: { value: 'testing123' } }); - // }); + it('should allow posting a comment', async () => { + renderComponent(discussionPostId); + await act(async () => { + fireEvent.mouseOver(await waitFor(() => screen.findByText('comment number 1', { exact: false }))); + }); + await act(async () => { + fireEvent.click( + screen.getAllByRole('button', { name: /add comment/i })[0], + ); + }); + act(() => { + fireEvent.change(screen.getByTestId('tinymce-editor'), { target: { value: 'testing123' } }); + }); - // await act(async () => { - // fireEvent.click( - // screen.getByText(/submit/i), - // ); - // }); - // expect(screen.queryByTestId('tinymce-editor')).not.toBeInTheDocument(); - // await waitFor(async () => expect(await screen.findByText('testing123', { exact: false })).toBeInTheDocument()); - // }); + await act(async () => { + fireEvent.click( + screen.getByText(/submit/i), + ); + }); + expect(screen.queryByTestId('tinymce-editor')).not.toBeInTheDocument(); + await waitFor(async () => expect(await screen.findByText('testing123', { exact: false })).toBeInTheDocument()); + }); - // it('should not allow posting a comment on a closed post', async () => { - // renderComponent(closedPostId); - // await waitFor(() => screen.findByText('thread-2', { exact: false })); - // await act(async () => { - // expect( - // screen.queryByRole('button', { name: /add a comment/i }), - // ).not.toBeInTheDocument(); - // }); - // }); + it('should not allow posting a comment on a closed post', async () => { + renderComponent(closedPostId); + await waitFor(() => screen.findByText('thread-2', { exact: false })); + await act(async () => { + expect( + screen.queryByRole('button', { name: /add a comment/i }), + ).not.toBeInTheDocument(); + }); + }); - // it('should allow editing an existing comment', async () => { - // renderComponent(discussionPostId); - // await waitFor(() => screen.findByText('comment number 1', { exact: false })); - // await act(async () => { - // fireEvent.click( - // // The first edit menu is for the post, the second will be for the first comment. - // screen.getAllByRole('button', { name: /actions menu/i })[1], - // ); - // }); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /edit/i })); - // }); - // act(() => { - // fireEvent.change(screen.getByTestId('tinymce-editor'), { target: { value: 'testing123' } }); - // }); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /submit/i })); - // }); - // await waitFor(async () => { - // expect(await screen.findByText('testing123', { exact: false })).toBeInTheDocument(); - // }); - // }); + it('should allow editing an existing comment', async () => { + renderComponent(discussionPostId); + await act(async () => { + fireEvent.mouseOver(await waitFor(() => screen.findByText('comment number 1', { exact: false }))); + }); + await act(async () => { + fireEvent.click( + // The first edit menu is for the post, the second will be for the first comment. + screen.getAllByRole('button', { name: /actions menu/i })[1], + ); + }); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /edit/i })); + }); + act(() => { + fireEvent.change(screen.getByTestId('tinymce-editor'), { target: { value: 'testing123' } }); + }); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /submit/i })); + }); + await waitFor(async () => { + expect(await screen.findByText('testing123', { exact: false })).toBeInTheDocument(); + }); + }); - // async function setupCourseConfig(reasonCodesEnabled = true) { - // axiosMock.onGet(`${courseConfigApiUrl}${courseId}/`).reply(200, { - // has_moderation_privileges: true, - // reason_codes_enabled: reasonCodesEnabled, - // editReasons: [ - // { code: 'reason-1', label: 'reason 1' }, - // { code: 'reason-2', label: 'reason 2' }, - // ], - // postCloseReasons: [ - // { code: 'reason-1', label: 'reason 1' }, - // { code: 'reason-2', label: 'reason 2' }, - // ], - // }); - // axiosMock.onGet(`${courseConfigApiUrl}${courseId}/settings`).reply(200, {}); - // await executeThunk(fetchCourseConfig(courseId), store.dispatch, store.getState); - // } + async function setupCourseConfig(reasonCodesEnabled = true) { + axiosMock.onGet(`${courseConfigApiUrl}${courseId}/`).reply(200, { + has_moderation_privileges: true, + reason_codes_enabled: reasonCodesEnabled, + editReasons: [ + { code: 'reason-1', label: 'reason 1' }, + { code: 'reason-2', label: 'reason 2' }, + ], + postCloseReasons: [ + { code: 'reason-1', label: 'reason 1' }, + { code: 'reason-2', label: 'reason 2' }, + ], + }); + axiosMock.onGet(`${courseConfigApiUrl}${courseId}/settings`).reply(200, {}); + await executeThunk(fetchCourseConfig(courseId), store.dispatch, store.getState); + } - // it('should show reason codes when editing an existing comment', async () => { - // setupCourseConfig(); - // renderComponent(discussionPostId); - // await waitFor(() => screen.findByText('comment number 1', { exact: false })); - // await act(async () => { - // fireEvent.click( - // // The first edit menu is for the post, the second will be for the first comment. - // screen.getAllByRole('button', { name: /actions menu/i })[1], - // ); - // }); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /edit/i })); - // }); - // expect(screen.queryByRole('combobox', { name: /reason for editing/i })).toBeInTheDocument(); - // expect(screen.getAllByRole('option', { name: /reason \d/i })).toHaveLength(2); - // await act(async () => { - // fireEvent.change(screen.queryByRole('combobox', { name: /reason for editing/i }), { target: { value: null } }); - // }); - // await act(async () => { - // fireEvent.change(screen.queryByRole('combobox', { name: /reason for editing/i }), { target: { value: 'reason-1' } }); - // }); - // await act(async () => { - // fireEvent.change(screen.getByTestId('tinymce-editor'), { target: { value: 'testing123' } }); - // }); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /submit/i })); - // }); - // assertLastUpdateData({ edit_reason_code: 'reason-1' }); - // }); + it('should show reason codes when editing an existing comment', async () => { + setupCourseConfig(); + renderComponent(discussionPostId); + await act(async () => { + fireEvent.mouseOver(await waitFor(() => screen.findByText('comment number 1', { exact: false }))); + }); + await act(async () => { + fireEvent.click( + // The first edit menu is for the post, the second will be for the first comment. + screen.getAllByRole('button', { name: /actions menu/i })[1], + ); + }); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /edit/i })); + }); + expect(screen.queryByRole('combobox', { name: /reason for editing/i })).toBeInTheDocument(); + expect(screen.getAllByRole('option', { name: /reason \d/i })).toHaveLength(2); + await act(async () => { + fireEvent.change(screen.queryByRole('combobox', { name: /reason for editing/i }), { target: { value: null } }); + }); + await act(async () => { + fireEvent.change(screen.queryByRole('combobox', { name: /reason for editing/i }), { target: { value: 'reason-1' } }); + }); + await act(async () => { + fireEvent.change(screen.getByTestId('tinymce-editor'), { target: { value: 'testing123' } }); + }); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /submit/i })); + }); + assertLastUpdateData({ edit_reason_code: 'reason-1' }); + }); - // it('should show reason codes when closing a post', async () => { - // setupCourseConfig(); - // renderComponent(discussionPostId); - // await act(async () => { - // fireEvent.click( - // // The first edit menu is for the post - // screen.getAllByRole('button', { - // name: /actions menu/i, - // })[0], - // ); - // }); - // expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /close/i })); - // }); - // expect(screen.queryByRole('dialog', { name: /close post/i })).toBeInTheDocument(); - // expect(screen.queryByRole('combobox', { name: /reason/i })).toBeInTheDocument(); - // expect(screen.getAllByRole('option', { name: /reason \d/i })).toHaveLength(2); - // await act(async () => { - // fireEvent.change(screen.queryByRole('combobox', { name: /reason/i }), { target: { value: 'reason-1' } }); - // }); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /close post/i })); - // }); - // expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); - // assertLastUpdateData({ closed: true, close_reason_code: 'reason-1' }); - // }); + it('should show reason codes when closing a post', async () => { + setupCourseConfig(); + renderComponent(discussionPostId); + await act(async () => { + fireEvent.mouseOver(screen.getByTestId('post-thread-1')); + }); + await act(async () => { + fireEvent.click( + // The first edit menu is for the post + screen.getAllByRole('button', { + name: /actions menu/i, + })[0], + ); + }); + expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /close/i })); + }); + expect(screen.queryByRole('dialog', { name: /close post/i })).toBeInTheDocument(); + expect(screen.queryByRole('combobox', { name: /reason/i })).toBeInTheDocument(); + expect(screen.getAllByRole('option', { name: /reason \d/i })).toHaveLength(2); + await act(async () => { + fireEvent.change(screen.queryByRole('combobox', { name: /reason/i }), { target: { value: 'reason-1' } }); + }); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /close post/i })); + }); + expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); + assertLastUpdateData({ closed: true, close_reason_code: 'reason-1' }); + }); - // it('should close the post directly if reason codes are not enabled', async () => { - // setupCourseConfig(false); - // renderComponent(discussionPostId); - // await act(async () => { - // fireEvent.click( - // // The first edit menu is for the post - // screen.getAllByRole('button', { name: /actions menu/i })[0], - // ); - // }); - // expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /close/i })); - // }); - // expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); - // assertLastUpdateData({ closed: true }); - // }); + it('should close the post directly if reason codes are not enabled', async () => { + setupCourseConfig(false); + renderComponent(discussionPostId); + await act(async () => { + fireEvent.mouseOver(screen.getByTestId('post-thread-1')); + }); + await act(async () => { + fireEvent.click( + // The first edit menu is for the post + screen.getAllByRole('button', { name: /actions menu/i })[0], + ); + }); + expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /close/i })); + }); + expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); + assertLastUpdateData({ closed: true }); + }); - // it.each([true, false])( - // 'should reopen the post directly when reason codes enabled=%s', - // async (reasonCodesEnabled) => { - // setupCourseConfig(reasonCodesEnabled); - // renderComponent(closedPostId); - // await act(async () => { - // fireEvent.click( - // // The first edit menu is for the post - // screen.getAllByRole('button', { name: /actions menu/i })[0], - // ); - // }); - // expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /reopen/i })); - // }); - // expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); - // assertLastUpdateData({ closed: false }); - // }, - // ); + it.each([true, false])( + 'should reopen the post directly when reason codes enabled=%s', + async (reasonCodesEnabled) => { + setupCourseConfig(reasonCodesEnabled); + renderComponent(closedPostId); + await act(async () => { + fireEvent.mouseOver(screen.getByTestId('post-thread-2')); + }); + await act(async () => { + fireEvent.click( + // The first edit menu is for the post + screen.getAllByRole('button', { name: /actions menu/i })[0], + ); + }); + expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /reopen/i })); + }); + expect(screen.queryByRole('dialog', { name: /close post/i })).not.toBeInTheDocument(); + assertLastUpdateData({ closed: false }); + }, + ); - // it('should show the editor if the post is edited', async () => { - // setupCourseConfig(false); - // renderComponent(discussionPostId); - // await act(async () => { - // fireEvent.click( - // // The first edit menu is for the post - // screen.getAllByRole('button', { name: /actions menu/i })[0], - // ); - // }); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /edit/i })); - // }); - // expect(testLocation.pathname).toBe(`/${courseId}/posts/${discussionPostId}/edit`); - // }); + it('should show the editor if the post is edited', async () => { + setupCourseConfig(false); + renderComponent(discussionPostId); + await act(async () => { + fireEvent.mouseOver(screen.getByTestId('post-thread-1')); + }); + await act(async () => { + fireEvent.click( + // The first edit menu is for the post + screen.getAllByRole('button', { name: /actions menu/i })[0], + ); + }); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /edit/i })); + }); + expect(testLocation.pathname).toBe(`/${courseId}/posts/${discussionPostId}/edit`); + }); - // it('should allow pinning the post', async () => { - // renderComponent(discussionPostId); - // await act(async () => { - // fireEvent.click( - // // The first edit menu is for the post - // screen.getAllByRole('button', { name: /actions menu/i })[0], - // ); - // }); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /pin/i })); - // }); - // assertLastUpdateData({ pinned: false }); - // }); + it('should allow pinning the post', async () => { + renderComponent(discussionPostId); + await act(async () => { + fireEvent.mouseOver(screen.getByTestId('post-thread-1')); + }); + await act(async () => { + fireEvent.click( + // The first edit menu is for the post + screen.getAllByRole('button', { name: /actions menu/i })[0], + ); + }); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /pin/i })); + }); + assertLastUpdateData({ pinned: false }); + }); - // it('should allow reporting the post', async () => { - // renderComponent(discussionPostId); - // await act(async () => { - // fireEvent.click( - // // The first edit menu is for the post - // screen.getAllByRole('button', { name: /actions menu/i })[0], - // ); - // }); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /report/i })); - // }); - // expect(screen.queryByRole('dialog', { name: /Report \w+/i, exact: false })).toBeInTheDocument(); - // await act(async () => { - // fireEvent.click(screen.queryByRole('button', { name: /Confirm/i })); - // }); - // expect(screen.queryByRole('dialog', { name: /Report \w+/i, exact: false })).not.toBeInTheDocument(); - // assertLastUpdateData({ abuse_flagged: true }); - // }); + it('should allow reporting the post', async () => { + renderComponent(discussionPostId); + await act(async () => { + fireEvent.mouseOver(screen.getByTestId('post-thread-1')); + }); + await act(async () => { + fireEvent.click( + // The first edit menu is for the post + screen.getAllByRole('button', { name: /actions menu/i })[0], + ); + }); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /report/i })); + }); + expect(screen.queryByRole('dialog', { name: /Report \w+/i, exact: false })).toBeInTheDocument(); + await act(async () => { + fireEvent.click(screen.queryByRole('button', { name: /Confirm/i })); + }); + expect(screen.queryByRole('dialog', { name: /Report \w+/i, exact: false })).not.toBeInTheDocument(); + assertLastUpdateData({ abuse_flagged: true }); + }); - // it('handles liking a comment', async () => { - // renderComponent(discussionPostId); + it('handles liking a comment', async () => { + renderComponent(discussionPostId); - // // Wait for the content to load - // await screen.findByText('comment number 7', { exact: false }); - // const view = screen.getByTestId('comment-comment-1'); + // Wait for the content to load + await act(async () => { + fireEvent.mouseOver(await waitFor(() => screen.findByText('comment number 7', { exact: false }))); + }); + const view = screen.getByTestId('comment-comment-1'); - // const likeButton = within(view).getByRole('button', { name: /like/i }); - // await act(async () => { - // fireEvent.click(likeButton); - // }); - // expect(axiosMock.history.patch).toHaveLength(2); - // expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ voted: true }); - // }); + const likeButton = within(view).getByRole('button', { name: /like/i }); + await act(async () => { + fireEvent.click(likeButton); + }); + expect(axiosMock.history.patch).toHaveLength(2); + expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ voted: true }); + }); - // it('handles endorsing comments', async () => { - // renderComponent(discussionPostId); - // // Wait for the content to load - // await screen.findByText('comment number 7', { exact: false }); + it('handles endorsing comments', async () => { + renderComponent(discussionPostId); + // Wait for the content to load + await act(async () => { + fireEvent.mouseOver(await waitFor(() => screen.findByText('comment number 7', { exact: false }))); + }); - // // There should be three buttons, one for the post, the second for the - // // comment and the third for a response to that comment - // const actionButtons = screen.queryAllByRole('button', { name: /actions menu/i }); - // await act(async () => { - // fireEvent.click(actionButtons[1]); - // }); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /Endorse/i })); + }); + expect(axiosMock.history.patch).toHaveLength(2); + expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ endorsed: true }); + }); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /Endorse/i })); - // }); - // expect(axiosMock.history.patch).toHaveLength(2); - // expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ endorsed: true }); - // }); + it('handles reporting comments', async () => { + renderComponent(discussionPostId); + // Wait for the content to load + await act(async () => { + fireEvent.mouseOver(await waitFor(() => screen.findByText('comment number 7', { exact: false }))); + }); + const actionButtons = screen.queryAllByRole('button', { name: /actions menu/i }); + await act(async () => { + fireEvent.click(actionButtons[0]); + }); - // it('handles reporting comments', async () => { - // renderComponent(discussionPostId); - // // Wait for the content to load - // await screen.findByText('comment number 7', { exact: false }); + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: /Report/i })); + }); + expect(screen.queryByRole('dialog', { name: /Report \w+/i, exact: false })).toBeInTheDocument(); + await act(async () => { + fireEvent.click(screen.queryByRole('button', { name: /Confirm/i })); + }); + expect(screen.queryByRole('dialog', { name: /Report \w+/i, exact: false })).not.toBeInTheDocument(); + expect(axiosMock.history.patch).toHaveLength(2); + expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ abuse_flagged: true }); + }); + }); - // // There should be three buttons, one for the post, the second for the - // // comment and the third for a response to that comment - // const actionButtons = screen.queryAllByRole('button', { name: /actions menu/i }); - // await act(async () => { - // fireEvent.click(actionButtons[1]); - // }); + describe('for discussion thread', () => { + const findLoadMoreCommentsButton = () => screen.findByTestId('load-more-comments'); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /Report/i })); - // }); - // expect(screen.queryByRole('dialog', { name: /Report \w+/i, exact: false })).toBeInTheDocument(); - // await act(async () => { - // fireEvent.click(screen.queryByRole('button', { name: /Confirm/i })); - // }); - // expect(screen.queryByRole('dialog', { name: /Report \w+/i, exact: false })).not.toBeInTheDocument(); - // expect(axiosMock.history.patch).toHaveLength(2); - // expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ abuse_flagged: true }); - // }); - // }); + it('shown post not found when post id does not belong to course', async () => { + renderComponent('unloaded-id'); + expect(await screen.findByText('Thread not found', { exact: true })) + .toBeInTheDocument(); + }); - // describe('for discussion thread', () => { - // const findLoadMoreCommentsButton = () => screen.findByTestId('load-more-comments'); + it('initially loads only the first page', async () => { + renderComponent(discussionPostId); + expect(await screen.findByText('comment number 1', { exact: false })) + .toBeInTheDocument(); + expect(screen.queryByText('comment number 2', { exact: false })) + .not + .toBeInTheDocument(); + }); - // it('shown post not found when post id does not belong to course', async () => { - // renderComponent('unloaded-id'); - // expect(await screen.findByText('Thread not found', { exact: true })) - // .toBeInTheDocument(); - // }); + it('pressing load more button will load next page of comments', async () => { + renderComponent(discussionPostId); - // it('initially loads only the first page', async () => { - // renderComponent(discussionPostId); - // expect(await screen.findByText('comment number 1', { exact: false })) - // .toBeInTheDocument(); - // expect(screen.queryByText('comment number 2', { exact: false })) - // .not - // .toBeInTheDocument(); - // }); + const loadMoreButton = await findLoadMoreCommentsButton(); + fireEvent.click(loadMoreButton); - // it('pressing load more button will load next page of comments', async () => { - // renderComponent(discussionPostId); + await screen.findByText('comment number 1', { exact: false }); + await screen.findByText('comment number 2', { exact: false }); + }); - // const loadMoreButton = await findLoadMoreCommentsButton(); - // fireEvent.click(loadMoreButton); + it('newly loaded comments are appended to the old ones', async () => { + renderComponent(discussionPostId); - // await screen.findByText('comment number 1', { exact: false }); - // await screen.findByText('comment number 2', { exact: false }); - // }); + const loadMoreButton = await findLoadMoreCommentsButton(); + fireEvent.click(loadMoreButton); - // it('newly loaded comments are appended to the old ones', async () => { - // renderComponent(discussionPostId); + await screen.findByText('comment number 1', { exact: false }); + // check that comments from the first page are also displayed + expect(screen.queryByText('comment number 2', { exact: false })) + .toBeInTheDocument(); + }); - // const loadMoreButton = await findLoadMoreCommentsButton(); - // fireEvent.click(loadMoreButton); + it('load more button is hidden when no more comments pages to load', async () => { + const totalPages = 2; + renderComponent(discussionPostId); - // await screen.findByText('comment number 1', { exact: false }); - // // check that comments from the first page are also displayed - // expect(screen.queryByText('comment number 2', { exact: false })) - // .toBeInTheDocument(); - // }); + const loadMoreButton = await findLoadMoreCommentsButton(); + for (let page = 1; page < totalPages; page++) { + fireEvent.click(loadMoreButton); + } - // it('load more button is hidden when no more comments pages to load', async () => { - // const totalPages = 2; - // renderComponent(discussionPostId); + await screen.findByText('comment number 2', { exact: false }); + await expect(findLoadMoreCommentsButton()) + .rejects + .toThrow(); + }); + }); - // const loadMoreButton = await findLoadMoreCommentsButton(); - // for (let page = 1; page < totalPages; page++) { - // fireEvent.click(loadMoreButton); - // } + describe('for question thread', () => { + const findLoadMoreCommentsButtons = () => screen.findAllByTestId('load-more-comments'); - // await screen.findByText('comment number 2', { exact: false }); - // await expect(findLoadMoreCommentsButton()) - // .rejects - // .toThrow(); - // }); - // }); + it('initially loads only the first page', async () => { + act(() => renderComponent(questionPostId)); + expect(await screen.findByText('comment number 3', { exact: false })) + .toBeInTheDocument(); + expect(await screen.findByText('endorsed comment number 5', { exact: false })) + .toBeInTheDocument(); + expect(screen.queryByText('comment number 4', { exact: false })) + .not + .toBeInTheDocument(); + }); - // describe('for question thread', () => { - // const findLoadMoreCommentsButtons = () => screen.findAllByTestId('load-more-comments'); + it('pressing load more button will load next page of comments', async () => { + act(() => { + renderComponent(questionPostId); + }); - // it('initially loads only the first page', async () => { - // act(() => renderComponent(questionPostId)); - // expect(await screen.findByText('comment number 3', { exact: false })) - // .toBeInTheDocument(); - // expect(await screen.findByText('endorsed comment number 5', { exact: false })) - // .toBeInTheDocument(); - // expect(screen.queryByText('comment number 4', { exact: false })) - // .not - // .toBeInTheDocument(); - // }); + const [loadMoreButtonEndorsed, loadMoreButtonUnendorsed] = await findLoadMoreCommentsButtons(); + // Both load more buttons should show + expect(await findLoadMoreCommentsButtons()).toHaveLength(2); + expect(await screen.findByText('unendorsed comment number 3', { exact: false })) + .toBeInTheDocument(); + expect(await screen.findByText('endorsed comment number 5', { exact: false })) + .toBeInTheDocument(); + // Comments from next page should not be loaded yet. + expect(await screen.queryByText('endorsed comment number 6', { exact: false })) + .not + .toBeInTheDocument(); + expect(await screen.queryByText('unendorsed comment number 4', { exact: false })) + .not + .toBeInTheDocument(); - // it('pressing load more button will load next page of comments', async () => { - // act(() => { - // renderComponent(questionPostId); - // }); + await act(async () => { + fireEvent.click(loadMoreButtonEndorsed); + }); + // Endorsed comment from next page should be loaded now. + await waitFor(() => expect(screen.queryByText('endorsed comment number 6', { exact: false })) + .toBeInTheDocument()); + // Unendorsed comment from next page should not be loaded yet. + expect(await screen.queryByText('unendorsed comment number 4', { exact: false })) + .not + .toBeInTheDocument(); + // Now only one load more buttons should show, for unendorsed comments + expect(await findLoadMoreCommentsButtons()).toHaveLength(1); + await act(async () => { + fireEvent.click(loadMoreButtonUnendorsed); + }); + // Unendorsed comment from next page should be loaded now. + await waitFor(() => expect(screen.queryByText('unendorsed comment number 4', { exact: false })) + .toBeInTheDocument()); + await expect(findLoadMoreCommentsButtons()).rejects.toThrow(); + }); + }); - // const [loadMoreButtonEndorsed, loadMoreButtonUnendorsed] = await findLoadMoreCommentsButtons(); - // // Both load more buttons should show - // expect(await findLoadMoreCommentsButtons()).toHaveLength(2); - // expect(await screen.findByText('unendorsed comment number 3', { exact: false })) - // .toBeInTheDocument(); - // expect(await screen.findByText('endorsed comment number 5', { exact: false })) - // .toBeInTheDocument(); - // // Comments from next page should not be loaded yet. - // expect(await screen.queryByText('endorsed comment number 6', { exact: false })) - // .not - // .toBeInTheDocument(); - // expect(await screen.queryByText('unendorsed comment number 4', { exact: false })) - // .not - // .toBeInTheDocument(); + describe('comments responses', () => { + const findLoadMoreCommentsResponsesButton = () => screen.findByTestId('load-more-comments-responses'); - // await act(async () => { - // fireEvent.click(loadMoreButtonEndorsed); - // }); - // // Endorsed comment from next page should be loaded now. - // await waitFor(() => expect(screen.queryByText('endorsed comment number 6', { exact: false })) - // .toBeInTheDocument()); - // // Unendorsed comment from next page should not be loaded yet. - // expect(await screen.queryByText('unendorsed comment number 4', { exact: false })) - // .not - // .toBeInTheDocument(); - // // Now only one load more buttons should show, for unendorsed comments - // expect(await findLoadMoreCommentsButtons()).toHaveLength(1); - // await act(async () => { - // fireEvent.click(loadMoreButtonUnendorsed); - // }); - // // Unendorsed comment from next page should be loaded now. - // await waitFor(() => expect(screen.queryByText('unendorsed comment number 4', { exact: false })) - // .toBeInTheDocument()); - // await expect(findLoadMoreCommentsButtons()).rejects.toThrow(); - // }); - // }); + it('initially loads only the first page', async () => { + renderComponent(discussionPostId); - // describe('comments responses', () => { - // const findLoadMoreCommentsResponsesButton = () => screen.findByTestId('load-more-comments-responses'); + await waitFor(() => screen.findByText('comment number 7', { exact: false })); + expect(screen.queryByText('comment number 8', { exact: false })).not.toBeInTheDocument(); + }); - // it('initially loads only the first page', async () => { - // renderComponent(discussionPostId); + it('pressing load more button will load next page of responses', async () => { + renderComponent(discussionPostId); - // await waitFor(() => screen.findByText('comment number 7', { exact: false })); - // expect(screen.queryByText('comment number 8', { exact: false })).not.toBeInTheDocument(); - // }); + const loadMoreButton = await findLoadMoreCommentsResponsesButton(); + await act(async () => { + fireEvent.click(loadMoreButton); + }); - // it('pressing load more button will load next page of responses', async () => { - // renderComponent(discussionPostId); + await screen.findByText('comment number 8', { exact: false }); + }); - // const loadMoreButton = await findLoadMoreCommentsResponsesButton(); - // await act(async () => { - // fireEvent.click(loadMoreButton); - // }); + it('newly loaded responses are appended to the old ones', async () => { + renderComponent(discussionPostId); - // await screen.findByText('comment number 8', { exact: false }); - // }); + const loadMoreButton = await findLoadMoreCommentsResponsesButton(); + await act(async () => { + fireEvent.click(loadMoreButton); + }); - // it('newly loaded responses are appended to the old ones', async () => { - // renderComponent(discussionPostId); + await screen.findByText('comment number 8', { exact: false }); + // check that comments from the first page are also displayed + expect(screen.queryByText('comment number 7', { exact: false })).toBeInTheDocument(); + }); - // const loadMoreButton = await findLoadMoreCommentsResponsesButton(); - // await act(async () => { - // fireEvent.click(loadMoreButton); - // }); + it('load more button is hidden when no more responses pages to load', async () => { + const totalPages = 2; + renderComponent(discussionPostId); - // await screen.findByText('comment number 8', { exact: false }); - // // check that comments from the first page are also displayed - // expect(screen.queryByText('comment number 7', { exact: false })).toBeInTheDocument(); - // }); + const loadMoreButton = await findLoadMoreCommentsResponsesButton(); + for (let page = 1; page < totalPages; page++) { + act(() => { + fireEvent.click(loadMoreButton); + }); + } - // it('load more button is hidden when no more responses pages to load', async () => { - // const totalPages = 2; - // renderComponent(discussionPostId); + await screen.findByText('comment number 8', { exact: false }); + await expect(findLoadMoreCommentsResponsesButton()) + .rejects + .toThrow(); + }); - // const loadMoreButton = await findLoadMoreCommentsResponsesButton(); - // for (let page = 1; page < totalPages; page++) { - // act(() => { - // fireEvent.click(loadMoreButton); - // }); - // } + // it('handles liking a comment', async () => { + // renderComponent(discussionPostId); - // await screen.findByText('comment number 8', { exact: false }); - // await expect(findLoadMoreCommentsResponsesButton()) - // .rejects - // .toThrow(); - // }); + // // Wait for the content to load + // await screen.findByText('comment number 7', { exact: false }); + // const view = screen.getByTestId('comment-comment-1'); - // it('handles liking a comment', async () => { - // renderComponent(discussionPostId); + // const likeButton = within(view).getByRole('button', { name: /like/i }); + // await act(async () => { + // fireEvent.click(likeButton); + // }); + // expect(axiosMock.history.patch).toHaveLength(2); + // expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ voted: true }); + // }); - // // Wait for the content to load - // await screen.findByText('comment number 7', { exact: false }); - // const view = screen.getByTestId('comment-comment-1'); + // it('handles endorsing comments', async () => { + // renderComponent(discussionPostId); + // // Wait for the content to load + // await screen.findByText('comment number 7', { exact: false }); - // const likeButton = within(view).getByRole('button', { name: /like/i }); - // await act(async () => { - // fireEvent.click(likeButton); - // }); - // expect(axiosMock.history.patch).toHaveLength(2); - // expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ voted: true }); - // }); + // // There should be three buttons, one for the post, the second for the + // // comment and the third for a response to that comment + // const actionButtons = screen.queryAllByRole('button', { name: /actions menu/i }); + // await act(async () => { + // fireEvent.click(actionButtons[1]); + // }); - // it('handles endorsing comments', async () => { - // renderComponent(discussionPostId); - // // Wait for the content to load - // await screen.findByText('comment number 7', { exact: false }); + // await act(async () => { + // fireEvent.click(screen.getByRole('button', { name: /Endorse/i })); + // }); + // expect(axiosMock.history.patch).toHaveLength(2); + // expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ endorsed: true }); + // }); - // // There should be three buttons, one for the post, the second for the - // // comment and the third for a response to that comment - // const actionButtons = screen.queryAllByRole('button', { name: /actions menu/i }); - // await act(async () => { - // fireEvent.click(actionButtons[1]); - // }); + // it('handles reporting comments', async () => { + // renderComponent(discussionPostId); + // // Wait for the content to load + // await screen.findByText('comment number 7', { exact: false }); - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /Endorse/i })); - // }); - // expect(axiosMock.history.patch).toHaveLength(2); - // expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ endorsed: true }); - // }); + // // There should be three buttons, one for the post, the second for the + // // comment and the third for a response to that comment + // const actionButtons = screen.queryAllByRole('button', { name: /actions menu/i }); + // await act(async () => { + // fireEvent.click(actionButtons[1]); + // }); - // it('handles reporting comments', async () => { - // renderComponent(discussionPostId); - // // Wait for the content to load - // await screen.findByText('comment number 7', { exact: false }); + // await act(async () => { + // fireEvent.click(screen.getByRole('button', { name: /Report/i })); + // }); + // expect(screen.queryByRole('dialog', { name: /Report \w+/i, exact: false })).toBeInTheDocument(); + // await act(async () => { + // fireEvent.click(screen.queryByRole('button', { name: /Confirm/i })); + // }); + // expect(screen.queryByRole('dialog', { name: /Report \w+/i, exact: false })).not.toBeInTheDocument(); + // expect(axiosMock.history.patch).toHaveLength(2); + // expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ abuse_flagged: true }); + // }); + }); - // // There should be three buttons, one for the post, the second for the - // // comment and the third for a response to that comment - // const actionButtons = screen.queryAllByRole('button', { name: /actions menu/i }); - // await act(async () => { - // fireEvent.click(actionButtons[1]); - // }); - - // await act(async () => { - // fireEvent.click(screen.getByRole('button', { name: /Report/i })); - // }); - // expect(screen.queryByRole('dialog', { name: /Report \w+/i, exact: false })).toBeInTheDocument(); - // await act(async () => { - // fireEvent.click(screen.queryByRole('button', { name: /Confirm/i })); - // }); - // expect(screen.queryByRole('dialog', { name: /Report \w+/i, exact: false })).not.toBeInTheDocument(); - // expect(axiosMock.history.patch).toHaveLength(2); - // expect(JSON.parse(axiosMock.history.patch[1].data)).toMatchObject({ abuse_flagged: true }); - // }); - // }); - - // describe.each([ - // { component: 'post', testId: 'post-thread-1' }, - // { component: 'comment', testId: 'comment-comment-1' }, - // { component: 'reply', testId: 'reply-comment-7' }, - // ])('delete confirmation modal', ({ - // component, - // testId, - // }) => { - // test(`for ${component}`, async () => { - // renderComponent(discussionPostId); - // // Wait for the content to load - // await waitFor(() => expect(screen.queryByText('comment number 7', { exact: false })).toBeInTheDocument()); - // const content = screen.getByTestId(testId); - // const actionsButton = within(content).getAllByRole('button', { name: /actions menu/i })[0]; - // await act(async () => { - // fireEvent.click(actionsButton); - // }); - // expect(screen.queryByRole('dialog', { name: /delete \w+/i, exact: false })).not.toBeInTheDocument(); - // const deleteButton = within(content).queryByRole('button', { name: /delete/i }); - // await act(async () => { - // fireEvent.click(deleteButton); - // }); - // expect(screen.queryByRole('dialog', { name: /delete \w+/i, exact: false })).toBeInTheDocument(); - // await act(async () => { - // fireEvent.click(screen.queryByRole('button', { name: /delete/i })); - // }); - // expect(screen.queryByRole('dialog', { name: /delete \w+/i, exact: false })).not.toBeInTheDocument(); - // }); - // }); + describe.each([ + { component: 'post', testId: 'post-thread-1' }, + { component: 'comment', testId: 'comment-comment-1' }, + { component: 'reply', testId: 'reply-comment-7' }, + ])('delete confirmation modal', ({ + component, + testId, + }) => { + test(`for ${component}`, async () => { + renderComponent(discussionPostId); + // Wait for the content to load + await waitFor(() => expect(screen.queryByText('comment number 7', { exact: false })).toBeInTheDocument()); + const content = screen.getByTestId(testId); + await act(async () => { + fireEvent.mouseOver(screen.getByTestId('post-thread-1')); + }); + const actionsButton = within(content).getAllByRole('button', { name: /actions menu/i })[0]; + await act(async () => { + fireEvent.click(actionsButton); + }); + expect(screen.queryByRole('dialog', { name: /delete \w+/i, exact: false })).not.toBeInTheDocument(); + const deleteButton = within(content).queryByRole('button', { name: /delete/i }); + await act(async () => { + fireEvent.click(deleteButton); + }); + expect(screen.queryByRole('dialog', { name: /delete \w+/i, exact: false })).toBeInTheDocument(); + await act(async () => { + fireEvent.click(screen.queryByRole('button', { name: /delete/i })); + }); + expect(screen.queryByRole('dialog', { name: /delete \w+/i, exact: false })).not.toBeInTheDocument(); + }); + }); }); diff --git a/src/discussions/comments/comment/CommentHeader.test.jsx b/src/discussions/comments/comment/CommentHeader.test.jsx deleted file mode 100644 index 031c9f7d..00000000 --- a/src/discussions/comments/comment/CommentHeader.test.jsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react'; - -import { render, screen } from '@testing-library/react'; -import { IntlProvider } from 'react-intl'; - -import { initializeMockApp } from '@edx/frontend-platform'; -import { AppProvider } from '@edx/frontend-platform/react'; - -import { initializeStore } from '../../../store'; -import { DiscussionContext } from '../../common/context'; -import CommentHeader from './CommentHeader'; - -let store; - -function renderComponent(comment, postType, actionHandlers) { - return render( - - - - - - - , - ); -} - -const mockComment = { - author: 'abc123', - authorLabel: 'ABC 123', - endorsed: true, - editableFields: ['endorsed'], -}; - -describe('Comment Header', () => { - beforeEach(async () => { - initializeMockApp({ - authenticatedUser: { - userId: 3, - username: 'abc123', - administrator: true, - roles: [], - }, - }); - store = initializeStore(); - }); - - // it('should render verified icon for endorsed discussion posts', () => { - // renderComponent(mockComment, 'discussion', {}); - // expect(screen.queryAllByTestId('check-icon')).toHaveLength(1); - // }); - // it('should render check icon for endorsed question posts', () => { - // renderComponent(mockComment, 'question', {}); - // expect(screen.queryAllByTestId('check-icon')).toHaveLength(1); - // }); -}); diff --git a/src/discussions/common/AuthorLabel.jsx b/src/discussions/common/AuthorLabel.jsx index f4b112d5..25f9fd26 100644 --- a/src/discussions/common/AuthorLabel.jsx +++ b/src/discussions/common/AuthorLabel.jsx @@ -73,7 +73,7 @@ function AuthorLabel({ trigger={['hover', 'focus']} >
{authorLabelMessage && ( - - {/* {icon && ( - - )} - {authorLabelMessage && ( - - {authorLabelMessage} - - )} */} { postCreatedAt && ( { - // expectText.forEach(message => { - // expect(screen.queryAllByText(message, { exact: false }).length).toBeGreaterThan(0); - // }); - // }); + it(`should show correct banner for a ${label}`, async () => { + expectText.forEach(message => { + expect(screen.queryAllByText(message, { exact: false }).length).toBeGreaterThan(0); + }); + }); }); diff --git a/src/discussions/common/HoverCard.jsx b/src/discussions/common/HoverCard.jsx index 3d0c0d19..708d4f9e 100644 --- a/src/discussions/common/HoverCard.jsx +++ b/src/discussions/common/HoverCard.jsx @@ -32,7 +32,10 @@ function HoverCard({ const userCanAddThreadInBlackoutDate = useUserCanAddThreadInBlackoutDate(); return ( -
+
{userCanAddThreadInBlackoutDate && (