import { mount, render } from 'enzyme'; import React, { useState } from 'react'; import { act } from 'react-dom/test-utils'; import type { BasicLayoutProps } from '@ant-design/pro-layout'; import BasicLayout from '@ant-design/pro-layout'; import { waitForComponentToPaint } from '../util'; describe('BasicLayout', () => { beforeAll(() => { process.env.NODE_ENV = 'TEST'; process.env.USE_MEDIA = 'md'; }); it('🥩 base use', async () => { const html = render(); expect(html).toMatchSnapshot(); }); it('🥩 support loading', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); expect(wrapper.render()).toMatchSnapshot(); }); it('🥩 do not render menu', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); const menu = wrapper.find('.ant-pro-sider'); expect(menu.exists()).toBe(false); const menuContent = wrapper.find('.ant-pro-sider-menu'); expect(menuContent.exists()).toBe(false); expect((wrapper.find('section.ant-layout div.ant-layout').props().style || {}).padding).toBe( undefined, ); act(() => { wrapper.unmount(); }); }); it('🥩 do not render menu content', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); const menu = wrapper.find('.ant-pro-sider'); expect(menu.exists()).toBe(true); const menuContent = wrapper.find('.ant-pro-sider-menu'); expect(menuContent.exists()).toBe(false); act(() => { wrapper.unmount(); }); }); it('🥩 support menuDataRender', async () => { const wrapper = mount( [ { path: '/home', name: '首页', locale: 'menu.home', children: [ { path: '/home/overview', name: '概述', hideInMenu: true, exact: true, locale: 'menu.home.overview', }, { path: '/home/search', name: '搜索', exact: true, hideInMenu: true, locale: 'menu.home.search', }, ], }, { path: '/data_hui', name: '汇总数据', locale: 'menu.data_hui', children: [ { collapsed: true, menuName: '域买家维度交易', name: '域买家维度交易', children: [ { id: 2, isNavHome: '2', itemId: '191020104', itemName: '_交易_买家_月表', tab: 'adm_rk_cr_tb_trd_byr_ms', tabProj: 'alifin_odps_birisk', name: '_交易_买家_月表', path: '/data_hui1?tableName=adm_rk_cr_tb_trd_byr_ms&tableSchema=alifin_odps_birisk', }, { id: 3, isNavHome: '3', name: '_航旅交易_买家_日表', path: '/data_hui2?tableName=adm_rk_cr_tb_trv_byr_ds&tableSchema=alifin_odps_birisk', }, ], }, { collapsed: true, name: '域买家维度交易2', children: [ { id: 5, name: '_交易_买家_月表', path: '/data_hui3?tableName=adm_rk_cr_tb_trd_byr_ms&tableSchema=alifin_odps_birisk', }, { id: 6, name: '_航旅交易_买家_日表', path: '/data_hui4?tableName=adm_rk_cr_tb_trv_byr_ds&tableSchema=alifin_odps_birisk', }, ], }, { collapsed: true, name: '域买家维度交易3', children: [ { id: 7, name: '_交易_买家_月表2', path: '/data_hui5?tableName=adm_rk_cr_tb_trd_byr_ms&tableSchema=alifin_odps_birisk', }, { id: 8, name: '_航旅交易_买家_日表3', path: '/data_hui6?tableName=adm_rk_cr_tb_trv_byr_ds&tableSchema=alifin_odps_birisk', }, ], }, ], }, { path: '/data_ming', name: '明细数据', locale: 'menu.data_ming', }, { path: '/other', name: '其他', locale: 'menu.other', children: [ { path: '/other/upLoad', name: 'odps同步导入', exact: true, locale: 'menu.other.upLoad', hideInMenu: true, }, { path: '/other/upLoadMenu', name: '菜单导入', exact: true, locale: 'menu.other.upLoadMenu', hideInMenu: true, }, { path: '/other/homeEdit', name: '概述编辑', exact: true, locale: 'menu.other.homeEdit', hideInMenu: true, }, ], }, ] as any } />, ); await waitForComponentToPaint(wrapper); expect(wrapper.render()).toMatchSnapshot(); }); it('🥩 do not render footer', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); const footer = wrapper.find('footer'); expect(footer.exists()).toBe(false); act(() => { wrapper.unmount(); }); }); it('🥩 menuDataRender change date', async () => { const wrapper = mount( []} />); await waitForComponentToPaint(wrapper, 100); expect(wrapper.find('ul.ant-pro-sider-menu').exists()).toBeFalsy(); act(() => { wrapper.setProps({ menuDataRender: () => [ { path: '/home', name: '首页', children: [ { path: '/home/overview', name: '概述', exact: true, }, { path: '/home/search', name: '搜索', exact: true, }, ], }, ], }); }); await waitForComponentToPaint(wrapper, 1000); expect(wrapper.find('ul.ant-pro-sider-menu').exists()).toBeTruthy(); }); it('🥩 use onLogoClick', async () => { const onLogoClick = jest.fn(); const wrapper = mount( Logo } />, ); await waitForComponentToPaint(wrapper); const logo = wrapper.find('#test_log'); act(() => { logo.simulate('click'); }); expect(onLogoClick).toHaveBeenCalled(); act(() => { wrapper.unmount(); }); }); it('🥩 render logo', async () => { const wrapper = mount(Logo} />); await waitForComponentToPaint(wrapper); const logo = wrapper.find('#test_log'); expect(logo.text()).toEqual('Logo'); act(() => { wrapper.unmount(); }); }); it('🥩 render logo by function', async () => { const wrapper = mount(
Logo
} />); await waitForComponentToPaint(wrapper); const logo = wrapper.find('#test_log'); expect(logo.text()).toEqual('Logo'); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 onCollapse', async () => { const onCollapse = jest.fn(); const wrapper = mount(); await waitForComponentToPaint(wrapper); wrapper.find('li.ant-pro-sider-collapsed-button').map((item) => item && item.simulate('click')); expect(onCollapse).toHaveBeenCalled(); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 siderWidth default', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); expect(wrapper.find('.ant-pro-sider').get(1).props.width).toBe(208); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 siderWidth=160', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); expect(wrapper.find('.ant-pro-sider').get(1).props.width).toBe(160); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 do not render collapsed button', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); expect(wrapper.find('.ant-pro-sider-collapsed-button').exists()).toBe(false); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 when renderMenu=false, do not render collapsed button', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); expect(wrapper.find('.ant-pro-sider-collapsed-button').exists()).toBe(false); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 render customize collapsed button', async () => { const wrapper = mount( ( {`${collapsed}`} )} />, ); await waitForComponentToPaint(wrapper); const dom = wrapper.find('#customize_collapsed_button'); expect(dom.text()).toEqual('false'); act(() => { wrapper.setProps({ collapsed: true, }); }); await waitForComponentToPaint(wrapper); expect(dom.text()).toEqual('true'); }); it('🥩 do not render menu header', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); const dom = wrapper.find('#logo'); expect(dom.exists()).toBe(false); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 customize render menu header', async () => { const wrapper = mount( (
{logo} {title}
customize_menu_header
)} />, ); await waitForComponentToPaint(wrapper); const dom = wrapper.find('#customize_menu_header'); expect(dom.exists()).toBe(true); expect(dom.find('#customize_menu_header_text').text()).toEqual('customize_menu_header'); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 contentStyle should change dom', async () => { const wrapper = render( , ); expect(wrapper).toMatchSnapshot(); }); it('🥩 support className', async () => { const wrapper = mount( , ); expect(wrapper.find('div.chenshuai2144').exists()).toBeTruthy(); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 support links', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); const dom = wrapper.find('.ant-pro-sider-link'); expect(dom.exists()).toBeTruthy(); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 do no render links', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); const dom = wrapper.find('.ant-pro-sider-link'); expect(dom.exists()).toBeFalsy(); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 pure style', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); const menu = wrapper.find('.ant-pro-sider-menu'); expect(menu.exists()).toBe(false); const dom = wrapper.find('.ant-pro-sider-link'); expect(dom.exists()).toBeFalsy(); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 set page title render', async () => { const wrapper = mount( { if (info) { return info.pageName; } return pageName || 'ant'; }} />, ); await waitForComponentToPaint(wrapper); const dom = wrapper.find('.ant-pro-sider-link'); expect(dom.exists()).toBeFalsy(); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 onPageChange', async () => { const onPageChange = jest.fn(); const wrapper = mount( , ); await waitForComponentToPaint(wrapper); act(() => { wrapper.setProps({ location: { pathname: '/name', }, }); }); expect(onPageChange).toBeCalled(); await waitForComponentToPaint(wrapper); act(() => { wrapper.unmount(); }); }); it('🥩 headerTitleRender ', async () => { const wrapper = mount(

mix title

} layout="mix" location={{ pathname: '/', }} />, ); await waitForComponentToPaint(wrapper); expect(wrapper.find('h2#mix-test').text()).toBe('mix title'); }); it('🥩 onMenuHeaderClick', async () => { const onMenuHeaderClick = jest.fn(); const wrapper = mount( , ); await waitForComponentToPaint(wrapper); act(() => { wrapper.find('div.ant-pro-global-header-logo').simulate('click'); }); expect(onMenuHeaderClick).toBeCalled(); }); it('🥩 fixSider and collapsed should have different style', async () => { const wrapper = mount(); await waitForComponentToPaint(wrapper); let dom = wrapper.find('.ant-pro-fixed-header'); expect(dom.exists()).toBeFalsy(); act(() => { wrapper.setProps({ fixedHeader: true, }); }); await waitForComponentToPaint(wrapper); dom = wrapper.find('header.ant-pro-fixed-header'); expect(dom.exists()).toBeTruthy(); expect(dom.props()?.style?.width).toBe('calc(100% - 48px)'); act(() => { wrapper.setProps({ fixedHeader: true, collapsed: false, }); }); dom = wrapper.find('header.ant-pro-fixed-header'); expect(dom.props()?.style?.width).toBe('calc(100% - 208px)'); act(() => { wrapper.setProps({ fixedHeader: true, collapsed: false, siderWidth: 120, }); }); dom = wrapper.find('header.ant-pro-fixed-header'); expect(dom.props()?.style?.width).toBe('calc(100% - 120px)'); act(() => { wrapper.setProps({ fixedHeader: true, collapsed: false, menuRender: false, }); }); dom = wrapper.find('header.ant-pro-fixed-header'); expect(dom.props()?.style?.width).toBe('100%'); act(() => { wrapper.setProps({ fixedHeader: true, layout: 'top', }); }); dom = wrapper.find('header.ant-pro-fixed-header'); expect(dom.props()?.style?.width).toBe('100%'); }); it('🥩 renderPageTitle return value should is string', async () => { const renderPageTitle = jest.fn(); const wrapper = mount( { renderPageTitle(); return 1221; }} location={{ pathname: '/', }} />, ); await waitForComponentToPaint(wrapper); expect(renderPageTitle).toBeCalled(); }); it('🥩 rightContentRender should work in top', async () => { const wrapper = mount(
right
} layout="top" location={{ pathname: '/', }} />, ); await waitForComponentToPaint(wrapper); act(() => { wrapper.setProps({ rightContentRender: () => (
right
), }); }); expect(wrapper.find('#layout_right').exists()).toBeTruthy(); }); it('🥩 support get config form menuItem', async () => { const wrapper = mount( [ { path: '/home/overview', name: '概述', exact: true, layout: 'side', }, { path: '/home/search', name: '搜索', exact: true, layout: 'mix', navTheme: 'light', }, { path: '/home', name: '首页', layout: 'top', }, ]} />, ); await waitForComponentToPaint(wrapper, 100); expect( wrapper.find('.ant-design-pro').props().className?.includes('ant-pro-basicLayout-side'), ).toBeTruthy(); act(() => { wrapper.setProps({ location: { pathname: '/home/search', }, }); }); await waitForComponentToPaint(wrapper, 100); expect( wrapper.find('.ant-design-pro').props().className?.includes('ant-pro-basicLayout-mix'), ).toBeTruthy(); act(() => { wrapper.setProps({ location: { pathname: '/home', }, }); }); await waitForComponentToPaint(wrapper, 100); expect( wrapper.find('.ant-design-pro').props().className?.includes('ant-pro-basicLayout-top'), ).toBeTruthy(); }); it('🥩 mix layout hideInMenu render right', async () => { const wrapper = mount( [ { path: '/welcome', name: '欢迎', hideInMenu: true, }, { path: '/admin', name: '管理页', routes: [ { path: '/admin/sub-page1', name: '一级页面', }, { path: '/admin/sub-page2', name: '二级页面', }, { path: '/admin/sub-page3', name: '三级页面', }, ], }, { name: '列表页', path: '/list', }, ]} />, ); await waitForComponentToPaint(wrapper); expect(wrapper.render()).toMatchSnapshot(); }); it('🥩 BasicLayout menu support menu.true', async () => { const wrapper = render( <> [ { path: '/welcome', name: '欢迎', }, { name: '列表页', path: '/list', }, ]} /> [ { path: '/welcome', name: '欢迎', }, { name: '列表页', path: '/list', }, ]} /> [ { path: '/welcome', name: '欢迎', }, { name: '列表页', path: '/list', }, ]} /> , ); expect(wrapper).toMatchSnapshot(); }); it('🥩 BasicLayout support current menu', async () => { const wrapper = mount( [ { path: '/welcome', name: '欢迎', layout: {}, }, ]} />, ); await waitForComponentToPaint(wrapper); expect(wrapper.find('.ant-pro-basicLayout-side').exists()).toBeTruthy(); act(() => { wrapper.setProps({ menu: { loading: true, }, menuDataRender: () => [ { path: '/welcome', name: '欢迎', layout: 'top', }, ], }); }); await waitForComponentToPaint(wrapper); wrapper.setProps({ menu: { loading: false, }, menuDataRender: () => [ { path: '/welcome', name: '欢迎', layout: 'top', }, ], }); await waitForComponentToPaint(wrapper, 100); expect(wrapper.find('.ant-pro-basicLayout-top').exists()).toBeTruthy(); }); it('🥩 BasicLayout menu support autoClose', async () => { const Demo = () => { const [pathname, setPathname] = useState('/admin/sub-page1'); return ( ( { item.onClick(); setPathname(item.path || '/welcome'); }} > {dom} )} menuDataRender={() => [ { path: '/admin', name: '管理页', routes: [ { path: '/admin/sub-page1', name: '一级页面', }, { path: '/admin/sub-page2', name: '二级页面', }, { path: '/admin/sub-page3', name: '三级页面', }, ], }, { name: '列表页', icon: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg', path: '/list', routes: [ { path: '/list/sub-page', name: '一级列表页面', }, { path: '/list/sub-page2', name: '二级列表页面', }, { path: 'https://ant.design', name: 'antd', }, ], }, ]} /> ); }; const html = mount(); await waitForComponentToPaint(html); expect(html.find('li.ant-menu-submenu').length).toBe(2); act(() => { html.find('li.ant-menu-submenu').at(1).find('div.ant-menu-submenu-title').simulate('click'); }); await waitForComponentToPaint(html, 100); act(() => { html.find('ul.ant-menu-sub').at(1).find('.ant-menu-item-only-child').at(1).simulate('click'); }); await waitForComponentToPaint(html, 100); act(() => { html.find('span.ant-pro-menu-item-link').simulate('click'); }); expect(html.find('li.ant-menu-submenu-open').length).toBe(2); }); it('🥩 BasicLayout menu support onSelect', async () => { const fn = jest.fn(); const Demo = () => { const [pathname, setPathname] = useState('/admin/sub-page1'); return ( ( { item.onClick(); setPathname(item.path || '/welcome'); }} > {dom} )} menuDataRender={() => [ { path: '/admin', name: '管理页', routes: [ { path: '/admin/sub-page1', name: '一级页面', }, { path: '/admin/sub-page2', name: '二级页面', }, { path: '/admin/sub-page3', name: '三级页面', }, ], }, { name: '列表页', path: '/list', routes: [ { path: '/list/sub-page', name: '一级列表页面', }, { path: '/list/sub-page2', name: '二级列表页面', }, { path: '/list/sub-page3', name: 'antd', }, ], }, ]} /> ); }; const html = mount(); await waitForComponentToPaint(html); act(() => { html.find('li.ant-menu-submenu').at(1).find('div.ant-menu-submenu-title').simulate('click'); }); await waitForComponentToPaint(html, 100); act(() => { html.find('ul.ant-menu-sub').at(1).find('.ant-menu-item-only-child').at(1).simulate('click'); }); await waitForComponentToPaint(html, 100); expect(fn).toBeCalled(); }); it('🥩 BasicLayout support menu.request', async () => { const fn = jest.fn(); const actionRef = React.createRef< | { reload: () => void; } | undefined >(); const Demo = () => { return ( { fn(); return [ { path: '/admin', name: '管理页', routes: [ { path: '/admin/sub-page1', name: '一级页面', }, { path: '/admin/sub-page2', name: '二级页面', }, { path: '/admin/sub-page3', name: '三级页面', }, ], }, { name: '列表页', path: '/list', routes: [ { path: '/list/sub-page', name: '一级列表页面', }, { path: '/list/sub-page2', name: '二级列表页面', }, { path: '/list/sub-page3', name: 'antd', }, ], }, ]; }, }} /> ); }; const html = mount(); await waitForComponentToPaint(html, 1000); expect(fn).toBeCalledTimes(1); actionRef.current?.reload(); expect(fn).toBeCalledTimes(2); }); it('🥩 BasicLayout support menu.params', async () => { const fn = jest.fn(); const defaultMenu = { locale: false, params: {}, request: async (params: Record) => { fn(params); return [ { path: '/admin', name: '管理页', }, { name: '列表页', path: '/list', }, ]; }, }; const html = mount(); await waitForComponentToPaint(html, 1000); expect(fn).toBeCalledTimes(1); act(() => { html.setProps({ menu: { ...defaultMenu, params: { id: '1212', }, }, }); }); await waitForComponentToPaint(html, 100); expect(fn).toBeCalledTimes(2); expect(fn).toBeCalledWith({ id: '1212', }); act(() => { html.setProps({ menu: { ...defaultMenu, params: { id: '123', }, }, }); }); await waitForComponentToPaint(html, 100); expect(fn).toBeCalledTimes(3); expect(fn).toBeCalledWith({ id: '123', }); act(() => { html.setProps({ menu: { ...defaultMenu, params: { id: '123', }, }, }); }); await waitForComponentToPaint(html, 100); expect(fn).toBeCalledTimes(3); }); });