import { keyboardKey } from '@fluentui/keyboard-key';
import { ReactWrapper } from 'enzyme';
import * as faker from 'faker';
import * as _ from 'lodash';
import * as React from 'react';
import { htmlInputAttrs } from 'src/utils';
import { Box } from 'src/components/Box/Box';
import { Input, inputSlotClassNames } from 'src/components/Input/Input';
import { consoleUtil, mountWithProvider as mount } from 'test/utils';
import { isConformant, implementsShorthandProp, implementsWrapperProp } from 'test/specs/commonTests';
const testValue = 'test value';
const getInputDomNode = (inputComp: ReactWrapper): HTMLInputElement =>
inputComp.find('input').getDOMNode() as HTMLInputElement;
const setUserInputValue = (inputComp: ReactWrapper, value: string) => {
inputComp.find('input').simulate('change', { target: { value } });
};
describe('Input', () => {
isConformant(Input, {
constructorName: 'Input',
eventTargets: {
onChange: 'input',
onKeyDown: 'input',
onKeyPress: 'input',
onKeyUp: 'input',
},
autoControlledProps: ['value'],
forwardsRefTo: `Box[className~="${inputSlotClassNames.input}"]`,
});
implementsShorthandProp(Input)('input', Box, { mapsValueToProp: 'type' });
describe('wrapper', () => {
implementsShorthandProp(Input)('wrapper', Box, { mapsValueToProp: 'children' });
implementsWrapperProp(Input, { wrapppedComponentSelector: 'input' });
});
it('renders a text by default', () => {
const inputComp = mount();
expect(inputComp.find('input[type="text"]').length).toBeGreaterThan(0);
});
describe('input related HTML attribute', () => {
// `input` will be always controlled component so there is no need to pass down `defaultValue`
_.without(htmlInputAttrs, 'defaultValue').forEach(attr => {
it(`'${attr}' is set correctly to '${testValue}'`, () => {
// as `testValue` is a string it can cause propTypes errors on `Input`
consoleUtil.disableOnce();
const wrapper = mount().find('input');
expect(wrapper.prop(attr)).toBe(testValue);
});
});
});
describe('clearable', () => {
it('calls onChange on Clearable icon click with an `empty` value', () => {
const onChange = jest.fn();
const wrapper = mount();
wrapper
.find(`.${inputSlotClassNames.icon}`)
.first()
.simulate('click');
expect(onChange).toBeCalledTimes(1);
expect(onChange).toHaveBeenCalledWith(
expect.objectContaining({ type: 'click' }),
expect.objectContaining({ value: '' }),
);
});
it('calls onChange on Escape key with an `empty` value and stops propagation when has content', () => {
const onChange = jest.fn();
const stopPropagation = jest.fn();
const nativeEventStopPropagation = jest.fn();
const wrapper = mount();
wrapper.find('input').simulate('keydown', {
keyCode: keyboardKey.Escape,
key: 'Escape',
stopPropagation,
nativeEvent: { stopPropagation: nativeEventStopPropagation },
});
expect(onChange).toBeCalledTimes(1);
expect(onChange).toHaveBeenCalledWith(
expect.objectContaining({ type: 'keydown' }),
expect.objectContaining({ value: '' }),
);
expect(stopPropagation).toHaveBeenCalledTimes(1);
expect(nativeEventStopPropagation).toHaveBeenCalledTimes(1);
});
it('does not call onChange and does not stop propagation if is already empty', () => {
const onChange = jest.fn();
const stopPropagation = jest.fn();
const nativeEventStopPropagation = jest.fn();
const wrapper = mount();
wrapper.find('input').simulate('keydown', {
keyCode: keyboardKey.Escape,
key: 'Escape',
stopPropagation,
nativeEvent: { stopPropagation: nativeEventStopPropagation },
});
expect(onChange).not.toBeCalled();
expect(stopPropagation).not.toBeCalled();
expect(nativeEventStopPropagation).not.toBeCalled();
});
});
describe('icon', () => {
const SearchIcon = () => ;
it('creates the Icon component when the icon shorthand is provided', () => {
const inputComp = mount(} />);
expect(inputComp.find('SearchIcon').length).toBeGreaterThan(0);
});
it('creates an empty Icon component when the clearable prop is provided and the input has content, removes the icon and value when the icon is clicked', () => {
const inputComp = mount();
const domNode = getInputDomNode(inputComp);
setUserInputValue(inputComp, testValue); // user types into the input
const iconComp = inputComp.find(`Box[className~="${inputSlotClassNames.icon}"]`);
expect(domNode.value).toEqual(testValue); // input value is the one typed by the user
expect(iconComp.length).toBeGreaterThan(0); // the 'x' icon appears
iconComp.simulate('click'); // user clicks on 'x' icon
expect(domNode.value).toEqual(''); // input value gets cleared
expect(inputComp.find(`Box[className~="${inputSlotClassNames.icon}"]`).length).toEqual(0); // the 'x' icon disappears
});
});
it('disabled prop makes the input un-actionable', () => {
const inputComp = mount();
const domNode = getInputDomNode(inputComp);
expect(domNode).toHaveAttribute('disabled');
setUserInputValue(inputComp, testValue); // user types into the input
expect(domNode.value).toEqual(''); // but nothing happens
domNode.focus();
expect(domNode).not.toHaveFocus();
domNode.click();
expect(domNode).not.toHaveFocus();
});
});