Skip to content

Commit

Permalink
test: update tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bradenmacdonald committed Oct 5, 2024
1 parent 86518db commit 413259e
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 9 deletions.
113 changes: 113 additions & 0 deletions src/library-authoring/component-info/ComponentAdvancedInfo.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import {
fireEvent,
initializeMocks,
render,
screen,
waitFor,
} from '../../testUtils';
import {
mockContentLibrary,
mockLibraryBlockMetadata,
mockSetXBlockOLX,
mockXBlockAssets,
mockXBlockOLX,
} from '../data/api.mocks';
import { LibraryProvider } from '../common/context';
import { ComponentAdvancedInfo } from './ComponentAdvancedInfo';

mockContentLibrary.applyMock();
mockLibraryBlockMetadata.applyMock();
mockXBlockAssets.applyMock();
mockXBlockOLX.applyMock();
const setOLXspy = mockSetXBlockOLX.applyMock();

const withLibraryId = (libraryId: string = mockContentLibrary.libraryId) => ({
extraWrapper: ({ children }: { children: React.ReactNode }) => (
<LibraryProvider libraryId={libraryId}>{children}</LibraryProvider>
),
});

describe('<ComponentAdvancedInfo />', () => {
it('should display nothing when collapsed', async () => {
initializeMocks();
render(<ComponentAdvancedInfo usageKey={mockLibraryBlockMetadata.usageKeyPublished} />, withLibraryId());
const expandButton = await screen.findByRole('button', { name: /Advanced details/ });
expect(expandButton).toBeInTheDocument();
expect(screen.queryByText(mockLibraryBlockMetadata.usageKeyPublished)).not.toBeInTheDocument();
});

it('should display the usage key of the block (when expanded)', async () => {
initializeMocks();
render(<ComponentAdvancedInfo usageKey={mockLibraryBlockMetadata.usageKeyPublished} />, withLibraryId());
const expandButton = await screen.findByRole('button', { name: /Advanced details/ });
fireEvent.click(expandButton);
expect(await screen.findByText(mockLibraryBlockMetadata.usageKeyPublished)).toBeInTheDocument();
});

it('should display the static assets of the block (when expanded)', async () => {
initializeMocks();
render(<ComponentAdvancedInfo usageKey={mockLibraryBlockMetadata.usageKeyPublished} />, withLibraryId());
const expandButton = await screen.findByRole('button', { name: /Advanced details/ });
fireEvent.click(expandButton);
expect(await screen.findByText(/static\/image1\.png/)).toBeInTheDocument();
expect(await screen.findByText(/\(12M\)/)).toBeInTheDocument(); // size of the above file
expect(await screen.findByText(/static\/data\.csv/)).toBeInTheDocument();
expect(await screen.findByText(/\(8K\)/)).toBeInTheDocument(); // size of the above file
});

it('should display the OLX source of the block (when expanded)', async () => {
initializeMocks();
render(<ComponentAdvancedInfo usageKey={mockXBlockOLX.usageKeyHtml} />, withLibraryId());
const expandButton = await screen.findByRole('button', { name: /Advanced details/ });
fireEvent.click(expandButton);
// Because of syntax highlighting, the OLX will be borken up by many different tags so we need to search for
// just a substring:
const olxPart = /This is a text component which uses/;
expect(await screen.findByText(olxPart)).toBeInTheDocument();
});

it('does not display "Edit OLX" button when the library is read-only', async () => {
initializeMocks();
render(
<ComponentAdvancedInfo usageKey={mockXBlockOLX.usageKeyHtml} />,
withLibraryId(mockContentLibrary.libraryIdReadOnly),
);
const expandButton = await screen.findByRole('button', { name: /Advanced details/ });
fireEvent.click(expandButton);
expect(screen.queryByRole('button', { name: /Edit OLX/ })).not.toBeInTheDocument();
});

it('can edit the OLX', async () => {
initializeMocks();
render(<ComponentAdvancedInfo usageKey={mockLibraryBlockMetadata.usageKeyPublished} />, withLibraryId());
const expandButton = await screen.findByRole('button', { name: /Advanced details/ });
fireEvent.click(expandButton);
const editButton = await screen.findByRole('button', { name: /Edit OLX/ });
fireEvent.click(editButton);

expect(setOLXspy).not.toHaveBeenCalled();

const saveButton = await screen.findByRole('button', { name: /Save/ });
fireEvent.click(saveButton);

await waitFor(() => expect(setOLXspy).toHaveBeenCalled());
});

it('displays an error if editing the OLX failed', async () => {
initializeMocks();

setOLXspy.mockImplementation(async () => {
throw new Error('Example error - setting OLX failed');
});

render(<ComponentAdvancedInfo usageKey={mockLibraryBlockMetadata.usageKeyPublished} />, withLibraryId());
const expandButton = await screen.findByRole('button', { name: /Advanced details/ });
fireEvent.click(expandButton);
const editButton = await screen.findByRole('button', { name: /Edit OLX/ });
fireEvent.click(editButton);
const saveButton = await screen.findByRole('button', { name: /Save/ });
fireEvent.click(saveButton);

expect(await screen.findByText(/An error occurred and the OLX could not be saved./)).toBeInTheDocument();
});
});
22 changes: 13 additions & 9 deletions src/library-authoring/component-info/ComponentDetails.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@ import {
render,
screen,
} from '../../testUtils';
import { mockContentLibrary, mockLibraryBlockMetadata } from '../data/api.mocks';
import {
mockContentLibrary,
mockLibraryBlockMetadata,
mockXBlockAssets,
mockXBlockOLX,
} from '../data/api.mocks';
import { LibraryProvider } from '../common/context';
import ComponentDetails from './ComponentDetails';

mockContentLibrary.applyMock();
mockLibraryBlockMetadata.applyMock();
mockXBlockAssets.applyMock();
mockXBlockOLX.applyMock();

const withLibraryId = (libraryId: string = mockContentLibrary.libraryId) => ({
extraWrapper: ({ children }: { children: React.ReactNode }) => (
Expand All @@ -16,32 +24,28 @@ const withLibraryId = (libraryId: string = mockContentLibrary.libraryId) => ({
});

describe('<ComponentDetails />', () => {
it('should render the component details loading', async () => {
beforeEach(() => {
initializeMocks();
mockLibraryBlockMetadata.applyMock();
});

it('should render the component details loading', async () => {
render(<ComponentDetails usageKey={mockLibraryBlockMetadata.usageKeyThatNeverLoads} />, withLibraryId());
expect(await screen.findByText('Loading...')).toBeInTheDocument();
});

it('should render the component details error', async () => {
initializeMocks();
mockLibraryBlockMetadata.applyMock();
render(<ComponentDetails usageKey={mockLibraryBlockMetadata.usageKeyError404} />, withLibraryId());
expect(await screen.findByText(/Mocked request failed with status code 404/)).toBeInTheDocument();
});

it('should render the component usage', async () => {
initializeMocks();
mockLibraryBlockMetadata.applyMock();
render(<ComponentDetails usageKey={mockLibraryBlockMetadata.usageKeyNeverPublished} />, withLibraryId());
expect(await screen.findByText('Component Usage')).toBeInTheDocument();
// TODO: replace with actual data when implement tag list
expect(screen.queryByText('This will show the courses that use this component.')).toBeInTheDocument();
});

it('should render the component history', async () => {
initializeMocks();
mockLibraryBlockMetadata.applyMock();
render(<ComponentDetails usageKey={mockLibraryBlockMetadata.usageKeyNeverPublished} />, withLibraryId());
// Show created date
expect(await screen.findByText('June 20, 2024')).toBeInTheDocument();
Expand Down
51 changes: 51 additions & 0 deletions src/library-authoring/data/api.mocks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* istanbul ignore file */
import { mockContentTaxonomyTagsData } from '../../content-tags-drawer/data/api.mocks';
import { getBlockType } from '../../generic/key-utils';
import { createAxiosError } from '../../testUtils';
import * as api from './api';

Expand Down Expand Up @@ -269,3 +270,53 @@ mockGetCollectionMetadata.collectionData = {
mockGetCollectionMetadata.applyMock = () => {
jest.spyOn(api, 'getCollectionMetadata').mockImplementation(mockGetCollectionMetadata);
};

/**
* Mock for `getXBlockOLX()`
*
* This mock returns different data/responses depending on the ID of the block
* that you request. Use `mockXBlockOLX.applyMock()` to apply it to the whole
* test suite.
*/
export async function mockXBlockOLX(usageKey: string): Promise<string> {
const thisMock = mockXBlockOLX;
switch (usageKey) {
case thisMock.usageKeyHtml: return thisMock.olxHtml;
default: {
const blockType = getBlockType(usageKey);
return `<${blockType}>This is mock OLX for usageKey "${usageKey}"</${blockType}>`;
}
}
}
// Mock of a "regular" HTML (Text) block:
mockXBlockOLX.usageKeyHtml = mockXBlockFields.usageKeyHtml;
mockXBlockOLX.olxHtml = `
<html display_name="${mockXBlockFields.dataHtml.displayName}">
${mockXBlockFields.dataHtml.data}
</html>
`;
/** Apply this mock. Returns a spy object that can tell you if it's been called. */
mockXBlockOLX.applyMock = () => jest.spyOn(api, 'getXBlockOLX').mockImplementation(mockXBlockOLX);

/**
* Mock for `setXBlockOLX()`
*/
export async function mockSetXBlockOLX(_usageKey: string, newOLX: string): Promise<string> {
return newOLX;
}
/** Apply this mock. Returns a spy object that can tell you if it's been called. */
mockSetXBlockOLX.applyMock = () => jest.spyOn(api, 'setXBlockOLX').mockImplementation(mockSetXBlockOLX);

/**
* Mock for `getXBlockAssets()`
*
* Use `getXBlockAssets.applyMock()` to apply it to the whole test suite.
*/
export async function mockXBlockAssets(): ReturnType<typeof api['getXBlockAssets']> {
return [
{ path: 'static/image1.png', url: 'https://cdn.test.none/image1.png', size: 12_345_000 },
{ path: 'static/data.csv', url: 'https://cdn.test.none/data.csv', size: 8_000 },
];
}
/** Apply this mock. Returns a spy object that can tell you if it's been called. */
mockXBlockAssets.applyMock = () => jest.spyOn(api, 'getXBlockAssets').mockImplementation(mockXBlockAssets);
3 changes: 3 additions & 0 deletions src/library-authoring/data/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export async function createCollection(libraryId: string, collectionData: Create
/**
* Fetch the OLX for the given XBlock.
*/
// istanbul ignore next
export async function getXBlockOLX(usageKey: string): Promise<string> {
const { data } = await getAuthenticatedHttpClient().get(getXBlockOLXApiUrl(usageKey));
return data.olx;
Expand All @@ -313,6 +314,7 @@ export async function getXBlockOLX(usageKey: string): Promise<string> {
* Set the OLX for the given XBlock.
* Returns the OLX as it was actually saved.
*/
// istanbul ignore next
export async function setXBlockOLX(usageKey: string, newOLX: string): Promise<string> {
const { data } = await getAuthenticatedHttpClient().post(getXBlockOLXApiUrl(usageKey), { olx: newOLX });
return data.olx;
Expand All @@ -321,6 +323,7 @@ export async function setXBlockOLX(usageKey: string, newOLX: string): Promise<st
/**
* Fetch the asset (static file) list for the given XBlock.
*/
// istanbul ignore next
export async function getXBlockAssets(usageKey: string): Promise<{ path: string; url: string; size: number }[]> {
const { data } = await getAuthenticatedHttpClient().get(getXBlockAssetsApiUrl(usageKey));
return data.files;
Expand Down

0 comments on commit 413259e

Please sign in to comment.