src/components/CodeInput/__test__/codeInput.spec.js
import React from 'react';
import { mount } from 'enzyme';
import CodeInput from '..';
import InputItems from '../inputItems';
import InputItem from '../inputItem';
import { StyledErrorMessage, StyledHelpText } from '../styled';
import useFocusedIndexState from '../hooks/useFocusedIndexState';
import usePreviousIndex from '../hooks/usePreviousIndex';
import useValueState from '../hooks/useValueState';
import getNormalizedValue from '../helpers/getNormalizedValue';
import getNumbersFromClipboard from '../helpers/getNumbersFromClipboard';
jest.mock('../hooks/useFocusedIndexState', () => jest.fn(() => 0));
jest.mock('../hooks/usePreviousIndex', () => jest.fn(() => undefined));
jest.mock('../hooks/useValueState', () => jest.fn(() => ['', '', '', '']));
jest.mock('../helpers/getNormalizedValue', () => jest.fn(() => ''));
jest.mock('../helpers/getNumbersFromClipboard', () => jest.fn(() => ''));
describe('<CodeInput />', () => {
it('should have value length as 6 when length is 6', () => {
useValueState.mockImplementation(() => ['', '', '', '', '', '']);
const component = mount(<CodeInput length={6} />);
expect(component.find(InputItems).prop('value').length).toBe(6);
});
it('should pass the right props to the Label component', () => {
const component = mount(<CodeInput label="custom label" required />);
expect(component.find('Label').props()).toEqual({
label: 'custom label',
required: true,
readOnly: false,
labelAlignment: 'center',
hideLabel: false,
as: 'legend',
variant: 'default',
size: 'medium',
});
});
it('should have bottomHelpText rendered if is sent as param', () => {
const component = mount(<CodeInput bottomHelpText="help-text-test" />);
expect(component.find(StyledHelpText).exists()).toBe(true);
});
it('should not have bottomHelpText rendered when bottomHelpText is empty', () => {
const component = mount(<CodeInput />);
expect(component.find(StyledHelpText).exists()).toBe(false);
});
it('should have error rendered if is sent as param', () => {
const component = mount(<CodeInput error="error-test" />);
expect(component.find(StyledErrorMessage).exists()).toBe(true);
});
it('should not have error rendered if is not sent as param', () => {
const component = mount(<CodeInput />);
expect(component.find(StyledErrorMessage).exists()).toBe(false);
});
it('should keep isActive as true on active input whenever any other input is clicked', () => {
const component = mount(<CodeInput />);
const input0 = component.find(InputItem).at(0);
const input2 = component.find(InputItem).at(2);
input2.simulate('click');
expect(input0.prop('isActive')).toBe(true);
expect(input2.prop('isActive')).toBe(false);
});
it('should set isActive as true over the second input when first input is filled', () => {
const component = mount(<CodeInput />);
useValueState.mockImplementation(() => ['1', '', '', '']);
useFocusedIndexState.mockImplementation(() => 1);
component.setProps({ value: '1' });
expect(
component
.find(InputItem)
.at(0)
.prop('isActive'),
).toBe(false);
expect(
component
.find(InputItem)
.at(1)
.prop('isActive'),
).toBe(true);
});
it('should keep isActive as true on the last input when all inputs are filled an last input changes', () => {
const component = mount(<CodeInput />);
useValueState.mockImplementation(() => ['1', '2', '3', '4']);
useFocusedIndexState.mockImplementation(() => 3);
component.setProps({ value: '1234' });
expect(
component
.find(InputItem)
.at(3)
.prop('isActive'),
).toBe(true);
});
it('should call onChange with the number value when input value changes and is number', () => {
getNormalizedValue.mockImplementation(() => '3');
const onChangeFn = jest.fn();
const component = mount(<CodeInput onChange={onChangeFn} />);
const inputIndex = 0;
component
.find(InputItems)
.props()
.onChange('3', inputIndex);
expect(onChangeFn).toHaveBeenCalledWith('3');
});
it('should not call onChange when input value changes and is not a number', () => {
getNormalizedValue.mockImplementation(() => '');
const onChangeFn = jest.fn();
const component = mount(<CodeInput onChange={onChangeFn} />);
const inputIndex = 0;
component
.find(InputItems)
.props()
.onChange('A', inputIndex);
expect(onChangeFn).not.toHaveBeenCalled();
});
it('should call getNumbersFromClipboard with the copy and pasted value', () => {
getNumbersFromClipboard.mockClear();
const component = mount(<CodeInput />);
component
.find(InputItem)
.at(0)
.props()
.onPaste({
clipboardData: {
getData: () => '12345abcdfe',
},
});
expect(getNumbersFromClipboard).toHaveBeenCalledWith('12345abcdfe');
});
it('should call onChange with numbers only when we copy and paste a mixed text and numbers string', () => {
getNumbersFromClipboard.mockImplementation(() => '12345');
const onChangeFn = jest.fn();
const component = mount(<CodeInput onChange={onChangeFn} length={5} />);
component
.find(InputItem)
.at(0)
.props()
.onPaste({
clipboardData: {
getData: () => '12345abcdfe',
},
});
expect(onChangeFn).toHaveBeenCalledWith('12345');
});
it('should call getNormalizedValue with the right values when value changes', () => {
useValueState.mockImplementation(() => ['1', '2', '', '']);
const component = mount(<CodeInput value="12" />);
const inputIndex = 2;
component
.find(InputItems)
.props()
.onChange('3', inputIndex);
expect(getNormalizedValue).toHaveBeenCalledWith('3', 2, ['1', '2', '', '']);
});
it('should call useValueState with the right value and length', () => {
useValueState.mockReset();
mount(<CodeInput value="1" length={4} />);
expect(useValueState).toHaveBeenCalledWith('1', 4);
});
it('should call useFocusedIndexState with the right value and length', () => {
useValueState.mockReset();
mount(<CodeInput value="6" length={3} />);
expect(useValueState).toHaveBeenCalledWith('6', 3);
});
it('should call usePreviousIndex with the right focusedIndex value', () => {
usePreviousIndex.mockReset();
useFocusedIndexState.mockImplementation(() => 2);
mount(<CodeInput value="12" />);
expect(usePreviousIndex).toHaveBeenCalledWith(2);
});
});