229 lines
8.5 KiB
JavaScript
229 lines
8.5 KiB
JavaScript
import { useEffect } from 'react';
|
|
import { MockUseState } from '../../../testUtils';
|
|
|
|
import tinyMCE from '../../data/constants/tinyMCE';
|
|
import { keyStore } from '../../utils';
|
|
import * as appHooks from '../../hooks';
|
|
import pluginConfig from './pluginConfig';
|
|
import * as module from './hooks';
|
|
|
|
jest.mock('react', () => ({
|
|
...jest.requireActual('react'),
|
|
createRef: jest.fn(val => ({ ref: val })),
|
|
useRef: jest.fn(val => ({ current: val })),
|
|
useEffect: jest.fn(),
|
|
useCallback: (cb, prereqs) => ({ cb, prereqs }),
|
|
}));
|
|
|
|
const state = new MockUseState(module);
|
|
const moduleKeys = keyStore(module);
|
|
|
|
const mockNode = {
|
|
src: 'sOmEuRl.cOm',
|
|
alt: 'aLt tExt',
|
|
width: 2022,
|
|
height: 1619,
|
|
};
|
|
|
|
let hook;
|
|
let output;
|
|
|
|
describe('TextEditor hooks', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
describe('state hooks', () => {
|
|
state.testGetter(state.keys.isModalOpen);
|
|
state.testGetter(state.keys.imageSelection);
|
|
state.testGetter(state.keys.refReady);
|
|
});
|
|
|
|
describe('appHooks', () => {
|
|
it('forwards navigateCallback from appHooks', () => {
|
|
expect(module.navigateCallback).toEqual(appHooks.navigateCallback);
|
|
});
|
|
it('forwards navigateTo from appHooks', () => {
|
|
expect(module.navigateTo).toEqual(appHooks.navigateTo);
|
|
});
|
|
it('forwards nullMethod from appHooks', () => {
|
|
expect(module.nullMethod).toEqual(appHooks.nullMethod);
|
|
});
|
|
});
|
|
|
|
describe('non-state hooks', () => {
|
|
beforeEach(() => { state.mock(); });
|
|
afterEach(() => { state.restore(); });
|
|
|
|
describe('setupCustomBehavior', () => {
|
|
test('It calls addButton and addToggleButton in the editor, but openModal is not called', () => {
|
|
const addButton = jest.fn();
|
|
const addToggleButton = jest.fn();
|
|
const openModal = jest.fn();
|
|
const setImage = jest.fn();
|
|
const editor = {
|
|
ui: { registry: { addButton, addToggleButton } },
|
|
};
|
|
const mockOpenModalWithImage = args => ({ openModalWithSelectedImage: args });
|
|
const expectedSettingsAction = mockOpenModalWithImage({ editor, setImage, openModal });
|
|
const openCodeEditor = expect.any(Function);
|
|
const toggleCodeFormatting = expect.any(Function);
|
|
const setupCodeFormatting = expect.any(Function);
|
|
jest.spyOn(module, moduleKeys.openModalWithSelectedImage)
|
|
.mockImplementationOnce(mockOpenModalWithImage);
|
|
output = module.setupCustomBehavior({ openModal, setImage })(editor);
|
|
expect(addButton.mock.calls).toEqual([
|
|
[tinyMCE.buttons.imageUploadButton, { icon: 'image', tooltip: 'Add Image', onAction: openModal }],
|
|
[tinyMCE.buttons.editImageSettings, { icon: 'image', tooltip: 'Edit Image Settings', onAction: expectedSettingsAction }],
|
|
[tinyMCE.buttons.code, { text: 'HTML', tooltip: 'Source code', onAction: openCodeEditor }],
|
|
]);
|
|
expect(addToggleButton.mock.calls).toEqual([
|
|
[tinyMCE.buttons.codeBlock, {
|
|
icon: 'sourcecode', tooltip: 'Code Block', onAction: toggleCodeFormatting, onSetup: setupCodeFormatting,
|
|
}],
|
|
]);
|
|
expect(openModal).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('editorConfig', () => {
|
|
const props = {
|
|
blockValue: null,
|
|
lmsEndpointUrl: 'sOmEuRl.cOm',
|
|
studioEndpointUrl: 'sOmEoThEruRl.cOm',
|
|
};
|
|
const evt = 'fakeEvent';
|
|
const editor = 'myEditor';
|
|
const setupCustomBehavior = args => ({ setupCustomBehavior: args });
|
|
beforeEach(() => {
|
|
props.setEditorRef = jest.fn();
|
|
props.openModal = jest.fn();
|
|
props.initializeEditor = jest.fn();
|
|
jest.spyOn(module, moduleKeys.setupCustomBehavior)
|
|
.mockImplementationOnce(setupCustomBehavior);
|
|
output = module.editorConfig(props);
|
|
});
|
|
test('It creates an onInit which calls initializeEditor and setEditorRef', () => {
|
|
output.onInit(evt, editor);
|
|
expect(props.setEditorRef).toHaveBeenCalledWith(editor);
|
|
expect(props.initializeEditor).toHaveBeenCalled();
|
|
});
|
|
test('It sets the blockvalue to be empty string by default', () => {
|
|
expect(output.initialValue).toBe('');
|
|
});
|
|
test('It sets the blockvalue to be the blockvalue if nonempty', () => {
|
|
const htmltext = 'SomE hTML content';
|
|
const blockValue = { data: { data: htmltext } };
|
|
output = module.editorConfig({ ...props, blockValue });
|
|
expect(output.initialValue).toBe(htmltext);
|
|
});
|
|
test('It configures plugins and toolbars correctly', () => {
|
|
expect(output.init.plugins).toEqual(pluginConfig.plugins);
|
|
expect(output.init.imagetools_toolbar).toEqual(pluginConfig.imageToolbar);
|
|
expect(output.init.toolbar).toEqual(pluginConfig.toolbar);
|
|
Object.keys(pluginConfig.config).forEach(key => {
|
|
expect(output.init[key]).toEqual(pluginConfig.config[key]);
|
|
});
|
|
// Commented out as we investigate whether this is only needed for image proxy
|
|
// expect(output.init.imagetools_cors_hosts).toMatchObject([props.lmsEndpointUrl]);
|
|
});
|
|
|
|
it('calls setupCustomBehavior on setup', () => {
|
|
expect(output.init.setup).toEqual(
|
|
setupCustomBehavior({ openModal: props.openModal, setImage: props.setSelection }),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('modalToggle', () => {
|
|
const hookKey = state.keys.isModalOpen;
|
|
beforeEach(() => {
|
|
hook = module.modalToggle();
|
|
});
|
|
test('isOpen: state value', () => {
|
|
expect(hook.isOpen).toEqual(state.stateVals[hookKey]);
|
|
});
|
|
test('openModal: calls setter with true', () => {
|
|
hook.openModal();
|
|
expect(state.setState[hookKey]).toHaveBeenCalledWith(true);
|
|
});
|
|
test('closeModal: calls setter with false', () => {
|
|
hook.closeModal();
|
|
expect(state.setState[hookKey]).toHaveBeenCalledWith(false);
|
|
});
|
|
});
|
|
|
|
describe('openModalWithSelectedImage', () => {
|
|
test('image is set to be value stored in editor, modal is opened', () => {
|
|
const setImage = jest.fn();
|
|
const openModal = jest.fn();
|
|
const editor = { selection: { getNode: () => mockNode } };
|
|
module.openModalWithSelectedImage({ editor, openModal, setImage })();
|
|
expect(setImage).toHaveBeenCalledWith({
|
|
externalUrl: mockNode.src,
|
|
altText: mockNode.alt,
|
|
width: mockNode.width,
|
|
height: mockNode.height,
|
|
});
|
|
expect(openModal).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('prepareEditorRef', () => {
|
|
beforeEach(() => {
|
|
hook = module.prepareEditorRef();
|
|
});
|
|
const key = state.keys.refReady;
|
|
test('sets refReady to false by default, ref is null', () => {
|
|
expect(state.stateVals[key]).toEqual(false);
|
|
expect(hook.editorRef.current).toBe(null);
|
|
});
|
|
test('when useEffect triggers, refReady is set to true', () => {
|
|
expect(state.setState[key]).not.toHaveBeenCalled();
|
|
const [cb, prereqs] = useEffect.mock.calls[0];
|
|
expect(prereqs).toStrictEqual([]);
|
|
cb();
|
|
expect(state.setState[key]).toHaveBeenCalledWith(true);
|
|
});
|
|
test('calling setEditorRef sets the ref value', () => {
|
|
const fakeEditor = { editor: 'faKe Editor' };
|
|
expect(hook.editorRef.current).not.toBe(fakeEditor);
|
|
hook.setEditorRef.cb(fakeEditor);
|
|
expect(hook.editorRef.current).toBe(fakeEditor);
|
|
});
|
|
});
|
|
|
|
describe('getContent', () => {
|
|
const visualContent = 'sOmEViSualContent';
|
|
const rawContent = 'soMeRawContent';
|
|
const editorRef = {
|
|
current: {
|
|
getContent: () => visualContent,
|
|
value: rawContent,
|
|
},
|
|
};
|
|
test('returns correct ontent based on isRaw', () => {
|
|
expect(module.getContent({ editorRef, isRaw: false })()).toEqual(visualContent);
|
|
expect(module.getContent({ editorRef, isRaw: true })()).toEqual(rawContent);
|
|
});
|
|
});
|
|
|
|
describe('selectedImage hooks', () => {
|
|
const val = { a: 'VaLUe' };
|
|
beforeEach(() => {
|
|
hook = module.selectedImage(val);
|
|
});
|
|
test('selection: state value', () => {
|
|
expect(hook.selection).toEqual(state.stateVals[state.keys.imageSelection]);
|
|
});
|
|
test('setSelection: setter for value', () => {
|
|
expect(hook.setSelection).toEqual(state.setState[state.keys.imageSelection]);
|
|
});
|
|
test('clearSelection: calls setter with null', () => {
|
|
expect(hook.setSelection).not.toHaveBeenCalled();
|
|
hook.clearSelection();
|
|
expect(hook.setSelection).toHaveBeenCalledWith(null);
|
|
});
|
|
});
|
|
});
|
|
});
|