test: added test cases for learner view

This commit is contained in:
sundasnoreen12
2023-03-08 18:50:38 +05:00
parent 91cb347456
commit d6a38ae6d7
4 changed files with 213 additions and 45 deletions

View File

@@ -72,6 +72,7 @@ function Search({ intl }) {
<Icon
src={SearchIcon}
onClick={() => onSubmit(searchValue)}
data-testid="search-icon"
/>
</span>
</SearchField.Advanced>

View File

@@ -1,6 +1,9 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import {
fireEvent, render, screen, waitFor,
within,
} from '@testing-library/react';
import MockAdapter from 'axios-mock-adapter';
import { act } from 'react-dom/test-utils';
import { IntlProvider } from 'react-intl';
@@ -11,11 +14,13 @@ import { initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { AppProvider } from '@edx/frontend-platform/react';
import { PostActionsBar } from '../../components';
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, getUserProfileApiUrl } from './data/api';
import { getUserProfileApiUrl, learnersApiUrl } from './data/api';
import { fetchLearners } from './data/thunks';
import LearnersView from './LearnersView';
@@ -23,27 +28,32 @@ import './data/__factories__';
let store;
let axiosMock;
const coursesApiUrl = getCoursesApiUrl();
const courseConfigApiUrl = getCourseConfigApiUrl();
const userProfileApiUrl = getUserProfileApiUrl();
const courseId = 'course-v1:edX+TestX+Test_Course';
let container;
function renderComponent() {
return render(
async function renderComponent() {
const wrapper = await render(
<IntlProvider locale="en">
<AppProvider store={store}>
<MemoryRouter initialEntries={[`/${courseId}/`]}>
<Route path="/:courseId/">
<LearnersView />
</Route>
</MemoryRouter>
<DiscussionContext.Provider value={{
page: 'learners',
}}
>
<MemoryRouter initialEntries={[`/${courseId}/`]}>
<Route path="/:courseId/">
<PostActionsBar />
<LearnersView />
</Route>
</MemoryRouter>
</DiscussionContext.Provider>
</AppProvider>
</IntlProvider>,
);
container = wrapper.container;
}
describe('LearnersView', () => {
const learnerCount = 3;
describe('Learners view test cases', () => {
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
@@ -53,40 +63,197 @@ describe('LearnersView', () => {
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
store = initializeStore();
Factory.resetAll();
const learnersData = Factory.build('learnersResult', {}, {
count: learnerCount,
pageSize: 6,
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(`${coursesApiUrl}${courseId}/activity_stats/`)
.reply(() => [200, learnersData]);
const learnersProfile = Factory.build('learnersProfile', {}, {
username: ['learner-1', 'learner-2', 'learner-3'],
});
axiosMock.onGet(`${userProfileApiUrl}?username=learner-1,learner-2,learner-3`)
.reply(() => [200, learnersProfile.profiles]);
await executeThunk(fetchLearners(courseId), store.dispatch, store.getState);
});
describe('Basic', () => {
test('Learners tab is disabled by default', async () => {
await act(async () => {
await renderComponent();
});
expect(screen.queryByText(/Last active/i)).toBeFalsy();
async function setUpLearnerMockResponse(
count = 3,
pageSize = 6,
page = 1,
username = ['learner-1', 'learner-2', 'learner-3'],
searchText,
) {
Factory.resetAll();
const learnersData = Factory.build('learnersResult', {}, {
count,
pageSize,
page,
});
test('Learners tab is enabled', async () => {
axiosMock.onGet(`${courseConfigApiUrl}${courseId}/`).reply(200, {
learners_tab_enabled: true,
user_is_privileged: true,
});
axiosMock.onGet(`${courseConfigApiUrl}${courseId}/settings`).reply(200, {});
await executeThunk(fetchCourseConfig(courseId), store.dispatch, store.getState);
axiosMock.onGet(learnersApiUrl(courseId))
.reply(() => [200, learnersData]);
axiosMock.onGet(`${getUserProfileApiUrl()}?username=${username.join()}`)
.reply(() => [200, Factory.build('learnersProfile', {}, {
username,
}).profiles]);
await executeThunk(fetchLearners(courseId, { usernameSearch: searchText }), store.dispatch, store.getState);
}
async function assignPrivilages() {
axiosMock.onGet(`${courseConfigApiUrl}${courseId}/`).reply(200, {
learners_tab_enabled: true,
user_is_privileged: true,
});
axiosMock.onGet(`${courseConfigApiUrl}${courseId}/settings`).reply(200, {});
await executeThunk(fetchCourseConfig(courseId), store.dispatch, store.getState);
}
it('Learners tab is disabled by default', async () => {
await setUpLearnerMockResponse();
await act(async () => {
await renderComponent();
});
expect(screen.queryByText(/Last active/i)).toBeFalsy();
});
it('Learners tab is enabled', async () => {
await setUpLearnerMockResponse();
await assignPrivilages();
await act(async () => {
await renderComponent();
});
});
it('Most activity should be selected by default for the non-moderator role.', async () => {
await setUpLearnerMockResponse();
await act(async () => {
await renderComponent();
});
const filterBar = await container.querySelector('.collapsible-trigger');
await act(async () => {
fireEvent.click(filterBar);
});
await waitFor(async () => {
const mostActivity = await screen.getByTestId('activity selected');
expect(mostActivity).toBeInTheDocument();
});
});
it.each([
{ searchBy: 'sort-recency', result: 0 },
{ searchBy: 'sort-activity', result: 3 },
])('Successfully display learners by %s.', async ({ searchBy, result }) => {
await setUpLearnerMockResponse();
await assignPrivilages();
await act(async () => {
await renderComponent();
});
const filterBar = await container.querySelector('.collapsible-trigger');
await act(async () => {
fireEvent.click(filterBar);
});
await waitFor(async () => {
const activity = await container.querySelector(`#${searchBy}`);
await act(async () => {
await renderComponent();
fireEvent.click(activity);
});
await waitFor(async () => {
const learners = await container.querySelectorAll('.discussion-post') ?? [];
expect(learners).toHaveLength(result);
});
});
});
it('It should display a learner\'s list.', async () => {
await setUpLearnerMockResponse();
await assignPrivilages();
await act(async () => {
await renderComponent();
});
await waitFor(async () => {
const learners = await container.querySelectorAll('.discussion-post') ?? [];
const learnerAvatar = learners[0].querySelector('[alt=learner-1]');
const learnerTitle = within(learners[0]).queryByText('learner-1');
const stats = learners[0].querySelectorAll('.icon-size');
expect(learners).toHaveLength(3);
expect(learnerAvatar).toBeInTheDocument();
expect(learnerTitle).toBeInTheDocument();
expect(stats).toHaveLength(2);
});
});
it.each([
{
searchText: 'hello world',
output: 'Showing 0 results for',
learnersCount: 0,
username: [],
},
{
searchText: 'learner',
output: 'Showing 2 results for',
learnersCount: 2,
username:
['learner-1', 'learner-2'],
},
])('It should have a search bar with a clear button and \'$output\' results found text.',
async ({
searchText, output, learnersCount, username,
}) => {
await setUpLearnerMockResponse();
await assignPrivilages();
await renderComponent();
const searchField = await within(container).getByPlaceholderText('Search learners');
const searchButton = await within(container).getByTestId('search-icon');
await fireEvent.change(searchField, { target: { value: searchText } });
await act(async () => {
fireEvent.click(searchButton);
await setUpLearnerMockResponse(learnersCount, learnersCount, 1, username, searchText);
});
await waitFor(async () => {
const clearButton = within(container).queryByText('Clear results');
const searchMessage = within(container).queryByText(`${output} "${searchText}"`);
const units = container.querySelectorAll('.discussion-post') ?? [];
expect(searchMessage).toBeInTheDocument();
expect(clearButton).toBeInTheDocument();
expect(units).toHaveLength(learnersCount);
});
});
it('When click on the clear button it should move to a list of all learners.', async () => {
await setUpLearnerMockResponse();
await assignPrivilages();
await renderComponent();
const searchField = await within(container).getByPlaceholderText('Search learners');
const searchButton = await within(container).getByTestId('search-icon');
await fireEvent.change(searchField, { target: { value: 'learner' } });
await act(async () => {
fireEvent.click(searchButton);
await setUpLearnerMockResponse(2, 2, 1, ['learner-1', 'learner-2'], 'learner');
});
await waitFor(async () => {
const clearButton = await within(container).queryByText('Clear results');
await act(async () => fireEvent.click(clearButton));
await waitFor(async () => {
await act(async () => {
await setUpLearnerMockResponse();
});
await waitFor(async () => {
const units = container.querySelectorAll('.discussion-post') ?? [];
expect(units).toHaveLength(3);
});
});
});
});

View File

@@ -13,9 +13,9 @@ Factory.define('learner')
});
Factory.define('learnersResult')
.option('count', null, 3)
.option('page', null, 1)
.option('pageSize', null, 5)
.option('count', null)
.option('page', null)
.option('pageSize', null)
.option('courseId', null, 'course-v1:Test+TestX+Test_Course')
.option('activeFlags', null, 0)
.attr(

View File

@@ -24,7 +24,7 @@ const ActionItem = ({
<label
htmlFor={id}
className="focus border-bottom-0 d-flex align-items-center w-100 py-2 m-0 font-weight-500 filter-menu"
data-testid={value === selected ? 'selected' : null}
data-testid={value === selected ? `${value} selected` : null}
style={{ cursor: 'pointer' }}
aria-checked={value === selected}
>