test: add tests for TopicsView component
This commit is contained in:
@@ -38,7 +38,7 @@ function TopicsView() {
|
||||
),
|
||||
);
|
||||
|
||||
if (nonCoursewareTopics && category === undefined) {
|
||||
if (nonCoursewareTopics?.length > 1 && category === undefined) {
|
||||
topicElements.unshift(<TopicGroup subtopics={nonCoursewareTopics} filter={filter} key="non-courseware" />);
|
||||
}
|
||||
|
||||
|
||||
186
src/discussions/topics/TopicsView.test.jsx
Normal file
186
src/discussions/topics/TopicsView.test.jsx
Normal file
@@ -0,0 +1,186 @@
|
||||
import {
|
||||
fireEvent, queryByText, render, screen, waitFor,
|
||||
} from '@testing-library/react';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { MemoryRouter, Route } from 'react-router';
|
||||
import { Factory } from 'rosie';
|
||||
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
|
||||
import { API_BASE_URL } from '../../data/constants';
|
||||
import { initializeStore } from '../../store';
|
||||
import TopicsView from './TopicsView';
|
||||
|
||||
import './data/__factories__';
|
||||
|
||||
const courseId = 'course-v1:edX+TestX+Test_Course';
|
||||
const topicsApiUrl = `${API_BASE_URL}/api/discussion/v1/course_topics/${courseId}`;
|
||||
let store;
|
||||
let axiosMock;
|
||||
let lastLocation;
|
||||
|
||||
function renderComponent() {
|
||||
render(
|
||||
<IntlProvider locale="en">
|
||||
<AppProvider store={store}>
|
||||
<MemoryRouter initialEntries={[`/discussions/${courseId}/topics/`]}>
|
||||
<Route path="/discussions/:courseId/topics/">
|
||||
<TopicsView />
|
||||
</Route>
|
||||
<Route path="/discussions/:courseId/category/:category">
|
||||
<TopicsView />
|
||||
</Route>
|
||||
<Route
|
||||
render={({ location }) => {
|
||||
lastLocation = location;
|
||||
return null;
|
||||
}}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</AppProvider>
|
||||
</IntlProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
describe('TopicsView', () => {
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
|
||||
store = initializeStore();
|
||||
Factory.resetAll();
|
||||
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
|
||||
|
||||
lastLocation = undefined;
|
||||
});
|
||||
|
||||
it('displays non-courseware topics', async () => {
|
||||
axiosMock
|
||||
.onGet(topicsApiUrl)
|
||||
.reply(200, {
|
||||
courseware_topics: [],
|
||||
non_courseware_topics: Factory.buildList('topic', 3),
|
||||
});
|
||||
renderComponent();
|
||||
|
||||
await screen.findByText('topic 1');
|
||||
expect(screen.queryByText('topic 2')).toBeInTheDocument();
|
||||
expect(screen.queryByText('topic 3')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays non-courseware in one topic group', async () => {
|
||||
axiosMock
|
||||
.onGet(topicsApiUrl)
|
||||
.reply(200, {
|
||||
courseware_topics: [],
|
||||
non_courseware_topics: Factory.buildList('topic', 3),
|
||||
});
|
||||
renderComponent();
|
||||
|
||||
await screen.findByText('topic 1');
|
||||
const topicGroups = screen.queryAllByTestId('topic-group');
|
||||
expect(topicGroups).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('displays courseware topics', async () => {
|
||||
axiosMock
|
||||
.onGet(topicsApiUrl)
|
||||
.reply(200, {
|
||||
courseware_topics: Factory.buildList('topic', 3),
|
||||
non_courseware_topics: [],
|
||||
});
|
||||
renderComponent();
|
||||
|
||||
await screen.findByText('topic 1');
|
||||
expect(screen.queryByText('topic 2')).toBeInTheDocument();
|
||||
expect(screen.queryByText('topic 3')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays courseware topics in individual topic groups', async () => {
|
||||
axiosMock
|
||||
.onGet(topicsApiUrl)
|
||||
.reply(200, {
|
||||
courseware_topics: Factory.buildList('topic', 3),
|
||||
non_courseware_topics: [],
|
||||
});
|
||||
renderComponent();
|
||||
|
||||
await screen.findByText('topic 1');
|
||||
const topicGroups = screen.queryAllByTestId('topic-group');
|
||||
expect(topicGroups).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('displays non-courseware topics before courseware topics', async () => {
|
||||
axiosMock
|
||||
.onGet(topicsApiUrl)
|
||||
.reply(200, {
|
||||
courseware_topics: Factory.buildList('topic', 3),
|
||||
non_courseware_topics: Factory.buildList('topic', 3),
|
||||
});
|
||||
renderComponent();
|
||||
|
||||
await screen.findByText('topic 1');
|
||||
const topicGroups = screen.queryAllByTestId('topic-group');
|
||||
expect(queryByText(topicGroups[0], 'topic 4')).toBeInTheDocument();
|
||||
expect(queryByText(topicGroups[0], 'topic 5')).toBeInTheDocument();
|
||||
expect(queryByText(topicGroups[0], 'topic 6')).toBeInTheDocument();
|
||||
expect(queryByText(topicGroups[1], 'topic 1')).toBeInTheDocument();
|
||||
expect(queryByText(topicGroups[2], 'topic 2')).toBeInTheDocument();
|
||||
expect(queryByText(topicGroups[3], 'topic 3')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('clicking on courseware topic (category) takes to category page', async () => {
|
||||
axiosMock
|
||||
.onGet(topicsApiUrl)
|
||||
.reply(200, {
|
||||
courseware_topics: Factory.buildList('topic', 3),
|
||||
non_courseware_topics: Factory.buildList('topic', 3),
|
||||
});
|
||||
renderComponent();
|
||||
|
||||
const topic = await screen.findByText('topic 1');
|
||||
fireEvent.click(topic);
|
||||
|
||||
await waitFor(() => expect(screen.queryByText('topic 2')).not.toBeInTheDocument());
|
||||
expect(lastLocation.pathname.endsWith('/category/topic 1')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('on category page only selected category and it\'s children are displayed', async () => {
|
||||
const category = Factory.build('topic');
|
||||
category.children = Factory.buildList('topic', 3);
|
||||
axiosMock
|
||||
.onGet(topicsApiUrl)
|
||||
.reply(200, {
|
||||
courseware_topics: [
|
||||
category,
|
||||
Factory.build('topic'),
|
||||
],
|
||||
non_courseware_topics: Factory.buildList('topic', 3),
|
||||
});
|
||||
renderComponent();
|
||||
|
||||
const topic = await screen.findByText('topic 1');
|
||||
fireEvent.click(topic);
|
||||
|
||||
await waitFor(() => expect(screen.queryByText('topic 6')).not.toBeInTheDocument());
|
||||
// children
|
||||
expect(screen.queryByText('topic 2')).toBeInTheDocument();
|
||||
expect(screen.queryByText('topic 3')).toBeInTheDocument();
|
||||
expect(screen.queryByText('topic 4')).toBeInTheDocument();
|
||||
|
||||
// other courseware topics (categories) and non-courseware topics
|
||||
expect(screen.queryByText('topic 5')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('topic 6')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('topic 7')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('topic 8')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
1
src/discussions/topics/data/__factories__/index.js
Normal file
1
src/discussions/topics/data/__factories__/index.js
Normal file
@@ -0,0 +1 @@
|
||||
import './topics.factory';
|
||||
@@ -0,0 +1,6 @@
|
||||
import { Factory } from 'rosie';
|
||||
|
||||
Factory.define('topic')
|
||||
.sequence('id', (idx) => `topic-${idx}`)
|
||||
.sequence('name', (idx) => `topic ${idx}`)
|
||||
.attr('children', []);
|
||||
@@ -42,7 +42,11 @@ function TopicGroup({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="discussion-topic-group d-flex flex-column" data-topic-id={id}>
|
||||
<div
|
||||
className="discussion-topic-group d-flex flex-column"
|
||||
data-topic-id={id}
|
||||
data-testid="topic-group"
|
||||
>
|
||||
{name && (
|
||||
<Link
|
||||
className="topic-name list-group-item p-4 text-primary-500"
|
||||
|
||||
Reference in New Issue
Block a user