test: add TextEditor Tests (#21)

This commit is contained in:
connorhaugh
2022-02-25 15:06:12 -05:00
committed by GitHub
parent 042246be86
commit 7ccba63a85
3 changed files with 283 additions and 36 deletions

View File

@@ -1,51 +1,91 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import TextEditor from './TextEditor';
import EditorPageContext from '../EditorPageContext';
import { ActionStates } from '../data/constants';
import { shallow } from 'enzyme';
import { TextEditor, mapStateToProps, mapDispatchToProps } from './TextEditor';
import { actions, selectors } from '../../data/redux';
import { RequestKeys } from '../../data/constants/requests';
import { modalToggle } from './hooks';
// Per https://github.com/tinymce/tinymce-react/issues/91 React unit testing in JSDOM is not supported by tinymce.
// Consequently, mock the Editor out.
const mockRole = 'Tiny-MCE-Mock';
jest.mock('@tinymce/tinymce-react', () => {
const originalModule = jest.requireActual('@tinymce/tinymce-react');
return {
__esModule: true,
...originalModule,
Editor: () => <div role={mockRole} />
Editor: () => 'TiNYmCE EDitOR'
,
};
});
test('Loading State:', () => {
const context = {
blockValue: null,
blockError: null,
blockLoading: ActionStates.IN_PROGRESS,
editorRef: null,
jest.mock('./hooks', () => ({
editorConfig: jest.fn(args => ({ editorConfig: args })),
modalToggle: jest.fn(args => ({ modalToggle: args })),
nullMethod: jest.fn().mockName('nullMethod'),
}));
jest.mock('../../data/redux', () => ({
actions: {
app: {
initializeEditor: jest.fn().mockName('actions.app.initializeEditor'),
},
},
selectors: {
app: {
blockValue: jest.fn(state => ({ blockValue: state })),
},
requests: {
isFailed: jest.fn((state, params) => ({ isFailed: { state, params } })),
isFinished: jest.fn((state, params) => ({ isFailed: { state, params } })),
},
},
}));
describe('TextEditor', () => {
const props = {
setEditorRef: jest.fn().mockName('args.setEditorRef'),
// redux
blockValue: { data: 'eDiTablE Text' },
blockFailed: false,
blockFinished: true,
initializeEditor: jest.fn().mockName('args.intializeEditor'),
};
render(
<EditorPageContext.Provider value={context}>
<TextEditor />
</EditorPageContext.Provider>,
);
expect(screen.queryByRole(mockRole)).not.toBeTruthy();
});
test('Loaded State-- No Error', () => {
const htmltext = 'Im baby palo santo ugh celiac fashion axe. La croix lo-fi venmo whatever. Beard man braid migas single-origin coffee forage ramps.';
const context = {
blockValue:
{
data:
{ data: { htmltext } },
},
blockError: null,
blockLoading: ActionStates.FINISHED,
};
render(
<EditorPageContext.Provider value={context}>
<TextEditor />
</EditorPageContext.Provider>,
);
expect(screen.findByRole(mockRole)).toBeTruthy();
describe('snapshots', () => {
modalToggle.mockReturnValue({
isOpen: false,
openModal: jest.fn().mockName('modal.openModal'),
closeModal: jest.fn().mockName('modal.closeModal'),
});
test('renders as expected with default behavior', () => {
expect(shallow(<TextEditor {...props} />)).toMatchSnapshot();
});
test('not yet loaded, Spinner appears', () => {
expect(shallow(<TextEditor {...props} blockFinished={false} />)).toMatchSnapshot();
});
test('block failed to load, Toast is shown', () => {
expect(shallow(<TextEditor {...props} blockFailed />)).toMatchSnapshot();
});
});
describe('mapStateToProps', () => {
const testState = { A: 'pple', B: 'anana', C: 'ucumber' };
test('blockValue from app.blockValue', () => {
expect(
mapStateToProps(testState).blockValue,
).toEqual(selectors.app.blockValue(testState));
});
test('blockFailed from requests.isFailed', () => {
expect(
mapStateToProps(testState).blockFailed,
).toEqual(selectors.requests.isFailed(testState, { requestKey: RequestKeys.fetchBlock }));
});
test('blockFinished from requests.isFinished', () => {
expect(
mapStateToProps(testState).blockFinished,
).toEqual(selectors.requests.isFinished(testState, { requestKey: RequestKeys.fetchBlock }));
});
});
describe('mapDispatchToProps', () => {
test('initializeEditor from actions.app.initializeEditor', () => {
expect(mapDispatchToProps.initializeEditor).toEqual(actions.app.initializeEditor);
});
});
});

View File

@@ -0,0 +1,97 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TextEditor snapshots block failed to load, Toast is shown 1`] = `
<div
className="editor-body h-75"
>
<ImageUploadModal
close={[MockFunction modal.closeModal]}
isOpen={false}
/>
<Toast
onClose={[MockFunction nullMethod]}
show={true}
>
<FormattedMessage
defaultMessage="Error: Could Not Load Text Content"
description="Error Message Dispayed When HTML content fails to Load"
id="authoring.texteditor.load.error"
/>
</Toast>
<Editor
editorConfig={
Object {
"blockValue": Object {
"data": "HYleTsEditTeaxt",
},
"initializeEditor": [MockFunction args.intializeEditor],
"openModal": [MockFunction modal.openModal],
"setEditorRef": [MockFunction args.setEditorRef],
}
}
/>
</div>
`;
exports[`TextEditor snapshots not yet loaded, Spinner appears 1`] = `
<div
className="editor-body h-75"
>
<ImageUploadModal
close={[MockFunction modal.closeModal]}
isOpen={false}
/>
<Toast
onClose={[MockFunction nullMethod]}
show={false}
>
<FormattedMessage
defaultMessage="Error: Could Not Load Text Content"
description="Error Message Dispayed When HTML content fails to Load"
id="authoring.texteditor.load.error"
/>
</Toast>
<div
className="text-center p-6"
>
<Spinner
animation="border"
className="m-3"
screenreadertext="loading"
/>
</div>
</div>
`;
exports[`TextEditor snapshots renders as expected with default behavior 1`] = `
<div
className="editor-body h-75"
>
<ImageUploadModal
close={[MockFunction modal.closeModal]}
isOpen={false}
/>
<Toast
onClose={[MockFunction nullMethod]}
show={false}
>
<FormattedMessage
defaultMessage="Error: Could Not Load Text Content"
description="Error Message Dispayed When HTML content fails to Load"
id="authoring.texteditor.load.error"
/>
</Toast>
<Editor
editorConfig={
Object {
"blockValue": Object {
"data": "HYleTsEditTeaxt",
},
"initializeEditor": [MockFunction args.intializeEditor],
"openModal": [MockFunction modal.openModal],
"setEditorRef": [MockFunction args.setEditorRef],
}
}
/>
</div>
`;

View File

@@ -0,0 +1,110 @@
import React from 'react';
import * as module from './hooks';
jest.mock('react', () => {
const updateState = jest.fn();
return {
updateState,
useState: jest.fn(val => ([{ state: val }, (newVal) => updateState({ val, newVal })])),
createRef: jest.fn(val => ({ ref: val })),
};
});
describe('TextEditor hooks', () => {
describe('Editor Init hooks', () => {
describe('addImageUploadButton', () => {
const mockOpenModal = jest.fn();
const mockAddbutton = jest.fn(val => ({ onAction: val }));
const editor = {
ui: {
registry: {
addButton: mockAddbutton,
},
},
};
let output;
beforeEach(() => {
output = module.addImageUploadButton(mockOpenModal);
});
test('It calls addButton in the editor, but openModal is not called', () => {
output(editor);
expect(mockAddbutton).toHaveBeenCalledWith('imageuploadbutton', { icon: 'image', onAction: mockOpenModal });
expect(mockOpenModal).not.toHaveBeenCalled();
});
});
describe('initializeEditorRef', () => {
const mockSetRef = jest.fn(val => ({ editor: val }));
const editor = {
editme: 'MakE sOMe Text',
};
const evt = {
garbage: 'fOr TInYmCE',
};
let output;
beforeEach(() => {
output = module.initializeEditorRef(mockSetRef);
});
test('It calls setref with editor as params', () => {
output(evt, editor);
expect(mockSetRef).toHaveBeenCalledWith(editor);
});
});
describe('editorConfig', () => {
const blockvalue = null;
const props = {
setEditorRef: jest.fn(),
blockValue: blockvalue,
openModal: jest.fn(),
initializeEditor: jest.fn(),
};
let output;
test('It creates an onInit which calls initializeEditor, but not setEditorRef', () => {
output = module.editorConfig(props);
output.onInit();
expect(props.initializeEditor).toHaveBeenCalled();
expect(props.setEditorRef).not.toHaveBeenCalled();
});
test('It sets the blockvalue to be empty string by default', () => {
output = module.editorConfig(props);
expect(output.initialValue).toBe('');
});
test('It sets the blockvalue to be the blockvalue if nonempty', () => {
const htmltext = 'SomE hTML content';
const newprops = {
setEditorRef: jest.fn(),
blockValue: {
data: {
data: htmltext,
},
},
openModal: jest.fn(),
initializeEditor: jest.fn(),
};
output = module.editorConfig(newprops);
expect(output.initialValue).toBe(htmltext);
});
});
});
describe('modalToggle hook', () => {
let output;
beforeEach(() => {
output = module.modalToggle();
});
test('returns isOpen field, defaulted to false', () => {
expect(output.isOpen).toEqual({ state: false });
});
test('returns openModal field, which sets modal to true and calls updateState', () => {
output.openModal();
expect(React.updateState).toHaveBeenCalledWith({ val: false, newVal: true });
});
test('returns closeModal field, which sets modal to true and calls updateState', () => {
output.closeModal();
expect(React.updateState).toHaveBeenCalledWith({ val: false, newVal: false });
});
});
describe('nullMethod hook', () => {
test('it outputs null', () => {
expect(module.nullMethod()).toBe(undefined);
});
});
});