src/components/Lookup/__test__/lookup.spec.js
import React from 'react';
import { mount } from 'enzyme';
import ButtonIcon from '../../ButtonIcon';
import Lookup from '..';
import StyledTextError from '../../Input/styled/errorText';
import StyledInput from '../styled/input';
jest.mock('../../InternalOverlay', () =>
jest.fn(props => <div data-id="internal-dropdown">{props.isVisible && props.children}</div>),
);
describe('<Lookup />', () => {
it('should set an id in the input element', () => {
const component = mount(<Lookup />);
expect(component.find('input').prop('id')).toMatch(/lookup-input/);
});
it('should set type "search" in the input element', () => {
const component = mount(<Lookup />);
expect(component.find('input').prop('type')).toBe('search');
});
it('should pass a generated id to the Error element and set the same id to the aria-describedby for the input when a error is passed', () => {
const component = mount(<Lookup error="error message" />);
expect(component.find(StyledTextError).prop('id')).toMatch(/error-message/);
expect(component.find('input').prop('aria-describedby')).toMatch(/error-message/);
});
it('should pass the right props to the Label component', () => {
const component = mount(<Lookup label="custom label" required />);
expect(component.find('Label').props()).toEqual({
label: 'custom label',
required: true,
readOnly: false,
labelAlignment: 'center',
hideLabel: false,
inputId: expect.any(String),
variant: 'default',
size: 'medium',
});
});
it('should render the Options menu when there are options and the input is focused', () => {
const component = mount(<Lookup label="custom label" options={[{}]} />);
expect(component.find('Options').exists()).toBe(false);
component.find('input').simulate('focus');
expect(component.find('Options').exists()).toBe(true);
});
it('should render the Options menu when there are not options but the input has value typed and is focused', () => {
const component = mount(<Lookup label="custom label" options={[]} />);
expect(component.find('Options').exists()).toBe(false);
component.find('input').simulate('focus');
component.find('input').simulate('change', {
target: {
value: 'abc',
},
});
expect(component.find('input').prop('value')).toBe('abc');
expect(component.find('Options').exists()).toBe(true);
});
it('should call onChange with the right data when select an option', () => {
const options = [
{ label: 'San Francisco' },
{ label: 'New York', description: 'awesome city' },
];
const onChangeMockFn = jest.fn();
const component = mount(
<Lookup label="custom label" options={options} onChange={onChangeMockFn} />,
);
component.find('input').simulate('focus');
component
.find('Options')
.find('li')
.at(1)
.simulate('mouseEnter');
expect(component.find('Options').prop('focusedItemIndex')).toBe(1);
component
.find('Options')
.find('li')
.at(1)
.simulate('mousedown');
expect(onChangeMockFn).toHaveBeenCalledWith({
label: 'New York',
description: 'awesome city',
});
});
it('should reset input value when select an option', () => {
const options = [
{ label: 'San Francisco' },
{ label: 'New York', description: 'awesome city' },
];
const onChangeMockFn = jest.fn();
const component = mount(
<Lookup label="custom label" options={options} onChange={onChangeMockFn} />,
);
component.find('input').simulate('focus');
component.find('input').simulate('change', {
target: {
value: 'abc',
},
});
expect(component.find('input').prop('value')).toBe('abc');
component
.find('Options')
.find('li')
.at(0)
.simulate('mousedown');
expect(component.find('input').prop('value')).toBe('');
});
it('should call onSearch with the right value when type in the input', () => {
const onSearchMockFn = jest.fn();
const component = mount(<Lookup label="custom label" onSearch={onSearchMockFn} />);
component.find('input').simulate('focus');
component.find('input').simulate('change', {
target: {
value: 'london',
},
});
expect(onSearchMockFn).toHaveBeenCalledWith('london');
});
it('should not render a SelectedValue component when value passed is other than object', () => {
const values = ['', 'my value', 123, undefined, null, NaN, [], () => {}];
values.forEach(value => {
const component = mount(<Lookup label="custom label" value={value} />);
expect(component.find('SelectedValue').exists()).toBe(false);
expect(component.find('input[type="search"]').exists()).toBe(true);
});
});
it('should render a SelectedValue component when value is passed', () => {
const value = { label: 'New York', description: 'awesome city' };
const onChangeMockFn = jest.fn();
const onSearchMockFn = jest.fn();
const component = mount(
<Lookup
label="custom label"
value={value}
onChange={onChangeMockFn}
onSearch={onSearchMockFn}
/>,
);
expect(component.find('SelectedValue').exists()).toBe(true);
});
it('should call onChange and onSearch with the right values when remove the value selected', () => {
const value = { label: 'New York', description: 'awesome city' };
const onChangeMockFn = jest.fn();
const onSearchMockFn = jest.fn();
const component = mount(
<Lookup
label="custom label"
value={value}
onChange={onChangeMockFn}
onSearch={onSearchMockFn}
/>,
);
component
.find('SelectedValue')
.find(ButtonIcon)
.simulate('click');
expect(onChangeMockFn).toHaveBeenCalledWith(null);
expect(onSearchMockFn).toHaveBeenCalledWith('');
});
it('should reset the input value when click the close button', () => {
const onSearchMockFn = jest.fn();
const component = mount(<Lookup label="custom label" onSearch={onSearchMockFn} />);
component.find('input').simulate('focus');
component.find('input').simulate('change', {
target: {
value: 'london',
},
});
expect(component.find('input').prop('value')).toBe('london');
component
.find('RightElement')
.find(ButtonIcon)
.simulate('click');
expect(component.find('input').prop('value')).toBe('');
expect(onSearchMockFn.mock.calls[0][0]).toBe('london');
expect(onSearchMockFn.mock.calls[1][0]).toBe('');
});
it('should call onChange with the right data and reset the input value when press enter key with the options menu open', () => {
const options = [
{ label: 'San Francisco' },
{ label: 'New York', description: 'awesome city' },
];
const onChangeMockFn = jest.fn();
const component = mount(
<Lookup label="custom label" options={options} onChange={onChangeMockFn} />,
);
component.find('input').simulate('focus');
component.find('input').simulate('change', {
target: {
value: 'abc',
},
});
expect(component.find('input').prop('value')).toBe('abc');
component.find('input').simulate('keyDown', { keyCode: 13 });
expect(onChangeMockFn).toHaveBeenCalledWith({
label: 'San Francisco',
});
expect(component.find('input').prop('value')).toBe('');
});
it('should call onChange with the right data when press arrow down key and then enter key with the options menu open', () => {
const options = [
{ label: 'San Francisco' },
{ label: 'New York', description: 'awesome city' },
];
const onChangeMockFn = jest.fn();
const component = mount(
<Lookup label="custom label" options={options} onChange={onChangeMockFn} />,
);
component.find('input').simulate('focus');
component.find('input').simulate('keyDown', { keyCode: 40 });
expect(component.find('Options').prop('focusedItemIndex')).toBe(1);
component.find('input').simulate('keyDown', { keyCode: 13 });
expect(onChangeMockFn).toHaveBeenCalledWith({
label: 'New York',
description: 'awesome city',
});
});
it('should call onChange with the right data when press down, up and enter key with the options menu open', () => {
const options = [
{ label: 'San Francisco' },
{ label: 'New York', description: 'awesome city' },
];
const onChangeMockFn = jest.fn();
const component = mount(
<Lookup label="custom label" options={options} onChange={onChangeMockFn} />,
);
component.find('input').simulate('focus');
component.find('input').simulate('keyDown', { keyCode: 40 });
component.find('input').simulate('keyDown', { keyCode: 38 });
component.find('input').simulate('keyDown', { keyCode: 13 });
expect(onChangeMockFn).toHaveBeenCalledWith({
label: 'San Francisco',
});
});
it('should pass a function to onClearValue prop in SelectedValue component', () => {
const value = { label: 'New York', description: 'awesome city' };
const component = mount(<Lookup label="custom label" value={value} />);
expect(component.find('SelectedValue').prop('onClearValue')).toEqual(expect.any(Function));
});
it('should not set the onClearValue prop in SelectedValue component when pass disabled', () => {
const value = { label: 'New York', description: 'awesome city' };
const component = mount(<Lookup label="custom label" value={value} disabled />);
expect(component.find('SelectedValue').prop('onClearValue')).toBeUndefined();
});
it('should not set the onClearValue prop in SelectedValue component when pass readOnly', () => {
const value = { label: 'New York', description: 'awesome city' };
const component = mount(<Lookup label="custom label" value={value} readOnly />);
expect(component.find('SelectedValue').prop('onClearValue')).toBeUndefined();
});
it('should set the right options and reset the focusedItemIndex when the options changes', () => {
const options = [
{ label: 'Paris', description: 'An awesome city' },
{ label: 'Madrid' },
{ label: 'New York' },
{ label: 'San Fransisco' },
];
const component = mount(<Lookup label="custom label" options={options} />);
component.find('input').simulate('focus');
component
.find('Options')
.find('li')
.at(2)
.simulate('mouseEnter');
expect(component.find('Options').prop('focusedItemIndex')).toBe(2);
component.setProps({
options: [
{ label: 'Paris', description: 'An awesome city' },
{ label: 'Madrid' },
{ label: 'New York' },
],
});
component.update();
expect(component.find('Options').prop('focusedItemIndex')).toBe(0);
expect(component.find('Options').prop('items')).toEqual([
{ label: 'Paris', description: 'An awesome city' },
{ label: 'Madrid' },
{ label: 'New York' },
]);
});
it('should set the right options and reset the focusedItemIndex when the options changes and are type "section"', () => {
const options = [
{
type: 'section',
label: 'European Cities',
options: [{ label: 'Paris', description: 'An awesome city' }, { label: 'Madrid' }],
},
{
type: 'section',
label: 'American Cities',
options: [{ label: 'New York' }, { label: 'San Fransisco' }, { label: 'Miami' }],
},
];
const component = mount(<Lookup label="custom label" options={options} />);
component.find('input').simulate('focus');
component
.find('Options')
.find('li')
.at(1)
.simulate('mouseEnter');
expect(component.find('Options').prop('focusedItemIndex')).toBe(1);
component.setProps({
options: [
{
type: 'section',
label: 'European Cities',
options: [{ label: 'Madrid' }],
},
{
type: 'section',
label: 'American Cities',
options: [{ label: 'Miami' }],
},
],
});
component.update();
expect(component.find('Options').prop('focusedItemIndex')).toBe(1);
expect(component.find('Options').prop('items')).toEqual([
{ label: 'European Cities', type: 'header' },
{ label: 'Madrid' },
{ label: 'American Cities', type: 'header' },
{ label: 'Miami' },
]);
});
it('should call event.stopPropagation when press esc key and the input has value typed', () => {
const stopPropagationMockFn = jest.fn();
const component = mount(<Lookup label="custom label" />);
component.find('input').simulate('focus');
component.find('input').simulate('change', {
target: {
value: 'test',
},
});
component.find('input').simulate('keyDown', {
keyCode: 27,
stopPropagation: stopPropagationMockFn,
});
expect(stopPropagationMockFn).toHaveBeenCalledTimes(1);
});
it('should not call event.stopPropagation when press esc key and the input has not value typed', () => {
const stopPropagationMockFn = jest.fn();
const component = mount(<Lookup label="custom label" />);
component.find('input').simulate('focus');
component.find('input').simulate('keyDown', {
keyCode: 27,
stopPropagation: stopPropagationMockFn,
});
expect(stopPropagationMockFn).not.toHaveBeenCalled();
});
it('should fire onBlur with null', () => {
const onBlurMockFn = jest.fn();
const component = mount(<Lookup label="custom label" onBlur={onBlurMockFn} />);
component.find('input').simulate('focus');
component.find('input').simulate('blur');
expect(onBlurMockFn).toHaveBeenCalledWith(null);
});
it('should set the initial visual-focus to the option that is passed as preferredSelectedOption', () => {
const options = [
{ label: 'Paris' },
{ label: 'New York' },
{ label: 'Los Angeles' },
{ label: 'Brussels' },
{ label: 'San Fransisco' },
];
const component = mount(
<Lookup label="custom label" options={options} preferredSelectedOption={3} />,
);
component.find('input').simulate('focus');
expect(component.find('Options').prop('focusedItemIndex')).toBe(3);
});
it('should fallback to 0 if the index passed as preferredSelectedOption does not exist', () => {
const options = [{ label: 'Paris' }, { label: 'New York' }];
const component = mount(
<Lookup label="custom label" options={options} preferredSelectedOption={3} />,
);
component.find('input').simulate('focus');
expect(component.find('Options').prop('focusedItemIndex')).toBe(0);
});
it('should show error when isLoading is not passed', () => {
const component = mount(<Lookup label="custom label" error="wrong value" />);
expect(component.find('RightElement').prop('error')).toBe('wrong value');
expect(component.find(StyledInput).prop('error')).toBe('wrong value');
expect(component.find(StyledTextError).exists()).toBe(true);
});
it('should not show error when isLoading is passed', () => {
const component = mount(<Lookup label="custom label" error="wrong value" isLoading />);
expect(component.find('RightElement').prop('error')).toBe(null);
expect(component.find(StyledInput).prop('error')).toBe(null);
expect(component.find(StyledTextError).exists()).toBe(false);
});
});