360 lines
11 KiB
JavaScript
360 lines
11 KiB
JavaScript
/* eslint-disable no-undef */
|
|
import React from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import { mount } from 'enzyme';
|
|
import KeyCode from 'rc-util/lib/KeyCode';
|
|
import Menu, { MenuItem, SubMenu } from '../src';
|
|
|
|
describe('SubMenu', () => {
|
|
beforeAll(() => {
|
|
jest.useFakeTimers();
|
|
});
|
|
|
|
afterAll(() => {
|
|
});
|
|
|
|
function createMenu(props) {
|
|
return (
|
|
<Menu {...props}>
|
|
<SubMenu key="s1" title="submenu1">
|
|
<MenuItem key="s1-1">1</MenuItem>
|
|
<SubMenu key="s1-2" title="submenu1-1">
|
|
<MenuItem key="s1-2-1">2</MenuItem>
|
|
</SubMenu>
|
|
</SubMenu>
|
|
<SubMenu key="s2" title="submenu2">
|
|
<MenuItem key="s2-2">2</MenuItem>
|
|
</SubMenu>
|
|
</Menu>
|
|
);
|
|
}
|
|
|
|
it('don\'t show submenu when disabled', () => {
|
|
const wrapper = mount(
|
|
<Menu mode="vertical">
|
|
<SubMenu key="s" title="submenu" disabled>
|
|
<MenuItem key="1">1</MenuItem>
|
|
</SubMenu>
|
|
</Menu>,
|
|
);
|
|
wrapper.find('.rc-menu-submenu-title').first().simulate('mouseEnter');
|
|
expect(wrapper.instance().store.getState().openKeys).toEqual([]);
|
|
});
|
|
|
|
it('offsets the submenu popover', () => {
|
|
const wrapper = mount(
|
|
<Menu mode="horizontal">
|
|
<SubMenu key="s" title="submenu" popupOffset={[0, 15]}>
|
|
<MenuItem key="1">1</MenuItem>
|
|
</SubMenu>
|
|
</Menu>,
|
|
);
|
|
|
|
const popupAlign = wrapper.find('Trigger').prop('popupAlign');
|
|
expect(popupAlign).toEqual({ offset: [0, 15] });
|
|
});
|
|
|
|
describe('openSubMenuOnMouseEnter and closeSubMenuOnMouseLeave are true', () => {
|
|
it('toggles when mouse enter and leave', () => {
|
|
const wrapper = mount(createMenu());
|
|
|
|
wrapper.find('.rc-menu-submenu-title').first().simulate('mouseEnter');
|
|
jest.runAllTimers();
|
|
expect(wrapper.instance().store.getState().openKeys).toEqual(['s1']);
|
|
|
|
wrapper.find('.rc-menu-submenu-title').first().simulate('mouseLeave');
|
|
jest.runAllTimers();
|
|
expect(wrapper.instance().store.getState().openKeys).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('openSubMenuOnMouseEnter and closeSubMenuOnMouseLeave are false', () => {
|
|
let wrapper;
|
|
|
|
beforeEach(() => {
|
|
wrapper = mount(createMenu({
|
|
triggerSubMenuAction: 'click',
|
|
}));
|
|
});
|
|
|
|
it('toggles when mouse click', () => {
|
|
wrapper.find('.rc-menu-submenu-title').first().simulate('click');
|
|
expect(wrapper.instance().store.getState().openKeys).toEqual(['s1']);
|
|
|
|
wrapper.find('.rc-menu-submenu-title').first().simulate('click');
|
|
expect(wrapper.instance().store.getState().openKeys).toEqual([]);
|
|
});
|
|
});
|
|
|
|
it('fires openChange event', () => {
|
|
const handleOpenChange = jest.fn();
|
|
const wrapper = mount(
|
|
<Menu onOpenChange={handleOpenChange}>
|
|
<MenuItem key="1">1</MenuItem>
|
|
<SubMenu title="s1">
|
|
<MenuItem key="2">2</MenuItem>
|
|
<SubMenu title="s2">
|
|
<MenuItem key="3">3</MenuItem>
|
|
</SubMenu>
|
|
</SubMenu>
|
|
</Menu>,
|
|
);
|
|
|
|
wrapper.find('.rc-menu-submenu-title').at(0).simulate('mouseEnter');
|
|
jest.runAllTimers();
|
|
expect(handleOpenChange).toBeCalledWith(['item_1']);
|
|
|
|
wrapper.update();
|
|
|
|
wrapper.find('.rc-menu-submenu-title').at(1).simulate('mouseEnter');
|
|
jest.runAllTimers();
|
|
expect(handleOpenChange).toBeCalledWith(['item_1', 'item_1-menu-item_1']);
|
|
});
|
|
|
|
describe('mouse events', () => {
|
|
it('mouse enter event on a submenu should not activate first item', () => {
|
|
const wrapper = mount(createMenu({ openKeys: ['s1'] }));
|
|
const title = wrapper.find('.rc-menu-submenu-title').first();
|
|
title.simulate('mouseEnter');
|
|
|
|
jest.runAllTimers();
|
|
wrapper.update();
|
|
|
|
expect(wrapper.find('.rc-menu-sub').first().is('.rc-menu-hidden')).toBe(false);
|
|
expect(wrapper.find('MenuItem').first().props().active).toBe(false);
|
|
});
|
|
|
|
it('click to open a submenu should not activate first item', () => {
|
|
const wrapper = mount(createMenu({ triggerSubMenuAction: 'click' }));
|
|
const subMenuTitle = wrapper.find('.rc-menu-submenu-title').first();
|
|
subMenuTitle.simulate('click');
|
|
|
|
jest.runAllTimers();
|
|
wrapper.update();
|
|
|
|
expect(wrapper.find('.rc-menu-sub').first().is('.rc-menu-hidden')).toBe(false);
|
|
expect(wrapper.find('MenuItem').first().props().active).toBe(false);
|
|
});
|
|
|
|
it('mouse enter/mouse leave on a subMenu item should trigger hooks', () => {
|
|
const onMouseEnter = jest.fn();
|
|
const onMouseLeave = jest.fn();
|
|
const wrapper = mount(
|
|
<Menu openKeys={['s1']}>
|
|
<SubMenu
|
|
key="s1"
|
|
title="submenu1"
|
|
onMouseEnter={onMouseEnter}
|
|
onMouseLeave={onMouseLeave}
|
|
>
|
|
<MenuItem key="s1-1">1</MenuItem>
|
|
</SubMenu>
|
|
</Menu>,
|
|
);
|
|
const subMenu = wrapper.find('.rc-menu-submenu').first();
|
|
|
|
subMenu.simulate('mouseEnter');
|
|
expect(onMouseEnter).toHaveBeenCalledTimes(1);
|
|
|
|
subMenu.simulate('mouseLeave');
|
|
expect(onMouseLeave).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
|
|
describe('key press', () => {
|
|
describe('enter key', () => {
|
|
it('opens menu and active first item', () => {
|
|
const wrapper = mount(createMenu());
|
|
const title = wrapper.find('.rc-menu-submenu-title').first();
|
|
|
|
title.simulate('mouseEnter').simulate('keyDown', { keyCode: KeyCode.ENTER });
|
|
|
|
jest.runAllTimers();
|
|
wrapper.update();
|
|
|
|
expect(wrapper.find('.rc-menu-sub').first().is('.rc-menu-hidden')).toBe(false);
|
|
expect(wrapper.find('MenuItem').first().props().active).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('left & right key', () => {
|
|
it('toggles menu', () => {
|
|
const wrapper = mount(createMenu({ defaultActiveFirst: true }));
|
|
const title = wrapper.find('.rc-menu-submenu-title').first();
|
|
|
|
title.simulate('mouseEnter').simulate('keyDown', { keyCode: KeyCode.LEFT });
|
|
expect(wrapper.instance().store.getState().openKeys).toEqual([]);
|
|
title.simulate('keyDown', { keyCode: KeyCode.RIGHT });
|
|
expect(wrapper.instance().store.getState().openKeys).toEqual(['s1']);
|
|
expect(wrapper.find('MenuItem').first().props().active).toBe(true);
|
|
});
|
|
});
|
|
|
|
it('up & down key', () => {
|
|
const wrapper = mount(createMenu());
|
|
const titles = wrapper.find('.rc-menu-submenu-title');
|
|
|
|
titles.first().simulate('mouseEnter')
|
|
.simulate('keyDown', { keyCode: KeyCode.LEFT })
|
|
.simulate('keyDown', { keyCode: KeyCode.DOWN });
|
|
expect(wrapper.find('.rc-menu-submenu').last().is('.rc-menu-submenu-active')).toBe(true);
|
|
|
|
titles.last().simulate('keyDown', { keyCode: KeyCode.UP });
|
|
expect(wrapper.find('.rc-menu-submenu').first().is('.rc-menu-submenu-active')).toBe(true);
|
|
});
|
|
|
|
it('combined key presses', () => {
|
|
const wrapper = mount(createMenu());
|
|
const titles = wrapper.find('.rc-menu-submenu-title');
|
|
const firstItem = titles.first();
|
|
|
|
// testing keydown event after submenu is closed and then opened again
|
|
firstItem.simulate('mouseEnter')
|
|
.simulate('keyDown', { keyCode: KeyCode.RIGHT })
|
|
.simulate('keyDown', { keyCode: KeyCode.LEFT })
|
|
.simulate('keyDown', { keyCode: KeyCode.RIGHT })
|
|
.simulate('keyDown', { keyCode: KeyCode.DOWN })
|
|
.simulate('keyDown', { keyCode: KeyCode.DOWN })
|
|
.simulate('keyDown', { keyCode: KeyCode.DOWN });
|
|
|
|
expect(
|
|
wrapper
|
|
.find('[title="submenu1-1"]')
|
|
.find('.rc-menu-submenu')
|
|
.first()
|
|
.is('.rc-menu-submenu-active'),
|
|
).toBe(true);
|
|
});
|
|
});
|
|
|
|
it('fires select event', () => {
|
|
const handleSelect = jest.fn();
|
|
const wrapper = mount(createMenu({ onSelect: handleSelect }));
|
|
wrapper.find('.rc-menu-submenu-title').first().simulate('mouseEnter');
|
|
|
|
jest.runAllTimers();
|
|
wrapper.update();
|
|
|
|
wrapper.find('MenuItem').first().simulate('click');
|
|
expect(handleSelect.mock.calls[0][0].key).toBe('s1-1');
|
|
});
|
|
|
|
it('fires select event', () => {
|
|
const wrapper = mount(createMenu());
|
|
wrapper.find('.rc-menu-submenu-title').first().simulate('mouseEnter');
|
|
|
|
jest.runAllTimers();
|
|
wrapper.update();
|
|
|
|
wrapper.find('MenuItem').first().simulate('click');
|
|
expect(wrapper.find('.rc-menu-submenu').first().is('.rc-menu-submenu-selected')).toBe(true);
|
|
});
|
|
|
|
it('fires deselect event for multiple menu', () => {
|
|
const handleDeselect = jest.fn();
|
|
const wrapper = mount(createMenu({
|
|
multiple: true,
|
|
onDeselect: handleDeselect,
|
|
}));
|
|
wrapper.find('.rc-menu-submenu-title').first().simulate('mouseEnter');
|
|
|
|
jest.runAllTimers();
|
|
wrapper.update();
|
|
|
|
wrapper.find('MenuItem').first().simulate('click');
|
|
wrapper.find('MenuItem').first().simulate('click');
|
|
|
|
expect(handleDeselect.mock.calls[0][0].key).toBe('s1-1');
|
|
});
|
|
|
|
describe('horizontal menu', () => {
|
|
it('should automatically adjust width', () => {
|
|
const props = {
|
|
mode: 'horizontal',
|
|
openKeys: ['s1'],
|
|
};
|
|
|
|
const wrapper = mount(
|
|
<Menu {...props}>
|
|
<MenuItem key="1">1</MenuItem>
|
|
<SubMenu title="s1" key="s1">
|
|
<MenuItem key="2">2</MenuItem>
|
|
</SubMenu>
|
|
</Menu>,
|
|
);
|
|
|
|
const subMenuInstance = wrapper.find('SubMenu').first().instance();
|
|
const adjustWidthSpy = jest.spyOn(subMenuInstance, 'adjustWidth');
|
|
|
|
jest.runAllTimers();
|
|
|
|
expect(adjustWidthSpy).toHaveBeenCalledTimes(2);
|
|
});
|
|
});
|
|
|
|
describe('submenu animation', () => {
|
|
const appear = () => {};
|
|
|
|
it('should animate with transition class', () => {
|
|
const wrapper = mount(createMenu({
|
|
openTransitionName: 'fade',
|
|
mode: 'inline',
|
|
}));
|
|
|
|
const title = wrapper.find('.rc-menu-submenu-title').first();
|
|
|
|
title.simulate('click');
|
|
jest.runAllTimers();
|
|
|
|
expect(wrapper.find('Animate').prop('transitionName')).toEqual('fade');
|
|
});
|
|
|
|
it('should animate on initially opened menu', () => {
|
|
const wrapper = mount(createMenu({
|
|
openAnimation: { appear },
|
|
mode: 'inline',
|
|
openKeys: ['s1'],
|
|
}));
|
|
|
|
expect(wrapper.find('Animate').first().prop('animation')).toEqual({ appear });
|
|
});
|
|
|
|
it('should animate with config', () => {
|
|
const wrapper = mount(createMenu({
|
|
openAnimation: { appear },
|
|
mode: 'inline',
|
|
}));
|
|
|
|
const title = wrapper.find('.rc-menu-submenu-title').first();
|
|
|
|
title.simulate('click');
|
|
jest.runAllTimers();
|
|
|
|
expect(wrapper.find('Animate').first().prop('animation')).toEqual({ appear });
|
|
});
|
|
});
|
|
|
|
describe('.componentWillUnmount()', () => {
|
|
it('should invoke hooks', () => {
|
|
const onDestroy = jest.fn();
|
|
const App = props => (
|
|
<Menu>
|
|
{props.show && <SubMenu key="s1" title="submenu1" onDestroy={onDestroy}>
|
|
<MenuItem key="s1-1">1</MenuItem>
|
|
</SubMenu>}
|
|
</Menu>
|
|
);
|
|
|
|
App.propTypes = {
|
|
show: PropTypes.bool,
|
|
};
|
|
|
|
const wrapper = mount(<App show />);
|
|
|
|
wrapper.setProps({ show: false });
|
|
|
|
expect(onDestroy).toHaveBeenCalledWith('s1');
|
|
});
|
|
});
|
|
});
|