import { Icon, Dropdown, Tag } from '../../index'; import { string } from 'prop-types'; import { noop, drop } from 'lodash'; import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants'; const defaultItems = [{ children: 'Menu Item 1' }, { children: 'Menu Item 2' }, { children: 'Menu Item 3' }]; function getSubMenu(items = defaultItems) { let dropdownItems = items.map(item => ); return {dropdownItems}; } function getDD(props) { let bcProps = { // Dropdown use Popup Layer to show candidate option, // but all Popup Layer which extends from Tooltip (eg Popover, Dropdown) have animation and delay. // Turn off animation and delay during testing, to avoid wating (something like setTimeOut/balabala...) in the test code motion: false, mouseEnterDelay: 0, mouseLeaveDelay: 0, render: getSubMenu(), children: semi dropdown, ...props, }; return mount(, { attachTo: document.getElementById('container'), }); } let el_portal_inner = `.${BASE_CLASS_PREFIX}-portal-inner`; let el_item = `.${BASE_CLASS_PREFIX}-dropdown-item`; describe('Dropdown', () => { beforeEach(() => { document.body.innerHTML = ''; // Avoid `attachTo: document.body` Warning const div = document.createElement('div'); div.setAttribute('id', 'container'); document.body.appendChild(div); }); afterEach(() => { const div = document.getElementById('container'); if (div) { document.body.removeChild(div); } }); it('Dropdown-custom className & style', () => { let props = { visible: true, trigger: 'custom', className: 'test', style: { color: 'red', }, }; const dropdown = getDD(props); expect(dropdown.exists(`.${BASE_CLASS_PREFIX}-dropdown-wrapper.test`)).toEqual(true); expect(dropdown.find(`.${BASE_CLASS_PREFIX}-dropdown`)).toHaveStyle('color', 'red'); }); // Dropdown can't find `.${BASE_CLASS_PREFIX}-portal` (can confirm it't existence through documenty.body.innerHTML) // but find `.${BASE_CLASS_PREFIX}-portal-inner` // 由于.${BASE_CLASS_PREFIX}-portal 不是有dropdown或其子元素的render函数渲染出来的dom,而是portal在constructore阶段通过createElement/appendChild 插入的,所以无法使用find来找 // 只能通过document.querySelector来获取 it('Dropdown-zIndex', () => { let zIndex = 2000; let props = { visible: true, trigger: 'custom', zIndex: zIndex, }; const dropdown = getDD(props); expect(Number(document.querySelector(`.${BASE_CLASS_PREFIX}-portal`).style.zIndex)).toEqual(zIndex); }); it('Dropdown-trigger-hover', () => { let props = { trigger: 'hover', }; const dropdown = getDD(props); // Before hover, dropdown is not displayed expect(dropdown.exists(el_portal_inner)).toEqual(false); // After trigger, dropdown content will show dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('mouseEnter', {}); expect(dropdown.exists(el_portal_inner)).toEqual(true); expect(dropdown.find(el_item)).toHaveLength(3); // auto hide dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('mouseLeave', {}); expect(dropdown.exists(el_portal_inner)).toEqual(false); expect(dropdown.find(el_item)).toHaveLength(0); }); it('Dropdown-trigger-click', () => { let props = { trigger: 'click', }; const dropdown = getDD(props); // Before click expect(dropdown.exists(el_portal_inner)).toEqual(false); expect(dropdown.exists(el_item)).toEqual(false); // After click dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('click', {}); expect(dropdown.exists(el_portal_inner)).toEqual(true); expect(dropdown.find(el_item)).toHaveLength(3); }); it('Dropdown-contentClassName', () => { let props = { contentClassName: 'test', trigger: 'custom', visible: true, }; const dd = getDD(props); expect(dd.exists(`.${BASE_CLASS_PREFIX}-dropdown.test`)).toEqual(true); }); // TODO ??? visibleChange在Jest中没有被触发,实际上代码是work的 // it('Dropdown-onVisibleChange', () => { // let onVisibleChange = visible => { // debugger; // }; // // let spyVisibleChange = sinon.spy(onVisibleChange); // let props = { // trigger: 'hover', // onVisibleChange: onVisibleChange, // }; // const dropdown = getDD(props); // dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('mouseEnter', {}); // expect(spyVisibleChange.calledOnce).toBe(true); // expect(spyVisibleChange.calledWithMatch(true)).toBe(true); // dropdown.find(`.${BASE_CLASS_PREFIX}-tag`).simulate('mouseLeave', {}); // expect(spyVisibleChange.calledWithMatch(false)).toBe(true); // }); // it('Dropdown-clickToHide', () => { // let props = { // clickToHide: true, // }; // }); it('Dropdown-showTick', () => { let items = [{ children: 'Item 1' }, { active: true, children: 'Item 2' }, { children: 'Item 3' }]; let props = { showTick: true, render: getSubMenu(items), visible: true, trigger: 'custom', }; let DD = getDD(props); expect(DD.find(`.${BASE_CLASS_PREFIX}-dropdown-item-withTick.${BASE_CLASS_PREFIX}-dropdown-item-active`).text()).toEqual('Item 2'); }); it('Dropdown.Item active', () => { let items = [{ children: 'Item 1' }, { active: true, children: 'Item 2' }, { children: 'Item 3' }]; let props = { render: getSubMenu(items), visible: true, trigger: 'custom', }; let DD = getDD(props); expect(DD.find(`.${BASE_CLASS_PREFIX}-dropdown-item-active`).text()).toEqual('Item 2'); }); it('Dropdown.Item type', () => { let types = ['primary', 'secondary', 'tertiary', 'warning', 'danger']; let items = types.map(type => { return { type, children: `${type}Item` }; }); let props = { render: getSubMenu(items), trigger: 'custom', visible: true, }; let DD = getDD(props); items.forEach(item => { expect(DD.find(`.${BASE_CLASS_PREFIX}-dropdown-item-${item.type}`).text()).toEqual(`${item.children}`); }); }); it('Dropdown.Item className & style', () => { let items = [ { type: 'primary', children: 'primaryItem', className: 'primary-test', style: { color: 'red' } }, { type: 'secondary', children: 'secondaryItem' }, ]; let props = { render: getSubMenu(items), trigger: 'custom', visible: true, }; let DD = getDD(props); expect(DD.find('li.primary-test')).toHaveStyle('color', 'red'); }); it('Dropdown.Item disabled', () => { let items = [ { disabled: true, children: 'Item 1' }, { disabled: false, children: 'Item 2' }, ]; let props = { render: getSubMenu(items), trigger: 'custom', visible: true, }; let DD = getDD(props); expect(DD.find(`.${BASE_CLASS_PREFIX}-dropdown-item-disabled`).text()).toEqual('Item 1'); }); it('Dropdown.Item onClick', () => { let onClick = event => {}; let spyItemCLick = sinon.spy(onClick); let items = [{ children: 'A' }, { children: 'B', onClick: spyItemCLick, className: 'test' }]; let props = { render: getSubMenu(items), trigger: 'custom', visible: true, }; let DD = getDD(props); let targetItem = DD.find('li.test'); let event = { target: { value: 'B1', }, }; targetItem.simulate('click', event); expect(spyItemCLick.calledOnce).toEqual(true); expect(spyItemCLick.calledWithMatch(event)).toEqual(true); }); it('Dropdown.Item onMouseEnter/onMouseLeave', () => { let onMouseEnter = e => {}; let spyItemMouseEnter = sinon.spy(onMouseEnter); let spyItemMouseLeave = sinon.spy(e => {}); let items = [ { children: 'A' }, { children: 'B', onMouseEnter: spyItemMouseEnter, onMouseLeave: spyItemMouseLeave, className: 'test' }, ]; let props = { render: getSubMenu(items), trigger: 'custom', visible: true, }; let DD = getDD(props); let targetItem = DD.find('li.test'); let event = { target: { value: 'B1', }, }; targetItem.simulate('mouseEnter', event); expect(spyItemMouseEnter.calledOnce).toEqual(true); expect(spyItemMouseEnter.calledWithMatch(event)).toEqual(true); targetItem.simulate('mouseLeave', event); expect(spyItemMouseLeave.calledOnce).toEqual(true); expect(spyItemMouseLeave.calledWithMatch(event)).toEqual(true); }); it('Dropdown.Title className & style', () => { let props = { render: ( 分组1 primary secondary 分组2 danger ), trigger: 'custom', visible: true, }; let DD = getDD(props); expect(DD.find('div.test')).toHaveStyle('margin', 5); }); it('Dropdown array menu', () => { const menu = [ { node: 'title', name: '分组1' }, { node: 'item', name: 'primary1', type: 'primary', onClick: () => console.log('click primary') }, { node: 'item', name: 'secondary', type: 'secondary' }, { node: 'divider', }, { node: 'title', name: '分组2' }, { node: 'item', name: 'tertiary', type: 'tertiary' }, { node: 'item', name: 'warning', type: 'warning', active: true }, { node: 'item', name: 'danger', type: 'danger' }, ]; let DD = mount(, { attachTo: document.getElementById('container'), }); expect(DD.find('.semi-dropdown-menu').children().length).toEqual(menu.length); const menu2 = [ { node: 'title', name: '分组1', iconType: 'menu' }, { node: 'item', name: 'secondary', type: 'secondary' }, { node: 'divider', }, { node: 'title', name: '分组2' }, { node: 'invalid node', name: '分组2' }, ]; DD.setProps({ menu: menu2 }) DD.update() expect(DD.find('.semi-dropdown-menu').children().length).toEqual(menu2.length - 1); }); });