import React, { useState } from 'react'; import { mount } from 'enzyme'; import { MailOutlined, InboxOutlined, AppstoreOutlined, PieChartOutlined, UserOutlined, } from '@ant-design/icons'; import Menu from '..'; import Layout from '../../layout'; import Tooltip from '../../tooltip'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; import { resetWarned } from '../../_util/warning'; const { SubMenu } = Menu; describe('Menu', () => { mountTest(() => ( )); rtlTest(() => ( )); beforeEach(() => { jest.useFakeTimers(); }); afterEach(() => { jest.useRealTimers(); }); it('If has select nested submenu item ,the menu items on the grandfather level should be highlight', () => { const wrapper = mount( Option 1 Option 2 Option 3 Option 4 menu2 , ); expect(wrapper.find('.ant-menu-submenu-selected').length).toBe(1); }); it('should accept defaultOpenKeys in mode horizontal', () => { const wrapper = mount( Option 1 Option 2 menu2 , ); expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true); }); it('should accept defaultOpenKeys in mode inline', () => { const wrapper = mount( Option 1 Option 2 menu2 , ); expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true); }); it('should accept defaultOpenKeys in mode vertical', () => { const wrapper = mount( Option 1 Option 2 menu2 , ); expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true); }); it('horizontal', () => { const wrapper = mount( Option 1 Option 2 menu2 , ); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).not.toBe( true, ); wrapper.setProps({ openKeys: [] }); wrapper.update(); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).toBe(true); wrapper.setProps({ openKeys: ['1'] }); wrapper.update(); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).not.toBe( true, ); }); it('inline', () => { const wrapper = mount( Option 1 Option 2 menu2 , ); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).not.toBe( true, ); wrapper.setProps({ openKeys: [] }); wrapper.update(); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).toBe(true); wrapper.setProps({ openKeys: ['1'] }); wrapper.update(); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).not.toBe( true, ); }); it('vertical', () => { const wrapper = mount( Option 1 Option 2 menu2 , ); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).not.toBe( true, ); wrapper.setProps({ openKeys: [] }); wrapper.update(); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).toBe(true); wrapper.setProps({ openKeys: ['1'] }); wrapper.update(); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).not.toBe( true, ); }); // https://github.com/ant-design/ant-design/pulls/4677 // https://github.com/ant-design/ant-design/issues/4692 // TypeError: Cannot read property 'indexOf' of undefined it('pr #4677 and issue #4692', () => { const wrapper = mount( menu1 menu2 , ); wrapper.update(); // just expect no error emit }); it('should always follow openKeys when mode is switched', () => { const wrapper = mount( Option 1 Option 2 menu2 , ); expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(false); wrapper.setProps({ mode: 'vertical' }); expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(false); wrapper.setProps({ mode: 'inline' }); expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(false); }); it('should always follow openKeys when inlineCollapsed is switched', () => { const wrapper = mount( Option Option Option , ); expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-inline')).toBe(true); expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(false); wrapper.setProps({ inlineCollapsed: true }); // 动画结束后套样式; jest.runAllTimers(); wrapper.update(); wrapper.simulate('transitionEnd', { propertyName: 'width' }); expect(wrapper.find('ul.ant-menu-root').at(0).hasClass('ant-menu-vertical')).toBe(true); expect(wrapper.find('ul.ant-menu-sub').length).toBe(0); wrapper.setProps({ inlineCollapsed: false }); jest.runAllTimers(); wrapper.update(); expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-inline')).toBe(true); expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(false); }); it('inlineCollapsed should works well when specify a not existed default openKeys', () => { const wrapper = mount( Option Option Option , ); expect(wrapper.find('.ant-menu-sub').length).toBe(0); wrapper.setProps({ inlineCollapsed: true }); jest.runAllTimers(); wrapper.update(); wrapper.simulate('transitionEnd', { propertyName: 'width' }); wrapper.find('.ant-menu-submenu-title').at(0).simulate('mouseEnter'); jest.runAllTimers(); wrapper.update(); expect(wrapper.find('.ant-menu-submenu').at(0).hasClass('ant-menu-submenu-vertical')).toBe( true, ); expect(wrapper.find('.ant-menu-submenu').at(0).hasClass('ant-menu-submenu-open')).toBe(true); expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-vertical')).toBe(true); expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(false); }); it('inlineCollapsed Menu.Item Tooltip can be removed', () => { const wrapper = mount( node.parentNode} > item item item item item item , ); expect(wrapper.find(Menu.Item).at(0).find(Tooltip).props().title).toBe('item'); expect(wrapper.find(Menu.Item).at(1).find(Tooltip).props().title).toBe('title'); expect(wrapper.find(Menu.Item).at(2).find(Tooltip).props().title).toBe('item'); expect(wrapper.find(Menu.Item).at(3).find(Tooltip).props().title).toBe(null); expect(wrapper.find(Menu.Item).at(4).find(Tooltip).props().title).toBe(''); expect(wrapper.find(Menu.Item).at(4).find(Tooltip).props().title).toBe(''); }); describe('open submenu when click submenu title', () => { beforeEach(() => { jest.useFakeTimers(); }); afterEach(() => { jest.useRealTimers(); }); const toggleMenu = (wrapper, index, event) => { wrapper.find('.ant-menu-submenu-title').at(index).simulate(event); jest.runAllTimers(); wrapper.update(); }; it('inline', () => { const wrapper = mount( Option 1 Option 2 menu2 , ); expect(wrapper.find('.ant-menu-sub').length).toBe(0); toggleMenu(wrapper, 0, 'click'); expect(wrapper.find('.ant-menu-sub').hostNodes().length).toBe(1); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).not.toBe( true, ); toggleMenu(wrapper, 0, 'click'); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).toBe( true, ); }); it('vertical', () => { const wrapper = mount( Option 1 Option 2 menu2 , ); expect(wrapper.find('.ant-menu-sub').length).toBe(0); toggleMenu(wrapper, 0, 'mouseenter'); expect(wrapper.find('.ant-menu-sub').hostNodes().length).toBe(1); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).not.toBe( true, ); toggleMenu(wrapper, 0, 'mouseleave'); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).toBe( true, ); }); it('horizontal', () => { jest.useFakeTimers(); const wrapper = mount( Option 1 Option 2 menu2 , ); expect(wrapper.find('.ant-menu-sub').length).toBe(0); toggleMenu(wrapper, 0, 'mouseenter'); expect(wrapper.find('.ant-menu-sub').hostNodes().length).toBe(1); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).not.toBe( true, ); toggleMenu(wrapper, 0, 'mouseleave'); expect(wrapper.find('.ant-menu-sub').hostNodes().at(0).hasClass('ant-menu-hidden')).toBe( true, ); }); }); it('inline title', () => { jest.useFakeTimers(); const wrapper = mount( Option 1 test , ); wrapper.find('.ant-menu-item').simulate('mouseenter'); jest.runAllTimers(); wrapper.update(); const text = wrapper.find('.ant-tooltip-inner').text(); expect(text).toBe('bamboo lucky'); jest.useRealTimers(); }); it('render correctly when using with Layout.Sider', () => { class Demo extends React.Component { state = { collapsed: false, }; onCollapse = collapsed => this.setState({ collapsed }); render() { const { collapsed } = this.state; return (
User } > Tom Bill Alex ); } } const wrapper = mount(); wrapper.find('.ant-menu-submenu-title').simulate('click'); wrapper.find('.ant-layout-sider-trigger').simulate('click'); jest.runAllTimers(); wrapper.update(); expect(wrapper.find('.ant-menu-submenu-popup').length).toBe(0); }); it('onMouseEnter should work', () => { const onMouseEnter = jest.fn(); const wrapper = mount( Navigation One Navigation Two , ); wrapper.find('Menu').at(1).simulate('mouseenter'); expect(onMouseEnter).toHaveBeenCalled(); }); describe('motion', () => { it('get correct animation type when switched from inline', () => { const wrapper = mount(); wrapper.setProps({ mode: 'horizontal' }); expect(wrapper.find('InternalMenu').instance().getOpenMotionProps('')).toEqual({ motion: { motionName: '' }, }); }); it('warning if use `openAnimation` as object', () => { resetWarned(); const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); mount(); expect(warnSpy).toHaveBeenCalledWith( 'Warning: [antd: Menu] `openAnimation` do not support object. Please use `motion` instead.', ); warnSpy.mockRestore(); }); it('motion object', () => { const motion = { test: true }; const wrapper = mount(); expect(wrapper.find('InternalMenu').instance().getOpenMotionProps('')).toEqual({ motion }); }); it('legacy openTransitionName', () => { const wrapper = mount(); expect(wrapper.find('InternalMenu').instance().getOpenMotionProps('')).toEqual({ openTransitionName: 'legacy', }); }); }); it('MenuItem should not render Tooltip when inlineCollapsed is false', () => { const wrapper = mount( Navigation One Navigation Two Navigation Four - Link , ); wrapper.find('MenuItem').first().simulate('mouseenter'); jest.runAllTimers(); wrapper.update(); expect(wrapper.find('.ant-tooltip-inner').length).toBe(0); }); it('MenuItem should render icon and icon should be the first child when icon exists', () => { const wrapper = mount( }> Navigation One , ); expect(wrapper.find('.ant-menu-item .anticon').hasClass('anticon-mail')).toBe(true); }); it('should controlled collapse work', () => { const wrapper = mount( Option 1 , ); expect(wrapper.render()).toMatchSnapshot(); wrapper.setProps({ inlineCollapsed: true }); expect(wrapper.render()).toMatchSnapshot(); }); it('not title if not collapsed', () => { jest.useFakeTimers(); const wrapper = mount( Option 1 , ); wrapper.find('.ant-menu-item').simulate('mouseenter'); jest.runAllTimers(); wrapper.update(); expect(wrapper.find('.ant-tooltip-inner').length).toBeFalsy(); jest.useRealTimers(); }); it('props#onOpen and props#onClose do not warn anymore', () => { const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); const onOpen = jest.fn(); const onClose = jest.fn(); mount( Option 1 Option 2 menu2 , ); expect(errorSpy.mock.calls.length).toBe(1); expect(errorSpy.mock.calls[0][0]).not.toContain( '`onOpen` and `onClose` are removed, please use `onOpenChange` instead, see: https://u.ant.design/menu-on-open-change.', ); expect(onOpen).not.toHaveBeenCalled(); expect(onClose).not.toHaveBeenCalled(); }); // https://github.com/ant-design/ant-design/issues/18825 // https://github.com/ant-design/ant-design/issues/8587 it('should keep selectedKeys in state when collapsed to 0px', () => { jest.useFakeTimers(); const wrapper = mount( Option 1 Option 2 Option 4 , ); expect(wrapper.find('.ant-menu-item-selected').getDOMNode().textContent).toBe('Option 1'); wrapper.find('.ant-menu-item').at(1).simulate('click'); expect(wrapper.find('.ant-menu-item-selected').getDOMNode().textContent).toBe('Option 2'); wrapper.setProps({ inlineCollapsed: true }); jest.runAllTimers(); wrapper.update(); expect( wrapper .find('Trigger') .map(node => node.prop('popupVisible')) .findIndex(node => !!node), ).toBe(-1); wrapper.setProps({ inlineCollapsed: false }); expect(wrapper.find('.ant-menu-item-selected').getDOMNode().textContent).toBe('Option 2'); jest.useRealTimers(); }); it('Menu.Item with icon children auto wrap span', () => { const wrapper = mount( }> Navigation One }> Navigation One } title="Navigation One" /> } title={Navigation One} /> , ); expect(wrapper.render()).toMatchSnapshot(); }); // https://github.com/ant-design/ant-design/issues/23755 it('should trigger onOpenChange when collapse inline menu', () => { const onOpenChange = jest.fn(); function App() { const [inlineCollapsed, setInlineCollapsed] = useState(false); return ( <> menu menu ); } const wrapper = mount(); wrapper.find('button').simulate('click'); expect(onOpenChange).toHaveBeenCalledWith([]); }); });