box-ui-elements-mlh
Version:
521 lines (447 loc) • 20.9 kB
JavaScript
import React from 'react';
import { List, Record } from 'immutable';
import PillSelectorDropdown from '../PillSelectorDropdown';
describe('components/pill-selector-dropdown/PillSelectorDropdown', () => {
const OptionRecord = Record({
text: '',
value: '',
});
const getWrapper = (props, children) => {
const options = children || (
<>
<div>Option 1</div>
<div>Option 2</div>
</>
);
return shallow(
<PillSelectorDropdown
inputProps={{ 'aria-label': 'test' }}
onInput={jest.fn()}
onRemove={jest.fn()}
onSelect={jest.fn()}
{...props}
>
{options}
</PillSelectorDropdown>,
);
};
describe('render()', () => {
test('should render selector dropdown', () => {
const className = 'test';
const children = 'hi';
const wrapper = getWrapper({ className }, children);
const instance = wrapper.instance();
const selectorDropdown = wrapper.find('SelectorDropdown');
expect(selectorDropdown.is('SelectorDropdown')).toBe(true);
expect(selectorDropdown.hasClass('bdl-PillSelectorDropdown')).toBe(true);
expect(selectorDropdown.hasClass(className)).toBe(true);
expect(selectorDropdown.prop('onEnter')).toEqual(instance.handleEnter);
expect(selectorDropdown.prop('onSelect')).toEqual(instance.handleSelect);
expect(selectorDropdown.contains(children)).toBe(true);
});
test('should render pill selector', () => {
const inputProps = { 'aria-label': 'test' };
const wrapper = getWrapper({ inputProps });
wrapper.setState({ inputValue: 'value' });
const pillSelector = shallow(wrapper.find('SelectorDropdown').prop('selector'));
const instance = pillSelector.instance();
expect(pillSelector.prop('onInput')).toEqual(instance.handleInput);
expect(pillSelector.prop('onPaste')).toEqual(instance.handlePaste);
expect(pillSelector.instance().props.value).toEqual('value');
});
test('should render disabled pill selector', () => {
const wrapper = getWrapper({ disabled: true });
wrapper.setState();
expect(wrapper).toMatchSnapshot();
});
test('should call addPillsFromInput when pill selector is blurred', () => {
const wrapper = getWrapper();
wrapper.setState({ inputValue: 'value' });
const instance = wrapper.instance();
const addPillsFromInputMock = jest.fn();
instance.addPillsFromInput = addPillsFromInputMock;
instance.handleBlur();
expect(addPillsFromInputMock).toHaveBeenCalledTimes(1);
});
});
describe('parsePills', () => {
test('should return a formatted map of pills', () => {
const wrapper = getWrapper();
const instance = wrapper.instance();
const inputValues = 'value1, value2,value3';
wrapper.setState({ inputValue: inputValues });
const result = instance.parsePills(inputValues);
expect(result).toEqual([
{ displayText: 'value1', text: 'value1', value: 'value1' },
{ displayText: 'value2', text: 'value2', value: 'value2' },
{ displayText: 'value3', text: 'value3', value: 'value3' },
]);
});
test('should only return pills that pass validator if one is provided and allowInvalidPills is false', () => {
const validator = text => {
// W3C type="email" input validation
const pattern = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
return pattern.test(text);
};
const wrapper = getWrapper({ validator });
const instance = wrapper.instance();
const inputValues = 'aaron@example.com, bademail,hello@gmail.com';
wrapper.setState({
inputValue: inputValues,
});
const result = instance.parsePills(inputValues);
expect(result).toEqual([
{ displayText: 'aaron@example.com', text: 'aaron@example.com', value: 'aaron@example.com' },
{ displayText: 'hello@gmail.com', text: 'hello@gmail.com', value: 'hello@gmail.com' },
]);
});
test('should ignore validator if one is provided but allowInvalidPills is true', () => {
const validator = text => {
// W3C type="email" input validation
const pattern = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
return pattern.test(text);
};
const wrapper = getWrapper({ allowInvalidPills: true, validator });
const instance = wrapper.instance();
const inputValues = 'aaron@example.com, bademail, hello@gmail.com';
wrapper.setState({
inputValue: inputValues,
});
const result = instance.parsePills(inputValues);
expect(result).toEqual([
{ displayText: 'aaron@example.com', text: 'aaron@example.com', value: 'aaron@example.com' },
{ displayText: 'bademail', text: 'bademail', value: 'bademail' },
{ displayText: 'hello@gmail.com', text: 'hello@gmail.com', value: 'hello@gmail.com' },
]);
});
test('should not map pills to options when custom parser returns array of objects', () => {
const wrapper = getWrapper({ allowInvalidPills: true });
wrapper.setState({ inputValue: 'a,b' });
const { parsePills } = wrapper.instance();
const stringParser = input => input.split(',');
const optionParser = input =>
input.split(',').map(token => ({
customProp: token,
}));
wrapper.setProps({ parseItems: stringParser });
expect(parsePills('a,b')).toStrictEqual([
{
displayText: 'a',
text: 'a',
value: 'a',
},
{
displayText: 'b',
text: 'b',
value: 'b',
},
]);
wrapper.setProps({ parseItems: optionParser });
expect(parsePills('a,b')).toStrictEqual([
{
customProp: 'a',
},
{
customProp: 'b',
},
]);
});
});
describe('addPillsFromInput', () => {
test('should not call onSelect and onPillCreate if allowCustomPills prop is not provided', () => {
const onPillCreateMock = jest.fn();
const onSelectMock = jest.fn();
const wrapper = getWrapper({ onPillCreate: onPillCreateMock, onSelect: onSelectMock });
const instance = wrapper.instance();
const inputValue = 'value';
wrapper.setState({ inputValue });
instance.addPillsFromInput(inputValue);
expect(onPillCreateMock).not.toHaveBeenCalled();
expect(onSelectMock).not.toHaveBeenCalled();
});
test('should "select" each pill, create a user pill, reset inputValue, and not call props.validateForError if valid pills exist', () => {
const pills = [
{ text: 'value1', value: 'value1' },
{ text: 'value2', value: 'value2' },
{ text: 'value3', value: 'value3' },
];
const onInputMock = jest.fn();
const onPillCreateMock = jest.fn();
const onSelectMock = jest.fn();
const validateForErrorMock = jest.fn();
const wrapper = getWrapper({
allowCustomPills: true,
onInput: onInputMock,
onPillCreate: onPillCreateMock,
onSelect: onSelectMock,
validateForError: validateForErrorMock,
});
const instance = wrapper.instance();
instance.parsePills = jest.fn().mockReturnValue(pills);
instance.addPillsFromInput();
expect(wrapper.state('inputValue')).toEqual('');
expect(onInputMock).toBeCalledWith('');
expect(onPillCreateMock).toBeCalledWith(pills);
expect(onSelectMock).toBeCalledWith(pills);
expect(validateForErrorMock).not.toBeCalled();
});
test('should call props.validateForError if no pills were added but input exists', () => {
const pills = [];
const selectedOptions = [{ text: 'a pill', value: 'pill' }];
const onInputMock = jest.fn();
const onPillCreateMock = jest.fn();
const onSelectMock = jest.fn();
const validateForErrorMock = jest.fn();
const wrapper = getWrapper({
allowCustomPills: true,
onInput: onInputMock,
onPillCreate: onPillCreateMock,
onSelect: onSelectMock,
selectedOptions,
validateForError: validateForErrorMock,
});
const instance = wrapper.instance();
wrapper.setState({ inputValue: 'value1' });
instance.parsePills = jest.fn().mockReturnValue(pills);
instance.addPillsFromInput();
expect(onInputMock).not.toBeCalled();
expect(onPillCreateMock).not.toBeCalled();
expect(onSelectMock).not.toBeCalled();
expect(validateForErrorMock).toBeCalled();
});
test('should call props.validateForError if no pills were added and no options are selected', () => {
const pills = [];
const selectedOptions = [];
const onInputMock = jest.fn();
const onPillCreateMock = jest.fn();
const onSelectMock = jest.fn();
const validateForErrorMock = jest.fn();
const wrapper = getWrapper({
allowCustomPills: true,
onInput: onInputMock,
onPillCreate: onPillCreateMock,
onSelect: onSelectMock,
selectedOptions,
validateForError: validateForErrorMock,
});
const instance = wrapper.instance();
wrapper.setState({ inputValue: '' });
instance.parsePills = jest.fn().mockReturnValue(pills);
instance.addPillsFromInput();
expect(onInputMock).not.toBeCalled();
expect(onPillCreateMock).not.toBeCalled();
expect(onSelectMock).not.toBeCalled();
expect(validateForErrorMock).toBeCalled();
});
test('should not call props.validateForError if no pills were added, input is empty, and options are selected', () => {
const pills = [];
const selectedOptions = [{ text: 'a pill', value: 'pill' }];
const onInputMock = jest.fn();
const onPillCreateMock = jest.fn();
const onSelectMock = jest.fn();
const validateForErrorMock = jest.fn();
const wrapper = getWrapper({
allowCustomPills: true,
onInput: onInputMock,
onPillCreate: onPillCreateMock,
onSelect: onSelectMock,
selectedOptions,
validateForError: validateForErrorMock,
});
const instance = wrapper.instance();
const inputValue = '';
wrapper.setState({ inputValue });
instance.parsePills = jest.fn().mockReturnValue(pills);
instance.addPillsFromInput(inputValue);
expect(onInputMock).not.toBeCalled();
expect(onPillCreateMock).not.toBeCalled();
expect(onSelectMock).not.toBeCalled();
expect(validateForErrorMock).not.toBeCalled();
});
test('should clear unmatched input after attempting to add pills when shouldClearUnmatchedInput is set to true', () => {
const onPillCreateMock = jest.fn();
const onSelectMock = jest.fn();
const wrapper = getWrapper({
allowCustomPills: true,
onPillCreate: onPillCreateMock,
onSelect: onSelectMock,
});
const onInput = jest.fn();
const initialValue = 'abc';
const { addPillsFromInput } = wrapper.instance();
wrapper.setProps({ onInput, parseItems: () => [] });
wrapper.setState({ inputValue: initialValue });
wrapper.setProps({ shouldClearUnmatchedInput: false });
addPillsFromInput(initialValue);
expect(wrapper.state().inputValue).toBe(initialValue);
expect(onInput).toHaveBeenCalledTimes(0);
wrapper.setProps({ shouldClearUnmatchedInput: true });
addPillsFromInput(initialValue);
expect(wrapper.state().inputValue).toBe('');
expect(onInput).toHaveBeenCalledWith('');
expect(onInput).toHaveBeenCalledTimes(1);
expect(onPillCreateMock).not.toBeCalled();
expect(onSelectMock).not.toBeCalled();
});
});
describe('handleInput', () => {
test('should update inputValue state when called', () => {
const wrapper = getWrapper();
const instance = wrapper.instance();
instance.handleInput({ target: { value: 'test' } });
expect(wrapper.state('inputValue')).toEqual('test');
});
test('should call onInput() with value when called', () => {
const onInputMock = jest.fn();
const wrapper = getWrapper({ onInput: onInputMock });
const instance = wrapper.instance();
instance.handleInput({ target: { value: 'test' } });
expect(onInputMock).toBeCalledWith('test', { target: { value: 'test' } });
});
});
describe('handleEnter()', () => {
test('should do nothing when in composition mode', () => {
const wrapper = getWrapper();
const instance = wrapper.instance();
const event = { preventDefault: jest.fn() };
instance.addPillsFromInput = jest.fn();
instance.handleCompositionStart();
instance.handleEnter(event);
expect(event.preventDefault).not.toHaveBeenCalled();
expect(instance.addPillsFromInput).not.toHaveBeenCalled();
});
test('should call addPillsFromInput and prevent default when called', () => {
const wrapper = getWrapper();
const addPillsFromInputMock = jest.fn();
const preventDefaultMock = jest.fn();
const instance = wrapper.instance();
instance.addPillsFromInput = addPillsFromInputMock;
instance.handleEnter({
preventDefault: preventDefaultMock,
});
expect(addPillsFromInputMock).toBeCalledTimes(1);
expect(preventDefaultMock).toBeCalled();
});
});
describe('handlePaste', () => {
test('should not call onPillCreate prop method with invalid input', () => {
const onInputMock = jest.fn();
const onPillCreateMock = jest.fn();
const mockPastedValue = 'pastedValue';
const mockEvent = {
clipboardData: {
getData: () => {
return mockPastedValue;
},
},
preventDefault: jest.fn(),
};
const wrapper = getWrapper({
allowCustomPills: true,
allowInvalidPills: false,
onInput: onInputMock,
onPillCreate: onPillCreateMock,
validator: () => false,
});
const instance = wrapper.instance();
instance.handlePaste(mockEvent);
expect(onInputMock).toHaveBeenCalledWith(mockPastedValue, mockEvent);
expect(onPillCreateMock).not.toHaveBeenCalled();
});
test('should call onPillCreate prop method with valid input', () => {
const onInputMock = jest.fn();
const onPillCreateMock = jest.fn();
const mockPastedValue = 'test@example.com';
const mockEvent = {
clipboardData: {
getData: () => {
return mockPastedValue;
},
},
preventDefault: jest.fn(),
};
const wrapper = getWrapper({
allowCustomPills: true,
onInput: onInputMock,
onPillCreate: onPillCreateMock,
});
const instance = wrapper.instance();
instance.handlePaste(mockEvent);
expect(onInputMock).toHaveBeenCalledWith(mockPastedValue, mockEvent);
expect(onPillCreateMock).toHaveBeenCalled();
});
});
describe('handleSelect', () => {
test('should call onSelect() with option and event when called', () => {
const option = { text: 'b', value: 'b' };
const options = [{ text: 'a', value: 'a' }, option];
const onSelectMock = jest.fn();
const onPillCreateMock = jest.fn();
const wrapper = getWrapper({
onSelect: onSelectMock,
onPillCreate: onPillCreateMock,
selectorOptions: options,
});
const instance = wrapper.instance();
const event = { type: 'click' };
instance.handleSelect(1, event);
expect(onSelectMock).toBeCalledWith([option], event);
expect(onPillCreateMock).toBeCalledWith([option]);
});
test('should call onSelect() with immutable option and event when called', () => {
const option = new OptionRecord({ text: 'b', value: 'b' });
const options = new List([new OptionRecord({ text: 'a', value: 'a' }), option]);
const onSelectMock = jest.fn();
const onPillCreateMock = jest.fn();
const wrapper = getWrapper({
onSelect: onSelectMock,
onPillCreate: onPillCreateMock,
selectorOptions: options,
});
const instance = wrapper.instance();
const event = { type: 'click' };
instance.handleSelect(1, event);
expect(onSelectMock).toBeCalledWith([option], event);
expect(onPillCreateMock).toBeCalledWith([option]);
});
test('should call handleInput() with empty string value when called', () => {
const options = [{ text: 'a', value: 'a' }];
const handleInputMock = jest.fn();
const wrapper = getWrapper({ selectorOptions: options });
const instance = wrapper.instance();
instance.handleInput = handleInputMock;
instance.handleSelect(0, {});
expect(handleInputMock).toBeCalledWith({ target: { value: '' } });
});
});
describe('handleBlur', () => {
test('should call onBlur() and addPillsFromInput() when underlying input is blurred', () => {
const onBlur = jest.fn();
const wrapper = getWrapper({ onBlur });
const instance = wrapper.instance();
const event = { type: 'blur' };
instance.addPillsFromInput = jest.fn();
instance.handleBlur(event);
expect(instance.addPillsFromInput).toHaveBeenCalled();
expect(onBlur).toHaveBeenCalled();
});
});
describe('handleCompositionStart()', () => {
test('should set composition mode', () => {
const wrapper = getWrapper();
const instance = wrapper.instance();
instance.setState = jest.fn();
instance.handleCompositionStart();
expect(instance.setState).toHaveBeenCalledWith({ isInCompositionMode: true });
});
});
describe('handleCompositionEnd()', () => {
test('should unset composition mode', () => {
const wrapper = getWrapper();
const instance = wrapper.instance();
instance.setState = jest.fn();
instance.handleCompositionEnd();
expect(instance.setState).toHaveBeenCalledWith({ isInCompositionMode: false });
});
});
});