ant-design/components/input/__tests__/otp.test.tsx
二货爱吃白萝卜 100fa29bef
feat: Input.OTP component support (#48076)
* chore: basic control

* chore: input instad

* docs: update demo

* chore: adjust operation interactive

* chore: lock selection

* chore: fix patch logic

* chore: merge logic

* chore: patch autoFocus

* test: update snapshot

* test: add test case

* test: coverage

* chore: update size limit

* docs: update docs

* test: fix test case

* chore: update comment

* refactor: change to length

* chore: blur all

* chore: size limit
2024-03-28 14:05:58 +08:00

132 lines
4.0 KiB
TypeScript

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(<OTP onChange={onChange} />);
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(<OTP onChange={onChange} autoFocus />);
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(<OTP defaultValue={CODE} onChange={onChange} />);
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(<OTP value="BAMBOO" />);
expect(getText(container)).toBe('BAMBOO');
rerender(<OTP value="LITTLE" />);
expect(getText(container)).toBe('LITTLE');
});
it('focus to selection', async () => {
const { container } = render(<OTP defaultValue="BAMBOO" />);
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(<OTP autoFocus />);
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(<OTP />);
fireEvent.input(container.querySelectorAll('input')[5], { target: { value: '1' } });
expect(getText(container)).toBe(' 1');
});
it('formatter', () => {
const { container } = render(
<OTP defaultValue="bamboo" formatter={(val) => val.toUpperCase()} />,
);
expect(getText(container)).toBe('BAMBOO');
// Type to trigger formatter
fireEvent.input(container.querySelector('input')!, { target: { value: 'little' } });
expect(getText(container)).toBe('LITTLE');
});
});