Compare commits
2 Commits
dependabot
...
sundas/INF
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f9ddda706 | ||
|
|
9b60c68b1d |
1
src/components/NavigationBar/data/__factories__/index.js
Normal file
1
src/components/NavigationBar/data/__factories__/index.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import './navigationBar.factory';
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { Factory } from 'rosie';
|
||||||
|
|
||||||
|
import { getApiBaseUrl } from '../../../../data/constants';
|
||||||
|
|
||||||
|
Factory.define('navigationBar')
|
||||||
|
.attr('can_show_upgrade_sock', null, false)
|
||||||
|
.attr('can_view_certificate', null, false)
|
||||||
|
.attr('celebrations', null, {
|
||||||
|
first_section: false, streak_discount_enabled: false, streak_length_to_celebrate: null, weekly_goal: false,
|
||||||
|
})
|
||||||
|
.option('hasCourseAccess', null, true)
|
||||||
|
|
||||||
|
.attr('course_access', ['hasCourseAccess'], (hasCourseAccess) => ({
|
||||||
|
additional_context_user_message: null,
|
||||||
|
developer_message: null,
|
||||||
|
error_code: null,
|
||||||
|
has_access: hasCourseAccess,
|
||||||
|
user_fragment: null,
|
||||||
|
user_message: null,
|
||||||
|
}))
|
||||||
|
.option('course_id', null, 'course-v1:edX+DemoX+Demo_Course')
|
||||||
|
.attr('is_enrolled', null, false)
|
||||||
|
.attr('is_self_paced', null, false)
|
||||||
|
.attr('is_staff', null, true)
|
||||||
|
.attr('number', null, 'DemoX')
|
||||||
|
.attr('org', null, 'edX')
|
||||||
|
.attr('original_user_is_staff', null, true)
|
||||||
|
.attr('title', null, 'Demonstration Course')
|
||||||
|
.attr('username', null, 'edx')
|
||||||
|
.attr('tabs', ['course_id'], (idx, courseId) => [
|
||||||
|
{
|
||||||
|
tab_id: 'courseware',
|
||||||
|
title: 'Course',
|
||||||
|
url: `${getApiBaseUrl}/course/${courseId}/home`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tab_id: 'progress',
|
||||||
|
title: 'Progress',
|
||||||
|
url: `${getApiBaseUrl}/course/${courseId}/progress`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tab_id: 'discussion',
|
||||||
|
title: 'Discussion',
|
||||||
|
url: `${getApiBaseUrl}/course/${courseId}/discussion/forum/`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tab_id: 'instructor',
|
||||||
|
title: 'Instructor',
|
||||||
|
url: `${getApiBaseUrl}/course/${courseId}/instructor`,
|
||||||
|
}]);
|
||||||
@@ -4,6 +4,8 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
|||||||
|
|
||||||
import { getApiBaseUrl } from '../../../data/constants';
|
import { getApiBaseUrl } from '../../../data/constants';
|
||||||
|
|
||||||
|
export const getCourseMetadataApiUrl = (courseId) => `${getApiBaseUrl()}/api/course_home/course_metadata/${courseId}`;
|
||||||
|
|
||||||
function normalizeCourseHomeCourseMetadata(metadata, rootSlug) {
|
function normalizeCourseHomeCourseMetadata(metadata, rootSlug) {
|
||||||
const data = camelCaseObject(metadata);
|
const data = camelCaseObject(metadata);
|
||||||
return {
|
return {
|
||||||
@@ -21,7 +23,7 @@ function normalizeCourseHomeCourseMetadata(metadata, rootSlug) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getCourseHomeCourseMetadata(courseId, rootSlug) {
|
export async function getCourseHomeCourseMetadata(courseId, rootSlug) {
|
||||||
const url = `${getApiBaseUrl()}/api/course_home/course_metadata/${courseId}`;
|
const url = getCourseMetadataApiUrl(courseId);
|
||||||
// don't know the context of adding timezone in url. hence omitting it
|
// don't know the context of adding timezone in url. hence omitting it
|
||||||
// url = appendBrowserTimezoneToUrl(url);
|
// url = appendBrowserTimezoneToUrl(url);
|
||||||
const { data } = await getAuthenticatedHttpClient().get(url);
|
const { data } = await getAuthenticatedHttpClient().get(url);
|
||||||
|
|||||||
65
src/components/NavigationBar/data/api.test.js
Normal file
65
src/components/NavigationBar/data/api.test.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
|
import { Factory } from 'rosie';
|
||||||
|
|
||||||
|
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||||
|
import { initializeMockApp } from '@edx/frontend-platform/testing';
|
||||||
|
|
||||||
|
import { initializeStore } from '../../../store';
|
||||||
|
import { executeThunk } from '../../../test-utils';
|
||||||
|
import { getCourseMetadataApiUrl } from './api';
|
||||||
|
import { fetchTab } from './thunks';
|
||||||
|
|
||||||
|
import './__factories__';
|
||||||
|
|
||||||
|
const courseId = 'course-v1:edX+TestX+Test_Course';
|
||||||
|
let axiosMock = null;
|
||||||
|
let store;
|
||||||
|
|
||||||
|
describe('Navigation bar api tests', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
initializeMockApp({
|
||||||
|
authenticatedUser: {
|
||||||
|
userId: 3,
|
||||||
|
username: 'abc123',
|
||||||
|
administrator: true,
|
||||||
|
roles: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
|
||||||
|
store = initializeStore();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
axiosMock.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Successfully get navigation tabs', async () => {
|
||||||
|
axiosMock.onGet(`${getCourseMetadataApiUrl(courseId)}`).reply(200, (Factory.build('navigationBar', 1)));
|
||||||
|
await executeThunk(fetchTab(courseId, 'outline'), store.dispatch, store.getState);
|
||||||
|
|
||||||
|
expect(store.getState().courseTabs.tabs).toHaveLength(4);
|
||||||
|
expect(store.getState().courseTabs.courseStatus).toEqual('loaded');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Failed to get navigation tabs', async () => {
|
||||||
|
axiosMock.onGet(`${getCourseMetadataApiUrl(courseId)}`).reply(404);
|
||||||
|
await executeThunk(fetchTab(courseId, 'outline'), store.dispatch, store.getState);
|
||||||
|
|
||||||
|
expect(store.getState().courseTabs.courseStatus).toEqual('failed');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Denied to get navigation tabs', async () => {
|
||||||
|
axiosMock.onGet(`${getCourseMetadataApiUrl(courseId)}`).reply(403, {});
|
||||||
|
await executeThunk(fetchTab(courseId, 'outline'), store.dispatch, store.getState);
|
||||||
|
|
||||||
|
expect(store.getState().courseTabs.courseStatus).toEqual('denied');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Denied to get navigation bar when user has no access on course', async () => {
|
||||||
|
axiosMock.onGet(`${getCourseMetadataApiUrl(courseId)}`).reply(200,
|
||||||
|
(Factory.build('navigationBar', 1, { hasCourseAccess: false })));
|
||||||
|
await executeThunk(fetchTab(courseId, 'outline'), store.dispatch, store.getState);
|
||||||
|
|
||||||
|
expect(store.getState().courseTabs.courseStatus).toEqual('denied');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable import/prefer-default-export, no-unused-expressions */
|
/* eslint-disable import/prefer-default-export, no-unused-expressions */
|
||||||
import { logError } from '@edx/frontend-platform/logging';
|
import { logError } from '@edx/frontend-platform/logging';
|
||||||
|
|
||||||
|
import { getHttpErrorStatus } from '../../../discussions/utils';
|
||||||
import { getCourseHomeCourseMetadata } from './api';
|
import { getCourseHomeCourseMetadata } from './api';
|
||||||
import {
|
import {
|
||||||
fetchTabDenied,
|
fetchTabDenied,
|
||||||
@@ -26,7 +27,11 @@ export function fetchTab(courseId, rootSlug) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (getHttpErrorStatus(e) === 403) {
|
||||||
|
dispatch(fetchTabDenied({ courseId }));
|
||||||
|
} else {
|
||||||
dispatch(fetchTabFailure({ courseId }));
|
dispatch(fetchTabFailure({ courseId }));
|
||||||
|
}
|
||||||
logError(e);
|
logError(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import { initializeMockApp } from '@edx/frontend-platform';
|
|||||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||||
import { AppProvider } from '@edx/frontend-platform/react';
|
import { AppProvider } from '@edx/frontend-platform/react';
|
||||||
|
|
||||||
|
import { getCourseMetadataApiUrl } from '../../components/NavigationBar/data/api';
|
||||||
|
import { fetchTab } from '../../components/NavigationBar/data/thunks';
|
||||||
import { getApiBaseUrl } from '../../data/constants';
|
import { getApiBaseUrl } from '../../data/constants';
|
||||||
import { initializeStore } from '../../store';
|
import { initializeStore } from '../../store';
|
||||||
import { executeThunk } from '../../test-utils';
|
import { executeThunk } from '../../test-utils';
|
||||||
@@ -28,6 +30,7 @@ import DiscussionsHome from './DiscussionsHome';
|
|||||||
import '../posts/data/__factories__/threads.factory';
|
import '../posts/data/__factories__/threads.factory';
|
||||||
import '../in-context-topics/data/__factories__/inContextTopics.factory';
|
import '../in-context-topics/data/__factories__/inContextTopics.factory';
|
||||||
import '../topics/data/__factories__/topics.factory';
|
import '../topics/data/__factories__/topics.factory';
|
||||||
|
import '../../components/NavigationBar/data/__factories__/navigationBar.factory';
|
||||||
|
|
||||||
const courseConfigApiUrl = getCourseConfigApiUrl();
|
const courseConfigApiUrl = getCourseConfigApiUrl();
|
||||||
let axiosMock;
|
let axiosMock;
|
||||||
@@ -247,4 +250,12 @@ describe('DiscussionsHome', () => {
|
|||||||
|
|
||||||
expect(screen.queryByText('No topic selected')).toBeInTheDocument();
|
expect(screen.queryByText('No topic selected')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should display navigation tabs', async () => {
|
||||||
|
axiosMock.onGet(`${getCourseMetadataApiUrl(courseId)}`).reply(200, (Factory.build('navigationBar', 1)));
|
||||||
|
await executeThunk(fetchTab(courseId, 'outline'), store.dispatch, store.getState);
|
||||||
|
renderComponent(`/${courseId}/topics`);
|
||||||
|
|
||||||
|
expect(screen.queryByText('Discussion')).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user