test: update editor-level tests (#26)
To complete https://openedx.atlassian.net/browse/TNL-9601
This commit is contained in:
59
src/editors/Editor.test.jsx
Normal file
59
src/editors/Editor.test.jsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import React from 'react';
|
||||
import { mount, shallow } from 'enzyme';
|
||||
import { Editor, mapDispatchToProps, supportedEditors } from './Editor';
|
||||
import { thunkActions } from './data/redux';
|
||||
import * as hooks from './hooks';
|
||||
import { blockTypes } from './data/constants/app';
|
||||
|
||||
jest.mock('./hooks', () => ({
|
||||
initializeApp: jest.fn(),
|
||||
prepareEditorRef: jest.fn().mockName('prepareEditorRef'),
|
||||
}));
|
||||
|
||||
jest.mock('./containers/TextEditor/TextEditor', () => 'TextEditor');
|
||||
jest.mock('./containers/VideoEditor/VideoEditor', () => 'VideoEditor');
|
||||
jest.mock('./containers/ProblemEditor/ProblemEditor', () => 'ProblemEditor');
|
||||
jest.mock('./components/EditorFooter', () => 'EditorFooter');
|
||||
jest.mock('./components/EditorHeader', () => 'EditorHeader');
|
||||
|
||||
const props = {
|
||||
courseId: 'course-v1:edX+DemoX+Demo_Course',
|
||||
blockId: 'block-v1:edX+DemoX+Demo_Course+type@html+block@030e35c4756a4ddc8d40b95fbbfff4d4',
|
||||
studioEndpointUrl: 'fakeurl.com',
|
||||
initialize: jest.fn(),
|
||||
};
|
||||
|
||||
describe('Editor', () => {
|
||||
describe('snapshots', () => {
|
||||
test('renders no editor when ref isnt ready', () => {
|
||||
hooks.prepareEditorRef.mockImplementationOnce(
|
||||
() => ({ editorRef: null, refReady: false, setEditorRef: jest.fn() }),
|
||||
);
|
||||
expect(shallow(<Editor blockType="AblOck" {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
test.each(Object.values(blockTypes))('renders %p editor when ref is ready', (blockType) => {
|
||||
hooks.prepareEditorRef.mockImplementationOnce(
|
||||
() => ({ editorRef: { current: 'ref' }, refReady: true, setEditorRef: jest.fn().mockName('setEditorRef') }),
|
||||
);
|
||||
const wrapper = shallow(<Editor blockType={blockType} {...props} />);
|
||||
if(blockType == 'html'){ // snap just one editor to make viewing easier
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
};
|
||||
expect(wrapper.children().children().at(1).is(supportedEditors[blockType])).toBe(true);
|
||||
});
|
||||
test('presents error message if no relevant editor found and ref ready', () => {
|
||||
hooks.prepareEditorRef.mockImplementationOnce(
|
||||
() => ({ editorRef: { current: 'ref' }, refReady: true, setEditorRef: jest.fn().mockName('setEditorRef') }),
|
||||
);
|
||||
expect(shallow(<Editor
|
||||
{...props}
|
||||
blockType="fAkEBlock"
|
||||
/>)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('mapDispatchToProps', () => {
|
||||
test('initialize from thunkActions.app.initialize', () => {
|
||||
expect(mapDispatchToProps.initialize).toEqual(thunkActions.app.initialize);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,39 +1,22 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { shallow } from 'enzyme';
|
||||
import EditorPage from './EditorPage';
|
||||
|
||||
test('rendering correctly with expected Input', () => {
|
||||
const courseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
const blockType = 'html';
|
||||
const blockId = 'block-v1:edX+DemoX+Demo_Course+type@html+block@030e35c4756a4ddc8d40b95fbbfff4d4';
|
||||
const studioEndpointUrl = 'fakeurl.com';
|
||||
render(<EditorPage
|
||||
courseId={courseId}
|
||||
blockType={blockType}
|
||||
blockId={blockId}
|
||||
studioEndpointUrl={studioEndpointUrl}
|
||||
/>);
|
||||
expect(screen.getByText('Text')).toBeTruthy();
|
||||
expect(screen.getByText('Cancel')).toBeTruthy();
|
||||
expect(screen.getAllByLabelText('Close')).toBeTruthy();
|
||||
expect(screen.getByText('Add To Course')).toBeTruthy();
|
||||
expect(screen.getByText('Error: Could Not Load Text Content')).toBeTruthy();
|
||||
});
|
||||
const props = {
|
||||
courseId: 'course-v1:edX+DemoX+Demo_Course',
|
||||
blockType: 'html',
|
||||
blockId: 'block-v1:edX+DemoX+Demo_Course+type@html+block@030e35c4756a4ddc8d40b95fbbfff4d4',
|
||||
studioEndpointUrl: 'fakeurl.com',
|
||||
};
|
||||
jest.mock('react-redux', () => ({
|
||||
Provider: 'Provider',
|
||||
}));
|
||||
jest.mock('./Editor', () => 'Editor');
|
||||
|
||||
test('rendering correctly with expected Error', () => {
|
||||
const courseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
const blockType = 'Smelly Garbage Xblock';
|
||||
const blockId = 'BadGarbadioU@Garbagefha4521ea ';
|
||||
const studioEndpointUrl = 'fakeurl.com';
|
||||
render(<EditorPage
|
||||
courseId={courseId}
|
||||
blockType={blockType}
|
||||
blockId={blockId}
|
||||
studioEndpointUrl={studioEndpointUrl}
|
||||
/>);
|
||||
expect(screen.getByText(blockType)).toBeTruthy();
|
||||
expect(screen.getByText('Cancel')).toBeTruthy();
|
||||
expect(screen.getAllByLabelText('Close')).toBeTruthy();
|
||||
expect(screen.getByText('Add To Course')).toBeTruthy();
|
||||
expect(screen.getByText('Error: Could Not find Editor')).toBeTruthy();
|
||||
describe('Editor Page', () => {
|
||||
describe('snapshots', () => {
|
||||
test('rendering correctly with expected Input', () => {
|
||||
expect(shallow(<EditorPage {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
75
src/editors/__snapshots__/Editor.test.jsx.snap
Normal file
75
src/editors/__snapshots__/Editor.test.jsx.snap
Normal file
@@ -0,0 +1,75 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Editor snapshots presents error message if no relevant editor found and ref ready 1`] = `
|
||||
<div
|
||||
className="d-flex flex-column vh-100"
|
||||
>
|
||||
<div
|
||||
aria-label="fAkEBlock"
|
||||
className="pgn__modal-fullscreen"
|
||||
role="dialog"
|
||||
>
|
||||
<EditorHeader
|
||||
editorRef={
|
||||
Object {
|
||||
"current": "ref",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<FormattedMessage
|
||||
defaultMessage="Error: Could Not find Editor"
|
||||
description="Error Message Dispayed When An unsopported Editor is desired in V2"
|
||||
id="authoring.editorpage.selecteditor.error"
|
||||
/>
|
||||
<EditorFooter
|
||||
editorRef={
|
||||
Object {
|
||||
"current": "ref",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Editor snapshots renders "html" editor when ref is ready 1`] = `
|
||||
<div
|
||||
className="d-flex flex-column vh-100"
|
||||
>
|
||||
<div
|
||||
aria-label="html"
|
||||
className="pgn__modal-fullscreen"
|
||||
role="dialog"
|
||||
>
|
||||
<EditorHeader
|
||||
editorRef={
|
||||
Object {
|
||||
"current": "ref",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<TextEditor
|
||||
setEditorRef={[MockFunction setEditorRef]}
|
||||
/>
|
||||
<EditorFooter
|
||||
editorRef={
|
||||
Object {
|
||||
"current": "ref",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Editor snapshots renders no editor when ref isnt ready 1`] = `
|
||||
<div
|
||||
className="d-flex flex-column vh-100"
|
||||
>
|
||||
<div
|
||||
aria-label="AblOck"
|
||||
className="pgn__modal-fullscreen"
|
||||
role="dialog"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
22
src/editors/__snapshots__/EditorPage.test.jsx.snap
Normal file
22
src/editors/__snapshots__/EditorPage.test.jsx.snap
Normal file
@@ -0,0 +1,22 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Editor Page snapshots rendering correctly with expected Input 1`] = `
|
||||
<Provider
|
||||
store={
|
||||
Object {
|
||||
"dispatch": [Function],
|
||||
"getState": [Function],
|
||||
"replaceReducer": [Function],
|
||||
"subscribe": [Function],
|
||||
Symbol(Symbol.observable): [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<Editor
|
||||
blockId="block-v1:edX+DemoX+Demo_Course+type@html+block@030e35c4756a4ddc8d40b95fbbfff4d4"
|
||||
blockType="html"
|
||||
courseId="course-v1:edX+DemoX+Demo_Course"
|
||||
studioEndpointUrl="fakeurl.com"
|
||||
/>
|
||||
</Provider>
|
||||
`;
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
Toast,
|
||||
} from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { nullMethod, saveTextBlock, navigateCallback } from '../../hooks';
|
||||
import { nullMethod, saveBlock, navigateCallback } from '../../hooks';
|
||||
|
||||
import { RequestKeys } from '../../data/constants/requests';
|
||||
import { selectors, thunkActions } from '../../data/redux';
|
||||
@@ -18,7 +18,7 @@ import { selectors, thunkActions } from '../../data/redux';
|
||||
import messages from '../messages';
|
||||
import * as module from '.';
|
||||
|
||||
export const handleSaveClicked = (props) => () => saveTextBlock(props);
|
||||
export const handleSaveClicked = (props) => () => saveBlock(props);
|
||||
export const handleCancelClicked = ({ returnUrl }) => navigateCallback(returnUrl);
|
||||
|
||||
export const EditorFooter = ({
|
||||
|
||||
@@ -3,7 +3,7 @@ import { shallow } from 'enzyme';
|
||||
import * as module from './index';
|
||||
import { selectors, thunkActions } from '../../data/redux';
|
||||
import { RequestKeys } from '../../data/constants/requests';
|
||||
import { saveTextBlock, navigateCallback } from '../../hooks';
|
||||
import { saveBlock, navigateCallback } from '../../hooks';
|
||||
|
||||
jest.mock('../../data/redux', () => ({
|
||||
thunkActions: {
|
||||
@@ -30,7 +30,7 @@ jest.mock('.', () => ({
|
||||
}));
|
||||
|
||||
jest.mock('../../hooks', () => ({
|
||||
saveTextBlock: jest.fn(),
|
||||
saveBlock: jest.fn(),
|
||||
navigateCallback: jest.fn(),
|
||||
nullMethod: jest.fn().mockName('nullMethod'),
|
||||
}));
|
||||
@@ -45,10 +45,10 @@ describe('EditorFooter', () => {
|
||||
};
|
||||
describe('behavior', () => {
|
||||
const realmodule = jest.requireActual('./index');
|
||||
test('handleSaveClicked calls saveTextBlock', () => {
|
||||
test('handleSaveClicked calls saveBlock', () => {
|
||||
const createdCallback = realmodule.handleSaveClicked(props);
|
||||
createdCallback();
|
||||
expect(saveTextBlock).toHaveBeenCalled();
|
||||
expect(saveBlock).toHaveBeenCalled();
|
||||
});
|
||||
test('handleCancelClicked calls navigateCallback', () => {
|
||||
realmodule.handleCancelClicked({ returnUrl: props.returnUrl });
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
useRef, useEffect, useCallback, useState,
|
||||
} from 'react';
|
||||
import * as module from './hooks';
|
||||
|
||||
export const initializeApp = ({ initialize, data }) => useEffect(() => initialize(data), []);
|
||||
|
||||
@@ -18,14 +19,14 @@ export const navigateTo = (destination) => {
|
||||
window.location.assign(destination);
|
||||
};
|
||||
|
||||
export const navigateCallback = (destination) => () => navigateTo(destination);
|
||||
export const navigateCallback = (destination) => () => module.navigateTo(destination);
|
||||
|
||||
export const saveTextBlock = ({
|
||||
export const saveBlock = ({
|
||||
editorRef,
|
||||
returnUrl,
|
||||
saveBlock,
|
||||
saveFunction,
|
||||
}) => {
|
||||
saveBlock({
|
||||
saveFunction({
|
||||
returnToUnit: module.navigateCallback(returnUrl),
|
||||
content: editorRef.current.getContent(),
|
||||
});
|
||||
|
||||
101
src/editors/hooks.test.jsx
Normal file
101
src/editors/hooks.test.jsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import { useEffect, updateState } from 'react';
|
||||
import * as module from './hooks';
|
||||
|
||||
jest.mock('react', () => {
|
||||
const updateStateMock = jest.fn();
|
||||
return {
|
||||
updateState: updateStateMock,
|
||||
useState: jest.fn(val => ([{ state: val }, (newVal) => updateStateMock({ val, newVal })])),
|
||||
useRef: jest.fn(val => ({ current: val })),
|
||||
useEffect: jest.fn(),
|
||||
useCallback: (cb, prereqs) => ({ cb, prereqs }),
|
||||
};
|
||||
});
|
||||
describe('hooks', () => {
|
||||
const locationTemp = window.location;
|
||||
beforeAll(() => {
|
||||
delete window.location;
|
||||
window.location = {
|
||||
assign: jest.fn(),
|
||||
};
|
||||
});
|
||||
afterAll(() => {
|
||||
window.location = locationTemp;
|
||||
});
|
||||
describe('initializeApp', () => {
|
||||
test('calls provided function with provided data as args when useEffect is called', () => {
|
||||
const mockIntialize = jest.fn(val => (val));
|
||||
const fakedata = { some: 'data' };
|
||||
module.initializeApp({ initialize: mockIntialize, data: fakedata });
|
||||
expect(mockIntialize).not.toHaveBeenCalledWith(fakedata);
|
||||
const [cb, prereqs] = useEffect.mock.calls[0];
|
||||
expect(prereqs).toStrictEqual([]);
|
||||
cb();
|
||||
expect(mockIntialize).toHaveBeenCalledWith(fakedata);
|
||||
});
|
||||
});
|
||||
describe('prepareEditorRef', () => {
|
||||
let output;
|
||||
beforeEach(() => {
|
||||
output = module.prepareEditorRef();
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
test('sets refReady to false by default, ref is null', () => {
|
||||
expect(output.refReady.state).toBe(false);
|
||||
expect(output.editorRef.current).toBe(null);
|
||||
});
|
||||
test('when useEffect triggers, refReady is set to true', () => {
|
||||
expect(updateState).not.toHaveBeenCalled();
|
||||
const [cb, prereqs] = useEffect.mock.calls[0];
|
||||
expect(prereqs).toStrictEqual([]);
|
||||
cb();
|
||||
expect(updateState).toHaveBeenCalledWith({ newVal: true, val: false });
|
||||
});
|
||||
test('calling setEditorRef sets the ref value', () => {
|
||||
const fakeEditor = { editor: 'faKe Editor' };
|
||||
expect(output.editorRef.current).not.toBe(fakeEditor);
|
||||
output.setEditorRef.cb(fakeEditor);
|
||||
expect(output.editorRef.current).toBe(fakeEditor);
|
||||
});
|
||||
});
|
||||
describe('navigateTo', () => {
|
||||
const destination = 'HoME';
|
||||
beforeEach(() => {
|
||||
module.navigateTo(destination);
|
||||
});
|
||||
test('it calls window assign', () => {
|
||||
expect(window.location.assign).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
describe('navigateCallback', () => {
|
||||
let output;
|
||||
const destination = 'hOmE';
|
||||
beforeEach(() => {
|
||||
output = module.navigateCallback(destination);
|
||||
});
|
||||
test('it calls navigateTo with output destination', () => {
|
||||
const spy = jest.spyOn(module, 'navigateTo');
|
||||
output();
|
||||
expect(spy).toHaveBeenCalledWith(destination);
|
||||
});
|
||||
});
|
||||
describe('saveBlock', () => {
|
||||
test('saveBlock calls the save function provided with created nav callback and content', () => {
|
||||
const mockNavCallback = (returnUrl) => ({ navigateCallback: returnUrl });
|
||||
jest.spyOn(module, 'navigateCallback').mockImplementationOnce(mockNavCallback);
|
||||
const content = { some: 'content' };
|
||||
const args = {
|
||||
editorRef: { current: { getContent: () => content } },
|
||||
returnUrl: 'rEtUrNUrl',
|
||||
saveFunction: jest.fn(),
|
||||
};
|
||||
module.saveBlock(args);
|
||||
expect(args.saveFunction).toHaveBeenCalledWith({
|
||||
returnToUnit: mockNavCallback(args.returnUrl),
|
||||
content,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user