Skip to content

Commit

Permalink
test: add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rpenido committed Oct 11, 2024
1 parent df9b518 commit d8f3d7a
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('<ComponentDetails />', () => {
it('should render the component usage', async () => {
render(mockLibraryBlockMetadata.usageKeyNeverPublished);
expect(await screen.findByText('Component Usage')).toBeInTheDocument();
// TODO: replace with actual data when implement tag list
// TODO: replace with actual data when implement course list
expect(screen.queryByText('This will show the courses that use this component.')).toBeInTheDocument();
});

Expand Down
15 changes: 10 additions & 5 deletions src/library-authoring/component-info/ComponentInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Tabs,
Stack,
} from '@openedx/paragon';
import { useContext } from 'react';
import { useContext, useEffect } from 'react';

import { ToastContext } from '../../generic/toast-context';
import { useLibraryContext } from '../common/context';
Expand All @@ -26,6 +26,7 @@ const ComponentInfo = () => {
readOnly,
openComponentEditor,
componentPickerMode,
parentLocator,
} = useLibraryContext();

// istanbul ignore if: this should never happen
Expand All @@ -37,15 +38,19 @@ const ComponentInfo = () => {
mutate: addComponentToCourse,
isSuccess: addComponentToCourseSuccess,
isError: addComponentToCourseError,
} = useAddComponentToCourse();
reset,
} = useAddComponentToCourse(parentLocator, usageKey);

if (addComponentToCourseSuccess) {
window.parent.postMessage('closeComponentPicker', '*');
}

if (addComponentToCourseError) {
showToast(intl.formatMessage(messages.addComponentToCourseError));
}
useEffect(() => {
if (addComponentToCourseError) {
showToast(intl.formatMessage(messages.addComponentToCourseError));
reset();
}
}, [addComponentToCourseError, showToast, intl]);

const canEdit = canEditComponent(usageKey);

Expand Down
47 changes: 47 additions & 0 deletions src/library-authoring/component-picker/ComponentPicker.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
initializeMocks,
fireEvent,
render,
screen,
} from '../../testUtils';
import {
mockGetContentLibraryV2List,
mockContentLibrary,
mockLibraryBlockMetadata,
} from '../data/api.mocks';
import { ComponentPicker } from './ComponentPicker';

mockGetContentLibraryV2List.applyMock();
mockContentLibrary.applyMock();
mockLibraryBlockMetadata.applyMock();

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useSearchParams: () => {
const [params] = [new URLSearchParams({
parentLocator: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1',
})];
return [
params,
];
},
}));

describe('<ComponentPicker />', () => {
beforeEach(() => {
initializeMocks();
});

it('should render the library list', async () => {
render(<ComponentPicker />);

expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
fireEvent.click(screen.getByDisplayValue(/lib:sampletaxonomyorg1:tl1/i));

fireEvent.click(screen.getByText('Next'));

// Wait for the content library to load
expect(await screen.findByText('Content library')).toBeInTheDocument();
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
});
});
1 change: 1 addition & 0 deletions src/library-authoring/component-picker/ComponentPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const ComponentPicker = () => {
throw new Error('parentLocator is required');
}

// URLSearchParams decodes '+' to ' ', so we need to convert it back
parentLocator = parentLocator.replaceAll(' ', '+');

const [currentStep, setCurrentStep] = useState('select-library');
Expand Down
49 changes: 49 additions & 0 deletions src/library-authoring/component-picker/SelectLibrary.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
initializeMocks,
render,
screen,
} from '../../testUtils';
import {
mockGetContentLibraryV2List,
} from '../data/api.mocks';
import { ComponentPicker } from './ComponentPicker';

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useSearchParams: () => {
const [params] = [new URLSearchParams({
parentLocator: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1',
})];
return [
params,
];
},
}));

describe('<ComponentPicker />', () => {
beforeEach(() => {
initializeMocks();
});

it('should render the library list', async () => {
mockGetContentLibraryV2List.applyMock();
render(<ComponentPicker />);

expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
});

it('should render the loading status', async () => {
mockGetContentLibraryV2List.applyMockLoading();
render(<ComponentPicker />);

expect(await screen.findByText('Loading...')).toBeInTheDocument();
});

it('should render the error status', async () => {
mockGetContentLibraryV2List.applyMockError();
render(<ComponentPicker />);

expect(await screen.findByText(/mocked request failed with status code 500/i)).toBeInTheDocument();
});
});
32 changes: 29 additions & 3 deletions src/library-authoring/data/api.mocks.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
/* istanbul ignore file */
import { camelCaseObject } from '@edx/frontend-platform';
import { mockContentTaxonomyTagsData } from '../../content-tags-drawer/data/api.mocks';
import { getBlockType } from '../../generic/key-utils';
import { createAxiosError } from '../../testUtils';
import contentLibrariesListV2 from '../__mocks__/contentLibrariesListV2';
import * as api from './api';

/**
* Mock for `getContentLibraryV2List()`
*/
export const mockGetContentLibraryV2List = {
applyMock: () => jest.spyOn(api, 'getContentLibraryV2List').mockResolvedValue(
camelCaseObject(contentLibrariesListV2),
),
applyMockError: () => jest.spyOn(api, 'getContentLibraryV2List').mockRejectedValue(
createAxiosError({ code: 500, message: 'Internal Error.', path: api.getContentLibraryV2ListApiUrl() }),
),
applyMockLoading: () => jest.spyOn(api, 'getContentLibraryV2List').mockResolvedValue(
new Promise(() => {}),
),
};

/**
* Mock for `getContentLibrary()`
*
Expand All @@ -15,7 +32,7 @@ export async function mockContentLibrary(libraryId: string): Promise<api.Content
switch (libraryId) {
case mockContentLibrary.libraryIdThatNeverLoads:
// Return a promise that never resolves, to simulate never loading:
return new Promise<any>(() => { });
return new Promise<any>(() => {});
case mockContentLibrary.library404:
throw createAxiosError({ code: 400, message: 'Not found.', path: api.getContentLibraryApiUrl(libraryId) });
case mockContentLibrary.library500:
Expand Down Expand Up @@ -85,6 +102,14 @@ export async function mockContentLibrary(libraryId: string): Promise<api.Content
slug: 'draftNoChanges',
numBlocks: 0,
};
case mockContentLibrary.libraryFromList:
return {
...mockContentLibrary.libraryData,
id: mockContentLibrary.libraryFromList,
slug: 'TL1',
org: 'SampleTaxonomyOrg1',
title: 'Test Library 1',
};
default:
throw new Error(`mockContentLibrary: unknown library ID "${libraryId}"`);
}
Expand Down Expand Up @@ -125,6 +150,7 @@ mockContentLibrary.libraryUnpublishedChanges = 'lib:Axim:unpublishedChanges';
mockContentLibrary.libraryPublished = 'lib:Axim:published';
mockContentLibrary.libraryPublishedWithoutUser = 'lib:Axim:publishedWithoutUser';
mockContentLibrary.libraryDraftWithoutChanges = 'lib:Axim:draftNoChanges';
mockContentLibrary.libraryFromList = 'lib:SampleTaxonomyOrg1:TL1';
mockContentLibrary.applyMock = () => jest.spyOn(api, 'getContentLibrary').mockImplementation(mockContentLibrary);

/**
Expand All @@ -139,7 +165,7 @@ export async function mockCreateLibraryBlock(
case 'problem': return mockCreateLibraryBlock.newProblemData;
case 'video': return mockCreateLibraryBlock.newVideoData;
default:
// Continue to error handling below.
// Continue to error handling below.
}
}
throw new Error(`mockCreateLibraryBlock doesn't know how to mock ${JSON.stringify(args)}`);
Expand Down Expand Up @@ -257,7 +283,7 @@ export async function mockLibraryBlockMetadata(usageKey: string): Promise<api.Li
switch (usageKey) {
case thisMock.usageKeyThatNeverLoads:
// Return a promise that never resolves, to simulate never loading:
return new Promise<any>(() => { });
return new Promise<any>(() => {});
case thisMock.usageKeyError404:
throw createAxiosError({ code: 404, message: 'Not found.', path: api.getLibraryBlockMetadataUrl(usageKey) });
case thisMock.usageKeyNeverPublished: return thisMock.dataNeverPublished;
Expand Down

0 comments on commit d8f3d7a

Please sign in to comment.