import { mount } from '@vue/test-utils'
import WdCollapse from '@/uni_modules/wot-design-uni/components/wd-collapse/wd-collapse.vue'
import WdCollapseItem from '@/uni_modules/wot-design-uni/components/wd-collapse-item/wd-collapse-item.vue'
import WdIcon from '@/uni_modules/wot-design-uni/components/wd-icon/wd-icon.vue'
import { describe, test, expect, vi, beforeEach } from 'vitest'
import { nextTick } from 'vue'
// 测试 WdCollapse 组件
describe('WdCollapse', () => {
beforeEach(() => {
vi.clearAllMocks()
})
// 测试基本渲染
test('基本渲染', async () => {
const wrapper = mount(WdCollapse, {
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.classes()).toContain('wd-collapse')
expect(wrapper.classes()).not.toContain('is-viewmore')
})
// 测试插槽内容
test('默认插槽内容', async () => {
const wrapper = mount(WdCollapse, {
slots: {
default: '
测试内容
'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.find('.test-content').exists()).toBe(true)
expect(wrapper.find('.test-content').text()).toBe('测试内容')
})
// 测试查看更多点击事件
test('点击更多按钮触发事件', async () => {
// 使用真实的 WdCollapse 组件
const wrapper = mount(WdCollapse, {
props: {
viewmore: true,
modelValue: false
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
// 直接调用 handleMore 方法,而不是点击按钮
const vm = wrapper.vm as any
vm.handleMore()
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([true])
expect(wrapper.emitted('change')?.[0]).toEqual([{ value: true }])
})
// 测试自定义类名
test('应用自定义类名', async () => {
const customClass = 'custom-collapse'
const wrapper = mount(WdCollapse, {
props: { customClass },
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.classes()).toContain(customClass)
})
// 测试自定义样式
test('应用自定义样式', async () => {
const customStyle = 'background: yellow;'
const wrapper = mount(WdCollapse, {
props: { customStyle },
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.attributes('style')).toBe(customStyle)
})
// 测试 toggleAll 方法 - 全部展开
test('toggleAll方法展开所有项', async () => {
const wrapper = mount(WdCollapse, {
props: {
modelValue: ['1'],
accordion: false
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
// 使用类型断言访问 vm 属性
const vm = wrapper.vm as any
vm.toggleAll(true)
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
expect(wrapper.emitted('change')).toBeTruthy()
})
// 测试 toggleAll 方法 - 跳过禁用项
test('toggleAll方法跳过禁用项', async () => {
const wrapper = mount(WdCollapse, {
props: {
modelValue: [],
accordion: false
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
// 使用类型断言访问 vm 属性
const vm = wrapper.vm as any
vm.toggleAll({ expanded: true, skipDisabled: true })
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
})
// 测试 toggleAll 方法在手风琴模式下不生效
test('手风琴模式下toggleAll方法无效', async () => {
const wrapper = mount(WdCollapse, {
props: {
modelValue: '1',
accordion: true
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
// 使用类型断言访问 vm 属性
const vm = wrapper.vm as any
vm.toggleAll(true)
expect(wrapper.emitted('update:modelValue')).toBeFalsy()
})
})
// 测试 WdCollapseItem 组件
describe('WdCollapseItem', () => {
beforeEach(() => {
vi.clearAllMocks()
})
// 测试基本渲染
test('基本渲染', async () => {
const wrapper = mount(WdCollapseItem, {
props: {
name: 'test'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.classes()).toContain('wd-collapse-item')
expect(wrapper.classes()).toContain('is-border')
})
// 测试标题
test('标题渲染', async () => {
const title = '标题'
const wrapper = mount(WdCollapseItem, {
props: {
title,
name: 'test'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.find('.wd-collapse-item__title').text()).toBe(title)
})
// 测试禁用状态
test('禁用状态渲染', async () => {
const wrapper = mount(WdCollapseItem, {
props: {
disabled: true,
name: 'test'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.classes()).toContain('is-disabled')
})
// 测试第一个项目的特殊样式
test('第一个项目应用特殊样式', async () => {
// 创建一个父组件 WdCollapse,并将 WdCollapseItem 作为子组件
// 这样才能正确设置 isFirst 属性
const wrapper = mount(WdCollapse, {
slots: {
default: '内容'
},
global: {
components: {
WdIcon,
WdCollapseItem
}
}
})
await nextTick()
// 找到子组件中的 header 元素
const collapseItem = wrapper.findComponent(WdCollapseItem)
expect(collapseItem.find('.wd-collapse-item__header').classes()).toContain('wd-collapse-item__header-first')
})
// 测试插槽内容
test('默认插槽内容', async () => {
const wrapper = mount(WdCollapseItem, {
props: {
name: 'test'
},
slots: {
default: '折叠面板内容
'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.find('.collapse-content').exists()).toBe(true)
expect(wrapper.find('.collapse-content').text()).toBe('折叠面板内容')
})
// 测试自定义标题插槽
test('自定义标题插槽', async () => {
const wrapper = mount(WdCollapseItem, {
props: {
name: 'test'
},
slots: {
title: '自定义标题
'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.find('.wd-collapse-item__header').classes()).toContain('is-custom')
expect(wrapper.find('.custom-title').exists()).toBe(true)
expect(wrapper.find('.custom-title').text()).toBe('自定义标题')
})
// 测试箭头图标
test('箭头图标渲染', async () => {
const wrapper = mount(WdCollapseItem, {
props: {
name: 'test'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
// 检查 WdIcon 组件是否存在
expect(wrapper.findComponent(WdIcon).exists()).toBe(true)
expect(wrapper.findComponent(WdIcon).props('name')).toBe('arrow-down')
// 检查 WdIcon 组件的 custom-class 属性
// 在 Vue 中,props 会被转换为 camelCase,但在模板中使用的是 kebab-case
// 由于 customClass 是通过 v-bind 传递的,我们可以通过检查 HTML 属性来验证
const iconComponent = wrapper.findComponent(WdIcon)
expect(iconComponent.attributes()).toBeDefined()
console.log()
expect(iconComponent.props('customClass')).toBeDefined()
expect(iconComponent.props('customClass')).toContain('wd-collapse-item__arrow')
})
// 测试点击事件
test('处理点击事件', async () => {
const wrapper = mount(WdCollapseItem, {
props: {
name: 'test'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
await wrapper.find('.wd-collapse-item__header').trigger('click')
})
// 测试禁用状态下点击事件
test('禁用状态下不处理点击事件', async () => {
const wrapper = mount(WdCollapseItem, {
props: {
name: 'test',
disabled: true
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
await wrapper.find('.wd-collapse-item__header').trigger('click')
})
// 测试自定义类名
test('应用自定义类名', async () => {
const customClass = 'custom-item'
const wrapper = mount(WdCollapseItem, {
props: {
customClass,
name: 'test'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.classes()).toContain(customClass)
})
// 测试自定义样式
test('应用自定义样式', async () => {
const customStyle = 'background: yellow;'
const wrapper = mount(WdCollapseItem, {
props: {
customStyle,
name: 'test'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.attributes('style')).toBe(customStyle)
})
// 测试自定义内容容器类名
test('应用自定义内容容器类名', async () => {
const customBodyClass = 'custom-body'
const wrapper = mount(WdCollapseItem, {
props: {
customBodyClass,
name: 'test'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.find('.wd-collapse-item__body').classes()).toContain(customBodyClass)
})
// 测试自定义内容容器样式
test('应用自定义内容容器样式', async () => {
const customBodyStyle = 'padding: 20px;'
const wrapper = mount(WdCollapseItem, {
props: {
customBodyStyle,
name: 'test'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.find('.wd-collapse-item__body').attributes('style')).toBe(customBodyStyle)
})
// 测试展开前钩子函数 - 返回 true
test('调用返回true的beforeExpend钩子', async () => {
const beforeExpend = vi.fn().mockReturnValue(true)
const wrapper = mount(WdCollapseItem, {
props: {
name: 'test',
beforeExpend
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
await wrapper.find('.wd-collapse-item__header').trigger('click')
expect(beforeExpend).toHaveBeenCalledWith('test')
})
// 测试展开前钩子函数 - 返回 false
test('调用返回false的beforeExpend钩子', async () => {
const beforeExpend = vi.fn().mockReturnValue(false)
const wrapper = mount(WdCollapseItem, {
props: {
name: 'test',
beforeExpend
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
await wrapper.find('.wd-collapse-item__header').trigger('click')
expect(beforeExpend).toHaveBeenCalledWith('test')
})
// 测试展开前钩子函数 - 返回 Promise
test('calls beforeExpend hook that returns Promise', async () => {
const beforeExpend = vi.fn().mockResolvedValue(true)
const wrapper = mount(WdCollapseItem, {
props: {
name: 'test',
beforeExpend
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
await wrapper.find('.wd-collapse-item__header').trigger('click')
expect(beforeExpend).toHaveBeenCalledWith('test')
})
// 测试过渡结束事件
test('handles transition end event', async () => {
const wrapper = mount(WdCollapseItem, {
props: {
name: 'test'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
// 设置为展开状态 - 使用类型断言
const vm = wrapper.vm as any
vm.expanded = true
// 触发过渡结束事件
await wrapper.find('.wd-collapse-item__wrapper').trigger('transitionend')
// 高度应该被重置为空字符串 - 使用类型断言
expect((wrapper.vm as any).height).toBe('')
})
})
// 测试 WdCollapse 和 WdCollapseItem 组件的集成
describe('WdCollapse and WdCollapseItem Integration', () => {
beforeEach(() => {
vi.clearAllMocks()
})
// 测试 WdCollapse 和 WdCollapseItem 组件的结合使用
test('renders with collapse items', async () => {
const wrapper = mount(WdCollapse, {
props: {
modelValue: ['item1']
},
slots: {
default: `
内容1
内容2
`
},
global: {
components: {
WdIcon,
WdCollapseItem
}
}
})
await nextTick()
expect(wrapper.findAllComponents(WdCollapseItem).length).toBe(2)
expect(wrapper.html()).toContain('标签1')
expect(wrapper.html()).toContain('标签2')
})
// 测试手风琴模式
test('works in accordion mode', async () => {
const wrapper = mount(WdCollapse, {
props: {
modelValue: 'item1',
accordion: true
},
slots: {
default: `
内容1
内容2
`
},
global: {
components: {
WdIcon,
WdCollapseItem
}
}
})
await nextTick()
// 找到第二个折叠项并点击
const items = wrapper.findAllComponents(WdCollapseItem)
await items[1].find('.wd-collapse-item__header').trigger('click')
// 应该发出更新事件,将值更改为 'item2'
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['item2'])
})
// 测试禁用项
test('respects disabled items', async () => {
const wrapper = mount(WdCollapse, {
props: {
modelValue: ['item1']
},
slots: {
default: `
内容1
内容2
`
},
global: {
components: {
WdIcon,
WdCollapseItem
}
}
})
await nextTick()
// 找到禁用的折叠项并点击
const items = wrapper.findAllComponents(WdCollapseItem)
await items[1].find('.wd-collapse-item__header').trigger('click')
// 不应该发出更新事件
expect(wrapper.emitted('update:modelValue')).toBeFalsy()
})
// 测试查看更多模式
test('works in viewmore mode', async () => {
const wrapper = mount(WdCollapse, {
props: {
modelValue: false,
viewmore: true,
lineNum: 2
},
slots: {
default: '这是一段很长的内容,需要折叠起来,点击查看更多才能看到全部内容。
'
},
global: {
components: {
WdIcon
}
}
})
await nextTick()
expect(wrapper.classes()).toContain('is-viewmore')
expect(wrapper.find('.wd-collapse__content').classes()).toContain('is-retract')
// 点击查看更多按钮
await wrapper.find('.wd-collapse__more').trigger('click')
// 应该发出更新事件,将值更改为 true
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([true])
})
})