mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-09 02:49:18 +08:00
* refactor: Search component refactoring using compact * test: update snap * test: update snap * test: update snap * chore: fix style * chore: fix search style * test: update snapshot * test: update snapshot * test: update snapshot --------- Co-authored-by: 刘欢 <lh01217311@antgroup.com> Co-authored-by: 二货机器人 <smith3816@gmail.com>
362 lines
14 KiB
TypeScript
362 lines
14 KiB
TypeScript
import React from 'react';
|
|
import { EditOutlined, UserOutlined } from '@ant-design/icons';
|
|
import { fireEvent, render } from '@testing-library/react';
|
|
|
|
import focusTest from '../../../tests/shared/focusTest';
|
|
import mountTest from '../../../tests/shared/mountTest';
|
|
import rtlTest from '../../../tests/shared/rtlTest';
|
|
import Button from '../../button';
|
|
import type { InputRef } from '../Input';
|
|
import Search from '../Search';
|
|
import type { SearchProps } from '../Search';
|
|
|
|
describe('Input.Search', () => {
|
|
focusTest(Search, { refFocus: true });
|
|
mountTest(Search);
|
|
rtlTest(Search);
|
|
|
|
it('should support custom button', () => {
|
|
const { asFragment } = render(<Search enterButton={<button type="button">ok</button>} />);
|
|
expect(asFragment().firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
it('should support custom Button', () => {
|
|
const { asFragment } = render(<Search enterButton={<Button>ok</Button>} />);
|
|
expect(asFragment().firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
it('should support enterButton null', () => {
|
|
expect(() => {
|
|
render(<Search enterButton={null} />);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('should support ReactNode suffix without error', () => {
|
|
const { asFragment } = render(<Search suffix={<div>ok</div>} />);
|
|
expect(asFragment().firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
it('should disable enter button when disabled prop is true', () => {
|
|
const { container } = render(<Search placeholder="input search text" enterButton disabled />);
|
|
expect(container.querySelectorAll('.ant-btn[disabled]')).toHaveLength(1);
|
|
});
|
|
|
|
it('should disable search icon when disabled prop is true', () => {
|
|
const onSearch = jest.fn();
|
|
const { container } = render(
|
|
<Search defaultValue="search text" onSearch={onSearch} disabled />,
|
|
);
|
|
fireEvent.click(container.querySelector('button')!);
|
|
expect(onSearch).toHaveBeenCalledTimes(0);
|
|
});
|
|
|
|
it('should trigger onSearch when click search icon', () => {
|
|
const onSearch = jest.fn();
|
|
const { container } = render(<Search defaultValue="search text" onSearch={onSearch} />);
|
|
fireEvent.click(container.querySelector('button')!);
|
|
expect(onSearch).toHaveBeenCalledTimes(1);
|
|
expect(onSearch).toHaveBeenCalledWith('search text', expect.anything(), { source: 'input' });
|
|
});
|
|
|
|
it('should trigger onSearch when click search button', () => {
|
|
const onSearch = jest.fn();
|
|
const { container } = render(
|
|
<Search defaultValue="search text" enterButton onSearch={onSearch} />,
|
|
);
|
|
fireEvent.click(container.querySelector('button')!);
|
|
expect(onSearch).toHaveBeenCalledTimes(1);
|
|
expect(onSearch).toHaveBeenCalledWith('search text', expect.anything(), { source: 'input' });
|
|
});
|
|
|
|
it('should trigger onSearch when click search button with text', () => {
|
|
const onSearch = jest.fn();
|
|
const { container } = render(
|
|
<Search defaultValue="search text" enterButton="button text" onSearch={onSearch} />,
|
|
);
|
|
fireEvent.click(container.querySelector('button')!);
|
|
expect(onSearch).toHaveBeenCalledTimes(1);
|
|
expect(onSearch).toHaveBeenCalledWith('search text', expect.anything(), { source: 'input' });
|
|
});
|
|
|
|
it('should trigger onSearch when click search button with customize button', () => {
|
|
const onSearch = jest.fn();
|
|
const { container } = render(
|
|
<Search
|
|
defaultValue="search text"
|
|
enterButton={<Button>antd button</Button>}
|
|
onSearch={onSearch}
|
|
/>,
|
|
);
|
|
fireEvent.click(container.querySelector('button')!);
|
|
expect(onSearch).toHaveBeenCalledTimes(1);
|
|
expect(onSearch).toHaveBeenCalledWith('search text', expect.anything(), { source: 'input' });
|
|
});
|
|
|
|
it('should trigger onSearch when click search button of native', () => {
|
|
const onSearch = jest.fn();
|
|
const onButtonClick = jest.fn();
|
|
const { container } = render(
|
|
<Search
|
|
defaultValue="search text"
|
|
enterButton={
|
|
<button type="button" onClick={onButtonClick}>
|
|
antd button
|
|
</button>
|
|
}
|
|
onSearch={onSearch}
|
|
/>,
|
|
);
|
|
fireEvent.click(container.querySelector('button')!);
|
|
expect(onSearch).toHaveBeenCalledTimes(1);
|
|
expect(onSearch).toHaveBeenCalledWith('search text', expect.anything(), { source: 'input' });
|
|
expect(onButtonClick).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should trigger onSearch when press enter', () => {
|
|
const onSearch = jest.fn();
|
|
const { container } = render(<Search defaultValue="search text" onSearch={onSearch} />);
|
|
fireEvent.keyDown(container.querySelector('input')!, { key: 'Enter', keyCode: 13 });
|
|
expect(onSearch).toHaveBeenCalledTimes(1);
|
|
expect(onSearch).toHaveBeenCalledWith('search text', expect.anything(), { source: 'input' });
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/34844
|
|
it('should not trigger onSearch when press enter using chinese inputting method', () => {
|
|
const onSearch = jest.fn();
|
|
const { container } = render(<Search defaultValue="search text" onSearch={onSearch} />);
|
|
fireEvent.compositionStart(container.querySelector('input')!);
|
|
fireEvent.keyDown(container.querySelector('input')!, { key: 'Enter', keyCode: 13 });
|
|
fireEvent.keyUp(container.querySelector('input')!, { key: 'Enter', keyCode: 13 });
|
|
expect(onSearch).not.toHaveBeenCalled();
|
|
|
|
fireEvent.compositionEnd(container.querySelector('input')!);
|
|
fireEvent.keyDown(container.querySelector('input')!, { key: 'Enter', keyCode: 13 });
|
|
fireEvent.keyUp(container.querySelector('input')!, { key: 'Enter', keyCode: 13 });
|
|
expect(onSearch).toHaveBeenCalledTimes(1);
|
|
expect(onSearch).toHaveBeenCalledWith('search text', expect.anything(), { source: 'input' });
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/14785
|
|
it('should support addonAfter', () => {
|
|
const addonAfter = <span>Addon After</span>;
|
|
const { asFragment } = render(<Search addonAfter={addonAfter} />);
|
|
const { asFragment: asFragmentWithEnterButton } = render(
|
|
<Search enterButton addonAfter={addonAfter} />,
|
|
);
|
|
expect(asFragment().firstChild).toMatchSnapshot();
|
|
expect(asFragmentWithEnterButton().firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/18729
|
|
it('should trigger onSearch when click clear icon', () => {
|
|
const onSearch = jest.fn();
|
|
const onChange = jest.fn();
|
|
const { container } = render(
|
|
<Search allowClear defaultValue="value" onSearch={onSearch} onChange={onChange} />,
|
|
);
|
|
fireEvent.click(container.querySelector('.ant-input-clear-icon')!);
|
|
expect(onSearch).toHaveBeenLastCalledWith('', expect.anything(), { source: 'clear' });
|
|
expect(onChange).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should support loading', () => {
|
|
const { asFragment } = render(<Search loading />);
|
|
const { asFragment: asFragmentWithEnterButton } = render(<Search loading enterButton />);
|
|
expect(asFragment().firstChild).toMatchSnapshot();
|
|
expect(asFragmentWithEnterButton().firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
it('should not trigger onSearch when press enter while loading', () => {
|
|
const onSearch = jest.fn();
|
|
const { container } = render(<Search loading onSearch={onSearch} />);
|
|
fireEvent.keyDown(container.querySelector('input')!, { key: 'Enter', keyCode: 13 });
|
|
expect(onSearch).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should support addonAfter and suffix for loading', () => {
|
|
const { asFragment } = render(<Search loading suffix="suffix" addonAfter="addonAfter" />);
|
|
const { asFragment: asFragmentWithEnterButton } = render(
|
|
<Search loading enterButton suffix="suffix" addonAfter="addonAfter" />,
|
|
);
|
|
expect(asFragment().firstChild).toMatchSnapshot();
|
|
expect(asFragmentWithEnterButton().firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
it('should support invalid suffix', () => {
|
|
const { asFragment } = render(<Search suffix={[]} />);
|
|
expect(asFragment().firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
it('should support invalid addonAfter', () => {
|
|
const { asFragment } = render(<Search addonAfter={[]} enterButton />);
|
|
expect(asFragment().firstChild).toMatchSnapshot();
|
|
});
|
|
|
|
it('should prevent search button mousedown event', () => {
|
|
const ref = React.createRef<InputRef>();
|
|
const { container } = render(<Search ref={ref} enterButton="button text" />, {
|
|
container: document.body,
|
|
});
|
|
ref.current?.focus();
|
|
expect(document.activeElement).toBe(container.querySelector('input'));
|
|
fireEvent.mouseDown(container.querySelector('button')!);
|
|
expect(document.activeElement).toBe(container.querySelector('input'));
|
|
});
|
|
|
|
it('not crash when use function ref', () => {
|
|
const ref = jest.fn();
|
|
const { container } = render(<Search ref={ref} enterButton />);
|
|
expect(() => {
|
|
fireEvent.mouseDown(container.querySelector('button')!);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/27258
|
|
it('Search with allowClear should have one className only', () => {
|
|
const { container } = render(<Search allowClear className="bamboo" />);
|
|
expect(container.querySelectorAll('.bamboo')).toHaveLength(1);
|
|
expect(container.querySelector('.ant-input-search')).toHaveClass('bamboo');
|
|
expect(container.querySelector('.ant-input-affix-wrapper')).not.toHaveClass('bamboo');
|
|
});
|
|
|
|
// https://github.com/ant-design/ant-design/issues/53897
|
|
it('should trigger onPressEnter when press enter', () => {
|
|
const onPressEnter = jest.fn();
|
|
const { container } = render(<Search onPressEnter={onPressEnter} />);
|
|
fireEvent.keyDown(container.querySelector('input')!, { key: 'Enter', keyCode: 13 });
|
|
expect(onPressEnter).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('support function classNames and styles', () => {
|
|
const functionClassNames = (info: { props: SearchProps }) => {
|
|
const { props } = info;
|
|
const { enterButton, disabled } = props;
|
|
return {
|
|
root: 'dynamic-root',
|
|
input: enterButton ? 'dynamic-input-with-button' : 'dynamic-input-without-button',
|
|
prefix: 'dynamic-prefix',
|
|
suffix: 'dynamic-suffix',
|
|
count: 'dynamic-count',
|
|
button: {
|
|
root: 'dynamic-button-root',
|
|
icon: disabled ? 'dynamic-button-icon-disabled' : 'dynamic-button-icon',
|
|
},
|
|
};
|
|
};
|
|
const functionStyles = (info: { props: SearchProps }) => {
|
|
const { props } = info;
|
|
const { enterButton, disabled } = props;
|
|
return {
|
|
root: { color: 'rgb(255, 0, 0)' },
|
|
input: { color: enterButton ? 'rgb(0, 255, 0)' : 'rgb(255, 0, 0)' },
|
|
prefix: { color: 'rgb(0, 0, 255)' },
|
|
suffix: { color: 'rgb(255, 0, 0)' },
|
|
count: { color: 'rgb(255, 0, 0)' },
|
|
button: {
|
|
root: { color: 'rgb(0, 255, 0)' },
|
|
icon: { color: disabled ? 'rgb(0, 0, 255)' : 'rgb(255, 0, 0)' },
|
|
},
|
|
};
|
|
};
|
|
const { container, rerender } = render(
|
|
<Search
|
|
showCount
|
|
prefix={<UserOutlined />}
|
|
suffix={<EditOutlined />}
|
|
defaultValue="Hello, Ant Design"
|
|
classNames={functionClassNames}
|
|
styles={functionStyles}
|
|
disabled
|
|
/>,
|
|
);
|
|
const root = container.querySelector('.ant-input-search');
|
|
const input = container.querySelector('.ant-input');
|
|
const prefix = container.querySelector('.ant-input-prefix');
|
|
const suffix = container.querySelector('.ant-input-suffix');
|
|
const count = container.querySelector('.ant-input-show-count-suffix');
|
|
const button = container.querySelector('.ant-btn');
|
|
const buttonIcon = container.querySelector('.ant-btn-icon');
|
|
|
|
expect(root).toHaveClass('dynamic-root');
|
|
expect(input).toHaveClass('dynamic-input-without-button');
|
|
expect(prefix).toHaveClass('dynamic-prefix');
|
|
expect(suffix).toHaveClass('dynamic-suffix');
|
|
expect(count).toHaveClass('dynamic-count');
|
|
expect(button).toHaveClass('dynamic-button-root');
|
|
expect(buttonIcon).toHaveClass('dynamic-button-icon-disabled');
|
|
|
|
expect(root).toHaveStyle('color: rgb(255, 0, 0)');
|
|
expect(input).toHaveStyle('color: rgb(255, 0, 0)');
|
|
expect(prefix).toHaveStyle('color: rgb(0, 0, 255)');
|
|
expect(suffix).toHaveStyle('color: rgb(255, 0, 0)');
|
|
expect(count).toHaveStyle('color: rgb(255, 0, 0)');
|
|
expect(button).toHaveStyle('color: rgb(0, 255, 0)');
|
|
expect(buttonIcon).toHaveStyle('color: rgb(0, 0, 255)');
|
|
|
|
const objectClassNames = {
|
|
root: 'dynamic-root-default',
|
|
input: 'dynamic-input-default',
|
|
prefix: 'dynamic-prefix-default',
|
|
suffix: 'dynamic-suffix-default',
|
|
count: 'dynamic-count-default',
|
|
};
|
|
const objectStyles = {
|
|
root: { color: 'rgb(255, 0, 0)' },
|
|
input: { color: 'rgb(0, 255, 0)' },
|
|
prefix: { color: 'rgb(0, 0, 255)' },
|
|
suffix: { color: 'rgb(0, 255, 0)' },
|
|
count: { color: 'rgb(0, 255, 0)' },
|
|
};
|
|
const objectButtonClassNames = {
|
|
root: 'dynamic-custom-button-root',
|
|
icon: 'dynamic-custom-button-icon',
|
|
content: 'dynamic-custom-button-content',
|
|
};
|
|
const objectButtonStyles = {
|
|
root: { color: 'rgb(0, 255, 0)' },
|
|
icon: { color: 'rgb(255, 0, 0)' },
|
|
content: { color: 'rgb(0, 255, 0)' },
|
|
};
|
|
rerender(
|
|
<Search
|
|
showCount
|
|
prefix={<UserOutlined />}
|
|
suffix={<EditOutlined />}
|
|
defaultValue="Hello, Ant Design"
|
|
classNames={objectClassNames}
|
|
styles={objectStyles}
|
|
disabled
|
|
enterButton={
|
|
<Button
|
|
classNames={objectButtonClassNames}
|
|
styles={objectButtonStyles}
|
|
icon={<UserOutlined />}
|
|
>
|
|
button text
|
|
</Button>
|
|
}
|
|
/>,
|
|
);
|
|
|
|
const buttonContent = container.querySelector('.ant-btn > .ant-btn-icon + span');
|
|
|
|
expect(root).toHaveClass('dynamic-root-default');
|
|
expect(input).toHaveClass('dynamic-input-default');
|
|
expect(prefix).toHaveClass('dynamic-prefix-default');
|
|
expect(suffix).toHaveClass('dynamic-suffix-default');
|
|
expect(count).toHaveClass('dynamic-count-default');
|
|
expect(button).toHaveClass('dynamic-custom-button-root');
|
|
expect(buttonIcon).toHaveClass('dynamic-custom-button-icon');
|
|
expect(buttonContent).toHaveClass('dynamic-custom-button-content');
|
|
|
|
expect(root).toHaveStyle('color: rgb(255, 0, 0)');
|
|
expect(input).toHaveStyle('color: rgb(0, 255, 0)');
|
|
expect(prefix).toHaveStyle('color: rgb(0, 0, 255)');
|
|
expect(suffix).toHaveStyle('color: rgb(0, 255, 0)');
|
|
expect(count).toHaveStyle('color: rgb(0, 255, 0)');
|
|
expect(button).toHaveStyle('color: rgb(0, 255, 0)');
|
|
expect(buttonIcon).toHaveStyle('color: rgb(255, 0, 0)');
|
|
expect(buttonContent).toHaveStyle('color: rgb(0, 255, 0)');
|
|
});
|
|
});
|