diff --git a/src/course-unit/CourseUnit.test.jsx b/src/course-unit/CourseUnit.test.jsx
index f969321fe..d197e75e6 100644
--- a/src/course-unit/CourseUnit.test.jsx
+++ b/src/course-unit/CourseUnit.test.jsx
@@ -17,6 +17,7 @@ import {
postXBlockBaseApiUrl,
} from './data/api';
import {
+ deleteUnitItemQuery,
editCourseUnitVisibilityAndData,
fetchCourseSectionVerticalData,
fetchCourseUnitQuery,
@@ -717,4 +718,187 @@ describe('', () => {
.getByText(sidebarMessages.sidebarTitlePublishedNotYetReleased.defaultMessage)).toBeInTheDocument();
expect(discardChangesBtn).not.toBeInTheDocument();
});
+
+ it('checks whether xblock is removed when the corresponding delete button is clicked and sidebar is the updated', async () => {
+ const {
+ getByText,
+ getAllByLabelText,
+ getByRole,
+ getAllByTestId,
+ queryByRole,
+ } = render();
+
+ await waitFor(() => {
+ userEvent.click(getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage }));
+ });
+
+ axiosMock
+ .onPost(getXBlockBaseApiUrl(blockId), {
+ publish: PUBLISH_TYPES.makePublic,
+ })
+ .reply(200, { dummy: 'value' });
+ axiosMock
+ .onGet(getCourseUnitApiUrl(blockId))
+ .reply(200, {
+ ...courseUnitIndexMock,
+ visibility_state: UNIT_VISIBILITY_STATES.live,
+ has_changes: false,
+ published_by: userName,
+ });
+
+ await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch);
+
+ axiosMock
+ .onDelete(getXBlockBaseApiUrl(courseVerticalChildrenMock.children[0].block_id))
+ .replyOnce(200, { dummy: 'value' });
+
+ await executeThunk(deleteUnitItemQuery(courseId, blockId), store.dispatch);
+
+ await waitFor(() => {
+ // check if the sidebar status is Published and Live
+ expect(getByText(sidebarMessages.sidebarTitlePublishedAndLive.defaultMessage)).toBeInTheDocument();
+ expect(getByText(
+ sidebarMessages.publishLastPublished.defaultMessage
+ .replace('{publishedOn}', courseUnitIndexMock.published_on)
+ .replace('{publishedBy}', userName),
+ )).toBeInTheDocument();
+ expect(queryByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })).not.toBeInTheDocument();
+
+ expect(getByText(unitDisplayName)).toBeInTheDocument();
+ const [xblockActionBtn] = getAllByLabelText(courseXBlockMessages.blockActionsDropdownAlt.defaultMessage);
+ userEvent.click(xblockActionBtn);
+
+ const deleteBtn = getByRole('button', { name: courseXBlockMessages.blockLabelButtonDelete.defaultMessage });
+ userEvent.click(deleteBtn);
+ expect(getByText(/Delete this component?/)).toBeInTheDocument();
+
+ const deleteConfirmBtn = getByRole('button', { name: deleteModalMessages.deleteButton.defaultMessage });
+ userEvent.click(deleteConfirmBtn);
+
+ expect(getAllByTestId('course-xblock')).toHaveLength(1);
+ });
+
+ axiosMock
+ .onGet(getCourseUnitApiUrl(blockId))
+ .reply(200, courseUnitIndexMock);
+
+ await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch);
+
+ // after removing the xblock, the sidebar status changes to Draft (unpublished changes)
+ expect(getByText(sidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.visibilityStaffAndLearnersTitle.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.releaseStatusTitle.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.sidebarBodyNote.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.visibilityWillBeVisibleToTitle.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument();
+ expect(getByText(courseUnitIndexMock.release_date)).toBeInTheDocument();
+ expect(getByText(
+ sidebarMessages.publishInfoDraftSaved.defaultMessage
+ .replace('{editedOn}', courseUnitIndexMock.edited_on)
+ .replace('{editedBy}', courseUnitIndexMock.edited_by),
+ )).toBeInTheDocument();
+ expect(getByText(
+ sidebarMessages.releaseInfoWithSection.defaultMessage
+ .replace('{sectionName}', courseUnitIndexMock.release_date_from),
+ )).toBeInTheDocument();
+ });
+
+ it('checks if xblock is a duplicate when the corresponding duplicate button is clicked and if the sidebar status is updated', async () => {
+ axiosMock
+ .onPost(postXBlockBaseApiUrl({
+ parent_locator: blockId,
+ duplicate_source_locator: courseVerticalChildrenMock.children[0].block_id,
+ }))
+ .replyOnce(200, { locator: '1234567890' });
+
+ axiosMock
+ .onGet(getCourseVerticalChildrenApiUrl(blockId))
+ .reply(200, {
+ ...courseVerticalChildrenMock,
+ children: [
+ ...courseVerticalChildrenMock.children,
+ {
+ ...courseVerticalChildrenMock.children[0],
+ name: 'New Cloned XBlock',
+ },
+ ],
+ });
+
+ const {
+ getByText,
+ getAllByLabelText,
+ getAllByTestId,
+ queryByRole,
+ getByRole,
+ } = render();
+
+ await waitFor(() => {
+ userEvent.click(getByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage }));
+ });
+
+ axiosMock
+ .onPost(getXBlockBaseApiUrl(blockId), {
+ publish: PUBLISH_TYPES.makePublic,
+ })
+ .reply(200, { dummy: 'value' });
+ axiosMock
+ .onGet(getCourseUnitApiUrl(blockId))
+ .reply(200, {
+ ...courseUnitIndexMock,
+ visibility_state: UNIT_VISIBILITY_STATES.live,
+ has_changes: false,
+ published_by: userName,
+ });
+
+ await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch);
+
+ await waitFor(() => {
+ // check if the sidebar status is Published and Live
+ expect(getByText(sidebarMessages.sidebarTitlePublishedAndLive.defaultMessage)).toBeInTheDocument();
+ expect(getByText(
+ sidebarMessages.publishLastPublished.defaultMessage
+ .replace('{publishedOn}', courseUnitIndexMock.published_on)
+ .replace('{publishedBy}', userName),
+ )).toBeInTheDocument();
+ expect(queryByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })).not.toBeInTheDocument();
+
+ expect(getByText(unitDisplayName)).toBeInTheDocument();
+ const [xblockActionBtn] = getAllByLabelText(courseXBlockMessages.blockActionsDropdownAlt.defaultMessage);
+ userEvent.click(xblockActionBtn);
+
+ const duplicateBtn = getByText(courseXBlockMessages.blockLabelButtonDuplicate.defaultMessage);
+ userEvent.click(duplicateBtn);
+
+ expect(getAllByTestId('course-xblock')).toHaveLength(3);
+ expect(getByText('New Cloned XBlock')).toBeInTheDocument();
+ });
+
+ axiosMock
+ .onGet(getCourseUnitApiUrl(blockId))
+ .reply(200, courseUnitIndexMock);
+
+ await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch);
+
+ // after duplicate the xblock, the sidebar status changes to Draft (unpublished changes)
+ expect(getByText(sidebarMessages.sidebarTitleDraftUnpublishedChanges.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.visibilityStaffAndLearnersTitle.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.releaseStatusTitle.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.sidebarBodyNote.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.visibilityWillBeVisibleToTitle.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument();
+ expect(getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument();
+ expect(getByText(courseUnitIndexMock.release_date)).toBeInTheDocument();
+ expect(getByText(
+ sidebarMessages.publishInfoDraftSaved.defaultMessage
+ .replace('{editedOn}', courseUnitIndexMock.edited_on)
+ .replace('{editedBy}', courseUnitIndexMock.edited_by),
+ )).toBeInTheDocument();
+ expect(getByText(
+ sidebarMessages.releaseInfoWithSection.defaultMessage
+ .replace('{sectionName}', courseUnitIndexMock.release_date_from),
+ )).toBeInTheDocument();
+ });
});
diff --git a/src/course-unit/data/thunk.js b/src/course-unit/data/thunk.js
index 7d5bdc3a9..23b39937a 100644
--- a/src/course-unit/data/thunk.js
+++ b/src/course-unit/data/thunk.js
@@ -287,6 +287,8 @@ export function deleteUnitItemQuery(itemId, xblockId) {
try {
await deleteUnitItem(xblockId);
dispatch(deleteXBlock(xblockId));
+ const courseUnit = await getCourseUnitData(itemId);
+ dispatch(fetchCourseItemSuccess(courseUnit));
dispatch(hideProcessingNotification());
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
} catch (error) {
@@ -308,6 +310,8 @@ export function duplicateUnitItemQuery(itemId, xblockId) {
newId: locator,
newCourseVerticalChildren,
}));
+ const courseUnit = await getCourseUnitData(itemId);
+ dispatch(fetchCourseItemSuccess(courseUnit));
dispatch(hideProcessingNotification());
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
} catch (error) {