From 45dea79a877138e130dd088e22cd1679f83fbdbf Mon Sep 17 00:00:00 2001 From: sundasnoreen12 <72802712+sundasnoreen12@users.noreply.github.com> Date: Mon, 13 Mar 2023 04:44:46 -0700 Subject: [PATCH] test: added test cases for learner post view (#466) * test: added test cases for learner post view * refactor: fixed requested changes for code optimization * refactor: added url change --------- Co-authored-by: sundasnoreen12 --- .../learners/LearnerPostsView.test.jsx | 137 ++++++++++++++---- src/discussions/learners/test-utils.js | 10 ++ 2 files changed, 117 insertions(+), 30 deletions(-) diff --git a/src/discussions/learners/LearnerPostsView.test.jsx b/src/discussions/learners/LearnerPostsView.test.jsx index 2ed75ba6..56dbc047 100644 --- a/src/discussions/learners/LearnerPostsView.test.jsx +++ b/src/discussions/learners/LearnerPostsView.test.jsx @@ -1,6 +1,8 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { + fireEvent, render, screen, waitFor, +} from '@testing-library/react'; import MockAdapter from 'axios-mock-adapter'; import { act } from 'react-dom/test-utils'; import { IntlProvider } from 'react-intl'; @@ -14,22 +16,22 @@ import { AppProvider } from '@edx/frontend-platform/react'; import { initializeStore } from '../../store'; import { executeThunk } from '../../test-utils'; import { DiscussionContext } from '../common/context'; -import { getCourseConfigApiUrl } from '../data/api'; -import { fetchCourseConfig } from '../data/thunks'; -import { getCoursesApiUrl } from './data/api'; +import { learnerPostsApiUrl } from './data/api'; +import { fetchUserPosts } from './data/thunks'; import LearnerPostsView from './LearnerPostsView'; +import { setUpPrivilages } from './test-utils'; import './data/__factories__'; let store; let axiosMock; -const coursesApiUrl = getCoursesApiUrl(); -const courseConfigApiUrl = getCourseConfigApiUrl(); const courseId = 'course-v1:edX+TestX+Test_Course'; const username = 'abc123'; +let container; +let lastLocation; -function renderComponent(path = `/${courseId}/learners/${username}/posts`) { - return render( +async function renderComponent() { + const wrapper = render( - - + + + { + lastLocation = location; + return null; + }} + /> , ); + container = wrapper.container; } -describe('LearnerPostsView', () => { +describe('Learner Posts View', () => { beforeEach(async () => { initializeMockApp({ authenticatedUser: { @@ -62,31 +71,99 @@ describe('LearnerPostsView', () => { store = initializeStore(); Factory.resetAll(); - const learnerPosts = Factory.build('learnerPosts', {}, { - abuseFlaggedCount: 1, - }); - const apiUrl = `${coursesApiUrl}${courseId}/learner/`; axiosMock = new MockAdapter(getAuthenticatedHttpClient()); - axiosMock.onGet(apiUrl, { username, count_flagged: true }) - .reply(() => [200, learnerPosts]); + axiosMock.onGet(learnerPostsApiUrl(courseId), { username, count_flagged: true }) + .reply(() => [200, Factory.build('learnerPosts', {}, { + abuseFlaggedCount: 1, + })]); + await executeThunk(fetchUserPosts(courseId), store.dispatch, store.getState); }); - describe('Basic', () => { - test('Reported icon is visible to moderator for post with reported comment', async () => { - axiosMock.onGet(`${courseConfigApiUrl}${courseId}/`).reply(200, { - has_moderation_privileges: true, + test('Reported icon is visible to moderator for post with reported comment', async () => { + await setUpPrivilages(axiosMock, store, true); + await waitFor(() => { renderComponent(); }); + + expect(container.querySelector('[data-testid="reported-post"]')).toBeInTheDocument(); + }); + + test('Reported icon is not visible to learner for post with reported comment', async () => { + await renderComponent(); + expect(screen.queryByTestId('reported-post')).not.toBeInTheDocument(); + }); + + test('Learner title bar should display a title bar, a learner name, and a back button', async () => { + await renderComponent(); + + const titleBar = container.querySelector('.discussion-posts:first-child'); + const learnerName = screen.queryByText('Activity for Abc123'); + const backButton = screen.getByLabelText('Back'); + + expect(titleBar).toBeInTheDocument(); + expect(learnerName).toBeInTheDocument(); + expect(backButton).toBeInTheDocument(); + }); + + test('Learner title bar should redirect to the learners list when clicking on the back button', + async () => { + await renderComponent(); + + const backButton = screen.getByLabelText('Back'); + + await act(() => fireEvent.click(backButton)); + await waitFor(() => { + expect(lastLocation.pathname.endsWith('/learners')).toBeTruthy(); }); - axiosMock.onGet(`${courseConfigApiUrl}${courseId}/settings`).reply(200, {}); - await executeThunk(fetchCourseConfig(courseId), store.dispatch, store.getState); - await act(async () => { - renderComponent(); - }); - expect(screen.queryAllByTestId('reported-post')[0]).toBeInTheDocument(); }); - test('Reported icon is not visible to learner for post with reported comment', async () => { - await renderComponent(); - expect(screen.queryByTestId('reported-post')).not.toBeInTheDocument(); + it('should display a post-filter bar and All posts sorted by recent activity text.', async () => { + await renderComponent(); + + const filterBar = container.querySelector('.filter-bar'); + const recentActivity = screen.getByText('All posts sorted by recent activity'); + + expect(filterBar).toBeInTheDocument(); + expect(recentActivity).toBeInTheDocument(); + }); + + it(`should display a list of the interactive posts of a selected learner and the posts count + should be equal to the API response count.`, async () => { + await waitFor(() => { + renderComponent(); + }); + const posts = await container.querySelectorAll('.discussion-post'); + + expect(posts).toHaveLength(2); + expect(posts).toHaveLength(Object.values(store.getState().threads.threadsById).length); + }); + + it.each([ + { searchBy: 'type-all', result: 2 }, + { searchBy: 'type-discussions', result: 2 }, + { searchBy: 'type-questions', result: 2 }, + { searchBy: 'status-unread', result: 2 }, + { searchBy: 'sort-comments', result: 2 }, + { searchBy: 'sort-votes', result: 2 }, + { searchBy: 'sort-activity', result: 2 }, + ])('successfully display learners by %s.', async ({ searchBy, result }) => { + await setUpPrivilages(axiosMock, store, true); + await renderComponent(); + + const filterBar = container.querySelector('.collapsible-trigger'); + await act(async () => { + fireEvent.click(filterBar); + }); + + await waitFor(async () => { + const activity = container.querySelector(`[for='${searchBy}']`); + + await act(async () => { + fireEvent.click(activity); + }); + await waitFor(() => { + const learners = container.querySelectorAll('.discussion-post'); + + expect(learners).toHaveLength(result); + }); }); }); }); diff --git a/src/discussions/learners/test-utils.js b/src/discussions/learners/test-utils.js index c3550721..489ad4d8 100644 --- a/src/discussions/learners/test-utils.js +++ b/src/discussions/learners/test-utils.js @@ -5,6 +5,8 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { initializeStore } from '../../store'; import { executeThunk } from '../../test-utils'; +import { getDiscussionsConfigUrl } from '../data/api'; +import { fetchCourseConfig } from '../data/thunks'; import { getUserProfileApiUrl, learnerPostsApiUrl, learnersApiUrl } from './data/api'; import { fetchLearners, fetchUserPosts } from './data/thunks'; @@ -50,3 +52,11 @@ export async function setupPostsMockResponse({ await executeThunk(fetchUserPosts(courseId, { filters }), store.dispatch, store.getState); return store.getState().threads; } + +export async function setUpPrivilages(axiosMock, store, hasModerationPrivileges) { + axiosMock.onGet(getDiscussionsConfigUrl(courseId)).reply(200, { + has_moderation_privileges: hasModerationPrivileges, + }); + + await executeThunk(fetchCourseConfig(courseId), store.dispatch, store.getState); +}