import '../mocks/wd-transition.mock' import { mount } from '@vue/test-utils' import { describe, expect, test, vi } from 'vitest' import WdDropMenu from '@/uni_modules/wot-design-uni/components/wd-drop-menu/wd-drop-menu.vue' import WdDropMenuItem from '@/uni_modules/wot-design-uni/components/wd-drop-menu-item/wd-drop-menu-item.vue' import WdPopup from '@/uni_modules/wot-design-uni/components/wd-popup/wd-popup.vue' import WdIcon from '@/uni_modules/wot-design-uni/components/wd-icon/wd-icon.vue' import WdOverlay from '@/uni_modules/wot-design-uni/components/wd-overlay/wd-overlay.vue' import { nextTick } from 'vue' const globalComponents = { WdDropMenu, WdDropMenuItem, WdPopup, WdIcon, WdOverlay } describe('WdDropMenu 和 WdDropMenuItem 集成测试', () => { test('基本渲染和结构', async () => { const wrapper = mount( { template: ` `, data() { return { value1: 0, options1: [ { label: '全部商品', value: 0 }, { label: '新款商品', value: 1 }, { label: '活动商品', value: 2 } ], value2: 'a', options2: [ { label: '默认排序', value: 'a' }, { label: '好评排序', value: 'b' }, { label: '销量排序', value: 'c' } ] } } }, { global: { components: globalComponents } } ) await wrapper.vm.$nextTick() expect(wrapper.find('.wd-drop-menu').exists()).toBe(true) const items = wrapper.findAllComponents(WdDropMenuItem) expect(items.length).toBe(2) expect(wrapper.findAll('.wd-drop-menu__item').length).toBe(2) const titles = wrapper.findAll('.wd-drop-menu__item-title-text') expect(titles[0].text()).toBe('全部商品') expect(titles[1].text()).toBe('默认排序') }) test('WdDropMenuItem 禁用状态', async () => { const wrapper = mount( { template: ` `, data() { return { value1: 0, options1: [{ label: '全部商品', value: 0 }], value2: 'a', options2: [{ label: '默认排序', value: 'a' }] } } }, { global: { components: globalComponents } } ) await wrapper.vm.$nextTick() const items = wrapper.findAll('.wd-drop-menu__item') expect(items[0].classes()).toContain('is-disabled') expect(items[1].classes()).not.toContain('is-disabled') await items[0].trigger('click') const dropMenuItems = wrapper.findAllComponents(WdDropMenuItem) expect(dropMenuItems[0].findComponent(WdPopup).exists()).toBe(false) await items[1].trigger('click') expect(dropMenuItems[1].findComponent(WdPopup).exists()).toBe(true) expect(dropMenuItems[1].findComponent(WdPopup).props('modelValue')).toBe(true) }) test('菜单项自定义标题 (title prop)', async () => { const wrapper = mount( { template: ` `, data() { return { value1: 0, options1: [{ label: '全部商品', value: 0 }] } } }, { global: { components: globalComponents } } ) await wrapper.vm.$nextTick() expect(wrapper.find('.wd-drop-menu__item-title-text').text()).toBe('自定义标题') }) test('点击菜单标题展开/收起菜单项', async () => { const wrapper = mount( { template: ` `, data() { return { value1: 0, options1: [ { label: '全部商品', value: 0 }, { label: '新款商品', value: 1 } ] } } }, { global: { components: globalComponents } } ) await wrapper.vm.$nextTick() const menuItemTitle = wrapper.find('.wd-drop-menu__item') expect(wrapper.findComponent(WdPopup).exists()).toBe(false) await menuItemTitle.trigger('click') expect(wrapper.findComponent(WdPopup).exists()).toBe(true) expect(wrapper.findComponent(WdPopup).props('modelValue')).toBe(true) await menuItemTitle.trigger('click') expect(wrapper.findComponent(WdPopup).exists() && wrapper.findComponent(WdPopup).props('modelValue')).toBe(false) }) test('菜单项展开收起事件 (open/close)', async () => { const onOpen = vi.fn() const onClose = vi.fn() const wrapper = mount( { template: ` `, data() { return { value1: 0, options1: [{ label: '全部商品', value: 0 }] } }, methods: { onOpen, onClose } }, { global: { components: globalComponents } } ) await wrapper.vm.$nextTick() const menuItemTitle = wrapper.find('.wd-drop-menu__item') await menuItemTitle.trigger('click') expect(onOpen).toHaveBeenCalledTimes(1) expect(onClose).not.toHaveBeenCalled() await nextTick() const menuOptions = wrapper.findComponent(WdDropMenuItem).findAll('.wd-drop-item__option') await menuOptions[0].trigger('click') await nextTick() expect(onOpen).toHaveBeenCalledTimes(1) // Should not be called again expect(onClose).toHaveBeenCalledTimes(1) }) test('切换菜单项选项触发 change 和 update:modelValue 事件', async () => { const onChange = vi.fn() const wrapper = mount( { template: ` `, data() { return { value1: 0, options1: [ { label: '全部商品', value: 0 }, { label: '新款商品', value: 1 }, { label: '活动商品', value: 2 } ] } }, methods: { onChange } }, { global: { components: globalComponents } } ) await wrapper.vm.$nextTick() const menuItemTitle = wrapper.find('.wd-drop-menu__item') await menuItemTitle.trigger('click') // Open the menu await nextTick() const options = wrapper.findAll('.wd-drop-item__option') expect(options.length).toBe(3) await options[1].trigger('click') await nextTick() const itemEmitted = wrapper.findComponent(WdDropMenuItem).emitted() expect(itemEmitted['update:modelValue']).toBeTruthy() expect(itemEmitted['update:modelValue'][0]).toEqual([1]) // Check v-model update expect(onChange).toHaveBeenCalledTimes(1) expect(onChange).toHaveBeenCalledWith({ value: 1, selectedItem: { label: '新款商品', value: 1 } }) expect(menuItemTitle.text()).toBe('新款商品') await nextTick() expect(wrapper.findComponent(WdPopup).exists() && wrapper.findComponent(WdPopup).props('modelValue')).toBe(false) }) test('菜单项 beforeToggle 钩子', async () => { const beforeToggle = vi.fn(({ status, resolve }) => { // console.log('beforeToggle called with status:', status) if (status) { // 只允许打开 resolve(true) } else { // console.log('Preventing close') resolve(false) // 阻止关闭 } }) const wrapper = mount( { template: ` `, data() { return { value1: 0, options1: [{ label: '全部商品', value: 0 }] } }, methods: { beforeToggle } }, { global: { components: globalComponents } } ) await wrapper.vm.$nextTick() const menuItemTitle = wrapper.find('.wd-drop-menu__item') await menuItemTitle.trigger('click') await nextTick() expect(beforeToggle).toHaveBeenCalledWith(expect.objectContaining({ status: true })) expect(wrapper.findComponent(WdPopup).exists()).toBe(true) expect(wrapper.findComponent(WdPopup).props('modelValue')).toBe(true) await menuItemTitle.trigger('click') await nextTick() expect(beforeToggle).toHaveBeenCalledWith(expect.objectContaining({ status: false })) // 由于 beforeToggle 解析为 false,应保持打开状态 expect(wrapper.findComponent(WdPopup).exists()).toBe(true) expect(wrapper.findComponent(WdPopup).props('modelValue')).toBe(true) }) test('菜单项自定义图标 (icon-name 和 options.icon)', async () => { const wrapper = mount( { template: ` `, data() { return { value1: 0, options1: [ { label: '全部商品', value: 0 }, // 选项图标 { label: '新款商品', value: 1 } ] } } }, { global: { components: globalComponents } } ) await wrapper.vm.$nextTick() expect(wrapper.find('.wd-drop-menu__item .wd-icon-star').exists()).toBe(true) // 打开菜单并检查选项图标 await wrapper.find('.wd-drop-menu__item').trigger('click') await nextTick() const options = wrapper.findAll('.wd-drop-item__option') expect(options[1].find('.wd-icon').exists()).toBe(false) }) test('切换不同菜单项时关闭其他菜单项', async () => { const wrapper = mount( { template: ` `, data() { return { value1: 0, options1: [{ label: '全部商品', value: 0 }], value2: 'a', options2: [{ label: '默认排序', value: 'a' }] } } }, { global: { components: globalComponents } } ) await wrapper.vm.$nextTick() const titles = wrapper.findAll('.wd-drop-menu__item') const items = wrapper.findAllComponents(WdDropMenuItem) // Open first item await titles[0].trigger('click') await nextTick() expect(items[0].findComponent(WdPopup).exists()).toBe(true) expect(items[1].findComponent(WdPopup).exists()).toBe(false) await titles[1].trigger('click') await nextTick() expect(items[0].findComponent(WdPopup).exists() && items[0].findComponent(WdPopup).props('modelValue')).toBe(false) expect(items[1].findComponent(WdPopup).exists()).toBe(true) }) test('点击遮罩层关闭菜单', async () => { const wrapper = mount( { template: ` `, data() { return { value1: 0, options1: [{ label: '全部商品', value: 0 }] } } }, { global: { components: globalComponents } } ) await wrapper.vm.$nextTick() await wrapper.find('.wd-drop-menu__item').trigger('click') await nextTick() expect(wrapper.findComponent(WdPopup).exists()).toBe(true) const overlay = wrapper.find('.wd-overlay') expect(overlay.exists()).toBe(true) await overlay.trigger('click') await nextTick() expect(wrapper.findComponent(WdPopup).exists() && wrapper.findComponent(WdPopup).props('modelValue')).toBe(false) }) })