import React from 'react'; import Input from '..'; import focusTest from '../../../tests/shared/focusTest'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; import { fireEvent, render, waitFakeTimer } from '../../../tests/utils'; const { OTP } = Input; describe('Input.OTP', () => { focusTest(Input.OTP, { refFocus: true }); mountTest(Input.OTP); rtlTest(Input.OTP); function getText(container: HTMLElement) { const inputList = container.querySelectorAll('input'); return Array.from(inputList) .map((input) => input.value || ' ') .join('') .replace(/\s*$/, ''); } beforeEach(() => { jest.useFakeTimers(); }); afterEach(() => { jest.clearAllTimers(); jest.useRealTimers(); }); it('paste to fill all', async () => { const onChange = jest.fn(); const { container } = render(); fireEvent.input(container.querySelector('input')!, { target: { value: '123456' } }); expect(onChange).toHaveBeenCalledTimes(1); expect(onChange).toHaveBeenCalledWith('123456'); }); it('fill step by step', () => { const CODE = 'BAMBOO'; const onChange = jest.fn(); render(); for (let i = 0; i < CODE.length; i += 1) { expect(onChange).not.toHaveBeenCalled(); fireEvent.input(document.activeElement!, { target: { value: CODE[i] } }); } expect(onChange).toHaveBeenCalledTimes(1); expect(onChange).toHaveBeenCalledWith(CODE); }); it('backspace to delete', async () => { const CODE = 'LITTLE'; const onChange = jest.fn(); const { container } = render(); expect(getText(container)).toBe(CODE); // Focus on the last cell const inputList = container.querySelectorAll('input'); inputList[inputList.length - 1].focus(); for (let i = 0; i < CODE.length; i += 1) { fireEvent.keyDown(document.activeElement!, { key: 'Backspace' }); fireEvent.input(document.activeElement!, { target: { value: '' } }); fireEvent.keyUp(document.activeElement!, { key: 'Backspace' }); } expect(getText(container)).toBe(''); // We do not trigger change if empty. It's safe to modify this logic if needed. expect(onChange).not.toHaveBeenCalled(); }); it('controlled', () => { const { container, rerender } = render(); expect(getText(container)).toBe('BAMBOO'); rerender(); expect(getText(container)).toBe('LITTLE'); rerender(); expect(getText(container)).toBe(''); rerender(); expect(getText(container)).toBe('EXCEED'); rerender(); expect(getText(container)).toBe(''); }); it('focus to selection', async () => { const { container } = render(); const firstInput = container.querySelector('input')!; const selectSpy = jest.spyOn(firstInput, 'select'); expect(selectSpy).not.toHaveBeenCalled(); // Trigger focus firstInput.focus(); await waitFakeTimer(); expect(selectSpy).toHaveBeenCalled(); }); it('arrow key to switch', () => { const { container } = render(); const inputList = Array.from(container.querySelectorAll('input')); expect(document.activeElement).toEqual(inputList[0]); fireEvent.keyDown(document.activeElement!, { key: 'ArrowRight' }); expect(document.activeElement).toEqual(inputList[1]); fireEvent.keyDown(document.activeElement!, { key: 'ArrowLeft' }); expect(document.activeElement).toEqual(inputList[0]); }); it('fill last cell', () => { const { container } = render(); fireEvent.input(container.querySelectorAll('input')[5], { target: { value: '1' } }); expect(getText(container)).toBe(' 1'); }); it('formatter', () => { const { container } = render( val.toUpperCase()} />, ); expect(getText(container)).toBe('BAMBOO'); // Type to trigger formatter fireEvent.input(container.querySelector('input')!, { target: { value: 'little' } }); expect(getText(container)).toBe('LITTLE'); }); });