Skip to content

Commit

Permalink
test: update tests accordingly
Browse files Browse the repository at this point in the history
  • Loading branch information
bradenmacdonald committed Oct 1, 2024
1 parent 48b58c6 commit 7924f5a
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 170 deletions.
2 changes: 1 addition & 1 deletion src/library-authoring/LibraryLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const LibraryLayout = () => {
}, [goBack]);

return (
<LibraryProvider>
<LibraryProvider libraryId={libraryId}>
<Routes>
{/*
TODO: we should be opening this editor as a modal, not making it a separate page/URL.
Expand Down
21 changes: 13 additions & 8 deletions src/library-authoring/add-content/AddContentContainer.test.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import {
fireEvent,
render,
render as baseRender,
screen,
waitFor,
initializeMocks,
} from '../../testUtils';
import { mockContentLibrary } from '../data/api.mocks';
import { getCreateLibraryBlockUrl, getLibraryPasteClipboardUrl } from '../data/api';
import { mockBroadcastChannel, mockClipboardEmpty, mockClipboardHtml } from '../../generic/data/api.mock';
import { LibraryProvider } from '../common/context';
import AddContentContainer from './AddContentContainer';

mockBroadcastChannel();

const { libraryId } = mockContentLibrary;
const renderOpts = { path: '/library/:libraryId/*', params: { libraryId } };
const render = () => baseRender(<AddContentContainer />, {
path: '/library/:libraryId/*',
params: { libraryId },
extraWrapper: ({ children }) => <LibraryProvider libraryId={libraryId}>{ children }</LibraryProvider>,
});

describe('<AddContentContainer />', () => {
it('should render content buttons', () => {
initializeMocks();
mockClipboardEmpty.applyMock();
render(<AddContentContainer />);
render();
expect(screen.getByRole('button', { name: /collection/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /text/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /problem/i })).toBeInTheDocument();
Expand All @@ -36,7 +41,7 @@ describe('<AddContentContainer />', () => {
const url = getCreateLibraryBlockUrl(libraryId);
axiosMock.onPost(url).reply(200);

render(<AddContentContainer />, renderOpts);
render();

const textButton = screen.getByRole('button', { name: /text/i });
fireEvent.click(textButton);
Expand All @@ -48,9 +53,9 @@ describe('<AddContentContainer />', () => {
initializeMocks();
// Simulate having an HTML block in the clipboard:
const getClipboardSpy = mockClipboardHtml.applyMock();
const doc = render(<AddContentContainer />, renderOpts);
render();
expect(getClipboardSpy).toHaveBeenCalled(); // Hmm, this is getting called three times! Refactor to use react-query.
await waitFor(() => expect(doc.queryByRole('button', { name: /paste from clipboard/i })).toBeInTheDocument());
await waitFor(() => expect(screen.queryByRole('button', { name: /paste from clipboard/i })).toBeInTheDocument());
});

it('should paste content', async () => {
Expand All @@ -61,7 +66,7 @@ describe('<AddContentContainer />', () => {
const pasteUrl = getLibraryPasteClipboardUrl(libraryId);
axiosMock.onPost(pasteUrl).reply(200);

render(<AddContentContainer />, renderOpts);
render();

expect(getClipboardSpy).toHaveBeenCalled(); // Hmm, this is getting called four times! Refactor to use react-query.

Expand All @@ -79,7 +84,7 @@ describe('<AddContentContainer />', () => {
const pasteUrl = getLibraryPasteClipboardUrl(libraryId);
axiosMock.onPost(pasteUrl).reply(400);

render(<AddContentContainer />, renderOpts);
render();

const pasteButton = await screen.findByRole('button', { name: /paste from clipboard/i });
fireEvent.click(pasteButton);
Expand Down
13 changes: 3 additions & 10 deletions src/library-authoring/common/context.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useToggle } from '@openedx/paragon';
import React from 'react';
import { useParams } from 'react-router-dom';

export enum SidebarBodyComponentId {
AddContent = 'add-content',
Expand Down Expand Up @@ -41,13 +40,7 @@ const LibraryContext = React.createContext<LibraryContextData | undefined>(undef
/**
* React component to provide `LibraryContext`
*/
export const LibraryProvider = (props: { children?: React.ReactNode }) => {
const { libraryId } = useParams();

if (libraryId === undefined) {
// istanbul ignore next - This shouldn't be possible; it's just here to satisfy the type checker.
throw new Error('Error: route is missing libraryId.');
}
export const LibraryProvider = (props: { children?: React.ReactNode, libraryId: string }) => {
const [sidebarBodyComponent, setSidebarBodyComponent] = React.useState<SidebarBodyComponentId | null>(null);
const [currentComponentUsageKey, setCurrentComponentUsageKey] = React.useState<string>();
const [currentCollectionId, setcurrentCollectionId] = React.useState<string>();
Expand Down Expand Up @@ -86,7 +79,7 @@ export const LibraryProvider = (props: { children?: React.ReactNode }) => {
}, []);

const context = React.useMemo<LibraryContextData>(() => ({
libraryId,
libraryId: props.libraryId,
sidebarBodyComponent,
closeLibrarySidebar,
openAddContentSidebar,
Expand All @@ -99,7 +92,7 @@ export const LibraryProvider = (props: { children?: React.ReactNode }) => {
openCollectionInfoSidebar,
currentCollectionId,
}), [
libraryId,
props.libraryId,
sidebarBodyComponent,
closeLibrarySidebar,
openAddContentSidebar,
Expand Down
8 changes: 7 additions & 1 deletion src/library-authoring/components/CollectionCard.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react';
import {
initializeMocks,
fireEvent,
render,
render as baseRender,
screen,
} from '../../testUtils';

import { LibraryProvider } from '../common/context';
import { type CollectionHit } from '../../search-manager';
import CollectionCard from './CollectionCard';

Expand All @@ -28,6 +30,10 @@ const CollectionHitSample: CollectionHit = {
tags: {},
};

const render = (ui: React.ReactElement) => baseRender(ui, {
extraWrapper: ({ children }) => <LibraryProvider libraryId="lib:Axim:TEST">{ children }</LibraryProvider>,
});

describe('<CollectionCard />', () => {
beforeEach(() => {
initializeMocks();
Expand Down
92 changes: 31 additions & 61 deletions src/library-authoring/components/ComponentCard.test.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
import React from 'react';
import { AppProvider } from '@edx/frontend-platform/react';
import { initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { render, fireEvent, waitFor } from '@testing-library/react';
import MockAdapter from 'axios-mock-adapter';
import type { Store } from 'redux';

import { ToastProvider } from '../../generic/toast-context';
import {
fireEvent,
render as baseRender,
screen,
waitFor,
initializeMocks,
} from '../../testUtils';
import { LibraryProvider } from '../common/context';
import { getClipboardUrl } from '../../generic/data/api';
import { ContentHit } from '../../search-manager';
import initializeStore from '../../store';
import ComponentCard from './ComponentCard';

let store: Store;
let axiosMock: MockAdapter;

const contentHit: ContentHit = {
id: '1',
usageKey: 'lb:org1:demolib:html:a1fa8bdd-dc67-4976-9bf5-0ea75a9bca3d',
type: 'library_block',
blockId: 'a1fa8bdd-dc67-4976-9bf5-0ea75a9bca3d',
contextKey: 'lb:org1:Demo_Course',
contextKey: 'lib:org1:Demo_Course',
org: 'org1',
breadcrumbs: [{ displayName: 'Demo Lib' }],
displayName: 'Text Display Name',
Expand All @@ -47,87 +41,63 @@ const clipboardBroadcastChannelMock = {

(global as any).BroadcastChannel = jest.fn(() => clipboardBroadcastChannelMock);

const RootWrapper = () => (
<AppProvider store={store}>
<IntlProvider locale="en">
<ToastProvider>
<ComponentCard
contentHit={contentHit}
blockTypeDisplayName="text"
/>
</ToastProvider>
</IntlProvider>
</AppProvider>
);
const libraryId = 'lib:org1:Demo_Course';
const render = () => baseRender(<ComponentCard contentHit={contentHit} blockTypeDisplayName="text" />, {
extraWrapper: ({ children }) => <LibraryProvider libraryId={libraryId}>{ children }</LibraryProvider>,
});

describe('<ComponentCard />', () => {
beforeEach(() => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});
store = initializeStore();

axiosMock = new MockAdapter(getAuthenticatedHttpClient());
});

afterEach(() => {
jest.clearAllMocks();
axiosMock.restore();
});

it('should render the card with title and description', () => {
const { getByText } = render(<RootWrapper />);
initializeMocks();
render();

expect(getByText('Text Display Formated Name')).toBeInTheDocument();
expect(getByText('This is a text: ID=1')).toBeInTheDocument();
expect(screen.getByText('Text Display Formated Name')).toBeInTheDocument();
expect(screen.getByText('This is a text: ID=1')).toBeInTheDocument();
});

it('should call the updateClipboard function when the copy button is clicked', async () => {
const { axiosMock, mockShowToast } = initializeMocks();
axiosMock.onPost(getClipboardUrl()).reply(200, {});
const { getByRole, getByTestId, getByText } = render(<RootWrapper />);
render();

// Open menu
expect(getByTestId('component-card-menu-toggle')).toBeInTheDocument();
fireEvent.click(getByTestId('component-card-menu-toggle'));
expect(screen.getByTestId('component-card-menu-toggle')).toBeInTheDocument();
fireEvent.click(screen.getByTestId('component-card-menu-toggle'));

// Click copy to clipboard
expect(getByRole('button', { name: 'Copy to clipboard' })).toBeInTheDocument();
fireEvent.click(getByRole('button', { name: 'Copy to clipboard' }));
expect(screen.getByRole('button', { name: 'Copy to clipboard' })).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Copy to clipboard' }));

expect(axiosMock.history.post.length).toBe(1);
expect(axiosMock.history.post[0].data).toBe(
JSON.stringify({ usage_key: contentHit.usageKey }),
);

await waitFor(() => {
expect(getByText('Component copied to clipboard')).toBeInTheDocument();
expect(mockShowToast).toHaveBeenCalledWith('Component copied to clipboard');
});
});

it('should show error message if the api call fails', async () => {
const { axiosMock, mockShowToast } = initializeMocks();
axiosMock.onPost(getClipboardUrl()).reply(400);
const { getByRole, getByTestId, getByText } = render(<RootWrapper />);
render();

// Open menu
expect(getByTestId('component-card-menu-toggle')).toBeInTheDocument();
fireEvent.click(getByTestId('component-card-menu-toggle'));
expect(screen.getByTestId('component-card-menu-toggle')).toBeInTheDocument();
fireEvent.click(screen.getByTestId('component-card-menu-toggle'));

// Click copy to clipboard
expect(getByRole('button', { name: 'Copy to clipboard' })).toBeInTheDocument();
fireEvent.click(getByRole('button', { name: 'Copy to clipboard' }));
expect(screen.getByRole('button', { name: 'Copy to clipboard' })).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Copy to clipboard' }));

expect(axiosMock.history.post.length).toBe(1);
expect(axiosMock.history.post[0].data).toBe(
JSON.stringify({ usage_key: contentHit.usageKey }),
);

await waitFor(() => {
expect(getByText('Failed to copy component to clipboard')).toBeInTheDocument();
expect(mockShowToast).toHaveBeenCalledWith('Failed to copy component to clipboard');
});
});
});
Loading

0 comments on commit 7924f5a

Please sign in to comment.