Skip to content

Commit

Permalink
test: improve coverage for course outline
Browse files Browse the repository at this point in the history
refactor: remove delete unit hook and thunk till unit list is implemented

test: additional tests for sections

test: additional tests for subsections

test: replace query calls by button clicks
  • Loading branch information
navinkarkera authored and KristinAoki committed Dec 20, 2023
1 parent b0cb53a commit df532b3
Show file tree
Hide file tree
Showing 13 changed files with 276 additions and 173 deletions.
261 changes: 140 additions & 121 deletions src/course-outline/CourseOutline.test.jsx

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/course-outline/__mocks__/courseOutlineIndex.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module.exports = {
},
],
showCorrectness: 'always',
highlightsEnabledForMessaging: true,
highlightsEnabledForMessaging: false,
highlightsEnabled: true,
highlightsPreviewOnly: false,
highlightsDocUrl: 'http://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/latest/developing_course/course_sections.html#set-section-highlights-for-weekly-course-highlight-messages',
Expand All @@ -72,7 +72,7 @@ module.exports = {
category: 'chapter',
hasChildren: true,
editedOn: 'Aug 23, 2023 at 12:35 UTC',
published: true,
published: false,
publishedOn: 'Aug 23, 2023 at 12:35 UTC',
studioUrl: '/course/course-v1:edX+DemoX+Demo_Course?show=block-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40chapter%2Bblock%40d8a6192ade314473a78242dfeedfbf5b',
releasedToStudents: true,
Expand Down
26 changes: 21 additions & 5 deletions src/course-outline/card-header/CardHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const CardHeader = ({
{isFormOpen ? (
<Form.Group className="m-0">
<Form.Control
data-testid="edit field"
data-testid={`${namePrefix}-edit-field`}
ref={(e) => e && e.focus()}
value={titleValue}
name="displayName"
Expand Down Expand Up @@ -115,7 +115,7 @@ const CardHeader = ({
<div className="ml-auto d-flex">
{!isFormOpen && (
<IconButton
data-testid="edit-button"
data-testid={`${namePrefix}-edit-button`}
alt={intl.formatMessage(messages.altButtonEdit)}
iconAs={EditIcon}
onClick={onClickEdit}
Expand All @@ -133,14 +133,30 @@ const CardHeader = ({
/>
<Dropdown.Menu>
<Dropdown.Item
data-testid={`${namePrefix}-card-header__menu-publish-button`}
disabled={isDisabledPublish}
onClick={onClickPublish}
>
{intl.formatMessage(messages.menuPublish)}
</Dropdown.Item>
<Dropdown.Item onClick={onClickConfigure}>{intl.formatMessage(messages.menuConfigure)}</Dropdown.Item>
<Dropdown.Item onClick={onClickDuplicate}>{intl.formatMessage(messages.menuDuplicate)}</Dropdown.Item>
<Dropdown.Item onClick={onClickDelete}>{intl.formatMessage(messages.menuDelete)}</Dropdown.Item>
<Dropdown.Item
data-testid={`${namePrefix}-card-header__menu-configure-button`}
onClick={onClickConfigure}
>
{intl.formatMessage(messages.menuConfigure)}
</Dropdown.Item>
<Dropdown.Item
data-testid={`${namePrefix}-card-header__menu-duplicate-button`}
onClick={onClickDuplicate}
>
{intl.formatMessage(messages.menuDuplicate)}
</Dropdown.Item>
<Dropdown.Item
data-testid={`${namePrefix}-card-header__menu-delete-button`}
onClick={onClickDelete}
>
{intl.formatMessage(messages.menuDelete)}
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/course-outline/card-header/CardHeader.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ describe('<CardHeader />', () => {
it('calls onClickEdit when the button is clicked', async () => {
const { findByTestId } = renderComponent();

const editButton = await findByTestId('edit-button');
const editButton = await findByTestId('section-edit-button');
fireEvent.click(editButton);
waitFor(() => {
expect(onClickEditMock).toHaveBeenCalled();
Expand All @@ -159,7 +159,7 @@ describe('<CardHeader />', () => {
isFormOpen: true,
});

expect(await findByTestId('edit field')).toBeInTheDocument();
expect(await findByTestId('section-edit-field')).toBeInTheDocument();
waitFor(() => {
expect(queryByTestId('section-card-header__expanded-btn')).not.toBeInTheDocument();
expect(queryByTestId('edit-button')).not.toBeInTheDocument();
Expand All @@ -173,7 +173,7 @@ describe('<CardHeader />', () => {
isDisabledEditField: true,
});

expect(await findByTestId('edit field')).toBeDisabled();
expect(await findByTestId('section-edit-field')).toBeDisabled();
});

it('calls onClickDelete when item is clicked', async () => {
Expand Down
18 changes: 0 additions & 18 deletions src/course-outline/data/slice.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,23 +121,6 @@ const slice = createSlice({
return section;
});
},
deleteUnit: (state, { payload }) => {
state.sectionsList = state.sectionsList.map((section) => {
if (section.id !== payload.sectionId) {
return section;
}
section.childInfo.children = section.childInfo.children.map((subsection) => {
if (subsection.id !== payload.subsectionId) {
return subsection;
}
subsection.childInfo.children = subsection.childInfo.children.filter(
({ id }) => id !== payload.itemId,
);
return subsection;
});
return section;
});
},
duplicateSection: (state, { payload }) => {
state.sectionsList = state.sectionsList.reduce((result, currentValue) => {
if (currentValue.id === payload.id) {
Expand Down Expand Up @@ -166,7 +149,6 @@ export const {
setCurrentSubsection,
deleteSection,
deleteSubsection,
deleteUnit,
duplicateSection,
reorderSectionList,
} = slice.actions;
Expand Down
10 changes: 0 additions & 10 deletions src/course-outline/data/thunk.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import {
updateFetchSectionLoadingStatus,
deleteSection,
deleteSubsection,
deleteUnit,
duplicateSection,
reorderSectionList,
} from './slice';
Expand Down Expand Up @@ -265,15 +264,6 @@ export function deleteCourseSubsectionQuery(subsectionId, sectionId) {
};
}

export function deleteCourseUnitQuery(unitId, subsectionId, sectionId) {
return async (dispatch) => {
dispatch(deleteCourseItemQuery(
unitId,
() => deleteUnit({ itemId: unitId, subsectionId, sectionId }),
));
};
}

/**
* Generic function to duplicate any course item. See wrapper functions below for specific implementations.
* @param {string} itemId
Expand Down
1 change: 1 addition & 0 deletions src/course-outline/delete-modal/DeleteModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const DeleteModal = ({ isOpen, close, onDeleteSubmit }) => {
{intl.formatMessage(messages.cancelButton)}
</Button>
<Button
data-testid="delete-confirm-button"
onClick={(e) => {
e.preventDefault();
onDeleteSubmit();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const HeaderNavigations = ({
>
<Button
onClick={handleReIndex}
data-testid="course-reindex"
variant="outline-primary"
disabled={isDisabledReindexButton}
>
Expand Down
7 changes: 1 addition & 6 deletions src/course-outline/hooks.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
addNewSubsectionQuery,
deleteCourseSectionQuery,
deleteCourseSubsectionQuery,
deleteCourseUnitQuery,
editCourseItemQuery,
duplicateSectionQuery,
duplicateSubsectionQuery,
Expand Down Expand Up @@ -133,11 +132,7 @@ const useCourseOutline = ({ courseId }) => {
dispatch(deleteCourseSubsectionQuery(currentItem.id, currentSection.id));
break;
case COURSE_BLOCK_NAMES.vertical.id:
dispatch(deleteCourseUnitQuery(
currentItem.id,
currentSubsection.id,
currentSection.id,
));
// delete unit
break;
default:
return;
Expand Down
5 changes: 4 additions & 1 deletion src/course-outline/publish-modal/PublishModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ const PublishModal = ({
<ModalDialog.CloseButton variant="tertiary">
{intl.formatMessage(messages.cancelButton)}
</ModalDialog.CloseButton>
<Button onClick={onPublishSubmit}>
<Button
data-testid="publish-confirm-button"
onClick={onPublishSubmit}
>
{intl.formatMessage(messages.publishButton)}
</Button>
</ActionRow>
Expand Down
75 changes: 70 additions & 5 deletions src/course-outline/section-card/SectionCard.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';

import initializeStore from '../../store';
import SectionCard from './SectionCard';
import cardHeaderMessages from '../card-header/messages';

// eslint-disable-next-line no-unused-vars
let axiosMock;
Expand All @@ -25,6 +26,8 @@ const section = {
highlights: ['highlight 1', 'highlight 2'],
};

const onEditSectionSubmit = jest.fn();

const renderComponent = (props) => render(
<AppProvider store={store}>
<IntlProvider locale="en">
Expand All @@ -33,14 +36,11 @@ const renderComponent = (props) => render(
onOpenPublishModal={jest.fn()}
onOpenHighlightsModal={jest.fn()}
onOpenDeleteModal={jest.fn()}
onEditClick={jest.fn()}
savingStatus=""
onEditSectionSubmit={jest.fn()}
onEditSectionSubmit={onEditSectionSubmit}
onDuplicateSubmit={jest.fn()}
isSectionsExpanded
namePrefix="section"
connectDragSource={(el) => el}
isDragging
onNewSubsectionSubmit={jest.fn()}
{...props}
>
<span>children</span>
Expand Down Expand Up @@ -83,4 +83,69 @@ describe('<SectionCard />', () => {
expect(queryByTestId('section-card__subsections')).toBeInTheDocument();
expect(queryByTestId('new-subsection-button')).toBeInTheDocument();
});

it('title only updates if changed', async () => {
const { findByTestId } = renderComponent();

let editButton = await findByTestId('section-edit-button');
fireEvent.click(editButton);
let editField = await findByTestId('section-edit-field');
fireEvent.blur(editField);

expect(onEditSectionSubmit).not.toHaveBeenCalled();

editButton = await findByTestId('section-edit-button');
fireEvent.click(editButton);
editField = await findByTestId('section-edit-field');
fireEvent.change(editField, { target: { value: 'some random value' } });
fireEvent.blur(editField);
expect(onEditSectionSubmit).toHaveBeenCalled();
});

it('renders live status', async () => {
const { findByText } = renderComponent();
expect(await findByText(cardHeaderMessages.statusBadgeLive.defaultMessage)).toBeInTheDocument();
});

it('renders published but live status', async () => {
const { findByText } = renderComponent({
section: {
...section,
published: true,
releasedToStudents: false,
visibleToStaffOnly: false,
visibilityState: 'visible',
staffOnlyMessage: false,
},
});
expect(await findByText(cardHeaderMessages.statusBadgePublishedNotLive.defaultMessage)).toBeInTheDocument();
});

it('renders staff status', async () => {
const { findByText } = renderComponent({
section: {
...section,
published: false,
releasedToStudents: false,
visibleToStaffOnly: true,
visibilityState: 'staff_only',
staffOnlyMessage: true,
},
});
expect(await findByText(cardHeaderMessages.statusBadgeStaffOnly.defaultMessage)).toBeInTheDocument();
});

it('renders draft status', async () => {
const { findByText } = renderComponent({
section: {
...section,
published: false,
releasedToStudents: false,
visibleToStaffOnly: false,
visibilityState: 'staff_only',
staffOnlyMessage: false,
},
});
expect(await findByText(cardHeaderMessages.statusBadgeDraft.defaultMessage)).toBeInTheDocument();
});
});
2 changes: 1 addition & 1 deletion src/course-outline/status-bar/StatusBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const StatusBar = ({
{intl.formatMessage(messages.highlightEmailsEnabled)}
</span>
) : (
<Button size="sm" onClick={openEnableHighlightsModal}>
<Button data-testid="highlights-enable-button" size="sm" onClick={openEnableHighlightsModal}>
{intl.formatMessage(messages.highlightEmailsButton)}
</Button>
)}
Expand Down
33 changes: 32 additions & 1 deletion src/course-outline/subsection-card/SubsectionCard.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ const subsection = {
hasChanges: false,
};

const onEditSubectionSubmit = jest.fn();

const renderComponent = (props) => render(
<AppProvider store={store}>
<IntlProvider locale="en">
Expand All @@ -47,7 +49,7 @@ const renderComponent = (props) => render(
onOpenDeleteModal={jest.fn()}
onEditClick={jest.fn()}
savingStatus=""
onEditSubmit={jest.fn()}
onEditSubmit={onEditSubectionSubmit}
onDuplicateSubmit={jest.fn()}
namePrefix="subsection"
{...props}
Expand Down Expand Up @@ -91,4 +93,33 @@ describe('<SubsectionCard />', () => {
expect(queryByTestId('subsection-card__units')).not.toBeInTheDocument();
expect(queryByTestId('new-unit-button')).not.toBeInTheDocument();
});

it('updates current section, subsection and item', async () => {
const { findByTestId } = renderComponent();

const menu = await findByTestId('subsection-card-header__menu');
fireEvent.click(menu);
const { currentSection, currentSubsection, currentItem } = store.getState().courseOutline;
expect(currentSection).toEqual(section);
expect(currentSubsection).toEqual(subsection);
expect(currentItem).toEqual(subsection);
});

it('title only updates if changed', async () => {
const { findByTestId } = renderComponent();

let editButton = await findByTestId('subsection-edit-button');
fireEvent.click(editButton);
let editField = await findByTestId('subsection-edit-field');
fireEvent.blur(editField);

expect(onEditSubectionSubmit).not.toHaveBeenCalled();

editButton = await findByTestId('subsection-edit-button');
fireEvent.click(editButton);
editField = await findByTestId('subsection-edit-field');
fireEvent.change(editField, { target: { value: 'some random value' } });
fireEvent.keyDown(editField, { key: 'Enter', keyCode: 13 });
expect(onEditSubectionSubmit).toHaveBeenCalled();
});
});

0 comments on commit df532b3

Please sign in to comment.