ant-design/components/splitter/__tests__/index.test.tsx
2024-08-27 19:10:08 +08:00

363 lines
12 KiB
TypeScript

import React from 'react';
import type { GetProps, SplitterProps } from 'antd';
import { ConfigProvider, Splitter } from 'antd';
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
type PanelProps = GetProps<typeof Splitter.Panel>;
const SplitterDemo = ({ items = [{}, {}], ...props }: { items?: PanelProps[] } & SplitterProps) => (
<Splitter {...props}>
{items?.map((item, idx) => (
// eslint-disable-next-line react/no-array-index-key
<Splitter.Panel key={idx} {...item}>
{idx}
</Splitter.Panel>
))}
</Splitter>
);
describe('Splitter', () => {
beforeEach(() => {
// jsdom 不执行任何布局,因此不会计算值 https://github.com/jsdom/jsdom/issues/1590
global.HTMLElement.prototype.getBoundingClientRect = () =>
({
height: 400,
width: 400,
}) as DOMRect;
jest.useFakeTimers();
});
afterEach(() => {
jest.clearAllTimers();
jest.useRealTimers();
});
const doMove = async (
container: HTMLElement,
index: number,
options: { clientX?: number; clientY?: number },
) => {
fireEvent.mouseDown(container?.querySelectorAll('.ant-splitter-bar')[index]!, {
clientX: 0,
clientY: 0,
});
fireEvent.mouseMove(document.documentElement, options); // 40%
await waitFakeTimer();
fireEvent.mouseUp(document.documentElement);
};
it('should correct render', () => {
const { container } = render(<SplitterDemo />);
expect(container?.querySelector('.ant-splitter')).toBeTruthy();
expect(container?.querySelectorAll('.ant-splitter-panel')?.length).toBe(2);
expect(container?.querySelector('.ant-splitter-bar')).toBeTruthy();
expect(container).toMatchSnapshot();
});
it('should correct render panel size', async () => {
// 修改 container 大小为添加操作杆后的大小 以便于测试
global.HTMLElement.prototype.getBoundingClientRect = () =>
({
height: 406,
width: 406,
}) as DOMRect;
jest.useFakeTimers();
const { container } = render(
<SplitterDemo
items={[{ defaultSize: 20 }, { defaultSize: '45%' }, { defaultSize: '40px' }, {}]}
/>,
);
await waitFakeTimer();
expect(container?.querySelectorAll('.ant-splitter-panel')?.[0]).toHaveStyle(
'flex-basis: calc(20% - 1.5px)',
);
expect(container?.querySelectorAll('.ant-splitter-panel')?.[1]).toHaveStyle(
'flex-basis: calc(45% - 1.5px)',
);
expect(container?.querySelectorAll('.ant-splitter-panel')?.[2]).toHaveStyle(
'flex-basis: calc(10% - 1.5px)',
);
expect(container?.querySelectorAll('.ant-splitter-panel')?.[3]).toHaveStyle(
'flex-basis: calc(25% - 1.5px)',
);
});
it('The layout should work fine.', () => {
const { container, rerender } = render(<SplitterDemo />);
expect(container?.querySelector('.ant-splitter-horizontal')).toBeTruthy();
rerender(<SplitterDemo items={[{}, {}, {}]} layout="vertical" />);
expect(container?.querySelector('.ant-splitter-vertical')).toBeTruthy();
});
it('The resizable should work fine.', () => {
const { container } = render(
<SplitterDemo items={[{ defaultSize: 20 }, { resizable: false }, {}]} />,
);
expect(container?.querySelectorAll('.ant-splitter-bar-resizable')?.length).toBe(1);
});
it('The collapsible should work fine.', () => {
const { container, rerender } = render(
<SplitterDemo items={[{ defaultSize: 20, collapsible: true }, {}]} />,
);
expect(container?.querySelectorAll('.ant-splitter-bar-collapse-icon')?.length).toBe(2);
expect(container?.querySelector('.ant-splitter-bar-collapse-previous')).toBeTruthy();
expect(container?.querySelector('.ant-splitter-bar-collapse-next')).toBeTruthy();
// support collapsible is object
rerender(
<SplitterDemo
items={[
{
defaultSize: 20,
collapsible: {
prev: true,
},
},
{
collapsible: {
next: true,
},
},
{},
]}
/>,
);
const barNodes = container?.querySelectorAll('.ant-splitter-bar');
expect(barNodes?.[0]?.querySelector('.ant-splitter-bar-collapse-previous')).toBeTruthy();
expect(barNodes?.[0]?.querySelector('.ant-splitter-bar-collapse-next')).toBeFalsy();
expect(barNodes?.[1]?.querySelector('.ant-splitter-bar-collapse-previous')).toBeFalsy();
expect(barNodes?.[1]?.querySelector('.ant-splitter-bar-collapse-next')).toBeTruthy();
});
it('The collapsible click should work fine.', () => {
const { container, rerender } = render(
<SplitterDemo
items={[
{
size: 20,
collapsible: {
prev: true,
},
},
{},
]}
/>,
);
// previous click
fireEvent.click(container?.querySelector('.ant-splitter-bar-collapse-previous')!);
expect(container?.querySelector('.ant-splitter-bar-collapse-previous')).toBeFalsy();
expect(container?.querySelector('.ant-splitter-bar-collapse-next')).toBeTruthy();
expect(container?.querySelectorAll('.ant-splitter-panel')[0]).toHaveStyle(
'flex-basis: calc(0% - 1px)',
);
expect(container?.querySelectorAll('.ant-splitter-panel')[1]).toHaveStyle(
'flex-basis: calc(100% - 1px)',
);
rerender(
<SplitterDemo
items={[
{
size: 60,
collapsible: {
next: true,
},
},
{},
]}
/>,
);
// next click
fireEvent.click(container?.querySelector('.ant-splitter-bar-collapse-next')!);
expect(container?.querySelector('.ant-splitter-bar-collapse-previous')).toBeTruthy();
expect(container?.querySelector('.ant-splitter-bar-collapse-next')).toBeFalsy();
expect(container?.querySelectorAll('.ant-splitter-panel')[0]).toHaveStyle(
'flex-basis: calc(100% - 1px)',
);
expect(container?.querySelectorAll('.ant-splitter-panel')[1]).toHaveStyle(
'flex-basis: calc(0% - 1px)',
);
// collapsible is boolean
rerender(
<SplitterDemo
items={[
{
size: 10,
collapsible: true,
},
{},
]}
/>,
);
// mouseDown icon
fireEvent.mouseDown(container?.querySelector('.ant-splitter-bar-collapse-next')!);
expect(container?.querySelector('.ant-splitter-resizing')).toBeFalsy();
fireEvent.mouseDown(container?.querySelector('.ant-splitter-bar-collapse-previous')!);
expect(container?.querySelector('.ant-splitter-resizing')).toBeFalsy();
fireEvent.click(container?.querySelector('.ant-splitter-bar-collapse-next')!);
expect(container?.querySelector('.ant-splitter-bar-collapse-previous')).toBeTruthy();
expect(container?.querySelector('.ant-splitter-bar-collapse-next')).toBeFalsy();
expect(container?.querySelectorAll('.ant-splitter-panel')[0]).toHaveStyle(
'flex-basis: calc(100% - 1px)',
);
expect(container?.querySelectorAll('.ant-splitter-panel')[1]).toHaveStyle(
'flex-basis: calc(0% - 1px)',
);
fireEvent.click(container?.querySelector('.ant-splitter-bar-collapse-previous')!);
expect(container?.querySelector('.ant-splitter-bar-collapse-previous')).toBeTruthy();
expect(container?.querySelector('.ant-splitter-bar-collapse-next')).toBeTruthy();
expect(container?.querySelectorAll('.ant-splitter-panel')[0]).toHaveStyle(
'flex-basis: calc(10% - 1px)',
);
expect(container?.querySelectorAll('.ant-splitter-panel')[1]).toHaveStyle(
'flex-basis: calc(90% - 1px)',
);
fireEvent.click(container?.querySelector('.ant-splitter-bar-collapse-previous')!);
expect(container?.querySelector('.ant-splitter-bar-collapse-previous')).toBeFalsy();
expect(container?.querySelector('.ant-splitter-bar-collapse-next')).toBeTruthy();
expect(container?.querySelectorAll('.ant-splitter-panel')[0]).toHaveStyle(
'flex-basis: calc(0% - 1px)',
);
expect(container?.querySelectorAll('.ant-splitter-panel')[1]).toHaveStyle(
'flex-basis: calc(100% - 1px)',
);
fireEvent.click(container?.querySelector('.ant-splitter-bar-collapse-next')!);
expect(container?.querySelector('.ant-splitter-bar-collapse-previous')).toBeTruthy();
expect(container?.querySelector('.ant-splitter-bar-collapse-next')).toBeTruthy();
expect(container?.querySelectorAll('.ant-splitter-panel')[0]).toHaveStyle(
'flex-basis: calc(10% - 1px)',
);
expect(container?.querySelectorAll('.ant-splitter-panel')[1]).toHaveStyle(
'flex-basis: calc(90% - 1px)',
);
});
it('The mousemove should work fine.', async () => {
// 修改 container 大小为添加操作杆后的大小 以便于测试
global.HTMLElement.prototype.getBoundingClientRect = () =>
({
height: 402,
width: 402,
}) as DOMRect;
const mockStart = jest.fn();
const mockMoving = jest.fn();
const mockMovingVertical = jest.fn();
const mockEnd = jest.fn();
// previous click
const { container } = render(
<Splitter>
<Splitter.Panel>
<SplitterDemo
items={[{}, { min: 20 }]}
onResizeStart={mockStart}
onResize={mockMoving}
onResizeEnd={mockEnd}
/>
,
</Splitter.Panel>
<Splitter.Panel>
<SplitterDemo items={[{}, { max: 75 }]} layout="vertical" onResize={mockMovingVertical} />
</Splitter.Panel>
</Splitter>,
);
// layout horizontal
fireEvent.mouseDown(container?.querySelectorAll('.ant-splitter-bar')[0]!, {
clientX: 0,
clientY: 0,
});
expect(container?.querySelector('.ant-splitter-resizing')).toBeTruthy();
// 模拟鼠标移动事件
fireEvent.mouseMove(document.documentElement, { clientX: 40 });
await waitFakeTimer();
// 模拟鼠标释放结束拖动
fireEvent.mouseUp(document.documentElement);
expect(mockStart).toHaveBeenCalled();
expect(mockMoving).toHaveBeenCalledWith([60, 40], 0);
expect(mockEnd).toHaveBeenCalled();
// layout vertical
fireEvent.mouseDown(container?.querySelectorAll('.ant-splitter-bar')[2]!, {
clientX: 0,
clientY: 0,
});
expect(container?.querySelector('.ant-splitter-resizing')).toBeTruthy();
fireEvent.mouseMove(document.documentElement, { clientY: 80 });
await waitFakeTimer();
fireEvent.mouseUp(document.documentElement);
expect(mockMovingVertical).toHaveBeenCalledWith([70, 30], 0);
expect(container).toMatchSnapshot();
});
it('The min max should work fine.', async () => {
const mockMoving = jest.fn();
const { container, rerender } = render(
<SplitterDemo items={[{ min: 10 }, { max: 60 }, {}, { min: 12 }]} onResize={mockMoving} />,
);
await doMove(container, 0, { clientX: -160 });
expect(mockMoving).toHaveBeenNthCalledWith(1, [10, 40, 25, 25], 0);
await doMove(container, 1, { clientX: 160 });
expect(mockMoving).toHaveBeenNthCalledWith(2, [10, 60, 5, 25], 1);
await doMove(container, 0, { clientX: -120 });
expect(mockMoving).toHaveBeenNthCalledWith(2, [10, 60, 5, 25], 1);
await doMove(container, 2, { clientX: 60 });
expect(mockMoving).toHaveBeenNthCalledWith(3, [10, 60, 18, 12], 2);
rerender(<SplitterDemo items={[{ size: 20 }, {}]} onResize={mockMoving} />);
await doMove(container, 0, { clientX: -120 });
expect(mockMoving).toHaveBeenNthCalledWith(4, [0, 100], 0);
await doMove(container, 0, { clientX: -120 });
expect(mockMoving).toHaveBeenNthCalledWith(4, [0, 100], 0);
await doMove(container, 0, { clientX: 120 });
expect(mockMoving).toHaveBeenNthCalledWith(4, [0, 100], 0);
await doMove(container, 0, { clientX: 440 });
expect(mockMoving).toHaveBeenNthCalledWith(5, [100, 0], 0);
await doMove(container, 0, { clientX: 120 });
expect(mockMoving).toHaveBeenNthCalledWith(5, [100, 0], 0);
});
it('The RTL should work fine.', async () => {
global.HTMLElement.prototype.getBoundingClientRect = () =>
({
height: 402,
width: 402,
}) as DOMRect;
const mockMoving = jest.fn();
const { container } = render(
<ConfigProvider direction="rtl">
<SplitterDemo items={[{}, {}]} onResize={mockMoving} />
</ConfigProvider>,
);
await doMove(container, 0, { clientX: -80 });
expect(mockMoving).toHaveBeenNthCalledWith(1, [70, 30], 0);
await doMove(container, 0, { clientX: 40 });
expect(mockMoving).toHaveBeenNthCalledWith(2, [60, 40], 0);
});
});