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; const SplitterDemo = ({ items = [{}, {}], ...props }: { items?: PanelProps[] } & SplitterProps) => ( {items?.map((item, idx) => ( // eslint-disable-next-line react/no-array-index-key {idx} ))} ); 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(); 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( , ); 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(); expect(container?.querySelector('.ant-splitter-horizontal')).toBeTruthy(); rerender(); expect(container?.querySelector('.ant-splitter-vertical')).toBeTruthy(); }); it('The resizable should work fine.', () => { const { container } = render( , ); expect(container?.querySelectorAll('.ant-splitter-bar-resizable')?.length).toBe(1); }); it('The collapsible should work fine.', () => { const { container, rerender } = render( , ); 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( , ); 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( , ); // 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( , ); // 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( , ); // 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( , , ); // 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( , ); 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(); 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( , ); 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); }); });