Skip to content

Commit

Permalink
test: add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
navinkarkera committed Nov 18, 2024
1 parent d720217 commit 4a43f32
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 15 deletions.
6 changes: 3 additions & 3 deletions src/course-unit/data/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const getCourseSectionVerticalApiUrl = (itemId) => `${getStudioBaseUrl()}
export const getCourseVerticalChildrenApiUrl = (itemId) => `${getStudioBaseUrl()}/api/contentstore/v1/container/vertical/${itemId}/children`;
export const getCourseOutlineInfoUrl = (courseId) => `${getStudioBaseUrl()}/course/${courseId}?format=concise`;
export const postXBlockBaseApiUrl = () => `${getStudioBaseUrl()}/xblock/`;
export const acceptLibraryBlockChangesUrl = (blockId) => `${getStudioBaseUrl()}/api/contentstore/v2/downstreams/${blockId}/sync`;
export const libraryBlockChangesUrl = (blockId) => `${getStudioBaseUrl()}/api/contentstore/v2/downstreams/${blockId}/sync`;

/**
* Get course unit.
Expand Down Expand Up @@ -213,7 +213,7 @@ export async function patchUnitItem(sourceLocator, targetParentLocator) {
*/
export async function acceptLibraryBlockChanges(blockId) {
await getAuthenticatedHttpClient()
.post(acceptLibraryBlockChangesUrl(blockId));
.post(libraryBlockChangesUrl(blockId));
}

/**
Expand All @@ -222,5 +222,5 @@ export async function acceptLibraryBlockChanges(blockId) {
*/
export async function ignoreLibraryBlockChanges(blockId) {
await getAuthenticatedHttpClient()
.delete(acceptLibraryBlockChangesUrl(blockId));
.delete(libraryBlockChangesUrl(blockId));
}
128 changes: 128 additions & 0 deletions src/course-unit/preview-changes/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import userEvent from '@testing-library/user-event';
import MockAdapter from 'axios-mock-adapter/types';
import {
act,
render as baseRender,
screen,
initializeMocks,
waitFor,
} from '../../testUtils';

import PreviewLibraryXBlockChanges, { LibraryChangesMessageData } from '.';
import { messageTypes } from '../constants';
import { IframeProvider } from '../context/iFrameContext';
import { libraryBlockChangesUrl } from '../data/api';
import { ToastActionData } from '../../generic/toast-context';

const usageKey = 'some-id';
const defaultEventData: LibraryChangesMessageData = {
displayName: 'Test block',
downstreamBlockId: usageKey,
upstreamBlockId: 'some-lib-id',
upstreamBlockVersionSynced: 1,
isVertical: false,
};

const mockSendMessageToIframe = jest.fn();
jest.mock('../context/hooks', () => ({
useIframe: () => ({
sendMessageToIframe: mockSendMessageToIframe,
}),
}));
const render = (eventData?: LibraryChangesMessageData) => {
baseRender(<PreviewLibraryXBlockChanges />, {
extraWrapper: ({ children }) => <IframeProvider>{ children }</IframeProvider>,
});
const message = {
data: {
type: messageTypes.showXBlockLibraryChangesPreview,
payload: eventData || defaultEventData,
},
};
// Dispatch showXBlockLibraryChangesPreview message event to open the preivew modal.
act(() => {
window.dispatchEvent(new MessageEvent('message', message));
});
};

let axiosMock: MockAdapter;
let mockShowToast: (message: string, action?: ToastActionData | undefined) => void;

describe('<PreviewLibraryXBlockChanges />', () => {
beforeEach(() => {
const mocks = initializeMocks();
axiosMock = mocks.axiosMock;
mockShowToast = mocks.mockShowToast;
});

it('renders modal', async () => {
render();

expect(await screen.findByText('Preview changes: Test block')).toBeInTheDocument();
expect(await screen.findByRole('button', { name: 'Accept changes' })).toBeInTheDocument();
expect(await screen.findByRole('button', { name: 'Ignore changes' })).toBeInTheDocument();
expect(await screen.findByRole('button', { name: 'Cancel' })).toBeInTheDocument();
expect(await screen.findByRole('tab', { name: 'New version' })).toBeInTheDocument();
expect(await screen.findByRole('tab', { name: 'Old version' })).toBeInTheDocument();
});

it('renders displayName for units', async () => {
render({ ...defaultEventData, isVertical: true, displayName: '' });

expect(await screen.findByText('Preview changes: Unit')).toBeInTheDocument();
});

it('renders default displayName for components with no displayName', async () => {
render({ ...defaultEventData, displayName: '' });

expect(await screen.findByText('Preview changes: Component')).toBeInTheDocument();
});

it('accept changes works', async () => {
axiosMock.onPost(libraryBlockChangesUrl(usageKey)).reply(200, {});
render();

expect(await screen.findByText('Preview changes: Test block')).toBeInTheDocument();
const acceptBtn = await screen.findByRole('button', { name: 'Accept changes' });
userEvent.click(acceptBtn);
await waitFor(() => {
expect(mockSendMessageToIframe).toHaveBeenCalledWith(messageTypes.refreshXBlock, null);
expect(axiosMock.history.post.length).toEqual(1);
expect(axiosMock.history.post[0].url).toEqual(libraryBlockChangesUrl(usageKey));
});
expect(screen.queryByText('Preview changes: Test block')).not.toBeInTheDocument();
});

it('shows toast if accept changes fails', async () => {
axiosMock.onPost(libraryBlockChangesUrl(usageKey)).reply(500, {});
render();

expect(await screen.findByText('Preview changes: Test block')).toBeInTheDocument();
const acceptBtn = await screen.findByRole('button', { name: 'Accept changes' });
userEvent.click(acceptBtn);
await waitFor(() => {
expect(mockSendMessageToIframe).not.toHaveBeenCalledWith(messageTypes.refreshXBlock, null);
expect(axiosMock.history.post.length).toEqual(1);
expect(axiosMock.history.post[0].url).toEqual(libraryBlockChangesUrl(usageKey));
});
expect(screen.queryByText('Preview changes: Test block')).not.toBeInTheDocument();
expect(mockShowToast).toHaveBeenCalledWith('Failed to update component');
});

it('ignore changes works', async () => {
axiosMock.onDelete(libraryBlockChangesUrl(usageKey)).reply(200, {});
render();

expect(await screen.findByText('Preview changes: Test block')).toBeInTheDocument();
const ignoreBtn = await screen.findByRole('button', { name: 'Ignore changes' });
userEvent.click(ignoreBtn);
const ignoreConfirmBtn = await screen.findByRole('button', { name: 'Ignore' });
userEvent.click(ignoreConfirmBtn);
await waitFor(() => {
expect(mockSendMessageToIframe).toHaveBeenCalledWith(messageTypes.refreshXBlock, null);
expect(axiosMock.history.delete.length).toEqual(1);
expect(axiosMock.history.delete[0].url).toEqual(libraryBlockChangesUrl(usageKey));
});
expect(screen.queryByText('Preview changes: Test block')).not.toBeInTheDocument();
});
});
25 changes: 13 additions & 12 deletions src/course-unit/preview-changes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import DeleteModal from '../../generic/delete-modal/DeleteModal';
import messages from './messages';
import { ToastContext } from '../../generic/toast-context';
import LoadingButton from '../../generic/loading-button';
import Loading from '../../generic/Loading';

interface LibraryChangesMessageData {
export interface LibraryChangesMessageData {
displayName: string,
downstreamBlockId: string,
upstreamBlockId: string,
Expand All @@ -23,16 +24,16 @@ interface LibraryChangesMessageData {
}

const PreviewLibraryXBlockChanges = () => {
const intl = useIntl();
const { showToast } = useContext(ToastContext);
const intl = useIntl();

const [blockData, setBlockData] = useState<LibraryChangesMessageData | undefined>(undefined);

// Main preview library modal toggle.
const [isModalOpen, openModal, closeModal] = useToggle(false);
// ignore changes confirmation modal toggle.
const [isConfirmModalOpen, openConfirmModal, closeConfirmModal] = useToggle(false);

const [blockData, setBlockData] = useState<LibraryChangesMessageData | undefined>(undefined);

const acceptChangesMutation = useAcceptLibraryBlockChanges();
const ignoreChangesMutation = useIgnoreLibraryBlockChanges();

Expand All @@ -54,17 +55,19 @@ const PreviewLibraryXBlockChanges = () => {

const getTitle = useCallback(() => {
if (blockData?.displayName) {
return blockData?.displayName;
return intl.formatMessage(messages.title, {
blockTitle: blockData?.displayName,
});
}
if (blockData?.isVertical) {
return 'Unit';
return intl.formatMessage(messages.defaultUnitTitle);
}
return 'Component';
return intl.formatMessage(messages.defaultComponentTitle);
}, [blockData]);

const getBody = useCallback(() => {
if (!blockData) {
return null;
return <Loading />;
}
return (
<CompareChangesWidget
Expand All @@ -76,6 +79,7 @@ const PreviewLibraryXBlockChanges = () => {
}, [blockData]);

const updateAndRefresh = useCallback(async (accept: boolean) => {
// istanbul ignore if: this should never happen
if (!blockData) {
return;
}
Expand Down Expand Up @@ -104,10 +108,7 @@ const PreviewLibraryXBlockChanges = () => {
>
<ModalDialog.Header>
<ModalDialog.Title>
<FormattedMessage
{...messages.title}
values={{ blockTitle: getTitle() }}
/>
{getTitle()}
</ModalDialog.Title>
</ModalDialog.Header>
<ModalDialog.Body>
Expand Down
10 changes: 10 additions & 0 deletions src/course-unit/preview-changes/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ const messages = defineMessages({
defaultMessage: 'Preview changes: {blockTitle}',
description: 'Preview changes modal title text',
},
defaultUnitTitle: {
id: 'authoring.course-unit.preview-changes.modal-default-unit-title',
defaultMessage: 'Preview changes: Unit',
description: 'Preview changes modal default title text for units',
},
defaultComponentTitle: {
id: 'authoring.course-unit.preview-changes.modal-default-component-title',
defaultMessage: 'Preview changes: Component',
description: 'Preview changes modal default title text for components',
},
acceptChangesBtn: {
id: 'authoring.course-unit.preview-changes.accept-changes-btn',
defaultMessage: 'Accept changes',
Expand Down

0 comments on commit 4a43f32

Please sign in to comment.