import type { ChangeEventHandler, TextareaHTMLAttributes } from 'react';
import React, { useState } from 'react';
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
import Input from '..';
import focusTest from '../../../tests/shared/focusTest';
import type { RenderOptions } from '../../../tests/utils';
import { fireEvent, pureRender, render, triggerResize, waitFakeTimer } from '../../../tests/utils';
import type { TextAreaRef } from '../TextArea';
const { TextArea } = Input;
focusTest(TextArea, { refFocus: true });
describe('TextArea', () => {
const originalGetComputedStyle = window.getComputedStyle;
beforeAll(() => {
Object.defineProperty(window, 'getComputedStyle', {
value: (node: Element) => ({
getPropertyValue: (prop: PropertyKey) =>
prop === 'box-sizing'
? originalGetComputedStyle(node)[prop as unknown as number] || 'border-box'
: originalGetComputedStyle(node)[prop as unknown as number],
}),
});
});
afterAll(() => {
Object.defineProperty(window, 'getComputedStyle', { value: originalGetComputedStyle });
});
it('should auto calculate height according to content length', async () => {
jest.useFakeTimers();
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const ref = React.createRef();
const onInternalAutoSize = jest.fn();
const genTextArea = (props = {}) => (
);
const { container, rerender } = pureRender(genTextArea());
await waitFakeTimer();
expect(onInternalAutoSize).toHaveBeenCalledTimes(1);
rerender(genTextArea({ value: '1111\n2222\n3333' }));
await waitFakeTimer();
expect(onInternalAutoSize).toHaveBeenCalledTimes(2);
rerender(genTextArea({ value: '1111' }));
await waitFakeTimer();
expect(onInternalAutoSize).toHaveBeenCalledTimes(3);
expect(container.querySelector('textarea')?.style.overflow).toBeFalsy();
expect(errorSpy).not.toHaveBeenCalled();
errorSpy.mockRestore();
jest.clearAllTimers();
jest.useRealTimers();
});
it('should support onPressEnter and onKeyDown', () => {
const fakeHandleKeyDown = jest.fn();
const fakeHandlePressEnter = jest.fn();
const { container } = render(
,
);
/** KeyCode 65 is A */
fireEvent.keyDown(container.querySelector('textarea')!, { keyCode: 65 });
expect(fakeHandleKeyDown).toHaveBeenCalledTimes(1);
expect(fakeHandlePressEnter).toHaveBeenCalledTimes(0);
/** KeyCode 13 is Enter */
fireEvent.keyDown(container.querySelector('textarea')!, { keyCode: 13 });
expect(fakeHandleKeyDown).toHaveBeenCalledTimes(2);
expect(fakeHandlePressEnter).toHaveBeenCalledTimes(1);
});
it('should support disabled', () => {
const { asFragment } = render();
expect(asFragment().firstChild).toMatchSnapshot();
});
describe('maxLength', () => {
it('should support maxLength', () => {
const { asFragment } = render();
expect(asFragment().firstChild).toMatchSnapshot();
});
it('maxLength should not block control', () => {
const { container } = render();
expect(container.querySelector('textarea')?.value).toEqual('light');
});
it('should exceed maxLength when use IME', () => {
const onChange = jest.fn();
const { container } = render();
fireEvent.compositionStart(container.querySelector('textarea')!);
fireEvent.change(container.querySelector('textarea')!, { target: { value: 'zhu' } });
fireEvent.compositionEnd(container.querySelector('textarea')!, {
currentTarget: { value: '竹' },
});
fireEvent.change(container.querySelector('textarea')!, { target: { value: '竹' } });
expect(onChange).toHaveBeenLastCalledWith(
expect.objectContaining({ target: expect.objectContaining({ value: '竹' }) }),
);
});
});
it('handleKeyDown', () => {
const onPressEnter = jest.fn();
const onKeyDown = jest.fn();
const { container } = render(
,
);
fireEvent.keyDown(container.querySelector('textarea')!, { keyCode: 13 });
expect(onPressEnter).toHaveBeenCalled();
expect(onKeyDown).toHaveBeenCalled();
});
it('should trigger onResize', async () => {
jest.useFakeTimers();
const onResize = jest.fn();
const ref = React.createRef();
const { container } = render();
await waitFakeTimer();
triggerResize(container.querySelector('textarea')!);
await waitFakeTimer();
expect(onResize).toHaveBeenCalledWith(
expect.objectContaining({ width: expect.any(Number), height: expect.any(Number) }),
);
jest.clearAllTimers();
jest.useRealTimers();
});
it('should disabled trigger onResize', async () => {
const { container } = render();
expect(container.innerHTML).toContain('resize: none;');
const { container: container2 } = render();
expect(container2.innerHTML).not.toContain('resize: none;');
});
it('should works same as Input', () => {
const { container: inputContainer, rerender: inputRerender } = render();
const { container: textareaContainer, rerender: textareaRerender } = render(
,
);
inputRerender();
textareaRerender();
expect(textareaContainer.querySelector('textarea')?.value).toBe(
inputContainer.querySelector('input')?.value,
);
});
describe('should support showCount', () => {
it('maxLength', () => {
const { container } = render();
expect(container.querySelector('textarea')?.value).toBe('12345');
expect(
container.querySelector('.ant-input-textarea-show-count')?.getAttribute('data-count'),
).toBe('5 / 5');
});
it('control exceed maxLength', () => {
const { container } = render();
expect(container.querySelector('textarea')?.value).toBe('12345678');
expect(
container.querySelector('.ant-input-textarea-show-count')?.getAttribute('data-count'),
).toBe('8 / 5');
});
it('className & style patch to outer', () => {
const { container } = render(
,
);
// Outer
expect(container.querySelector('span')?.classList.contains('bamboo')).toBeTruthy();
expect(container.querySelector('span')?.style.background).toEqual('red');
// Inner
expect(container.querySelector('.ant-input')?.classList.contains('bamboo')).toBeFalsy();
expect(container.querySelector('.ant-input')?.style.background).toBeFalsy();
});
it('count formatter', () => {
const { container } = render(