155 lines
6.1 KiB
TypeScript
155 lines
6.1 KiB
TypeScript
/**
|
|
* Test the whole workflow of adding content, editing it, saving it
|
|
*/
|
|
import { snakeCaseObject } from '@edx/frontend-platform';
|
|
import {
|
|
fireEvent,
|
|
render,
|
|
waitFor,
|
|
screen,
|
|
initializeMocks,
|
|
} from '../../testUtils';
|
|
import mockResult from '../__mocks__/library-search.json';
|
|
import editorCmsApi from '../../editors/data/services/cms/api';
|
|
import * as textEditorHooks from '../../editors/containers/TextEditor/hooks';
|
|
import {
|
|
mockContentLibrary,
|
|
mockCreateLibraryBlock,
|
|
mockXBlockFields,
|
|
} from '../data/api.mocks';
|
|
import { mockBroadcastChannel, mockClipboardEmpty } from '../../generic/data/api.mock';
|
|
import { mockContentSearchConfig, mockSearchResult } from '../../search-manager/data/api.mock';
|
|
import { studioHomeMock } from '../../studio-home/__mocks__';
|
|
import { getStudioHomeApiUrl } from '../../studio-home/data/api';
|
|
import LibraryLayout from '../LibraryLayout';
|
|
|
|
mockContentSearchConfig.applyMock();
|
|
mockClipboardEmpty.applyMock();
|
|
mockBroadcastChannel();
|
|
mockContentLibrary.applyMock();
|
|
mockCreateLibraryBlock.applyMock();
|
|
mockSearchResult(mockResult);
|
|
// Mocking the redux APIs in the src/editors/ folder is a bit more involved:
|
|
jest.spyOn(editorCmsApi as any, 'fetchBlockById').mockImplementation(
|
|
async (args: { blockId: string }) => (
|
|
{ status: 200, data: snakeCaseObject(await mockXBlockFields(args.blockId)) }
|
|
),
|
|
);
|
|
jest.spyOn(textEditorHooks, 'getContent').mockImplementation(() => () => '<p>Edited HTML content</p>');
|
|
jest.mock('frontend-components-tinymce-advanced-plugins', () => ({ a11ycheckerCss: '' }));
|
|
const saveSpy = jest.spyOn(editorCmsApi as any, 'saveBlock');
|
|
|
|
const { libraryId } = mockContentLibrary;
|
|
const renderOpts = {
|
|
// Mount the <LibraryLayout /> on this route, to simulate how it's mounted in the real app:
|
|
path: '/library/:libraryId/*',
|
|
// And set the current URL to the following:
|
|
routerProps: { initialEntries: [`/library/${libraryId}/components`] },
|
|
};
|
|
|
|
describe('AddContentWorkflow test', () => {
|
|
beforeEach(async () => {
|
|
const { axiosMock } = initializeMocks();
|
|
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock);
|
|
});
|
|
|
|
it('can create an HTML component', async () => {
|
|
render(<LibraryLayout />, renderOpts);
|
|
|
|
// Click "New [Component]"
|
|
const newComponentButton = await screen.findByRole('button', { name: /New/ });
|
|
fireEvent.click(newComponentButton);
|
|
|
|
// Click "Text" to create a text component
|
|
fireEvent.click(await screen.findByRole('button', { name: /Text/ }));
|
|
|
|
// Then the editor should open
|
|
expect(await screen.findByRole('heading', { name: /New Text Component/ })).toBeInTheDocument();
|
|
|
|
// Edit the title
|
|
fireEvent.click(screen.getByRole('button', { name: /Edit Title/ }));
|
|
const titleInput = screen.getByPlaceholderText('Title');
|
|
fireEvent.change(titleInput, { target: { value: 'A customized title' } });
|
|
fireEvent.blur(titleInput);
|
|
await waitFor(() => expect(screen.queryByRole('heading', { name: /New Text Component/ })).not.toBeInTheDocument());
|
|
expect(screen.getByRole('heading', { name: /A customized title/ }));
|
|
|
|
// Note that TinyMCE doesn't really load properly in our test environment
|
|
// so we can't really edit the text, but we have getContent() mocked to simulate
|
|
// using TinyMCE to enter some new HTML.
|
|
|
|
// Mock the save() REST API method:
|
|
saveSpy.mockReset().mockImplementationOnce(async () => ({
|
|
status: 200, data: { id: mockXBlockFields.usageKeyNewHtml },
|
|
}));
|
|
|
|
// Click Save
|
|
const saveButton = screen.getByLabelText('Save changes and return to learning context');
|
|
fireEvent.click(saveButton);
|
|
expect(saveSpy).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('can create a Problem component', async () => {
|
|
render(<LibraryLayout />, renderOpts);
|
|
|
|
// Click "New [Component]"
|
|
const newComponentButton = await screen.findByRole('button', { name: /New/ });
|
|
fireEvent.click(newComponentButton);
|
|
|
|
// Click "Problem" to create a capa problem component
|
|
fireEvent.click(await screen.findByRole('button', { name: /Problem/ }));
|
|
|
|
// Then the editor should open
|
|
expect(await screen.findByRole('heading', { name: /Select problem type/ })).toBeInTheDocument();
|
|
|
|
// Select the type: Numerical Input
|
|
fireEvent.click(await screen.findByRole('button', { name: 'Numerical input' }));
|
|
fireEvent.click(screen.getByRole('button', { name: 'Select' }));
|
|
|
|
expect(await screen.findByRole('heading', { name: /Numerical input/ })).toBeInTheDocument();
|
|
|
|
// Enter an answer value:
|
|
const inputA = await screen.findByPlaceholderText('Enter an answer');
|
|
fireEvent.change(inputA, { target: { value: '123456' } });
|
|
|
|
// Mock the save() REST API method:
|
|
saveSpy.mockReset().mockImplementationOnce(async () => ({
|
|
status: 200, data: { id: mockXBlockFields.usageKeyNewProblem },
|
|
}));
|
|
|
|
// Click Save
|
|
const saveButton = screen.getByLabelText('Save changes and return to learning context');
|
|
fireEvent.click(saveButton);
|
|
expect(saveSpy).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('can create a Video component', async () => {
|
|
render(<LibraryLayout />, renderOpts);
|
|
|
|
// Click "New [Component]"
|
|
const newComponentButton = await screen.findByRole('button', { name: /New/ });
|
|
fireEvent.click(newComponentButton);
|
|
|
|
// Click "Video" to create a video component
|
|
fireEvent.click(await screen.findByRole('button', { name: /Video/ }));
|
|
|
|
// Then the editor should open - this is the default title of a blank video in our mock
|
|
expect(await screen.findByRole('heading', { name: /New Video/ })).toBeInTheDocument();
|
|
|
|
// Enter the video URL
|
|
const urlInput = await screen.findByRole('textbox', { name: 'Video URL' });
|
|
fireEvent.click(urlInput);
|
|
fireEvent.change(urlInput, { target: { value: 'https://www.youtube.com/watch?v=9KIIlWS4mkg' } });
|
|
|
|
// Mock the save() REST API method:
|
|
saveSpy.mockReset().mockImplementationOnce(async () => ({
|
|
status: 200, data: { id: mockXBlockFields.usageKeyNewVideo },
|
|
}));
|
|
|
|
// Click Save
|
|
const saveButton = screen.getByLabelText('Save changes and return to learning context');
|
|
fireEvent.click(saveButton);
|
|
expect(saveSpy).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|