box-ui-elements-mlh
Version:
497 lines (419 loc) • 20.5 kB
JavaScript
import React from 'react';
import { mount, shallow } from 'enzyme';
import { List, Record } from 'immutable';
import sinon from 'sinon';
import PillSelector from '../PillSelector';
const sandbox = sinon.sandbox.create();
describe('components/pill-selector-dropdown/PillSelector', () => {
const onInputStub = sandbox.stub();
const onRemoveStub = sandbox.stub();
const OptionRecord = Record({
text: '',
value: '',
});
afterEach(() => {
sandbox.verifyAndRestore();
});
describe('render()', () => {
test('should render default component', () => {
const placeholder = 'test';
const wrapper = shallow(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} placeholder={placeholder} />,
);
const input = wrapper.find('textarea');
const selector = wrapper.find('.bdl-PillSelector');
expect(wrapper.find('Tooltip').exists()).toBe(true);
expect(selector.length).toBe(1);
expect(input.length).toBe(1);
expect(input.prop('onInput')).toEqual(onInputStub);
expect(input.prop('placeholder')).toEqual(placeholder);
});
test('should render disabled component', () => {
const wrapper = shallow(<PillSelector disabled onInput={() => {}} onRemove={() => {}} />);
expect(wrapper).toMatchSnapshot();
});
test('should add is-focused class when input is focused', () => {
const wrapper = shallow(<PillSelector onInput={onInputStub} onRemove={onRemoveStub} />);
wrapper.setState({ isFocused: true });
expect(wrapper.find('.is-focused').length).toBe(1);
});
test('should not add is-focused class when input is not focused', () => {
const wrapper = shallow(<PillSelector onInput={onInputStub} onRemove={onRemoveStub} />);
wrapper.setState({ isFocused: false });
expect(wrapper.find('.is-focused').length).toBe(0);
});
test('should add show-error class when error is given', () => {
const wrapper = shallow(<PillSelector error="hello" onInput={onInputStub} onRemove={onRemoveStub} />);
expect(wrapper.find('.show-error').length).toBe(1);
});
test('should not add show-error class when error is not given', () => {
const wrapper = shallow(<PillSelector onInput={onInputStub} onRemove={onRemoveStub} />);
expect(wrapper.find('.show-error').length).toBe(0);
});
test('should render pills when there are selected options using legacy text attribute', () => {
const options = [
{ text: 'test', value: 'test' },
{ text: 'blah', value: 'hi' },
];
const wrapper = shallow(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
expect(wrapper.find('Pill').length).toBe(2);
});
test('should render RoundPill instead of standard Pill when showRoundedPills prop is true', () => {
const options = [{ text: 'test', value: 'test' }];
const wrapper = shallow(
<PillSelector
onInput={onInputStub}
onRemove={onRemoveStub}
selectedOptions={options}
showRoundedPills
/>,
);
expect(wrapper.find('RoundPill').length).toBe(1);
});
test('should render pills when there are selected options', () => {
const options = [
{ displayText: 'test', value: 'test' },
{ displayText: 'blah', value: 'hi' },
];
const wrapper = shallow(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
const pills = wrapper.find('Pill');
expect(pills.length).toBe(2);
expect(pills.at(0).prop('isValid')).toBeTruthy();
expect(pills.at(1).prop('isValid')).toBeTruthy();
});
test('should render invalid pills when validator is provided and allowInvalidPills is true', () => {
const validator = ({ displayText }) => {
// W3C type="email" input validation
const pattern = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
return pattern.test(displayText);
};
const options = [
{ displayText: 'test', value: 'test' },
{ displayText: 'blah', value: 'hi' },
];
const wrapper = shallow(
<PillSelector
allowInvalidPills
onInput={onInputStub}
onRemove={onRemoveStub}
selectedOptions={options}
validator={validator}
/>,
);
const pills = wrapper.find('Pill');
expect(pills.length).toBe(2);
expect(pills.at(0).prop('isValid')).toBeFalsy();
expect(pills.at(1).prop('isValid')).toBeFalsy();
});
test('should render round pills using the class name returned by getPillClassName', () => {
const getPillClassName = ({ className }) => className;
const options = [
{ displayText: 'Pill 1', value: '1', className: 'MyClass1' },
{ displayText: 'Pill 2', value: '2', className: 'MyClass2' },
{ displayText: 'Pill 3', value: '3', className: 'MyClass2' },
];
const wrapper = shallow(
<PillSelector
showRoundedPills
onInput={onInputStub}
onRemove={onRemoveStub}
selectedOptions={options}
getPillClassName={getPillClassName}
/>,
);
const pills = wrapper.find('RoundPill');
expect(pills.at(0).prop('className')).toBe(options[0].className);
expect(pills.at(1).prop('className')).toBe(options[1].className);
expect(pills.at(2).prop('className')).toBe(options[2].className);
});
test('should render pills when selected options are immutable', () => {
const options = new List([
new OptionRecord({ text: 'test', value: 'test' }),
new OptionRecord({ text: 'blah', value: 'hi' }),
]);
const wrapper = shallow(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
expect(wrapper.find('Pill').length).toBe(2);
});
test('should render pill as selected when selected index is set', () => {
const options = [
{ text: 'test', value: 'test' },
{ text: 'blah', value: 'hi' },
];
const wrapper = shallow(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
wrapper.setState({ selectedIndex: 0 });
expect(
wrapper
.find('Pill')
.at(0)
.prop('isSelected'),
).toBe(true);
});
test('should render hidden pill selection helper', () => {
const wrapper = shallow(<PillSelector onInput={onInputStub} onRemove={onRemoveStub} />);
const hidden = wrapper.find('[data-testid="pill-selection-helper"]');
const instance = wrapper.instance();
expect(hidden.length).toBe(1);
expect(hidden.prop('onBlur')).toEqual(instance.resetSelectedIndex);
});
test('should render class name on input when specified', () => {
const className = 'test';
const wrapper = shallow(
<PillSelector className={className} onInput={onInputStub} onRemove={onRemoveStub} />,
);
const input = wrapper.find('textarea');
expect(input.hasClass('bdl-PillSelector-input')).toBe(true);
expect(input.hasClass(className)).toBe(true);
});
test('should pass input props when specified', () => {
const role = 'combobox';
const wrapper = shallow(
<PillSelector inputProps={{ role }} onInput={onInputStub} onRemove={onRemoveStub} />,
);
expect(wrapper.find('textarea').prop('role')).toEqual(role);
});
test('should pass through additional props when specified', () => {
const value = 'test';
const wrapper = shallow(
<PillSelector onChange={() => {}} onInput={onInputStub} onRemove={onRemoveStub} value={value} />,
);
expect(wrapper.find('textarea').prop('value')).toEqual(value);
});
test('should not render placeholder when there are pills', () => {
const options = [{ text: 'test', value: 'test' }];
const wrapper = shallow(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
expect(wrapper.find('textarea').prop('placeholder')).toEqual('');
});
test('should not render placeholder when there are immutable pills', () => {
const options = new List([new OptionRecord({ text: 'test', value: 'test' })]);
const wrapper = shallow(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
expect(wrapper.find('textarea').prop('placeholder')).toEqual('');
});
});
describe('onBlur', () => {
test('should set isFocused to false when called', () => {
const wrapper = shallow(<PillSelector onInput={onInputStub} onRemove={onRemoveStub} />);
wrapper.setState({ isFocused: true });
const inputWrapper = wrapper.find('.bdl-PillSelector');
inputWrapper.simulate('blur');
expect(wrapper.state('isFocused')).toBe(false);
});
});
describe('onClick', () => {
test('should focus input when called', () => {
const wrapper = mount(<PillSelector onInput={onInputStub} onRemove={onRemoveStub} />);
sandbox.mock(wrapper.find('textarea').getDOMNode()).expects('focus');
wrapper.simulate('click');
});
});
describe('onFocus', () => {
test('should set isFocused to true when called', () => {
const wrapper = shallow(<PillSelector onInput={onInputStub} onRemove={onRemoveStub} />);
const inputWrapper = wrapper.find('.bdl-PillSelector');
inputWrapper.simulate('focus');
expect(wrapper.state('isFocused')).toBe(true);
});
});
describe('onKeyDown - Backspace', () => {
test('should remove selected pill when backspace is pressed', () => {
const option = { text: 'test', value: 'test' };
const options = [option, { text: 'blah', value: 'blah' }];
const wrapper = mount(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
const instance = wrapper.instance();
wrapper.setState({ selectedIndex: 0 });
sandbox.mock(instance).expects('resetSelectedIndex');
sandbox.mock(wrapper.find('textarea').getDOMNode()).expects('focus');
wrapper.simulate('keyDown', {
key: 'Backspace',
preventDefault: sandbox.mock(),
stopPropagation: sandbox.mock(),
});
expect(onRemoveStub.calledWith(option, 0)).toBe(true);
});
test('should not prevent default when backspace is pressed and the input has value', () => {
const wrapper = mount(
<PillSelector onChange={() => {}} onInput={onInputStub} onRemove={onRemoveStub} value="test" />,
);
wrapper.simulate('keyDown', {
key: 'Backspace',
preventDefault: sandbox.mock().never(),
stopPropagation: sandbox.mock().never(),
});
});
test('should call onRemove() when backspace is pressed and there are pills but no input value', () => {
const option = { text: 'test', value: 'test' };
const options = [{ text: 'blah', value: 'blah' }, option];
const wrapper = mount(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
wrapper.simulate('keyDown', {
key: 'Backspace',
preventDefault: sandbox.mock(),
stopPropagation: sandbox.mock(),
});
expect(onRemoveStub.calledWith(option, 1)).toBe(true);
});
test('should call onRemove() when backspace is pressed and there are immutable pills but no input value', () => {
const option = new OptionRecord({ text: 'test', value: 'test' });
const options = new List([new OptionRecord({ text: 'blah', value: 'blah' }), option]);
const wrapper = mount(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
wrapper.simulate('keyDown', {
key: 'Backspace',
preventDefault: sandbox.mock(),
stopPropagation: sandbox.mock(),
});
expect(onRemoveStub.calledWith(option, 1)).toBe(true);
});
test('should not call onRemove() when backspace is pressed and there are no pills and no input value', () => {
const wrapper = mount(<PillSelector onInput={onInputStub} onRemove={onRemoveStub} />);
wrapper.simulate('keyDown', {
key: 'Backspace',
preventDefault: sandbox.mock().never(),
stopPropagation: sandbox.mock().never(),
});
expect(onRemoveStub.calledOnce).toBe(false);
});
});
describe('onKeyDown - ArrowLeft', () => {
test('should select previous pill when left arrow is pressed and pill is selected', () => {
const wrapper = mount(<PillSelector onInput={onInputStub} onRemove={onRemoveStub} />);
wrapper.setState({ selectedIndex: 1 });
wrapper.simulate('keyDown', {
key: 'ArrowLeft',
preventDefault: sandbox.mock(),
stopPropagation: sandbox.mock(),
});
expect(wrapper.state('selectedIndex')).toEqual(0);
});
test('should keep first pill selected when left arrow is pressed and first pill is selected', () => {
const wrapper = mount(<PillSelector onInput={onInputStub} onRemove={onRemoveStub} />);
wrapper.setState({ selectedIndex: 0 });
wrapper.simulate('keyDown', {
key: 'ArrowLeft',
preventDefault: sandbox.mock(),
stopPropagation: sandbox.mock(),
});
expect(wrapper.state('selectedIndex')).toEqual(0);
});
test('should select last pill when left arrow is pressed, input does not have value, and there are pills', () => {
const options = [
{ text: 'test', value: 'test' },
{ text: 'blah', value: 'blah' },
];
const wrapper = mount(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
sandbox.mock(wrapper.find('[data-testid="pill-selection-helper"]').getDOMNode()).expects('focus');
wrapper.simulate('keyDown', {
key: 'ArrowLeft',
preventDefault: sandbox.mock(),
stopPropagation: sandbox.mock(),
});
expect(wrapper.state('selectedIndex')).toEqual(1);
});
test('should not prevent default when left arrow is pressed and the input has value', () => {
const wrapper = mount(
<PillSelector onChange={() => {}} onInput={onInputStub} onRemove={onRemoveStub} value="test" />,
);
wrapper.simulate('keyDown', {
key: 'ArrowLeft',
preventDefault: sandbox.mock().never(),
stopPropagation: sandbox.mock().never(),
});
});
});
describe('onKeyDown - ArrowRight', () => {
test('should deselect last pill when right arrow is pressed and last pill is selected', () => {
const options = [
{ text: 'test', value: 'test' },
{ text: 'blah', value: 'blah' },
];
const wrapper = mount(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
const instance = wrapper.instance();
wrapper.setState({ selectedIndex: 1 });
sandbox.mock(instance).expects('resetSelectedIndex');
sandbox.mock(wrapper.find('textarea').getDOMNode()).expects('focus');
wrapper.simulate('keyDown', {
key: 'ArrowRight',
preventDefault: sandbox.mock(),
stopPropagation: sandbox.mock(),
});
});
test('should select next pill when right arrow is pressed and selected pill is not last', () => {
const options = [
{ text: 'test', value: 'test' },
{ text: 'blah', value: 'blah' },
];
const wrapper = mount(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
wrapper.setState({ selectedIndex: 0 });
wrapper.simulate('keyDown', {
key: 'ArrowRight',
preventDefault: sandbox.mock(),
stopPropagation: sandbox.mock(),
});
expect(wrapper.state('selectedIndex')).toEqual(1);
});
test('should not prevent default when right arrow is pressed and no pill is selected', () => {
const wrapper = mount(<PillSelector onInput={onInputStub} onRemove={onRemoveStub} />);
wrapper.simulate('keyDown', {
key: 'ArrowRight',
preventDefault: sandbox.mock().never(),
stopPropagation: sandbox.mock().never(),
});
});
});
describe('onRemove', () => {
test('should call onRemove() when pill onRemove is triggered', () => {
const option = { text: 'test', value: 'test' };
const options = [option, { text: 'blah', value: 'blah' }];
const wrapper = shallow(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
wrapper
.find('Pill')
.at(0)
.prop('onRemove')();
expect(onRemoveStub.calledWith(option, 0)).toBe(true);
});
test('should call onRemove() when immutable pill onRemove is triggered', () => {
const option = new OptionRecord({ text: 'test', value: 'test' });
const options = new List([option, new OptionRecord({ text: 'blah', value: 'blah' })]);
const wrapper = shallow(
<PillSelector onInput={onInputStub} onRemove={onRemoveStub} selectedOptions={options} />,
);
wrapper
.find('Pill')
.at(0)
.prop('onRemove')();
expect(onRemoveStub.calledWith(option, 0)).toBe(true);
});
});
describe('resetSelectedIndex()', () => {
test('should reset selected index when called', () => {
const wrapper = shallow(<PillSelector onInput={onInputStub} onRemove={onRemoveStub} />);
const instance = wrapper.instance();
wrapper.setState({ selectedIndex: 1 });
instance.resetSelectedIndex();
expect(wrapper.state('selectedIndex')).toEqual(-1);
});
});
});