box-ui-elements-mlh
Version:
372 lines (300 loc) • 13.8 kB
JavaScript
import React from 'react';
import { mount, shallow } from 'enzyme';
import { ContentState, EditorState } from 'draft-js';
import sinon from 'sinon';
import DraftJSMentionSelector from '..';
import * as messages from '../../input-messages';
const sandbox = sinon.sandbox.create();
describe('bcomponents/form-elements/draft-js-mention-selector/DraftJSMentionSelector', () => {
afterEach(() => {
sandbox.verifyAndRestore();
});
const requiredProps = {
contacts: [],
label: 'label',
name: 'name',
onMention: () => {},
};
describe('render()', () => {
test('should correctly render the component', () => {
const wrapper = shallow(<DraftJSMentionSelector {...requiredProps} />);
expect(wrapper.find('FormInput').length).toBe(1);
});
});
describe('getDerivedStateFromProps()', () => {
test('should return contacts from props', () => {
expect(DraftJSMentionSelector.getDerivedStateFromProps({ contacts: [] })).toEqual({ contacts: [] });
});
test('should return null if no contacts from props', () => {
expect(DraftJSMentionSelector.getDerivedStateFromProps({})).toEqual(null);
});
});
describe('componentDidUpdate()', () => {
let mockGetDerivedStateFromEditorState;
let mockCheckValidityIfAllowed;
let spySetState;
const setupInstance = props => {
const wrapper = shallow(<DraftJSMentionSelector {...props} />);
const instance = wrapper.instance();
mockGetDerivedStateFromEditorState = jest.fn();
mockCheckValidityIfAllowed = jest.fn();
spySetState = jest.spyOn(instance, 'setState');
instance.getDerivedStateFromEditorState = mockGetDerivedStateFromEditorState;
instance.checkValidityIfAllowed = mockCheckValidityIfAllowed;
return wrapper;
};
test('should set new state in internal editor state mode when it changes', () => {
const wrapper = setupInstance(requiredProps);
mockGetDerivedStateFromEditorState.mockReturnValue({});
wrapper.setState({
internalEditorState: EditorState.createWithContent(ContentState.createFromText('hello')),
});
expect(mockGetDerivedStateFromEditorState).toHaveBeenCalled();
expect(spySetState).toHaveBeenCalledWith({}, mockCheckValidityIfAllowed);
});
test('should check validity in internal editor state mode when it changes but derived state is null', () => {
const wrapper = setupInstance(requiredProps);
mockGetDerivedStateFromEditorState.mockReturnValue(null);
wrapper.setState({
internalEditorState: EditorState.createWithContent(ContentState.createFromText('hello')),
});
expect(mockGetDerivedStateFromEditorState).toHaveBeenCalled();
expect(spySetState).not.toHaveBeenCalled();
});
test('should set new state in external editor state mode when it changes', () => {
const initialProps = { ...requiredProps, editorState: EditorState.createEmpty() };
const wrapper = setupInstance(initialProps);
mockGetDerivedStateFromEditorState.mockReturnValue({});
wrapper.setProps({
editorState: EditorState.createWithContent(ContentState.createFromText('hello')),
});
expect(mockGetDerivedStateFromEditorState).toHaveBeenCalled();
expect(spySetState).toHaveBeenCalledWith({}, mockCheckValidityIfAllowed);
});
test('should check validity in external editor state mode when it changes but derived state is null', () => {
const initialProps = { ...requiredProps, editorState: EditorState.createEmpty() };
const wrapper = setupInstance(initialProps);
mockGetDerivedStateFromEditorState.mockReturnValue(null);
wrapper.setProps({
editorState: EditorState.createWithContent(ContentState.createFromText('hello')),
});
expect(mockGetDerivedStateFromEditorState).toHaveBeenCalled();
expect(spySetState).not.toHaveBeenCalled();
});
test('should not call getDerivedStateFromEditorState in internal editor state mode if same reference', () => {
const wrapper = setupInstance(requiredProps);
const constantEditorState = EditorState.createWithContent(ContentState.createFromText('hello'));
wrapper.setState({ internalEditorState: constantEditorState });
mockGetDerivedStateFromEditorState.mockClear();
wrapper.setState({ internalEditorState: constantEditorState });
expect(mockGetDerivedStateFromEditorState).not.toHaveBeenCalled();
expect(spySetState).not.toHaveBeenCalled();
});
test('should not call getDerivedStateFromEditorState in external editor state mode if same reference', () => {
const constantEditorState = EditorState.createWithContent(ContentState.createFromText('hello'));
const initialProps = { ...requiredProps, editorState: constantEditorState };
const wrapper = setupInstance(initialProps);
wrapper.setProps({
editorState: constantEditorState,
});
expect(mockGetDerivedStateFromEditorState).not.toHaveBeenCalled();
expect(spySetState).not.toHaveBeenCalled();
});
});
describe('getDerivedStateFromEditorState', () => {
let wrapper;
let instance;
let mockIsEditorStateEmpty;
beforeEach(() => {
wrapper = shallow(<DraftJSMentionSelector {...requiredProps} />);
instance = wrapper.instance();
mockIsEditorStateEmpty = jest.fn();
instance.isEditorStateEmpty = mockIsEditorStateEmpty;
});
test('should return isTouched false if is new editor state', () => {
mockIsEditorStateEmpty.mockReturnValueOnce(false).mockReturnValueOnce(true);
expect(instance.getDerivedStateFromEditorState()).toEqual({ isTouched: false, error: null });
});
test('should return isTouched true if editor state is dirty', () => {
mockIsEditorStateEmpty.mockReturnValueOnce(true).mockReturnValueOnce(false);
expect(instance.getDerivedStateFromEditorState()).toEqual({ isTouched: true });
});
test('should return null if not new editor state nor dirty editor', () => {
mockIsEditorStateEmpty.mockReturnValueOnce(true).mockReturnValueOnce(true);
expect(instance.getDerivedStateFromEditorState()).toEqual(null);
});
});
describe('getErrorFromValidityState()', () => {
const minLength = 4;
const maxLength = 9;
[
// too long optional string
{
str: 'foo bar baz woo',
isRequired: false,
expected: messages.tooLong(maxLength),
},
// too short optional string
{
str: 'foo',
isRequired: false,
expected: messages.tooShort(minLength),
},
{
str: '',
isRequired: true,
expected: messages.valueMissing(),
},
// empty required string
{
str: '',
isRequired: true,
expected: messages.valueMissing(),
},
// good lemgth required string
{
str: 'all good',
isRequired: true,
expected: null,
},
// good length optional string
{
str: 'all good',
isRequired: false,
expected: null,
},
].forEach(({ str, isRequired, expected }) => {
test('should return the correct error state', () => {
const editorState = EditorState.createWithContent(ContentState.createFromText(str));
const wrapper = shallow(
<DraftJSMentionSelector
{...requiredProps}
editorState={editorState}
isRequired={isRequired}
maxLength={maxLength}
minLength={minLength}
/>,
);
const instance = wrapper.instance();
const result = instance.getErrorFromValidityState();
expect(result).toEqual(expected);
});
});
});
describe('handleBlur()', () => {
[
{
validateOnBlur: true,
},
{
validateOnBlur: false,
},
].forEach(({ validateOnBlur }) => {
const wrapper = mount(<DraftJSMentionSelector {...requiredProps} validateOnBlur={validateOnBlur} />);
const instance = wrapper.instance();
afterEach(() => {
instance.handleBlur({
relatedTarget: document.createElement('div'),
});
});
if (validateOnBlur) {
test('should call checkValidity when called', () => {
sandbox.mock(instance).expects('checkValidity');
});
} else {
test('should not call checkValidity when called', () => {
sandbox
.mock(instance)
.expects('checkValidity')
.never();
});
}
});
});
describe('handleChange()', () => {
let wrapper;
let instance;
let mockOnChange;
let spySetState;
const setup = props => {
mockOnChange = jest.fn();
wrapper = shallow(<DraftJSMentionSelector {...props} onChange={mockOnChange} />);
instance = wrapper.instance();
spySetState = jest.spyOn(instance, 'setState');
};
test('should call onChange and setState if internal editor state exists', () => {
setup({ ...requiredProps });
const dummyEditorState = EditorState.createEmpty();
instance.handleChange(dummyEditorState);
expect(mockOnChange).toHaveBeenCalledWith(dummyEditorState);
expect(spySetState).toHaveBeenCalledWith({ internalEditorState: dummyEditorState });
});
test('should call onChange and not setState if no internal editor state exists', () => {
const dummyEditorState = EditorState.createEmpty();
setup({ ...requiredProps, editorState: dummyEditorState });
instance.handleChange(dummyEditorState);
expect(mockOnChange).toHaveBeenCalledWith(dummyEditorState);
expect(spySetState).not.toHaveBeenCalled();
});
});
describe('handleValidityStateUpdateHandler()', () => {
[
{
isTouched: true,
},
{
isTouched: false,
},
].forEach(({ isTouched }) => {
const err = 'oh no';
const wrapper = shallow(<DraftJSMentionSelector {...requiredProps} />);
const instance = wrapper.instance();
beforeEach(() => {
wrapper.setState({ isTouched });
sandbox.stub(instance, 'getErrorFromValidityState').returns(err);
});
afterEach(() => {
instance.handleValidityStateUpdateHandler();
});
if (isTouched) {
test('should update state', () => {
sandbox
.mock(instance)
.expects('setState')
.withArgs({ error: err });
});
} else {
test('should not update state', () => {
sandbox
.mock(instance)
.expects('setState')
.never();
});
}
});
});
describe('checkValidity()', () => {
test('should call handleValidityStateUpdateHandler when called', () => {
const wrapper = shallow(<DraftJSMentionSelector {...requiredProps} />);
const instance = wrapper.instance();
sandbox.mock(instance).expects('handleValidityStateUpdateHandler');
instance.checkValidity();
});
});
describe('isEditorStateEmpty', () => {
const emptyEditorState = EditorState.createEmpty();
const contentState = ContentState.createFromText('');
const editorStateWithChangeType = EditorState.push(emptyEditorState, contentState, 'backspace-character');
const nonEmptyEditorState = EditorState.createWithContent(ContentState.createFromText('hello'));
test.each`
testcase | editorState | expectedResult
${'empty'} | ${emptyEditorState} | ${true}
${'not empty'} | ${nonEmptyEditorState} | ${false}
${'has change type'} | ${editorStateWithChangeType} | ${false}
`('should return whether the editor state is empty or not: $testcase', ({ editorState, expectedResult }) => {
const wrapper = shallow(<DraftJSMentionSelector {...requiredProps} />);
const instance = wrapper.instance();
expect(instance.isEditorStateEmpty(editorState)).toEqual(expectedResult);
});
});
});