diff --git a/src/courseware/course/sidebar/sidebars/course-outline/CourseOutlineTray.jsx b/src/courseware/course/sidebar/sidebars/course-outline/CourseOutlineTray.jsx
index 17d75637f2..833562216a 100644
--- a/src/courseware/course/sidebar/sidebars/course-outline/CourseOutlineTray.jsx
+++ b/src/courseware/course/sidebar/sidebars/course-outline/CourseOutlineTray.jsx
@@ -26,7 +26,6 @@ import messages from './messages';
const CourseOutlineTray = ({ intl }) => {
const [selectedSection, setSelectedSection] = useState(null);
- const [openSequenceId, setOpenSequenceId] = useState(null);
const [isDisplaySequenceLevel, setDisplaySequenceLevel, setDisplaySectionLevel] = useToggle(true);
const dispatch = useDispatch();
@@ -63,10 +62,6 @@ const CourseOutlineTray = ({ intl }) => {
setSelectedSection(id);
};
- const handleToggleSequence = (sequenceId) => {
- setOpenSequenceId((prevOpenSequenceId) => (prevOpenSequenceId === sequenceId ? null : sequenceId));
- };
-
const sidebarHeading = (
{isDisplaySequenceLevel && backButtonTitle ? (
@@ -134,8 +129,7 @@ const CourseOutlineTray = ({ intl }) => {
key={sequenceId}
courseId={courseId}
sequence={sequences[sequenceId]}
- isOpen={sequenceId === openSequenceId}
- onToggle={() => handleToggleSequence(sequenceId)}
+ defaultOpen={sequenceId === activeSequenceId}
activeUnitId={unitId}
/>
))
diff --git a/src/courseware/course/sidebar/sidebars/course-outline/CourseOutlineTray.test.jsx b/src/courseware/course/sidebar/sidebars/course-outline/CourseOutlineTray.test.jsx
index 10f8315f01..0302f1e74f 100644
--- a/src/courseware/course/sidebar/sidebars/course-outline/CourseOutlineTray.test.jsx
+++ b/src/courseware/course/sidebar/sidebars/course-outline/CourseOutlineTray.test.jsx
@@ -15,6 +15,7 @@ describe('
', () => {
let store;
let section = {};
let sequence = {};
+ let unit;
let unitId;
let courseId;
let mockData;
@@ -31,6 +32,7 @@ describe('
', () => {
const activeSectionId = Object.keys(state.courseware.courseOutline.sections)[0];
section = state.courseware.courseOutline.sections[activeSectionId];
[unitId] = sequence.unitIds;
+ unit = state.courseware.courseOutline.units[unitId];
}
mockData = {
@@ -82,6 +84,7 @@ describe('
', () => {
expect(screen.getByRole('button', { name: section.title })).toBeInTheDocument();
expect(screen.getByRole('button', { name: messages.toggleCourseOutlineTrigger.defaultMessage })).toBeInTheDocument();
expect(screen.getByRole('button', { name: `${sequence.title} , ${courseOutlineMessages.incompleteAssignment.defaultMessage}` })).toBeInTheDocument();
+ expect(screen.getByText(unit.title)).toBeInTheDocument();
});
it('collapses sidebar correctly when toggle button is clicked', async () => {
@@ -99,30 +102,6 @@ describe('
', () => {
expect(mockToggleSidebar).toHaveBeenCalledWith(null);
});
- it('toggles openSequenceId correctly when a sequence is clicked', async () => {
- const user = userEvent.setup();
- await initTestStore();
- renderWithProvider();
- const sequenceButton = screen.getByRole('button', { name: `${sequence.title} , ${courseOutlineMessages.incompleteAssignment.defaultMessage}` });
- expect(sequenceButton).toBeInTheDocument();
- await user.click(sequenceButton);
- expect(screen.getByRole('button', { name: `${sequence.title} , ${courseOutlineMessages.incompleteAssignment.defaultMessage}` })).toHaveAttribute('aria-expanded', 'true');
- await user.click(sequenceButton);
- expect(screen.getByRole('button', { name: `${sequence.title} , ${courseOutlineMessages.incompleteAssignment.defaultMessage}` })).toHaveAttribute('aria-expanded', 'false');
- });
-
- it('updates setOpenSequenceId correctly when toggling sequences', async () => {
- const user = userEvent.setup();
- await initTestStore();
- renderWithProvider();
- const sequenceButton = screen.getByRole('button', { name: `${sequence.title} , ${courseOutlineMessages.incompleteAssignment.defaultMessage}` });
- expect(sequenceButton).toBeInTheDocument();
- await user.click(sequenceButton);
- expect(sequenceButton).toHaveAttribute('aria-expanded', 'true');
- await user.click(sequenceButton);
- expect(sequenceButton).toHaveAttribute('aria-expanded', 'false');
- });
-
it('navigates to section or sequence level correctly on click by back/section button', async () => {
const user = userEvent.setup();
await initTestStore();
diff --git a/src/courseware/course/sidebar/sidebars/course-outline/components/SidebarSequence.jsx b/src/courseware/course/sidebar/sidebars/course-outline/components/SidebarSequence.jsx
index ebd5cb9a0e..18d41071fb 100644
--- a/src/courseware/course/sidebar/sidebars/course-outline/components/SidebarSequence.jsx
+++ b/src/courseware/course/sidebar/sidebars/course-outline/components/SidebarSequence.jsx
@@ -1,3 +1,4 @@
+import { useState } from 'react';
import { useSelector } from 'react-redux';
import classNames from 'classnames';
import PropTypes from 'prop-types';
@@ -13,8 +14,7 @@ import { UNIT_ICON_TYPES } from './UnitIcon';
const SidebarSequence = ({
intl,
courseId,
- isOpen,
- onToggle,
+ defaultOpen,
sequence,
activeUnitId,
}) => {
@@ -28,6 +28,7 @@ const SidebarSequence = ({
completionStat,
} = sequence;
+ const [open, setOpen] = useState(defaultOpen);
const { units = {} } = useSelector(getCourseOutline);
const activeSequenceId = useSelector(getSequenceId);
const isActiveSequence = id === activeSequenceId;
@@ -52,11 +53,11 @@ const SidebarSequence = ({
return (
setOpen(!open)}
>
{unitIds.map((unitId, index) => (
@@ -81,8 +82,7 @@ const SidebarSequence = ({
SidebarSequence.propTypes = {
intl: intlShape.isRequired,
courseId: PropTypes.string.isRequired,
- isOpen: PropTypes.bool.isRequired,
- onToggle: PropTypes.func.isRequired,
+ defaultOpen: PropTypes.bool.isRequired,
sequence: PropTypes.shape({
complete: PropTypes.bool,
id: PropTypes.string,
diff --git a/src/courseware/course/sidebar/sidebars/course-outline/components/SidebarSequence.test.jsx b/src/courseware/course/sidebar/sidebars/course-outline/components/SidebarSequence.test.jsx
index 8f2b0dcb16..26a0c72261 100644
--- a/src/courseware/course/sidebar/sidebars/course-outline/components/SidebarSequence.test.jsx
+++ b/src/courseware/course/sidebar/sidebars/course-outline/components/SidebarSequence.test.jsx
@@ -1,11 +1,12 @@
import { MemoryRouter } from 'react-router-dom';
-import { render, screen } from '@testing-library/react';
+import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { AppProvider } from '@edx/frontend-platform/react';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import courseOutlineMessages from '@src/course-home/outline-tab/messages';
import { initializeMockApp, initializeTestStore } from '@src/setupTest';
+import messages from '../messages';
import SidebarSequence from './SidebarSequence';
initializeMockApp();
@@ -14,6 +15,7 @@ describe('', () => {
let courseId;
let store;
let sequence;
+ let unit;
const sequenceDescription = 'sequence test description';
const initTestStore = async (options) => {
@@ -23,6 +25,8 @@ describe('', () => {
let activeSequenceId = '';
[activeSequenceId] = Object.keys(state.courseware.courseOutline.sequences);
sequence = state.courseware.courseOutline.sequences[activeSequenceId];
+ const unitId = sequence.unitIds[0];
+ unit = state.courseware.courseOutline.units[unitId];
};
function renderWithProvider(props = {}) {
@@ -51,6 +55,7 @@ describe('', () => {
expect(screen.getByText(sequence.title)).toBeInTheDocument();
expect(screen.queryByText(sequenceDescription)).not.toBeInTheDocument();
expect(screen.getByText(`, ${courseOutlineMessages.incompleteAssignment.defaultMessage}`)).toBeInTheDocument();
+ expect(screen.queryByText(unit.title)).not.toBeInTheDocument();
});
it('renders correctly when sequence is not collapsed and complete', async () => {
@@ -68,6 +73,13 @@ describe('', () => {
expect(screen.getByText(sequence.title)).toBeInTheDocument();
expect(screen.getByText(sequenceDescription)).toBeInTheDocument();
expect(screen.getByText(`, ${courseOutlineMessages.completedAssignment.defaultMessage}`)).toBeInTheDocument();
+ expect(screen.getByText(unit.title)).toBeInTheDocument();
+ expect(screen.getByText(`, ${messages.incompleteUnit.defaultMessage}`)).toBeInTheDocument();
+
await user.click(screen.getByText(sequence.title));
+ await waitFor(() => {
+ expect(screen.queryByText(unit.title)).not.toBeInTheDocument();
+ expect(screen.queryByText(`, ${messages.incompleteUnit.defaultMessage}`)).not.toBeInTheDocument();
+ });
});
});