Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [FC-0044] Unit page - add new component section #828

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const BADGE_STATES = {
};

export const NOTIFICATION_MESSAGES = {
adding: 'Adding',
saving: 'Saving',
duplicating: 'Duplicating',
deleting: 'Deleting',
Expand Down
9 changes: 7 additions & 2 deletions src/course-unit/CourseUnit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import getPageHeadTitle from '../generic/utils';
import ProcessingNotification from '../generic/processing-notification';
import InternetConnectionAlert from '../generic/internet-connection-alert';
import Loading from '../generic/Loading';
import AddComponent from './add-component/AddComponent';
import HeaderTitle from './header-title/HeaderTitle';
import Breadcrumbs from './breadcrumbs/Breadcrumbs';
import HeaderNavigations from './header-navigations/HeaderNavigations';
Expand All @@ -33,6 +34,7 @@ const CourseUnit = ({ courseId }) => {
headerNavigationsActions,
handleTitleEdit,
handleInternetConnectionFailed,
handleCreateNewCourseXblock,
} = useCourseUnit({ courseId, blockId });

document.title = getPageHeadTitle('', unitTitle);
Expand Down Expand Up @@ -87,9 +89,12 @@ const CourseUnit = ({ courseId }) => {
xl={[{ span: 9 }, { span: 3 }]}
>
<Layout.Element>
{/* TODO: Unit content will be added in the following tasks. */}
Unit content
<AddComponent
blockId={blockId}
handleCreateNewCourseXblock={handleCreateNewCourseXblock}
/>
</Layout.Element>
<Layout.Element />
</Layout>
</section>
</Container>
Expand Down
1 change: 1 addition & 0 deletions src/course-unit/CourseUnit.scss
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
@import "./breadcrumbs/Breadcrumbs";
@import "./course-sequence/CourseSequence";
@import "./add-component/AddComponent";
65 changes: 65 additions & 0 deletions src/course-unit/CourseUnit.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,27 @@ import { getConfig, initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';

import {
getCourseSectionVerticalApiUrl,
getCourseUnitApiUrl,
getXBlockBaseApiUrl,
postXBlockBaseApiUrl,
} from './data/api';
import {
fetchCourseSectionVerticalData,
fetchCourseUnitQuery,
} from './data/thunk';
import initializeStore from '../store';
import {
courseCreateXblockMock,
courseSectionVerticalMock,
courseUnitIndexMock,
} from './__mocks__';
import { executeThunk } from '../utils';
import CourseUnit from './CourseUnit';
import headerNavigationsMessages from './header-navigations/messages';
import headerTitleMessages from './header-title/messages';
import { getUnitPreviewPath, getUnitViewLivePath } from './utils';
import messages from './add-component/messages';

let axiosMock;
let store;
Expand All @@ -32,10 +38,12 @@ const sectionId = 'graded_interactions';
const subsectionId = '19a30717eff543078a5d94ae9d6c18a5';
const blockId = '567890';
const unitDisplayName = courseUnitIndexMock.metadata.display_name;
const mockedUsedNavigate = jest.fn();

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: () => ({ blockId }),
useNavigate: () => mockedUsedNavigate,
}));

const RootWrapper = () => (
Expand Down Expand Up @@ -63,6 +71,10 @@ describe('<CourseUnit />', () => {
.onGet(getCourseUnitApiUrl(courseId))
.reply(200, courseUnitIndexMock);
await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch);
axiosMock
.onGet(getCourseSectionVerticalApiUrl(blockId))
.reply(200, courseSectionVerticalMock);
await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
});

it('render CourseUnit component correctly', async () => {
Expand Down Expand Up @@ -146,4 +158,57 @@ describe('<CourseUnit />', () => {
expect(titleEditField).not.toBeInTheDocument();
expect(await findByText(newDisplayName)).toBeInTheDocument();
});

it('doesn\'t handle creating xblock and displays an error message', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it('doesn\'t handle creating xblock and displays an error message', async () => {
it('doesn\'t handle creating video xblock and displays an error message', async () => {

Copy link
Contributor

@arbrandes arbrandes Feb 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this was made to be generic intentionally. In which case, ignore the comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right. It might be as a generic and can be reverted in next MR.

const { courseKey, locator } = courseCreateXblockMock;
axiosMock
.onPost(postXBlockBaseApiUrl({ type: 'video', category: 'video', parentLocator: blockId }))
.reply(500, {});
const { getByRole } = render(<RootWrapper />);

await waitFor(() => {
const videoButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Video`, 'i'),
});

userEvent.click(videoButton);
expect(mockedUsedNavigate).not.toHaveBeenCalledWith(`/course/${courseKey}/editor/video/${locator}`);
});
});

it('handle creating Problem xblock and navigate to editor page', async () => {
const { courseKey, locator } = courseCreateXblockMock;
axiosMock
.onPost(postXBlockBaseApiUrl({ type: 'problem', category: 'problem', parentLocator: blockId }))
.reply(200, courseCreateXblockMock);
const { getByRole } = render(<RootWrapper />);

await waitFor(() => {
const problemButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Problem`, 'i'),
});

userEvent.click(problemButton);
expect(mockedUsedNavigate).toHaveBeenCalled();
expect(mockedUsedNavigate).toHaveBeenCalledWith(`/course/${courseKey}/editor/problem/${locator}`);
});
});

it('handles creating Video xblock and navigates to editor page', async () => {
const { courseKey, locator } = courseCreateXblockMock;
axiosMock
.onPost(postXBlockBaseApiUrl({ type: 'video', category: 'video', parentLocator: blockId }))
.reply(200, courseCreateXblockMock);
const { getByRole } = render(<RootWrapper />);

await waitFor(() => {
const videoButton = getByRole('button', {
name: new RegExp(`${messages.buttonText.defaultMessage} Video`, 'i'),
});

userEvent.click(videoButton);
expect(mockedUsedNavigate).toHaveBeenCalled();
expect(mockedUsedNavigate).toHaveBeenCalledWith(`/course/${courseKey}/editor/video/${locator}`);
});
});
});
4 changes: 4 additions & 0 deletions src/course-unit/__mocks__/courseCreateXblock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
locator: 'block-v1:edX+L153+3T2023+type@drag-and-drop-v2+block@dc52e3cf8e6145e39ba5c1ff4888db4b',
courseKey: 'course-v1:edX+L153+3T2023',
};
Loading
Loading