From 24d02350a8ff2e3eaa289411df67ffcdffc84431 Mon Sep 17 00:00:00 2001 From: ayesha waris <73840786+ayeshoali@users.noreply.github.com> Date: Mon, 6 Mar 2023 21:10:49 +0500 Subject: [PATCH] fix: fix topic info for course-wide discussion topics (#458) * fix: fix topic info for course-wide discussion topics * refactor: removed const and used url directly * test: adds test cases for topic info * test: updated test cases --- .../post-comments/PostCommentsView.test.jsx | 51 ++++++++++++++++++- src/discussions/posts/PostsView.test.jsx | 14 ++--- .../data/__factories__/threads.factory.js | 2 +- src/discussions/posts/data/redux.test.js | 2 +- src/discussions/posts/post/Post.jsx | 11 ++-- 5 files changed, 67 insertions(+), 13 deletions(-) diff --git a/src/discussions/post-comments/PostCommentsView.test.jsx b/src/discussions/post-comments/PostCommentsView.test.jsx index 8ed1f54e..3835467c 100644 --- a/src/discussions/post-comments/PostCommentsView.test.jsx +++ b/src/discussions/post-comments/PostCommentsView.test.jsx @@ -10,6 +10,7 @@ import { camelCaseObject, initializeMockApp } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { AppProvider } from '@edx/frontend-platform/react'; +import { getApiBaseUrl } from '../../data/constants'; import { initializeStore } from '../../store'; import { executeThunk } from '../../test-utils'; import { DiscussionContext } from '../common/context'; @@ -17,11 +18,13 @@ import { getCourseConfigApiUrl } from '../data/api'; import { fetchCourseConfig } from '../data/thunks'; import DiscussionContent from '../discussions-home/DiscussionContent'; import { getThreadsApiUrl } from '../posts/data/api'; -import { fetchThreads } from '../posts/data/thunks'; +import { fetchThread, fetchThreads } from '../posts/data/thunks'; +import { fetchCourseTopics } from '../topics/data/thunks'; import { getCommentsApiUrl } from './data/api'; import '../posts/data/__factories__'; import './data/__factories__'; +import '../topics/data/__factories__'; const courseConfigApiUrl = getCourseConfigApiUrl(); const commentsApiUrl = getCommentsApiUrl(); @@ -30,6 +33,7 @@ const discussionPostId = 'thread-1'; const questionPostId = 'thread-2'; const closedPostId = 'thread-2'; const courseId = 'course-v1:edX+TestX+Test_Course'; +const topicsApiUrl = `${getApiBaseUrl()}/api/discussion/v1/course_topics/${courseId}`; const reverseOrder = false; let store; let axiosMock; @@ -83,6 +87,12 @@ function mockAxiosReturnPagedCommentsResponses() { } } +async function getThreadAPIResponse(threadId, topicId) { + axiosMock.onGet(`${threadsApiUrl}${discussionPostId}/`) + .reply(200, Factory.build('thread', { id: threadId, topic_id: topicId })); + await executeThunk(fetchThread(discussionPostId), store.dispatch, store.getState); +} + function renderComponent(postId) { const wrapper = render( @@ -107,6 +117,45 @@ function renderComponent(postId) { return wrapper; } +describe('PostView', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + + store = initializeStore(); + Factory.resetAll(); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + + axiosMock.onGet(topicsApiUrl) + .reply(200, { + non_courseware_topics: Factory.buildList('topic', 1, {}, { topicPrefix: 'non-courseware-' }), + courseware_topics: Factory.buildList('category', 1, {}, { name: 'courseware' }), + }); + executeThunk(fetchCourseTopics(courseId), store.dispatch, store.getState); + }); + + it('should show Topic Info for non-courseware topics', async () => { + await getThreadAPIResponse('thread-1', 'non-courseware-topic-1'); + renderComponent(discussionPostId); + expect(await screen.findByText('Related to')).toBeInTheDocument(); + expect(await screen.findByText('non-courseware-topic 1')).toBeInTheDocument(); + }); + + it('should show Topic Info for courseware topics with category', async () => { + await getThreadAPIResponse('thread-2', 'courseware-topic-2'); + + renderComponent('thread-2'); + expect(await screen.findByText('Related to')).toBeInTheDocument(); + expect(await screen.findByText('category-1 / courseware-topic 2')).toBeInTheDocument(); + }); +}); + describe('ThreadView', () => { beforeEach(() => { initializeMockApp({ diff --git a/src/discussions/posts/PostsView.test.jsx b/src/discussions/posts/PostsView.test.jsx index bd734436..7cc1efb1 100644 --- a/src/discussions/posts/PostsView.test.jsx +++ b/src/discussions/posts/PostsView.test.jsx @@ -160,9 +160,9 @@ describe('PostsView', () => { test('displays a list of posts in a topic', async () => { setupStore(); await act(async () => { - await renderComponent({ topicId: 'some-topic-1' }); + await renderComponent({ topicId: 'test-topic-1' }); }); - expect(screen.getAllByText(/this is thread-\d+ in topic some-topic-1/i)).toHaveLength(Math.ceil(threadCount / 3)); + expect(screen.getAllByText(/this is thread-\d+ in topic test-topic-1/i)).toHaveLength(Math.ceil(threadCount / 3)); }); test.each([true, false])( @@ -173,10 +173,10 @@ describe('PostsView', () => { blocks: { 'test-usage-key': { type: 'vertical', - topics: ['some-topic-2', 'some-topic-0'], + topics: ['test-topic-2', 'test-topic-0'], parent: 'test-seq-key', }, - 'test-seq-key': { type: 'sequential', topics: ['some-topic-0', 'some-topic-1', 'some-topic-2'] }, + 'test-seq-key': { type: 'sequential', topics: ['test-topic-0', 'test-topic-1', 'test-topic-2'] }, }, }, config: { groupAtSubsection: grouping, hasModerationPrivileges: true, provider: 'openedx' }, @@ -185,12 +185,12 @@ describe('PostsView', () => { await renderComponent({ category: 'test-usage-key', enableInContextSidebar: true, p: true }); }); const topicThreadCount = Math.ceil(threadCount / 3); - expect(screen.queryAllByText(/this is thread-\d+ in topic some-topic-2/i)) + expect(screen.queryAllByText(/this is thread-\d+ in topic test-topic-2/i)) .toHaveLength(topicThreadCount); - expect(screen.queryAllByText(/this is thread-\d+ in topic some-topic-0/i)) + expect(screen.queryAllByText(/this is thread-\d+ in topic test-topic-0/i)) .toHaveLength(topicThreadCount); // When grouping is enabled, topic 1 will be shown, but not otherwise. - expect(screen.queryAllByText(/this is thread-\d+ in topic some-topic-1/i)) + expect(screen.queryAllByText(/this is thread-\d+ in topic test-topic-1/i)) .toHaveLength(grouping ? topicThreadCount : 2); }, ); diff --git a/src/discussions/posts/data/__factories__/threads.factory.js b/src/discussions/posts/data/__factories__/threads.factory.js index f32a2454..ed74d293 100644 --- a/src/discussions/posts/data/__factories__/threads.factory.js +++ b/src/discussions/posts/data/__factories__/threads.factory.js @@ -7,7 +7,7 @@ Factory.define('thread') .sequence('rendered_body', (idx) => `Some contents for thread number ${idx}.`) .sequence('type', (idx) => (idx % 2 === 1 ? 'discussion' : 'question')) .sequence('pinned', idx => (idx < 3)) - .sequence('topic_id', idx => `some-topic-${(idx % 3)}`) + .sequence('topic_id', idx => `test-topic-${(idx % 3)}`) .sequence('closed', idx => Boolean(idx % 3 === 2)) // Mark every 3rd post closed .attr('comment_list_url', ['id'], (threadId) => `http://test.site/api/discussion/v1/comments/?thread_id=${threadId}`) .attrs({ diff --git a/src/discussions/posts/data/redux.test.js b/src/discussions/posts/data/redux.test.js index b4508e2e..5d463e5d 100644 --- a/src/discussions/posts/data/redux.test.js +++ b/src/discussions/posts/data/redux.test.js @@ -102,7 +102,7 @@ describe('Threads/Posts data layer tests', () => { expect(store.getState().threads.threadsById['thread-1']) .toHaveProperty('topicId'); expect(store.getState().threads.threadsById['thread-1'].topicId) - .toEqual('some-topic-1'); + .toEqual('test-topic-1'); }); test('successfully handles thread creation', async () => { diff --git a/src/discussions/posts/post/Post.jsx b/src/discussions/posts/post/Post.jsx index e84c3b78..1ecbb94d 100644 --- a/src/discussions/posts/post/Post.jsx +++ b/src/discussions/posts/post/Post.jsx @@ -5,6 +5,7 @@ import classNames from 'classnames'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory, useLocation } from 'react-router-dom'; +import { getConfig } from '@edx/frontend-platform'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { Hyperlink, useToggle } from '@edx/paragon'; @@ -87,6 +88,10 @@ function Post({ topicData.usageKey ? getTopicSubsection(topicData.usageKey)?.displayName : topicData.categoryId ); + const getTopicInfo = topicData => ( + getTopicCategoryName(topicData) ? `${getTopicCategoryName(topicData)} / ${topicData.name}` : `${topicData.name}` + ); + return (
- {topicContext && ( + {(topicContext || topic) && (
{intl.formatMessage(messages.relatedTo)}{' '} {(topicContext && !topic) @@ -148,7 +153,7 @@ function Post({ {topicContext.unitName} ) - : `${getTopicCategoryName(topic)} / ${topic.name}`} + : getTopicInfo(topic)}
)}