fix: breadcrumb preview link
This commit is contained in:
committed by
Feanil Patel
parent
cf4bea3604
commit
5b7f76b43d
@@ -1,134 +0,0 @@
|
||||
import React from 'react';
|
||||
import { screen, render } from '@testing-library/react';
|
||||
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { useModel, useModels } from '../../generic/model-store';
|
||||
import CourseBreadcrumbs from './CourseBreadcrumbs';
|
||||
|
||||
jest.mock('@edx/frontend-platform');
|
||||
jest.mock('@edx/frontend-platform/analytics');
|
||||
|
||||
// Remove When Fully rolled out>>>
|
||||
jest.mock('../../generic/model-store');
|
||||
jest.mock('@edx/frontend-platform/auth');
|
||||
getConfig.mockImplementation(() => ({ ENABLE_JUMPNAV: 'true' }));
|
||||
getAuthenticatedUser.mockImplementation(() => ({ administrator: true }));
|
||||
// ^^^^Remove When Fully rolled out
|
||||
|
||||
jest.mock('react-redux', () => ({
|
||||
connect: (mapStateToProps, mapDispatchToProps) => (ReactComponent) => ({
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
ReactComponent,
|
||||
}),
|
||||
Provider: ({ children }) => children,
|
||||
useSelector: () => 'loaded',
|
||||
}));
|
||||
jest.mock('react-router-dom', () => ({
|
||||
...jest.requireActual('react-router-dom'),
|
||||
Link: jest.fn().mockImplementation(({ to, children }) => (
|
||||
<a href={to}>{children}</a>
|
||||
)),
|
||||
}));
|
||||
|
||||
useModels.mockImplementation((name) => {
|
||||
if (name === 'sections') {
|
||||
return [
|
||||
{
|
||||
courseId: 'course-v1:edX+DemoX+Demo_Course',
|
||||
id: 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@d8a6192ade314473a78242dfeedfbf5b',
|
||||
sequenceIds: ['block-v1:edX+DemoX+Demo_Course+type@sequential+block@edx_introduction'],
|
||||
title: 'Introduction',
|
||||
},
|
||||
{
|
||||
courseId: 'course-v1:edX+DemoX+Demo_Course',
|
||||
id: 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations',
|
||||
sequenceIds: ['block-v1:edX+DemoX+Demo_Course+type@sequential+block@19a30717eff543078a5d94ae9d6c18a5',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions'],
|
||||
title: 'Example Week 1: Getting Started',
|
||||
},
|
||||
];
|
||||
}
|
||||
return [
|
||||
{
|
||||
id: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@19a30717eff543078a5d94ae9d6c18a5',
|
||||
sectionId: 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations',
|
||||
title: 'Lesson 1 - Getting Started',
|
||||
unitIds: [
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@867dddb6f55d410caaa9c1eb9c6743ec',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@4f6c1b4e316a419ab5b6bf30e6c708e9',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@3dc16db8d14842e38324e95d4030b8a0',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@4a1bba2a403f40bca5ec245e945b0d76',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@256f17a44983429fb1a60802203ee4e0',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@e3601c0abee6427d8c17e6d6f8fdddd1',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@134df56c516a4a0dbb24dd5facef746e',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions',
|
||||
sectionId: 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations',
|
||||
title: 'Homework - Question Styles',
|
||||
unitIds: [
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@2152d4a4aadc4cb0af5256394a3d1fc7',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@47dbd5f836544e61877a483c0b75606c',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@54bb9b142c6c4c22afc62bcb628f0e68',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical_0c92347a5c00',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical_1fef54c2b23b',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@2889db1677a549abb15eb4d886f95d1c',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@vertical+block@e8a5cc2aed424838853defab7be45e42',
|
||||
],
|
||||
},
|
||||
];
|
||||
});
|
||||
useModel.mockImplementation(() => ({
|
||||
sectionIds: ['block-v1:edX+DemoX+Demo_Course+type@chapter+block@d8a6192ade314473a78242dfeedfbf5b',
|
||||
'block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations'],
|
||||
}));
|
||||
|
||||
describe('CourseBreadcrumbs', () => {
|
||||
jest.spyOn(React, 'useMemo').mockImplementation(() => [
|
||||
[
|
||||
{
|
||||
default: false,
|
||||
id: 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@d8a6192ade314473a78242dfeedfbf5b',
|
||||
label: 'Introduction',
|
||||
url: 'http://localhost:2000/course/course-v1:edX+DemoX+Demo_Course/block-v1:edX+DemoX+Demo_Course+type@sequential+block@edx_introduction',
|
||||
},
|
||||
{
|
||||
default: true,
|
||||
id: 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations',
|
||||
label: 'Example Week 1: Getting Started',
|
||||
url: 'http://localhost:2000/course/course-v1:edX+DemoX+Demo_Course/block-v1:edX+DemoX+Demo_Course+type@sequential+block@19a30717eff543078a5d94ae9d6c18a5',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
id: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@simulations', label: "Lesson 2 - Let's Get Interactive!", default: true, url: 'http://localhost:2000/course/course-v1:edX+DemoX+D…e@vertical+block@d0d804e8863c4a95a659c04d8a2b2bc0',
|
||||
},
|
||||
{
|
||||
id: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@175e76c4951144a29d46211361266e0e', label: 'Homework - Essays', default: false, url: 'http://localhost:2000/course/course-v1:edX+DemoX+D…e@vertical+block@fb79dcbad35b466a8c6364f8ffee9050',
|
||||
},
|
||||
],
|
||||
]);
|
||||
render(
|
||||
<IntlProvider>
|
||||
<BrowserRouter>
|
||||
<CourseBreadcrumbs
|
||||
courseId="course-v1:edX+DemoX+Demo_Course"
|
||||
sectionId="block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations"
|
||||
sequenceId="block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions"
|
||||
isStaff
|
||||
/>
|
||||
</BrowserRouter>,
|
||||
</IntlProvider>,
|
||||
);
|
||||
it('renders course breadcrumbs as expected', async () => {
|
||||
expect(screen.queryAllByRole('link')).toHaveLength(1);
|
||||
const courseHomeButtonDestination = screen.getAllByRole('link')[0].href;
|
||||
expect(courseHomeButtonDestination).toBe('http://localhost/course/course-v1:edX+DemoX+Demo_Course/home');
|
||||
expect(screen.getByRole('navigation', { name: 'breadcrumb' })).toBeInTheDocument();
|
||||
expect(screen.queryAllByTestId('breadcrumb-item')).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
103
src/courseware/course/breadcrumbs/BreadcrumbItem.tsx
Normal file
103
src/courseware/course/breadcrumbs/BreadcrumbItem.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
import React, { useState } from 'react';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import {
|
||||
useToggle,
|
||||
ModalPopup,
|
||||
Menu,
|
||||
} from '@openedx/paragon';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import JumpNavMenuItem from '../JumpNavMenuItem';
|
||||
|
||||
interface Props {
|
||||
content: {
|
||||
default: boolean,
|
||||
id: string,
|
||||
label: string,
|
||||
sequences: {
|
||||
id: string,
|
||||
}[],
|
||||
} [];
|
||||
withSeparator: boolean | false,
|
||||
separator: string | '';
|
||||
courseId: string;
|
||||
sequenceId: string | '';
|
||||
unitId: string | '';
|
||||
isStaff: boolean | false;
|
||||
}
|
||||
|
||||
const BreadcrumbItem: React.FC<Props> = ({
|
||||
content,
|
||||
withSeparator,
|
||||
separator,
|
||||
courseId,
|
||||
sequenceId,
|
||||
unitId,
|
||||
isStaff,
|
||||
}) => {
|
||||
const defaultContent = content.filter(
|
||||
(destination: { default: boolean }) => destination.default,
|
||||
)[0] || { id: courseId, label: '', sequences: [] };
|
||||
|
||||
const showRegularLink = getConfig().ENABLE_JUMPNAV !== 'true' || content.length < 2 || !isStaff;
|
||||
const [isOpen, open, close] = useToggle(false);
|
||||
const [target, setTarget] = useState(null);
|
||||
|
||||
const { pathname } = useLocation();
|
||||
const isPreview = pathname.startsWith('/preview');
|
||||
const baseUrl = defaultContent.sequences.length
|
||||
? `/course/${courseId}/${defaultContent.sequences[0].id}`
|
||||
: `/course/${courseId}/${defaultContent.id}`;
|
||||
const link = isPreview ? `/preview${baseUrl}` : baseUrl;
|
||||
return (
|
||||
<>
|
||||
{withSeparator && separator && (
|
||||
<li className="col-auto p-0 mx-2 text-primary-500 text-truncate text-nowrap" role="presentation" aria-hidden>{separator}</li>
|
||||
)}
|
||||
|
||||
<li
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
data-testid="breadcrumb-item"
|
||||
>
|
||||
{showRegularLink ? (
|
||||
<Link
|
||||
className="text-primary-500"
|
||||
to={link}
|
||||
>
|
||||
{defaultContent.label}
|
||||
</Link>
|
||||
) : (
|
||||
<>
|
||||
{
|
||||
// @ts-ignore
|
||||
<a className="text-primary-500" variant="link" onClick={open} ref={setTarget}>
|
||||
{defaultContent.label}
|
||||
</a>
|
||||
}
|
||||
<ModalPopup positionRef={target} isOpen={isOpen} onClose={close}>
|
||||
<Menu>
|
||||
{content.map((item) => (
|
||||
<JumpNavMenuItem
|
||||
key={item.label}
|
||||
isDefault={item.default}
|
||||
sequences={item.sequences}
|
||||
courseId={courseId}
|
||||
title={item.label}
|
||||
currentSequence={sequenceId}
|
||||
currentUnit={unitId}
|
||||
onClick={close}
|
||||
/>
|
||||
))}
|
||||
</Menu>
|
||||
</ModalPopup>
|
||||
</>
|
||||
)}
|
||||
</li>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BreadcrumbItem;
|
||||
@@ -1,107 +1,12 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faHome } from '@fortawesome/free-solid-svg-icons';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useToggle, ModalPopup, Menu } from '@openedx/paragon';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useModel, useModels } from '../../generic/model-store';
|
||||
import JumpNavMenuItem from './JumpNavMenuItem';
|
||||
|
||||
const CourseBreadcrumb = ({
|
||||
content,
|
||||
withSeparator,
|
||||
courseId,
|
||||
sequenceId,
|
||||
unitId,
|
||||
isStaff,
|
||||
}) => {
|
||||
const defaultContent = content.filter(
|
||||
(destination) => destination.default,
|
||||
)[0] || { id: courseId, label: '', sequences: [] };
|
||||
|
||||
const showRegularLink = getConfig().ENABLE_JUMPNAV !== 'true' || content.length < 2 || !isStaff;
|
||||
const [isOpen, open, close] = useToggle(false);
|
||||
const [target, setTarget] = useState(null);
|
||||
return (
|
||||
<>
|
||||
{withSeparator && (
|
||||
<li className="col-auto p-0 mx-2 text-primary-500 text-truncate text-nowrap" role="presentation" aria-hidden>/</li>
|
||||
)}
|
||||
|
||||
<li
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
data-testid="breadcrumb-item"
|
||||
>
|
||||
{showRegularLink ? (
|
||||
<Link
|
||||
className="text-primary-500"
|
||||
to={
|
||||
defaultContent.sequences.length
|
||||
? `/course/${courseId}/${defaultContent.sequences[0].id}`
|
||||
: `/course/${courseId}/${defaultContent.id}`
|
||||
}
|
||||
>
|
||||
{defaultContent.label}
|
||||
</Link>
|
||||
) : (
|
||||
<>
|
||||
{
|
||||
// eslint-disable-next-line
|
||||
<a className="text-primary-500" onClick={open} ref={setTarget}>
|
||||
{defaultContent.label}
|
||||
</a>
|
||||
}
|
||||
<ModalPopup positionRef={target} isOpen={isOpen} onClose={close}>
|
||||
<Menu>
|
||||
{content.map((item) => (
|
||||
<JumpNavMenuItem
|
||||
key={item.label}
|
||||
isDefault={item.default}
|
||||
sequences={item.sequences}
|
||||
courseId={courseId}
|
||||
title={item.label}
|
||||
currentSequence={sequenceId}
|
||||
currentUnit={unitId}
|
||||
onClick={close}
|
||||
/>
|
||||
))}
|
||||
</Menu>
|
||||
</ModalPopup>
|
||||
</>
|
||||
)}
|
||||
</li>
|
||||
</>
|
||||
);
|
||||
};
|
||||
CourseBreadcrumb.propTypes = {
|
||||
content: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
default: PropTypes.bool,
|
||||
id: PropTypes.string,
|
||||
label: PropTypes.string,
|
||||
}),
|
||||
).isRequired,
|
||||
sequenceId: PropTypes.string,
|
||||
unitId: PropTypes.string,
|
||||
withSeparator: PropTypes.bool,
|
||||
courseId: PropTypes.string,
|
||||
isStaff: PropTypes.bool,
|
||||
};
|
||||
|
||||
CourseBreadcrumb.defaultProps = {
|
||||
withSeparator: false,
|
||||
sequenceId: null,
|
||||
unitId: null,
|
||||
courseId: null,
|
||||
isStaff: null,
|
||||
};
|
||||
import { useModel, useModels } from '../../../generic/model-store';
|
||||
import BreadcrumbItem from './BreadcrumbItem';
|
||||
|
||||
const CourseBreadcrumbs = ({
|
||||
courseId,
|
||||
@@ -110,14 +15,16 @@ const CourseBreadcrumbs = ({
|
||||
unitId,
|
||||
isStaff,
|
||||
}) => {
|
||||
const course = useModel('coursewareMeta', courseId);
|
||||
const course = useModel('coursewareMeta', courseId);
|
||||
const courseStatus = useSelector((state) => state.courseware.courseStatus);
|
||||
const sequenceStatus = useSelector(
|
||||
(state) => state.courseware.sequenceStatus,
|
||||
);
|
||||
console.log( useModels('sections', course.sectionIds));
|
||||
|
||||
|
||||
const allSequencesInSections = Object.fromEntries(
|
||||
useModels('sections', course.sectionIds).map((section) => [
|
||||
useModels('sections', course.sectionIds)?.map((section) => [
|
||||
section.id,
|
||||
{
|
||||
default: section.id === sectionId,
|
||||
@@ -152,6 +59,8 @@ const CourseBreadcrumbs = ({
|
||||
}
|
||||
return [chapters, sequentials];
|
||||
}, [courseStatus, sequenceStatus, allSequencesInSections]);
|
||||
console.log(links);
|
||||
|
||||
|
||||
return (
|
||||
<nav aria-label="breadcrumb" className="d-inline-block col-sm-10 mb-3">
|
||||
@@ -171,7 +80,7 @@ const CourseBreadcrumbs = ({
|
||||
</Link>
|
||||
</li>
|
||||
{links.map((content, i) => (
|
||||
<CourseBreadcrumb
|
||||
<BreadcrumbItem
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={i}
|
||||
courseId={courseId}
|
||||
@@ -179,6 +88,7 @@ const CourseBreadcrumbs = ({
|
||||
content={content}
|
||||
unitId={unitId}
|
||||
withSeparator
|
||||
separator="/"
|
||||
isStaff={isStaff}
|
||||
/>
|
||||
))}
|
||||
190
src/courseware/course/breadcrumbs/CourseBreadcrumbs.test.jsx
Normal file
190
src/courseware/course/breadcrumbs/CourseBreadcrumbs.test.jsx
Normal file
@@ -0,0 +1,190 @@
|
||||
import { Factory } from 'rosie';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { initializeMockApp, initializeTestStore } from '@src/setupTest';
|
||||
import CourseBreadcrumbs from './CourseBreadcrumbs';
|
||||
|
||||
// import { useModel, useModels } from '../../../generic/model-store';
|
||||
|
||||
// jest.mock('@edx/frontend-platform');
|
||||
// jest.mock('@edx/frontend-platform/analytics');
|
||||
|
||||
// // Remove When Fully rolled out>>>
|
||||
// jest.mock('../../../generic/model-store');
|
||||
// jest.mock('@edx/frontend-platform/auth');
|
||||
// getConfig.mockImplementation(() => ({ ENABLE_JUMPNAV: 'true' }));
|
||||
// getAuthenticatedUser.mockImplementation(() => ({ administrator: true }));
|
||||
// // ^^^^Remove When Fully rolled out
|
||||
|
||||
// jest.mock('react-redux', () => ({
|
||||
// connect: (mapStateToProps, mapDispatchToProps) => (ReactComponent) => ({
|
||||
// mapStateToProps,
|
||||
// mapDispatchToProps,
|
||||
// ReactComponent,
|
||||
// }),
|
||||
// Provider: ({ children }) => children,
|
||||
// useSelector: () => 'loaded',
|
||||
// }));
|
||||
// jest.mock('react-router-dom', () => ({
|
||||
// ...jest.requireActual('react-router-dom'),
|
||||
// Link: jest.fn().mockImplementation(({ to, children }) => (
|
||||
// <a href={to}>{children}</a>
|
||||
// )),
|
||||
// }));
|
||||
|
||||
// useModels.mockImplementation((name) => {
|
||||
// if (name === 'sections') {
|
||||
// return [
|
||||
// {
|
||||
// courseId: 'course-v1:edX+DemoX+Demo_Course',
|
||||
// id: 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@d8a6192ade314473a78242dfeedfbf5b',
|
||||
// sequenceIds: ['block-v1:edX+DemoX+Demo_Course+type@sequential+block@edx_introduction'],
|
||||
// title: 'Introduction',
|
||||
// },
|
||||
// {
|
||||
// courseId: 'course-v1:edX+DemoX+Demo_Course',
|
||||
// id: 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations',
|
||||
// sequenceIds: ['block-v1:edX+DemoX+Demo_Course+type@sequential+block@19a30717eff543078a5d94ae9d6c18a5',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions'],
|
||||
// title: 'Example Week 1: Getting Started',
|
||||
// },
|
||||
// ];
|
||||
// }
|
||||
// return [
|
||||
// {
|
||||
// id: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@19a30717eff543078a5d94ae9d6c18a5',
|
||||
// sectionId: 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations',
|
||||
// title: 'Lesson 1 - Getting Started',
|
||||
// unitIds: [
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@867dddb6f55d410caaa9c1eb9c6743ec',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@4f6c1b4e316a419ab5b6bf30e6c708e9',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@3dc16db8d14842e38324e95d4030b8a0',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@4a1bba2a403f40bca5ec245e945b0d76',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@256f17a44983429fb1a60802203ee4e0',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@e3601c0abee6427d8c17e6d6f8fdddd1',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@134df56c516a4a0dbb24dd5facef746e',
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// id: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions',
|
||||
// sectionId: 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations',
|
||||
// title: 'Homework - Question Styles',
|
||||
// unitIds: [
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@2152d4a4aadc4cb0af5256394a3d1fc7',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@47dbd5f836544e61877a483c0b75606c',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@54bb9b142c6c4c22afc62bcb628f0e68',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical_0c92347a5c00',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical_1fef54c2b23b',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@2889db1677a549abb15eb4d886f95d1c',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@e8a5cc2aed424838853defab7be45e42',
|
||||
// ],
|
||||
// },
|
||||
// ];
|
||||
// });
|
||||
// useModel.mockImplementation(() => ({
|
||||
// sectionIds: ['block-v1:edX+DemoX+Demo_Course+type@chapter+block@d8a6192ade314473a78242dfeedfbf5b',
|
||||
// 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations'],
|
||||
// }));
|
||||
|
||||
const props = {
|
||||
courseId: "course-v1:edX+DemoX+Demo_Course",
|
||||
sectionId: "block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations",
|
||||
sequenceId: "block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions",
|
||||
isStaff: true,
|
||||
}
|
||||
|
||||
const courseMetadata = Factory.build('courseMetadata', { courseId: props.courseId, sectionIds: [props.sectionId] });
|
||||
const sequenceBlocks = [Factory.build(
|
||||
'block',
|
||||
{ type: 'sequential', id: props.sequenceId, title: 'Subsection' },
|
||||
{ courseId: props.courseId },
|
||||
)];
|
||||
const sectionBlocks = [Factory.build(
|
||||
'block',
|
||||
{ type: 'chapter',
|
||||
id: props.sectionId,
|
||||
title: 'Section',
|
||||
children: [{ id: props.sequenceId}],
|
||||
},
|
||||
{ courseId: props.courseId },
|
||||
)];
|
||||
|
||||
initializeMockApp();
|
||||
|
||||
describe('CourseBreadcrumbs', () => {
|
||||
let store = {};
|
||||
let unit;
|
||||
let sequenceId;
|
||||
|
||||
const initTestStore = async () => {
|
||||
const courseBlocks = { sectionBlocks, sequenceBlocks };
|
||||
console.log(courseBlocks);
|
||||
|
||||
store = await initializeTestStore({ courseMetadata, ...courseBlocks });
|
||||
const state = store.getState();
|
||||
[sequenceId] = Object.keys(state.courseware.courseOutline.sequences);
|
||||
const sequence = state.courseware.courseOutline.sequences[sequenceId];
|
||||
unit = state.courseware.courseOutline.units[sequence.unitIds[0]];
|
||||
};
|
||||
|
||||
function renderWithProvider (pathname = '/course') {
|
||||
const { container } = render(
|
||||
<AppProvider store={store} wrapWithRouter={false}>
|
||||
<IntlProvider locale="en">
|
||||
<MemoryRouter initialEntries={[{ pathname }]}>
|
||||
<CourseBreadcrumbs {...props} />
|
||||
</MemoryRouter>
|
||||
</IntlProvider>
|
||||
</AppProvider>,
|
||||
);
|
||||
return container;
|
||||
}
|
||||
|
||||
describe('in live view', () => {
|
||||
it('renders course breadcrumbs as expected', async () => {
|
||||
await initTestStore();
|
||||
renderWithProvider();
|
||||
const courseHomeButtonDestination = screen.getAllByRole('link')[0].href;
|
||||
|
||||
expect(courseHomeButtonDestination).toBe('http://localhost/course/course-v1:edX+DemoX+Demo_Course/home');
|
||||
|
||||
expect(screen.getByRole('navigation', { name: 'breadcrumb' })).toBeInTheDocument();
|
||||
|
||||
expect(screen.queryAllByTestId('breadcrumb-item')).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('section link does not include /preview/', async () => {
|
||||
await initTestStore();
|
||||
renderWithProvider();
|
||||
const sectionBreadcrumb = screen.getByText(sectionBlocks[0].block_id);
|
||||
const sectionLink = sectionBreadcrumb.closest('a').href;
|
||||
|
||||
expect(sectionLink.includes('/preview/')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('in live view', () => {
|
||||
it('renders course breadcrumbs as expected', async () => {
|
||||
await initTestStore();
|
||||
renderWithProvider('/preview/courses');
|
||||
const courseHomeButtonDestination = screen.getAllByRole('link')[0].href;
|
||||
|
||||
expect(courseHomeButtonDestination).toBe('http://localhost/course/course-v1:edX+DemoX+Demo_Course/home');
|
||||
|
||||
expect(screen.getByRole('navigation', { name: 'breadcrumb' })).toBeInTheDocument();
|
||||
|
||||
expect(screen.queryAllByTestId('breadcrumb-item')).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('section link does includes /preview/', async () => {
|
||||
await initTestStore();
|
||||
renderWithProvider('/preview/courses');
|
||||
const sectionBreadcrumb = screen.getByText(sectionBlocks[0].block_id);
|
||||
const sectionLink = sectionBreadcrumb.closest('a').href;
|
||||
|
||||
expect(sectionLink.includes('/preview/')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
3
src/courseware/course/breadcrumbs/index.js
Normal file
3
src/courseware/course/breadcrumbs/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import CourseBreadcrumbs from './CourseBreadcrumbs';
|
||||
|
||||
export default CourseBreadcrumbs;
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
|
||||
import { PluginSlot } from '@openedx/frontend-plugin-framework';
|
||||
|
||||
import CourseBreadcrumbs from '../../courseware/course/CourseBreadcrumbs';
|
||||
import CourseBreadcrumbs from '../../courseware/course/breadcrumbs';
|
||||
|
||||
interface Props {
|
||||
courseId: string;
|
||||
|
||||
Reference in New Issue
Block a user