Skip to content

Commit

Permalink
feat: Unit page - tagging
Browse files Browse the repository at this point in the history
  • Loading branch information
Kyrylo Hudym-Levkovych authored and Kyrylo Hudym-Levkovych committed May 3, 2024
1 parent 65f45f7 commit 929bd25
Show file tree
Hide file tree
Showing 38 changed files with 1,569 additions and 43 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ INVITE_STUDENTS_EMAIL_TO=''
AI_TRANSLATIONS_BASE_URL=''
ENABLE_HOME_PAGE_COURSE_API_V2=false
ENABLE_CHECKLIST_QUALITY=''
SECURE_ORIGIN_XBLOCK_BOOTSTRAP_HTML_URL=null
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ INVITE_STUDENTS_EMAIL_TO="[email protected]"
AI_TRANSLATIONS_BASE_URL='http://localhost:18760'
ENABLE_HOME_PAGE_COURSE_API_V2=false
ENABLE_CHECKLIST_QUALITY=true
SECURE_ORIGIN_XBLOCK_BOOTSTRAP_HTML_URL=/xblock-bootstrap.html
1 change: 1 addition & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ BBB_LEARN_MORE_URL=''
INVITE_STUDENTS_EMAIL_TO="[email protected]"
ENABLE_HOME_PAGE_COURSE_API_V2=true
ENABLE_CHECKLIST_QUALITY=true
SECURE_ORIGIN_XBLOCK_BOOTSTRAP_HTML_URL=/xblock-bootstrap.html
121 changes: 121 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
"@testing-library/user-event": "^13.2.1",
"axios": "^0.28.0",
"axios-mock-adapter": "1.22.0",
"copy-webpack-plugin": "^11.0.0",
"eslint-import-resolver-webpack": "^0.13.8",
"fetch-mock-jest": "^1.5.1",
"glob": "7.2.3",
Expand Down
5 changes: 4 additions & 1 deletion src/course-unit/CourseUnit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,20 +164,23 @@ const CourseUnit = ({ courseId }) => {
strategy={verticalListSortingStrategy}
>
{unitXBlocks.map(({
name, id, blockType: type, shouldScroll, userPartitionInfo, validationMessages,
name, id, blockType: type, renderError, shouldScroll,
userPartitionInfo, validationMessages, actions,
}) => (
<CourseXBlock
id={id}
key={id}
title={name}
type={type}
blockId={blockId}
renderError={renderError}
validationMessages={validationMessages}
shouldScroll={shouldScroll}
handleConfigureSubmit={handleConfigureSubmit}
unitXBlockActions={unitXBlockActions}
data-testid="course-xblock"
userPartitionInfo={userPartitionInfo}
actions={actions}
/>
))}
</SortableContext>
Expand Down
148 changes: 148 additions & 0 deletions src/course-unit/CourseUnit.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,153 @@ describe('<CourseUnit />', () => {
)).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(<RootWrapper />);

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();
});

it('should hide action buttons when their corresponding properties are set to false', async () => {
const {
getByText,
getAllByLabelText,
queryByRole,
} = render(<RootWrapper />);

const convertedXBlockActions = camelCaseObject(courseVerticalChildrenMock.children[0].actions);

const updatedXBlockActions = Object.keys(convertedXBlockActions).reduce((acc, key) => {
acc[key] = false;
return acc;
}, {});

axiosMock
.onGet(getCourseVerticalChildrenApiUrl(blockId))
.reply(200, {
children: [
{
...courseVerticalChildrenMock.children[0],
actions: {
...courseVerticalChildrenMock.children[0].actions,
updatedXBlockActions,
},
},
],
});

await executeThunk(fetchCourseVerticalChildrenData(blockId), store.dispatch);

await waitFor(() => {
expect(getByText(unitDisplayName)).toBeInTheDocument();
const [xblockActionBtn] = getAllByLabelText(courseXBlockMessages.blockActionsDropdownAlt.defaultMessage);
userEvent.click(xblockActionBtn);
const deleteBtn = queryByRole('button', { name: courseXBlockMessages.blockLabelButtonDelete.defaultMessage });
const duplicateBtn = queryByRole('button', { name: courseXBlockMessages.blockLabelButtonDuplicate.defaultMessage });
const moveBtn = queryByRole('button', { name: courseXBlockMessages.blockLabelButtonMove.defaultMessage });
const copyToClipboardBtn = queryByRole('button', { name: courseXBlockMessages.blockLabelButtonCopyToClipboard.defaultMessage });
const manageAccessBtn = queryByRole('button', { name: courseXBlockMessages.blockLabelButtonManageAccess.defaultMessage });
const manageTagsBtn = queryByRole('button', { name: courseXBlockMessages.blockLabelButtonManageTags.defaultMessage });

expect(deleteBtn).not.toBeInTheDocument();
expect(duplicateBtn).not.toBeInTheDocument();
expect(moveBtn).not.toBeInTheDocument();
expect(copyToClipboardBtn).not.toBeInTheDocument();
expect(manageAccessBtn).not.toBeInTheDocument();
expect(manageTagsBtn).not.toBeInTheDocument();
});
});

it('should toggle visibility from header configure modal and update course unit state accordingly', async () => {
const { getByRole, getByTestId } = render(<RootWrapper />);
let courseUnitSidebar;
Expand Down Expand Up @@ -1152,6 +1299,7 @@ describe('<CourseUnit />', () => {
selected_partition_index: -1,
selected_groups_label: '',
},
actions: courseVerticalChildrenMock.children[0].actions,
},
],
});
Expand Down
2 changes: 2 additions & 0 deletions src/course-unit/__mocks__/courseVerticalChildren.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = {
can_duplicate: true,
can_move: true,
can_manage_access: true,
can_manage_tags: true,
can_delete: true,
},
user_partition_info: {
Expand Down Expand Up @@ -80,6 +81,7 @@ module.exports = {
can_duplicate: true,
can_move: true,
can_manage_access: true,
can_manage_tags: true,
can_delete: true,
},
user_partition_info: {
Expand Down
Loading

0 comments on commit 929bd25

Please sign in to comment.