diff --git a/packages/ccui/ui/button/test/button.test.ts b/packages/ccui/ui/button/test/button.test.ts
index 40b0409f..62c7f99c 100644
--- a/packages/ccui/ui/button/test/button.test.ts
+++ b/packages/ccui/ui/button/test/button.test.ts
@@ -18,25 +18,37 @@ const roundClass = ns.m('round')
const circleClass = ns.m('circle')
const loadingClass = ns.m('loading')
+// 测试辅助函数
+function createWrapper(props = {}, slots = {}) {
+ return mount(Button, {
+ props,
+ slots: {
+ default: 'Button',
+ ...slots,
+ },
+ })
+}
+
+function createShallowWrapper(props = {}, slots = {}) {
+ return shallowMount(Button, {
+ props,
+ slots: {
+ default: 'Button',
+ ...slots,
+ },
+ })
+}
+
describe('button', () => {
it('dom', () => {
- const wrapper = shallowMount(Button, {
- slots: {
- default: '确定',
- },
- })
-
- // 元素是否存在
+ const wrapper = createShallowWrapper({}, { default: '确定' })
expect(wrapper.find(baseClass).exists()).toBeTruthy()
-
- // 默认插槽的文本是否正确
expect(wrapper.find(baseClass).text()).toBe('确定')
-
wrapper.unmount()
})
it('type', async () => {
- const wrapper = shallowMount(Button, { props: { type: 'primary' } })
+ const wrapper = createShallowWrapper({ type: 'primary' })
expect(wrapper.find(getTypeClass('primary')).exists()).toBeTruthy()
await wrapper.setProps({ type: 'success' })
@@ -53,7 +65,7 @@ describe('button', () => {
})
it('size', async () => {
- const wrapper = shallowMount(Button, { props: { size: 'small' } })
+ const wrapper = createShallowWrapper({ size: 'small' })
expect(wrapper.find(getSizeClass('small')).exists()).toBeTruthy()
await wrapper.setProps({ size: 'large' })
@@ -61,181 +73,84 @@ describe('button', () => {
})
it('round', async () => {
- const wrapper = shallowMount(Button, { props: { round: true } })
+ const wrapper = createShallowWrapper({ round: true })
expect(wrapper.find(roundClass).exists()).toBeTruthy()
})
it('circle', async () => {
- const wrapper = shallowMount(Button, { props: { circle: true } })
+ const wrapper = createShallowWrapper({ circle: true })
expect(wrapper.find(circleClass).exists()).toBeTruthy()
})
- it('disabled', async () => {
+ it('click events', async () => {
const handleClick = vi.fn()
- const wrapper = shallowMount(Button, { props: { disabled: true } })
-
- // 检查是否应用了禁用样式类
- const disabledClass = ns.m('disabled').substring(1) // 移除开头的点
- expect(wrapper.find('button').classes()).toContain(disabledClass)
-
- await wrapper.trigger('click')
- expect(handleClick).not.toBeCalled()
- })
-
- it('emits click event when clicked', async () => {
- const handleClick = vi.fn()
- const wrapper = mount(Button, {
- slots: {
- default: 'Click me',
- },
- attrs: {
- onClick: handleClick,
- },
- })
+ // Test normal click
+ const wrapper = createWrapper({}, { default: 'Click me' })
+ wrapper.element.addEventListener('click', handleClick)
await wrapper.trigger('click')
expect(handleClick).toBeCalled()
-
wrapper.unmount()
- })
-
- it('does not emit click event when disabled', async () => {
- const handleClick = vi.fn()
- const wrapper = mount(Button, {
- props: {
- disabled: true,
- },
- slots: {
- default: 'Click me',
- },
- attrs: {
- onClick: handleClick,
- },
- })
- await wrapper.trigger('click')
+ // Test disabled - no click
+ handleClick.mockClear()
+ const disabledWrapper = createWrapper({ disabled: true })
+ const disabledClass = ns.m('disabled').substring(1)
+ expect(disabledWrapper.find('button').classes()).toContain(disabledClass)
+ disabledWrapper.element.addEventListener('click', handleClick)
+ await disabledWrapper.trigger('click')
expect(handleClick).not.toBeCalled()
-
- wrapper.unmount()
+ disabledWrapper.unmount()
+
+ // Test loading - no click
+ handleClick.mockClear()
+ const loadingWrapper = createWrapper({ loading: true })
+ expect(loadingWrapper.find(loadingClass).exists()).toBeTruthy()
+ expect(loadingWrapper.find('button').attributes('disabled')).toBe('')
+ expect(loadingWrapper.find('button').classes()).toContain(disabledClass)
+ loadingWrapper.element.addEventListener('click', handleClick)
+ await loadingWrapper.trigger('click')
+ expect(handleClick).not.toBeCalled()
+ loadingWrapper.unmount()
})
it('renders icon slot when provided', () => {
- const wrapper = mount(Button, {
- slots: {
- icon: '',
- default: 'Like',
- },
+ const wrapper = createWrapper({}, {
+ icon: '',
+ default: 'Like',
})
-
expect(wrapper.find('.cc-icon-heart').exists()).toBe(true)
-
wrapper.unmount()
})
it('applies plain style when plain prop is true', async () => {
- const wrapper = shallowMount(Button, {
- props: {
- type: 'primary',
- plain: true,
- },
- })
-
+ const wrapper = createShallowWrapper({ type: 'primary', plain: true })
expect(wrapper.find(ns.m('plain-primary')).exists()).toBeTruthy()
-
wrapper.unmount()
})
it('sets nativeType attribute correctly', () => {
- const wrapper = mount(Button, {
- props: {
- nativeType: 'submit',
- },
- slots: {
- default: 'Submit',
- },
- })
-
+ const wrapper = createWrapper({ nativeType: 'submit' }, { default: 'Submit' })
expect(wrapper.find('button').attributes('type')).toBe('submit')
-
wrapper.unmount()
})
it('sets autofocus attribute when autofocus is true', () => {
- const wrapper = mount(Button, {
- props: {
- autofocus: true,
- },
- slots: {
- default: 'Focus',
- },
- })
-
+ const wrapper = createWrapper({ autofocus: true }, { default: 'Focus' })
expect(wrapper.find('button').attributes('autofocus')).toBe('')
-
- wrapper.unmount()
- })
-
- it('shows loading state when loading prop is true', async () => {
- const wrapper = shallowMount(Button, { props: { loading: true } })
- expect(wrapper.find(loadingClass).exists()).toBeTruthy()
- expect(wrapper.find('button').attributes('disabled')).toBe('')
-
- // 检查是否应用了禁用样式类
- const disabledClass = ns.m('disabled').substring(1) // 移除开头的点
- expect(wrapper.find('button').classes()).toContain(disabledClass)
-
- wrapper.unmount()
- })
-
- it('does not emit click event when loading', async () => {
- const handleClick = vi.fn()
- const wrapper = mount(Button, {
- props: {
- loading: true,
- },
- slots: {
- default: 'Loading',
- },
- attrs: {
- onClick: handleClick,
- },
- })
-
- await wrapper.trigger('click')
- expect(handleClick).not.toBeCalled()
-
wrapper.unmount()
})
it('renders icon when icon prop is provided', () => {
- const wrapper = mount(Button, {
- props: {
- icon: 'cc-icon-star',
- },
- slots: {
- default: 'Star',
- },
- })
-
+ const wrapper = createWrapper({ icon: 'cc-icon-star' }, { default: 'Star' })
expect(wrapper.find('.cc-icon-star').exists()).toBe(true)
-
wrapper.unmount()
})
it('renders loading icon when loading is true', () => {
- const wrapper = mount(Button, {
- props: {
- loading: true,
- },
- slots: {
- default: 'Loading',
- },
- })
-
+ const wrapper = createWrapper({ loading: true }, { default: 'Loading' })
expect(wrapper.find(ns.e('loading-icon')).exists()).toBe(true)
- // 验证加载图标是空的span元素
expect(wrapper.find(ns.e('loading-icon')).text()).toBe('')
-
wrapper.unmount()
})
})
diff --git a/packages/ccui/ui/calendar/test/calendar.test.ts b/packages/ccui/ui/calendar/test/calendar.test.ts
index 12c1e758..e0876d56 100644
--- a/packages/ccui/ui/calendar/test/calendar.test.ts
+++ b/packages/ccui/ui/calendar/test/calendar.test.ts
@@ -10,159 +10,77 @@ const dayClass = ns.em('day-box', 'day')
const currentDateClass = '.current-date'
const headerClass = ns.e('header')
-describe('calendar', () => {
- it('dom', () => {
- const wrapper = mount(Calendar, {
- props: { modelValue: new Date() },
- global: {
- components: {
- CButton: Button,
- },
+// 测试辅助函数
+function createWrapper(props = {}, slots = {}) {
+ return mount(Calendar, {
+ props: {
+ modelValue: new Date(),
+ ...props,
+ },
+ slots,
+ global: {
+ components: {
+ CButton: Button,
},
- })
+ },
+ })
+}
- // 元素是否存在
+describe('calendar', () => {
+ it('dom', () => {
+ const wrapper = createWrapper()
expect(wrapper.find(baseClass).exists()).toBeTruthy()
-
- // 日期生成是否正确
expect(wrapper.findAll(dayClass).length).toBe(42)
-
wrapper.unmount()
})
it('props', async () => {
- const wrapper = mount(Calendar, {
- props: { modelValue: new Date() },
- global: {
- components: {
- CButton: Button,
- },
- },
- })
-
+ const wrapper = createWrapper()
const testDate = new Date(2022, 9, 10) // 2022-10-10
await wrapper.setProps({ modelValue: testDate })
-
expect(wrapper.find(currentDateClass).text()).toBe('10')
-
wrapper.unmount()
})
it('slots', async () => {
- const wrapper = mount(Calendar, {
- props: { modelValue: new Date() },
- slots: {
- dateCell: `
+ const wrapper = createWrapper({}, {
+ dateCell: `
{{isSelected ? '当前选中日期' : day}}
`,
- },
- global: {
- components: {
- CButton: Button,
- },
- },
})
-
- // slot 元素正确加载
expect(wrapper.find(currentDateClass).exists()).toBeTruthy()
-
- // slot 内容正确渲染
expect(wrapper.find(currentDateClass).text()).toBe('当前选中日期')
-
wrapper.unmount()
})
it('event', async () => {
- const wrapper = mount(Calendar, {
- props: { modelValue: new Date() },
- global: {
- components: {
- CButton: Button,
- },
- },
- })
-
- // 断言 change 事件是否正确触发
- // 获取第一个日期
+ const wrapper = createWrapper()
const firstDate = wrapper.find(dayClass).text()
-
- // 以第一个 day 元素触发 click 事件更新选中数据
await wrapper.find(dayClass).trigger('click')
-
- // 验证是否触发emit事件
expect(wrapper.emitted('change')).toBeTruthy()
-
- // 获取当前选中数据进行比对
expect(wrapper.find(currentDateClass).text()).toBe(firstDate)
-
wrapper.unmount()
})
- it('switches to next month', async () => {
+ it('month navigation', async () => {
const testDate = new Date(2022, 9, 10) // 2022-10-10
- const expectedNextMonth = '2022-11'
+ const wrapper = createWrapper({ modelValue: testDate })
- const wrapper = mount(Calendar, {
- props: { modelValue: testDate },
- global: {
- components: {
- CButton: Button,
- },
- },
- })
-
- // 点击下个月按钮 (第三个按钮)
- const buttons = wrapper.find(headerClass).findAllComponents(Button)
+ // Test next month
+ let buttons = wrapper.find(headerClass).findAllComponents(Button)
await buttons[2].trigger('click')
+ expect(wrapper.find(headerClass).text()).toContain('2022-11')
- // 验证月份是否正确更新
- expect(wrapper.find(headerClass).text()).toContain(expectedNextMonth)
-
- wrapper.unmount()
- })
-
- it('switches to previous month', async () => {
- const testDate = new Date(2022, 9, 10) // 2022-10-10
- const expectedPrevMonth = '2022-09'
-
- const wrapper = mount(Calendar, {
- props: { modelValue: testDate },
- global: {
- components: {
- CButton: Button,
- },
- },
- })
-
- // 点击上个月按钮 (第一个按钮)
- const buttons = wrapper.find(headerClass).findAllComponents(Button)
+ // Test previous month (from November back to October)
+ buttons = wrapper.find(headerClass).findAllComponents(Button)
await buttons[0].trigger('click')
+ expect(wrapper.find(headerClass).text()).toContain('2022-10')
- // 验证月份是否正确更新
- expect(wrapper.find(headerClass).text()).toContain(expectedPrevMonth)
-
- wrapper.unmount()
- })
-
- it('navigates to today', async () => {
- const testDate = new Date(2022, 9, 10) // 2022-10-10
+ // Test today button
+ buttons = wrapper.find(headerClass).findAllComponents(Button)
+ await buttons[1].trigger('click')
const today = new Date()
const todayMonth = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}`
-
- const wrapper = mount(Calendar, {
- props: { modelValue: testDate },
- global: {
- components: {
- CButton: Button,
- },
- },
- })
-
- // 点击今天按钮 (第二个按钮)
- const buttons = wrapper.find(headerClass).findAllComponents(Button)
- await buttons[1].trigger('click')
-
- // 验证月份是否正确更新为当前月份
expect(wrapper.find(headerClass).text()).toContain(todayMonth)
wrapper.unmount()
@@ -170,60 +88,30 @@ describe('calendar', () => {
it('highlights current date', async () => {
const today = new Date()
- const wrapper = mount(Calendar, {
- props: { modelValue: today },
- global: {
- components: {
- CButton: Button,
- },
- },
- })
-
- // 验证当前日期是否有高亮类
+ const wrapper = createWrapper({ modelValue: today })
expect(wrapper.find(currentDateClass).exists()).toBeTruthy()
-
wrapper.unmount()
})
it('works in read-only mode', async () => {
- const wrapper = mount(Calendar, {
- props: {
- modelValue: new Date(2022, 9, 10), // 2022-10-10
- readOnly: true,
- },
- global: {
- components: {
- CButton: Button,
- },
- },
+ const wrapper = createWrapper({
+ modelValue: new Date(2022, 9, 10),
+ readOnly: true,
})
-
- // 验证是否应用了只读属性
expect(wrapper.props().readOnly).toBe(true)
-
wrapper.unmount()
})
it('renders correct dates for month', async () => {
const testDate = new Date(2022, 9, 10) // 2022-10-10
- const wrapper = mount(Calendar, {
- props: { modelValue: testDate },
- global: {
- components: {
- CButton: Button,
- },
- },
- })
+ const wrapper = createWrapper({ modelValue: testDate })
- // 验证10月份有31天
const days = wrapper.findAll(dayClass)
expect(days.length).toBe(42) // 6周 x 7天
- // 验证10月1日存在
const firstDay = days.find(day => day.text() === '1')
expect(firstDay).toBeTruthy()
- // 验证10月31日存在
const lastDay = days.find(day => day.text() === '31')
expect(lastDay).toBeTruthy()
@@ -231,39 +119,19 @@ describe('calendar', () => {
})
it('renders custom header when header slot is provided', () => {
- const wrapper = mount(Calendar, {
- props: { modelValue: new Date() },
- slots: {
- header: `
+ const wrapper = createWrapper({}, {
+ header: `
`,
- },
- global: {
- components: {
- CButton: Button,
- },
- },
})
-
- // 验证自定义 header 是否正确渲染
expect(wrapper.find('.custom-header').exists()).toBeTruthy()
-
wrapper.unmount()
})
it('correctly handles month boundaries', () => {
- // 测试月份切换时的边界情况
const testDate = new Date(2022, 0, 15) // 2022-01-15
- const wrapper = mount(Calendar, {
- props: { modelValue: testDate },
- global: {
- components: {
- CButton: Button,
- },
- },
- })
+ const wrapper = createWrapper({ modelValue: testDate })
- // 2022年1月有31天,应该显示在日历中
const days = wrapper.findAll(dayClass)
const lastDay = days.find(day => day.text() === '31')
expect(lastDay).toBeTruthy()
diff --git a/packages/ccui/ui/input-number/test/input-number.test.ts b/packages/ccui/ui/input-number/test/input-number.test.ts
index 76a59a79..3a5c198a 100644
--- a/packages/ccui/ui/input-number/test/input-number.test.ts
+++ b/packages/ccui/ui/input-number/test/input-number.test.ts
@@ -3,31 +3,28 @@ import { describe, expect, it } from 'vitest'
import { nextTick } from 'vue'
import { InputNumber } from '../index'
+// 测试辅助函数
+function createWrapper(props = {}) {
+ return mount(InputNumber, {
+ props,
+ })
+}
+
describe('inputNumber', () => {
it('should render correctly', () => {
- const wrapper = mount(InputNumber)
+ const wrapper = createWrapper()
expect(wrapper.find('.ccui-input-number').exists()).toBe(true)
expect(wrapper.find('.ccui-input-number__inner').exists()).toBe(true)
})
it('should support v-model', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- modelValue: 5,
- },
- })
-
+ const wrapper = createWrapper({ modelValue: 5 })
const input = wrapper.find('.ccui-input-number__inner')
expect((input.element as HTMLInputElement).value).toBe('5')
})
it('should handle input change', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- modelValue: 0,
- },
- })
-
+ const wrapper = createWrapper({ modelValue: 0 })
const input = wrapper.find('.ccui-input-number__inner')
await input.setValue('10')
await input.trigger('input')
@@ -38,13 +35,7 @@ describe('inputNumber', () => {
})
it('should handle increase and decrease', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- modelValue: 5,
- step: 2,
- },
- })
-
+ const wrapper = createWrapper({ modelValue: 5, step: 2 })
const increaseBtn = wrapper.find('.ccui-input-number__increase')
const decreaseBtn = wrapper.find('.ccui-input-number__decrease')
@@ -56,14 +47,7 @@ describe('inputNumber', () => {
})
it('should respect min and max limits', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- modelValue: 5,
- min: 0,
- max: 10,
- },
- })
-
+ const wrapper = createWrapper({ modelValue: 5, min: 0, max: 10 })
const input = wrapper.find('.ccui-input-number__inner')
// Test max limit
@@ -73,14 +57,7 @@ describe('inputNumber', () => {
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([10])
// Reset wrapper to test min limit separately
- const wrapper2 = mount(InputNumber, {
- props: {
- modelValue: 5,
- min: 0,
- max: 10,
- },
- })
-
+ const wrapper2 = createWrapper({ modelValue: 5, min: 0, max: 10 })
const input2 = wrapper2.find('.ccui-input-number__inner')
// Test min limit
@@ -91,26 +68,13 @@ describe('inputNumber', () => {
})
it('should handle precision', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- modelValue: 1.234,
- precision: 2,
- },
- })
-
+ const wrapper = createWrapper({ modelValue: 1.234567, precision: 2 })
const input = wrapper.find('.ccui-input-number__inner')
expect((input.element as HTMLInputElement).value).toBe('1.23')
})
it('should disable buttons when reaching limits', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- modelValue: 10,
- min: 0,
- max: 10,
- },
- })
-
+ const wrapper = createWrapper({ modelValue: 10, min: 0, max: 10 })
const increaseBtn = wrapper.find('.ccui-input-number__increase')
const decreaseBtn = wrapper.find('.ccui-input-number__decrease')
@@ -122,12 +86,7 @@ describe('inputNumber', () => {
})
it('should handle disabled state', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- modelValue: 5,
- disabled: true,
- },
- })
+ const wrapper = createWrapper({ modelValue: 5, disabled: true })
expect(wrapper.classes()).toContain('ccui-input-number--disabled')
@@ -140,12 +99,7 @@ describe('inputNumber', () => {
})
it('should handle readonly state', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- modelValue: 5,
- readonly: true,
- },
- })
+ const wrapper = createWrapper({ modelValue: 5, readonly: true })
expect(wrapper.classes()).toContain('ccui-input-number--readonly')
@@ -154,12 +108,7 @@ describe('inputNumber', () => {
})
it('should support different sizes', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- size: 'lg',
- },
- })
-
+ const wrapper = createWrapper({ size: 'lg' })
expect(wrapper.classes()).toContain('ccui-input-number--lg')
await wrapper.setProps({ size: 'sm' })
@@ -167,22 +116,14 @@ describe('inputNumber', () => {
})
it('should handle controls position', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- controlsPosition: 'right',
- },
- })
+ const wrapper = createWrapper({ controlsPosition: 'right' })
expect(wrapper.classes()).toContain('ccui-input-number--controls-right')
expect(wrapper.find('.ccui-input-number__controls').exists()).toBe(true)
})
it('should hide controls when controls is false', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- controls: false,
- },
- })
+ const wrapper = createWrapper({ controls: false })
expect(wrapper.classes()).toContain('ccui-input-number--without-controls')
expect(wrapper.find('.ccui-input-number__increase').exists()).toBe(false)
@@ -190,13 +131,7 @@ describe('inputNumber', () => {
})
it('should handle keyboard events', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- modelValue: 5,
- step: 1,
- },
- })
-
+ const wrapper = createWrapper({ modelValue: 5, step: 1 })
const input = wrapper.find('.ccui-input-number__inner')
await input.trigger('keydown', { key: 'ArrowUp' })
@@ -207,7 +142,7 @@ describe('inputNumber', () => {
})
it('should handle focus and blur events', async () => {
- const wrapper = mount(InputNumber)
+ const wrapper = createWrapper()
const input = wrapper.find('.ccui-input-number__inner')
await input.trigger('focus')
@@ -219,12 +154,7 @@ describe('inputNumber', () => {
})
it('should handle allowEmpty option', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- allowEmpty: true,
- },
- })
-
+ const wrapper = createWrapper({ allowEmpty: true })
const input = wrapper.find('.ccui-input-number__inner')
await input.setValue('')
await input.trigger('change')
@@ -232,8 +162,16 @@ describe('inputNumber', () => {
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([undefined])
})
+ it('should support custom step', async () => {
+ const wrapper = createWrapper({ modelValue: 0, step: 0.1, precision: 1 })
+ const increaseBtn = wrapper.find('.ccui-input-number__increase')
+ await increaseBtn.trigger('click')
+
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([0.1])
+ })
+
it('should expose methods', () => {
- const wrapper = mount(InputNumber)
+ const wrapper = createWrapper()
const vm = wrapper.vm as any
expect(typeof vm.getValue).toBe('function')
@@ -243,49 +181,4 @@ describe('inputNumber', () => {
expect(typeof vm.increase).toBe('function')
expect(typeof vm.decrease).toBe('function')
})
-
- it('应该正确处理精度设置', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- modelValue: 1.234567,
- precision: 2,
- },
- })
-
- const input = wrapper.find('input')
- expect(input.element.value).toBe('1.23')
- })
-
- it('应该支持自定义步长', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- modelValue: 0,
- step: 0.1,
- precision: 1,
- },
- })
-
- const increaseBtn = wrapper.find('.ccui-input-number__increase')
- await increaseBtn.trigger('click')
-
- expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([0.1])
- })
-
- it('应该在达到边界值时禁用按钮', async () => {
- const wrapper = mount(InputNumber, {
- props: {
- modelValue: 10,
- min: 0,
- max: 10,
- },
- })
-
- const increaseBtn = wrapper.find('.ccui-input-number__increase')
- const decreaseBtn = wrapper.find('.ccui-input-number__decrease')
-
- expect(increaseBtn.classes()).toContain('is-disabled')
-
- await wrapper.setProps({ modelValue: 0 })
- expect(decreaseBtn.classes()).toContain('is-disabled')
- })
})
diff --git a/packages/ccui/ui/input/test/input.test.ts b/packages/ccui/ui/input/test/input.test.ts
index 0e97b37c..68c3e7dc 100644
--- a/packages/ccui/ui/input/test/input.test.ts
+++ b/packages/ccui/ui/input/test/input.test.ts
@@ -11,25 +11,25 @@ function getSizeClass(type: InputSize) {
return ns.em('wrapper', type)
}
+// 测试辅助函数
+function createWrapper(props = {}) {
+ return mount(Input, { props })
+}
+
+function createShallowWrapper(props = {}) {
+ return shallowMount(Input, { props })
+}
+
describe('input', () => {
it('dom', () => {
- const wrapper = shallowMount(Input, {
- props: {
- modelValue: 'test',
- },
- })
-
- // 元素是否存在
+ const wrapper = createShallowWrapper({ modelValue: 'test' })
expect(wrapper.find(baseClass).exists()).toBeTruthy()
-
- // 输入框是否存在
expect(wrapper.find('input').exists()).toBeTruthy()
-
wrapper.unmount()
})
it('type', async () => {
- const wrapper = shallowMount(Input, { props: { type: 'text' } })
+ const wrapper = createShallowWrapper({ type: 'text' })
expect(wrapper.find('input').attributes('type')).toBe('text')
await wrapper.setProps({ type: 'password' })
@@ -37,7 +37,7 @@ describe('input', () => {
})
it('size', async () => {
- const wrapper = shallowMount(Input, { props: { size: 'small' } })
+ const wrapper = createShallowWrapper({ size: 'small' })
expect(wrapper.find(getSizeClass('small')).exists()).toBeTruthy()
await wrapper.setProps({ size: 'large' })
@@ -45,159 +45,99 @@ describe('input', () => {
})
it('placeholder', async () => {
- const wrapper = shallowMount(Input, { props: { placeholder: '请输入内容' } })
+ const wrapper = createShallowWrapper({ placeholder: '请输入内容' })
expect(wrapper.find('input').attributes('placeholder')).toBe('请输入内容')
})
it('disabled', async () => {
- const wrapper = shallowMount(Input, { props: { disabled: true } })
-
- // 检查是否应用了禁用样式类
- const disabledClass = ns.m('disabled').substring(1) // 移除开头的点
+ const wrapper = createShallowWrapper({ disabled: true })
+ const disabledClass = ns.m('disabled').substring(1)
expect(wrapper.find('input').classes()).toContain(disabledClass)
-
- // 检查是否应用了禁用属性
expect(wrapper.find('input').attributes('disabled')).toBe('')
})
it('readonly', async () => {
- const wrapper = shallowMount(Input, { props: { readonly: true } })
-
- // 检查是否应用了只读属性
+ const wrapper = createShallowWrapper({ readonly: true })
expect(wrapper.find('input').attributes('readonly')).toBe('')
})
it('clearable', async () => {
- const wrapper = shallowMount(Input, { props: { clearable: true, modelValue: 'test' } })
-
- // 检查是否显示清空图标
+ const wrapper = createShallowWrapper({ clearable: true, modelValue: 'test' })
expect(wrapper.find(ns.e('clear')).exists()).toBeTruthy()
})
it('prepend', async () => {
- const wrapper = shallowMount(Input, { props: { prepend: 'http://' } })
-
- // 检查是否显示前置内容
+ const wrapper = createShallowWrapper({ prepend: 'http://' })
expect(wrapper.find(ns.e('prepend')).exists()).toBeTruthy()
expect(wrapper.find(ns.e('prepend')).text()).toBe('http://')
})
it('append', async () => {
- const wrapper = shallowMount(Input, { props: { append: '.com' } })
-
- // 检查是否显示后置内容
+ const wrapper = createShallowWrapper({ append: '.com' })
expect(wrapper.find(ns.e('append')).exists()).toBeTruthy()
expect(wrapper.find(ns.e('append')).text()).toBe('.com')
})
it('emits input event when input value changes', async () => {
const handleInput = vi.fn()
- const wrapper = mount(Input, {
- attrs: {
- onInput: handleInput,
- },
- })
-
+ const wrapper = createWrapper({ onInput: handleInput })
const input = wrapper.find('input')
await input.setValue('test')
expect(handleInput).toBeCalled()
-
wrapper.unmount()
})
it('emits change event when input value changes and loses focus', async () => {
const handleChange = vi.fn()
- const wrapper = mount(Input, {
- attrs: {
- onChange: handleChange,
- },
- })
-
+ const wrapper = createWrapper({ onChange: handleChange })
const input = wrapper.find('input')
await input.setValue('test')
await input.trigger('change')
expect(handleChange).toBeCalled()
-
wrapper.unmount()
})
- it('emits focus event when input is focused', async () => {
+ it('emits focus and blur events', async () => {
const handleFocus = vi.fn()
- const wrapper = mount(Input, {
- attrs: {
- onFocus: handleFocus,
- },
- })
-
- const input = wrapper.find('input')
- await input.trigger('focus')
- expect(handleFocus).toBeCalled()
-
- wrapper.unmount()
- })
-
- it('emits blur event when input loses focus', async () => {
const handleBlur = vi.fn()
- const wrapper = mount(Input, {
- attrs: {
- onBlur: handleBlur,
- },
- })
-
+ const wrapper = createWrapper({ onFocus: handleFocus, onBlur: handleBlur })
const input = wrapper.find('input')
await input.trigger('focus')
+ expect(handleFocus).toBeCalled()
await input.trigger('blur')
expect(handleBlur).toBeCalled()
-
wrapper.unmount()
})
it('clears input value when clear icon is clicked', async () => {
const handleClear = vi.fn()
- const wrapper = mount(Input, {
- props: {
- clearable: true,
- modelValue: 'test',
- },
- attrs: {
- onClear: handleClear,
- },
+ const wrapper = createWrapper({
+ clearable: true,
+ modelValue: 'test',
+ onClear: handleClear,
})
-
const clearIcon = wrapper.find(ns.e('clear'))
await clearIcon.trigger('click')
expect(handleClear).toBeCalled()
-
- // 检查输入框值是否被清空
expect(wrapper.find('input').element.value).toBe('')
-
wrapper.unmount()
})
it('toggles password visibility when showPassword is true', async () => {
- const wrapper = mount(Input, {
- props: {
- type: 'password',
- showPassword: true,
- modelValue: 'test',
- },
+ const wrapper = createWrapper({
+ type: 'password',
+ showPassword: true,
+ modelValue: 'test',
})
- // 检查是否显示密码切换图标
expect(wrapper.find(ns.e('password-hidden')).exists()).toBeTruthy()
- // 点击密码切换图标
const passwordIcon = wrapper.find(ns.e('password-hidden'))
await passwordIcon.trigger('click')
-
- // 检查密码是否变为可见
expect(wrapper.find(ns.e('password-visible')).exists()).toBeTruthy()
- // 再次点击密码切换图标
const passwordIcon2 = wrapper.find(ns.e('password-visible'))
await passwordIcon2.trigger('click')
-
- // 检查密码是否变为隐藏
expect(wrapper.find(ns.e('password-hidden')).exists()).toBeTruthy()
wrapper.unmount()
diff --git a/packages/ccui/ui/popover/test/popover.test.ts b/packages/ccui/ui/popover/test/popover.test.ts
index ae98a486..40a510b2 100644
--- a/packages/ccui/ui/popover/test/popover.test.ts
+++ b/packages/ccui/ui/popover/test/popover.test.ts
@@ -3,6 +3,33 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { nextTick } from 'vue'
import { Popover } from '../index'
+// 测试辅助函数
+function createWrapper(props = {}, slots = {}) {
+ return mount(Popover, {
+ props: {
+ teleported: false,
+ ...props,
+ },
+ slots: {
+ default: '',
+ ...slots,
+ },
+ })
+}
+
+function createShallowWrapper(props = {}, slots = {}) {
+ return shallowMount(Popover, {
+ props: {
+ teleported: false,
+ ...props,
+ },
+ slots: {
+ default: '',
+ ...slots,
+ },
+ })
+}
+
describe('popover', () => {
let wrapper: any
@@ -28,27 +55,17 @@ describe('popover', () => {
describe('基础功能', () => {
it('正确渲染组件', () => {
- wrapper = shallowMount(Popover, {
- slots: {
- default: '',
- },
- })
+ wrapper = createShallowWrapper()
expect(wrapper.exists()).toBe(true)
expect(wrapper.find('.ccui-popover').exists()).toBe(true)
expect(wrapper.find('.ccui-popover__trigger').exists()).toBe(true)
})
it('显示内容与标题', async () => {
- wrapper = mount(Popover, {
- props: {
- title: 'Title',
- content: 'Popover content',
- visible: true,
- teleported: false, // 测试中禁用 teleport,以便在组件内部查找元素
- },
- slots: {
- default: '',
- },
+ wrapper = createWrapper({
+ title: 'Title',
+ content: 'Popover content',
+ visible: true,
})
await nextTick()
expect(wrapper.find('.ccui-popover__popper').exists()).toBe(true)
@@ -57,148 +74,85 @@ describe('popover', () => {
})
it('支持插槽内容', async () => {
- wrapper = mount(Popover, {
- props: {
- visible: true,
- teleported: false, // 测试中禁用 teleport,以便在组件内部查找元素
- },
- slots: {
- default: '',
+ wrapper = createWrapper(
+ { visible: true },
+ {
title: 'Custom Title
',
content: 'Custom content
',
},
- })
+ )
await nextTick()
expect(wrapper.find('.custom-title').exists()).toBe(true)
expect(wrapper.find('.custom-content').exists()).toBe(true)
})
it('支持 HTML 内容', async () => {
- wrapper = mount(Popover, {
- props: {
- content: 'Bold',
- rawContent: true,
- visible: true,
- teleported: false, // 测试中禁用 teleport,以便在组件内部查找元素
- },
- slots: {
- default: '',
- },
+ wrapper = createWrapper({
+ content: 'Bold',
+ rawContent: true,
+ visible: true,
})
await nextTick()
expect(wrapper.find('.ccui-popover__content strong').exists()).toBe(true)
})
it('支持设置宽度', async () => {
- wrapper = mount(Popover, {
- props: {
- content: 'W',
- width: '200px',
- visible: true,
- teleported: false, // 测试中禁用 teleport,以便在组件内部查找元素
- },
- slots: {
- default: '',
- },
+ wrapper = createWrapper({
+ content: 'W',
+ width: '200px',
+ visible: true,
})
await nextTick()
- const popper = wrapper.find('.ccui-popover__popper')
- expect(popper.element.style.width).toBe('200px')
+ expect(wrapper.find('.ccui-popover__popper').element.style.width).toBe('200px')
})
})
describe('主题与样式', () => {
- it('应用 light 主题', async () => {
- wrapper = mount(Popover, {
- props: {
- content: 'Test',
- effect: 'light',
- visible: true,
- teleported: false, // 测试中禁用 teleport,以便在组件内部查找元素
- },
- slots: {
- default: '',
- },
+ it.each([
+ ['light', 'ccui-popover__popper--light'],
+ ['dark', 'ccui-popover__popper--dark'],
+ ])('应用 %s 主题', async (effect, expectedClass) => {
+ wrapper = createWrapper({
+ content: 'Test',
+ effect: effect as any,
+ visible: true,
})
await nextTick()
- expect(wrapper.find('.ccui-popover__popper--light').exists()).toBe(true)
- })
-
- it('应用 dark 主题', async () => {
- wrapper = mount(Popover, {
- props: {
- content: 'Test',
- effect: 'dark',
- visible: true,
- teleported: false, // 测试中禁用 teleport,以便在组件内部查找元素
- },
- slots: {
- default: '',
- },
- })
- await nextTick()
- expect(wrapper.find('.ccui-popover__popper--dark').exists()).toBe(true)
+ expect(wrapper.find(`.${expectedClass}`).exists()).toBe(true)
})
it('应用位置样式', async () => {
const placements = ['top', 'bottom', 'left', 'right']
+ wrapper = createWrapper({
+ content: 'Test',
+ placement: 'top',
+ visible: true,
+ })
+
for (const placement of placements) {
- wrapper = mount(Popover, {
- props: {
- content: 'Test',
- placement: placement as any,
- visible: true,
- teleported: false, // 测试中禁用 teleport,以便在组件内部查找元素
- },
- slots: {
- default: '',
- },
- })
+ await wrapper.setProps({ placement: placement as any })
await nextTick()
expect(wrapper.find(`.ccui-popover__popper--${placement}`).exists()).toBe(true)
- wrapper.unmount()
}
})
- it('显示箭头', async () => {
- wrapper = mount(Popover, {
- props: {
- content: 'Test',
- showArrow: true,
- visible: true,
- teleported: false, // 测试中禁用 teleport,以便在组件内部查找元素
- },
- slots: { default: '' },
+ it.each([
+ [true, true],
+ [false, false],
+ ])('箭头显示状态: showArrow=%s', async (showArrow, shouldExist) => {
+ wrapper = createWrapper({
+ content: 'Test',
+ showArrow,
+ visible: true,
})
await nextTick()
- expect(wrapper.find('.ccui-popover__arrow').exists()).toBe(true)
- })
-
- it('隐藏箭头', async () => {
- wrapper = mount(Popover, {
- props: {
- content: 'Test',
- showArrow: false,
- visible: true,
- teleported: false, // 测试中禁用 teleport,以便在组件内部查找元素
- },
- slots: { default: '' },
- })
- await nextTick()
- expect(wrapper.find('.ccui-popover__arrow').exists()).toBe(false)
+ expect(wrapper.find('.ccui-popover__arrow').exists()).toBe(shouldExist)
})
})
describe('交互功能', () => {
it('点击时切换显示状态', async () => {
- wrapper = mount(Popover, {
- props: {
- content: 'Test',
- trigger: 'click',
- teleported: false, // 测试中禁用 teleport,以便在组件内部查找元素
- },
- slots: { default: '' },
- })
+ wrapper = createWrapper({ content: 'Test', trigger: 'click' })
const trigger = wrapper.find('.ccui-popover__trigger')
await trigger.trigger('click')
await nextTick()
@@ -209,10 +163,7 @@ describe('popover', () => {
})
it('悬停时显示与隐藏', async () => {
- wrapper = mount(Popover, {
- props: { content: 'Test', trigger: 'hover', hideAfter: 0, teleported: false },
- slots: { default: '' },
- })
+ wrapper = createWrapper({ content: 'Test', trigger: 'hover', hideAfter: 0 })
const trigger = wrapper.find('.ccui-popover__trigger')
await trigger.trigger('mouseenter')
await nextTick()
@@ -223,10 +174,10 @@ describe('popover', () => {
})
it('获得焦点时显示,失焦时隐藏', async () => {
- wrapper = mount(Popover, {
- props: { content: 'Test', trigger: 'focus', hideAfter: 0, teleported: false },
- slots: { default: '' },
- })
+ wrapper = createWrapper(
+ { content: 'Test', trigger: 'focus', hideAfter: 0 },
+ { default: '' },
+ )
const trigger = wrapper.find('.ccui-popover__trigger')
await trigger.trigger('focus')
await nextTick()
@@ -239,10 +190,7 @@ describe('popover', () => {
describe('禁用与延迟', () => {
it('禁用时不显示', async () => {
- wrapper = mount(Popover, {
- props: { content: 'Test', disabled: true, trigger: 'hover', teleported: false },
- slots: { default: '' },
- })
+ wrapper = createWrapper({ content: 'Test', disabled: true, trigger: 'hover' })
const trigger = wrapper.find('.ccui-popover__trigger')
await trigger.trigger('mouseenter')
await nextTick()
@@ -257,10 +205,7 @@ describe('popover', () => {
vi.useRealTimers()
})
it('延迟显示', async () => {
- wrapper = mount(Popover, {
- props: { content: 'Test', trigger: 'hover', showAfter: 100, teleported: false },
- slots: { default: '' },
- })
+ wrapper = createWrapper({ content: 'Test', trigger: 'hover', showAfter: 100 })
const trigger = wrapper.find('.ccui-popover__trigger')
await trigger.trigger('mouseenter')
await nextTick()
@@ -270,10 +215,7 @@ describe('popover', () => {
expect(wrapper.find('.ccui-popover__popper').exists()).toBe(true)
})
it('延迟隐藏', async () => {
- wrapper = mount(Popover, {
- props: { content: 'Test', trigger: 'hover', hideAfter: 100, teleported: false },
- slots: { default: '' },
- })
+ wrapper = createWrapper({ content: 'Test', trigger: 'hover', hideAfter: 100 })
const trigger = wrapper.find('.ccui-popover__trigger')
await trigger.trigger('mouseenter')
await nextTick()
@@ -294,17 +236,14 @@ describe('popover', () => {
const show = vi.fn()
const beforeHide = vi.fn()
const hide = vi.fn()
- wrapper = mount(Popover, {
- props: {
- 'content': 'Test',
- 'trigger': 'hover',
- 'hideAfter': 0,
- 'onBefore-show': beforeShow,
- 'onShow': show,
- 'onBefore-hide': beforeHide,
- 'onHide': hide,
- },
- slots: { default: '' },
+ wrapper = createWrapper({
+ 'content': 'Test',
+ 'trigger': 'hover',
+ 'hideAfter': 0,
+ 'onBefore-show': beforeShow,
+ 'onShow': show,
+ 'onBefore-hide': beforeHide,
+ 'onHide': hide,
})
const trigger = wrapper.find('.ccui-popover__trigger')
await trigger.trigger('mouseenter')
@@ -318,10 +257,7 @@ describe('popover', () => {
})
it('aRIA 属性', async () => {
- wrapper = mount(Popover, {
- props: { content: 'Test', ariaLabel: 'Test popover', visible: true, teleported: false },
- slots: { default: '' },
- })
+ wrapper = createWrapper({ content: 'Test', ariaLabel: 'Test popover', visible: true })
await nextTick()
const trigger = wrapper.find('.ccui-popover__trigger')
const popper = wrapper.find('.ccui-popover__popper')
@@ -383,10 +319,7 @@ describe('popover', () => {
describe('新增功能测试', () => {
it('右键菜单触发', async () => {
- wrapper = mount(Popover, {
- props: { content: 'Test', trigger: 'contextmenu', teleported: false },
- slots: { default: '' },
- })
+ wrapper = createWrapper({ content: 'Test', trigger: 'contextmenu' })
const trigger = wrapper.find('.ccui-popover__trigger')
await trigger.trigger('contextmenu')
await nextTick()
@@ -416,10 +349,7 @@ describe('popover', () => {
it('自动关闭功能', async () => {
vi.useFakeTimers()
- wrapper = mount(Popover, {
- props: { content: 'Test', trigger: 'click', autoClose: 1000, teleported: false },
- slots: { default: '' },
- })
+ wrapper = createWrapper({ content: 'Test', trigger: 'click', autoClose: 1000 })
const trigger = wrapper.find('.ccui-popover__trigger')
await trigger.trigger('click')
await nextTick()
@@ -432,10 +362,10 @@ describe('popover', () => {
})
it('键盘触发功能', async () => {
- wrapper = mount(Popover, {
- props: { content: 'Test', trigger: 'focus', triggerKeys: ['Enter', ' '], hideAfter: 0, teleported: false },
- slots: { default: '' },
- })
+ wrapper = createWrapper(
+ { content: 'Test', trigger: 'focus', triggerKeys: ['Enter', ' '], hideAfter: 0 },
+ { default: '' },
+ )
const trigger = wrapper.find('.ccui-popover__trigger')
// focus 事件会自动显示 popover
@@ -487,17 +417,13 @@ describe('popover', () => {
const beforeLeave = vi.fn()
const afterLeave = vi.fn()
- wrapper = mount(Popover, {
- props: {
- 'content': 'Test',
- 'trigger': 'click',
- 'teleported': false,
- 'onBefore-enter': beforeEnter,
- 'onAfter-enter': afterEnter,
- 'onBefore-leave': beforeLeave,
- 'onAfter-leave': afterLeave,
- },
- slots: { default: '' },
+ wrapper = createWrapper({
+ 'content': 'Test',
+ 'trigger': 'click',
+ 'onBefore-enter': beforeEnter,
+ 'onAfter-enter': afterEnter,
+ 'onBefore-leave': beforeLeave,
+ 'onAfter-leave': afterLeave,
})
const trigger = wrapper.find('.ccui-popover__trigger')
@@ -525,10 +451,7 @@ describe('popover', () => {
})
it('exposes methods', async () => {
- wrapper = mount(Popover, {
- props: { content: 'Test', visible: true, teleported: false },
- slots: { default: '' },
- })
+ wrapper = createWrapper({ content: 'Test', visible: true })
await nextTick()
expect(wrapper.find('.ccui-popover__popper').exists()).toBe(true)
@@ -537,10 +460,7 @@ describe('popover', () => {
// 所以需要测试非受控模式
wrapper.unmount()
- wrapper = mount(Popover, {
- props: { content: 'Test', teleported: false },
- slots: { default: '' },
- })
+ wrapper = createWrapper({ content: 'Test' })
// 手动触发显示
const trigger = wrapper.find('.ccui-popover__trigger')
diff --git a/packages/ccui/ui/rate/test/rate.test.ts b/packages/ccui/ui/rate/test/rate.test.ts
index d60d9797..27422839 100644
--- a/packages/ccui/ui/rate/test/rate.test.ts
+++ b/packages/ccui/ui/rate/test/rate.test.ts
@@ -7,78 +7,56 @@ const ns = useNamespace('rate', true)
const baseClass = ns.b()
const iconClass = ns.e('icon')
+// 测试辅助函数
+function createWrapper(props = {}, slots = {}) {
+ return mount(Rate, { props, slots })
+}
+
+function createShallowWrapper(props = {}) {
+ return shallowMount(Rate, { props })
+}
+
describe('rate', () => {
it('dom', async () => {
- const wrapper = shallowMount(Rate)
-
+ const wrapper = createShallowWrapper()
expect(wrapper.find(baseClass).exists()).toBeTruthy()
wrapper.unmount()
})
it('props', async () => {
- const wrapper = shallowMount(Rate, {
- props: {
- count: 10,
- },
- })
-
+ const wrapper = createShallowWrapper({ count: 10 })
expect(wrapper.findAll(iconClass).length).toBe(10)
-
wrapper.unmount()
})
it('event', async () => {
- const wrapper = shallowMount(Rate, {
- props: {
- count: 10,
- },
- })
-
+ const wrapper = createShallowWrapper({ count: 10 })
expect(wrapper.findAll(iconClass).length).toBe(10)
const threeIcon = wrapper.findAll(iconClass)[2]
await threeIcon.trigger('click')
- // change 事件触发,icon 第三个 等于数字3
expect(wrapper.emitted('change')?.[0]).toEqual([3])
wrapper.unmount()
})
it('renders correct number of icons based on count prop', () => {
- const wrapper = mount(Rate, {
- props: {
- count: 5,
- },
- })
-
+ const wrapper = createWrapper({ count: 5 })
expect(wrapper.findAll(iconClass).length).toBe(5)
})
it('applies correct width to icons based on modelValue', async () => {
- const wrapper = mount(Rate, {
- props: {
- modelValue: 3,
- },
- })
-
- // 等待组件更新
+ const wrapper = createWrapper({ modelValue: 3 })
await wrapper.vm.$nextTick()
const icons = wrapper.findAll(iconClass)
- // 前三个图标应该是100%宽度
expect(icons[0].find(ns.m('active')).attributes('style')).toContain('width: 100%')
expect(icons[1].find(ns.m('active')).attributes('style')).toContain('width: 100%')
expect(icons[2].find(ns.m('active')).attributes('style')).toContain('width: 100%')
- // 第四个图标应该是0%宽度
expect(icons[3].find(ns.m('active')).attributes('style')).toContain('width: 0%')
})
it('emits change and update:modelValue events when clicked', async () => {
- const wrapper = mount(Rate, {
- props: {
- count: 5,
- },
- })
-
+ const wrapper = createWrapper({ count: 5 })
const thirdIcon = wrapper.findAll(iconClass)[2]
await thirdIcon.trigger('click')
@@ -89,13 +67,7 @@ describe('rate', () => {
})
it('does not emit events when readOnly is true', async () => {
- const wrapper = mount(Rate, {
- props: {
- readOnly: true,
- count: 5,
- },
- })
-
+ const wrapper = createWrapper({ readOnly: true, count: 5 })
const thirdIcon = wrapper.findAll(iconClass)[2]
await thirdIcon.trigger('click')
@@ -104,27 +76,17 @@ describe('rate', () => {
})
it('applies custom color when provided', async () => {
- const wrapper = mount(Rate, {
- props: {
- modelValue: 3,
- color: '#ff0000',
- },
- })
-
- // 等待组件更新
+ const wrapper = createWrapper({ modelValue: 3, color: '#ff0000' })
await wrapper.vm.$nextTick()
const activeIcon = wrapper.find(ns.m('active'))
- // 检查是否包含颜色样式
expect(activeIcon.attributes('style')).toContain('color: rgb(255, 0, 0)')
expect(activeIcon.attributes('style')).toContain('#ff0000')
})
it('renders info slot when provided', () => {
- const wrapper = mount(Rate, {
- slots: {
- info: 'Info Content
',
- },
+ const wrapper = createWrapper({}, {
+ info: 'Info Content
',
})
expect(wrapper.find('.info-slot').exists()).toBe(true)
@@ -132,27 +94,16 @@ describe('rate', () => {
})
it('resets icon state on mouse leave', async () => {
- const wrapper = mount(Rate, {
- props: {
- modelValue: 3,
- },
- })
-
- // 等待组件更新
+ const wrapper = createWrapper({ modelValue: 3 })
await wrapper.vm.$nextTick()
- // 模拟鼠标移动到第5个图标
const fifthIcon = wrapper.findAll(iconClass)[4]
await fifthIcon.trigger('mousemove')
- // 验证图标状态已更新
const icons = wrapper.findAll(iconClass)
expect(icons[4].find(ns.m('active')).attributes('style')).toContain('width: 100%')
- // 模拟鼠标离开
await wrapper.trigger('mouseleave')
-
- // 验证图标状态重置为初始值
expect(icons[4].find(ns.m('active')).attributes('style')).toContain('width: 0%')
})
})
diff --git a/packages/ccui/ui/slider/test/slider.test.ts b/packages/ccui/ui/slider/test/slider.test.ts
index 59e3a78e..43014e5b 100644
--- a/packages/ccui/ui/slider/test/slider.test.ts
+++ b/packages/ccui/ui/slider/test/slider.test.ts
@@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
-import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { describe, expect, it, vi } from 'vitest'
import { useNamespace } from '../../shared/hooks/use-namespace'
import { Slider } from '../index'
@@ -12,8 +12,14 @@ const buttonClass = ns.e('button')
describe('slider', () => {
let wrapper: any
- beforeEach(() => {
- wrapper = null
+ // Helper function to create mock rect
+ const createMockRect = (width = 100, height = 32) => ({
+ left: 0,
+ width,
+ top: 0,
+ height,
+ right: width,
+ bottom: height,
})
it('dom', () => {
@@ -27,7 +33,7 @@ describe('slider', () => {
wrapper.unmount()
})
- it('props - modelValue', async () => {
+ it('props - modelValue', () => {
const modelValue = 50
wrapper = mount(Slider, {
props: {
@@ -83,11 +89,9 @@ describe('slider', () => {
},
})
- // 需要触发悬停才能显示 tooltip
const button = wrapper.find(ns.e('button'))
await button.trigger('mouseenter')
- // 使用 CTooltip 组件,检查 tooltip 是否存在
const tooltipComponent = wrapper.findComponent({ name: 'CTooltip' })
expect(tooltipComponent.exists()).toBe(true)
expect(tooltipComponent.props('visible')).toBe(true)
@@ -102,7 +106,6 @@ describe('slider', () => {
},
})
- // tooltip 组件不应该存在
const tooltipComponent = wrapper.findComponent({ name: 'CTooltip' })
expect(tooltipComponent.exists()).toBe(false)
wrapper.unmount()
@@ -130,7 +133,6 @@ describe('slider', () => {
},
})
- // InputNumber 组件内部有控制按钮
expect(wrapper.find(ns.e('input-number')).exists()).toBe(true)
wrapper.unmount()
})
@@ -169,7 +171,6 @@ describe('slider', () => {
},
})
- // tooltip 组件应该存在但不显示内容
const tooltipComponent = wrapper.findComponent({ name: 'CTooltip' })
expect(tooltipComponent.exists()).toBe(true)
expect(tooltipComponent.props('content')).toBe('')
@@ -187,7 +188,6 @@ describe('slider', () => {
},
})
- // 需要触发悬停才能显示 tooltip
const button = wrapper.find(ns.e('button'))
await button.trigger('mouseenter')
@@ -207,14 +207,12 @@ describe('slider', () => {
},
})
- // 需要触发悬停才能显示 tooltip
const button = wrapper.find(ns.e('button'))
await button.trigger('mouseenter')
const tooltipComponent = wrapper.findComponent({ name: 'CTooltip' })
expect(tooltipComponent.exists()).toBe(true)
expect(tooltipComponent.props('visible')).toBe(true)
- // placement 应该使用用户设置的值
expect(tooltipComponent.props('placement')).toBe('bottom')
wrapper.unmount()
})
@@ -248,7 +246,7 @@ describe('slider', () => {
})
expect(wrapper.find(ns.e('stops')).exists()).toBe(true)
- expect(wrapper.findAll(ns.e('stop')).length).toBe(11) // 0-100 with step 10
+ expect(wrapper.findAll(ns.e('stop')).length).toBe(11)
wrapper.unmount()
})
@@ -270,20 +268,8 @@ describe('slider', () => {
},
})
- // 模拟点击滑块
const sliderWrapper = wrapper.find(wrapperClass)
-
- // 模拟 getBoundingClientRect
- const mockRect = {
- left: 0,
- width: 100,
- top: 0,
- height: 32,
- right: 100,
- bottom: 32,
- }
-
- vi.spyOn(sliderWrapper.element, 'getBoundingClientRect').mockReturnValue(mockRect)
+ vi.spyOn(sliderWrapper.element, 'getBoundingClientRect').mockReturnValue(createMockRect())
await sliderWrapper.trigger('click', { clientX: 50 })
@@ -336,18 +322,7 @@ describe('slider', () => {
})
const button = wrapper.find(buttonClass)
-
- // Mock getBoundingClientRect
- const mockRect = {
- left: 0,
- width: 100,
- top: 0,
- height: 32,
- right: 100,
- bottom: 32,
- }
-
- vi.spyOn(wrapper.vm.sliderRef, 'getBoundingClientRect').mockReturnValue(mockRect)
+ vi.spyOn(wrapper.vm.sliderRef, 'getBoundingClientRect').mockReturnValue(createMockRect())
await button.trigger('mousedown', { clientX: 50 })
expect(wrapper.vm.isDragging).toBe(true)
@@ -451,7 +426,6 @@ describe('slider', () => {
},
})
- // 使用 InputNumber 组件的事件
const inputNumber = wrapper.findComponent({ name: 'CInputNumber' })
await inputNumber.vm.$emit('update:modelValue', 75)
@@ -460,7 +434,7 @@ describe('slider', () => {
wrapper.unmount()
})
- it('input change with invalid value', async () => {
+ it('input change with invalid value', () => {
wrapper = mount(Slider, {
props: {
showInput: true,
@@ -470,7 +444,6 @@ describe('slider', () => {
},
})
- // InputNumber 组件内部处理无效值
const inputNumber = wrapper.findComponent({ name: 'CInputNumber' })
expect(inputNumber.exists()).toBe(true)
wrapper.unmount()
@@ -486,12 +459,10 @@ describe('slider', () => {
},
})
- // 使用 InputNumber 组件的事件,测试边界值处理
const inputNumber = wrapper.findComponent({ name: 'CInputNumber' })
await inputNumber.vm.$emit('update:modelValue', 150)
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
- // Should clamp to max value
const emittedValues = wrapper.emitted('update:modelValue') as any[]
expect(emittedValues[emittedValues.length - 1][0]).toBe(100)
wrapper.unmount()
@@ -507,18 +478,16 @@ describe('slider', () => {
},
})
- // 使用 InputNumber 组件的事件,测试边界值处理
const inputNumber = wrapper.findComponent({ name: 'CInputNumber' })
await inputNumber.vm.$emit('update:modelValue', -10)
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
- // Should clamp to min value
const emittedValues = wrapper.emitted('update:modelValue') as any[]
expect(emittedValues[emittedValues.length - 1][0]).toBe(0)
wrapper.unmount()
})
- it('event - input increase button', async () => {
+ it('event - input increase button', () => {
wrapper = mount(Slider, {
props: {
showInput: true,
@@ -529,13 +498,12 @@ describe('slider', () => {
},
})
- // InputNumber 组件内部处理增减按钮
const inputNumber = wrapper.findComponent({ name: 'CInputNumber' })
expect(inputNumber.exists()).toBe(true)
wrapper.unmount()
})
- it('event - input decrease button', async () => {
+ it('event - input decrease button', () => {
wrapper = mount(Slider, {
props: {
showInput: true,
@@ -546,13 +514,12 @@ describe('slider', () => {
},
})
- // InputNumber 组件内部处理增减按钮
const inputNumber = wrapper.findComponent({ name: 'CInputNumber' })
expect(inputNumber.exists()).toBe(true)
wrapper.unmount()
})
- it('event - input buttons disabled at boundaries', async () => {
+ it('event - input buttons disabled at boundaries', () => {
wrapper = mount(Slider, {
props: {
showInput: true,
@@ -563,7 +530,6 @@ describe('slider', () => {
},
})
- // InputNumber 组件内部处理边界禁用逻辑
const inputNumber = wrapper.findComponent({ name: 'CInputNumber' })
expect(inputNumber.exists()).toBe(true)
wrapper.unmount()
@@ -690,7 +656,6 @@ describe('slider', () => {
},
})
- // InputNumber 组件处理输入
const inputNumber = wrapper.findComponent({ name: 'CInputNumber' })
expect(inputNumber.exists()).toBe(true)
wrapper.unmount()
@@ -705,7 +670,6 @@ describe('slider', () => {
},
})
- // InputNumber 组件处理输入
const inputNumber = wrapper.findComponent({ name: 'CInputNumber' })
expect(inputNumber.exists()).toBe(true)
wrapper.unmount()
diff --git a/packages/ccui/ui/timeline/test/timeline.test.ts b/packages/ccui/ui/timeline/test/timeline.test.ts
index 63b8aa34..8e0130ef 100644
--- a/packages/ccui/ui/timeline/test/timeline.test.ts
+++ b/packages/ccui/ui/timeline/test/timeline.test.ts
@@ -3,21 +3,37 @@ import { describe, expect, it } from 'vitest'
import { h, markRaw } from 'vue'
import { Timeline, TimelineItem } from '../index'
+// 测试辅助函数
+function createTimelineWrapper(slots = {}) {
+ return mount(Timeline, { slots })
+}
+
+function createItemWrapper(props = {}, slots = {}) {
+ return mount(TimelineItem, {
+ props: {
+ timestamp: '2018/4/12',
+ ...props,
+ },
+ slots: {
+ default: 'Test content',
+ ...slots,
+ },
+ })
+}
+
describe('timeline', () => {
it('should render', () => {
- const wrapper = mount(Timeline)
+ const wrapper = createTimelineWrapper()
expect(wrapper.exists()).toBe(true)
expect(wrapper.classes()).toContain('ccui-timeline')
})
it('should render timeline items', () => {
- const wrapper = mount(Timeline, {
- slots: {
- default: () => [
- h(TimelineItem, { timestamp: '2018/4/12' }, () => 'Test content 1'),
- h(TimelineItem, { timestamp: '2018/4/3' }, () => 'Test content 2'),
- ],
- },
+ const wrapper = createTimelineWrapper({
+ default: () => [
+ h(TimelineItem, { timestamp: '2018/4/12' }, () => 'Test content 1'),
+ h(TimelineItem, { timestamp: '2018/4/3' }, () => 'Test content 2'),
+ ],
})
expect(wrapper.element.tagName).toBe('UL')
@@ -29,15 +45,7 @@ describe('timeline', () => {
describe('timelineItem', () => {
it('should render with timestamp', () => {
- const wrapper = mount(TimelineItem, {
- props: {
- timestamp: '2018/4/12',
- },
- slots: {
- default: 'Test content',
- },
- })
-
+ const wrapper = createItemWrapper()
expect(wrapper.exists()).toBe(true)
expect(wrapper.classes()).toContain('ccui-timeline-item')
expect(wrapper.find('.ccui-timeline-item__timestamp').text()).toBe('2018/4/12')
@@ -45,115 +53,49 @@ describe('timelineItem', () => {
})
it('should hide timestamp when hideTimestamp is true', () => {
- const wrapper = mount(TimelineItem, {
- props: {
- timestamp: '2018/4/12',
- hideTimestamp: true,
- },
- slots: {
- default: 'Test content',
- },
- })
-
+ const wrapper = createItemWrapper({ hideTimestamp: true })
expect(wrapper.find('.ccui-timeline-item__timestamp').exists()).toBe(false)
})
- it('should render with different types', () => {
- const wrapper = mount(TimelineItem, {
- props: {
- timestamp: '2018/4/12',
- type: 'primary',
- },
- slots: {
- default: 'Test content',
- },
- })
-
- expect(wrapper.find('.ccui-timeline-item__node--primary').exists()).toBe(true)
+ it.each([
+ ['primary', '.ccui-timeline-item__node--primary'],
+ ['success', '.ccui-timeline-item__node--success'],
+ ['warning', '.ccui-timeline-item__node--warning'],
+ ['danger', '.ccui-timeline-item__node--danger'],
+ ['info', '.ccui-timeline-item__node--info'],
+ ])('should render with type %s', (type, expectedClass) => {
+ const wrapper = createItemWrapper({ type })
+ expect(wrapper.find(expectedClass).exists()).toBe(true)
})
it('should render with custom color', () => {
- const wrapper = mount(TimelineItem, {
- props: {
- timestamp: '2018/4/12',
- color: '#ff0000',
- },
- slots: {
- default: 'Test content',
- },
- })
-
+ const wrapper = createItemWrapper({ color: '#ff0000' })
const node = wrapper.find('.ccui-timeline-item__node')
expect(node.attributes('style')).toContain('background-color: rgb(255, 0, 0)')
})
it('should render with large size', () => {
- const wrapper = mount(TimelineItem, {
- props: {
- timestamp: '2018/4/12',
- size: 'large',
- },
- slots: {
- default: 'Test content',
- },
- })
-
+ const wrapper = createItemWrapper({ size: 'large' })
expect(wrapper.find('.ccui-timeline-item__node--large').exists()).toBe(true)
})
it('should render with hollow style', () => {
- const wrapper = mount(TimelineItem, {
- props: {
- timestamp: '2018/4/12',
- hollow: true,
- },
- slots: {
- default: 'Test content',
- },
- })
-
+ const wrapper = createItemWrapper({ hollow: true })
expect(wrapper.find('.ccui-timeline-item__node.is-hollow').exists()).toBe(true)
})
it('should render timestamp at top when placement is top', () => {
- const wrapper = mount(TimelineItem, {
- props: {
- timestamp: '2018/4/12',
- placement: 'top',
- },
- slots: {
- default: 'Test content',
- },
- })
-
+ const wrapper = createItemWrapper({ placement: 'top' })
expect(wrapper.find('.ccui-timeline-item__timestamp.is-top').exists()).toBe(true)
})
it('should render with center alignment', () => {
- const wrapper = mount(TimelineItem, {
- props: {
- timestamp: '2018/4/12',
- center: true,
- },
- slots: {
- default: 'Test content',
- },
- })
-
+ const wrapper = createItemWrapper({ center: true })
expect(wrapper.classes()).toContain('ccui-timeline-item__center')
})
it('should render with string icon', () => {
- const wrapper = mount(TimelineItem, {
- props: {
- timestamp: '2018/4/12',
- icon: 'icon-class-name',
- },
- slots: {
- default: 'Test content',
- },
- })
-
+ const wrapper = createItemWrapper({ icon: 'icon-class-name' })
expect(wrapper.find('.ccui-timeline-item__icon').exists()).toBe(true)
expect(wrapper.find('.icon-class-name').exists()).toBe(true)
})
@@ -166,31 +108,15 @@ describe('timelineItem', () => {
},
})
- const wrapper = mount(TimelineItem, {
- props: {
- timestamp: '2018/4/12',
- icon: IconComponent,
- },
- slots: {
- default: 'Test content',
- },
- })
-
+ const wrapper = createItemWrapper({ icon: IconComponent })
expect(wrapper.find('.ccui-timeline-item__icon').exists()).toBe(true)
expect(wrapper.find('.test-icon').exists()).toBe(true)
})
it('should render with custom dot slot', () => {
- const wrapper = mount(TimelineItem, {
- props: {
- timestamp: '2018/4/12',
- },
- slots: {
- default: 'Test content',
- dot: 'Custom
',
- },
+ const wrapper = createItemWrapper({}, {
+ dot: 'Custom
',
})
-
expect(wrapper.find('.ccui-timeline-item__dot').exists()).toBe(true)
expect(wrapper.find('.custom-dot').exists()).toBe(true)
})
diff --git a/packages/ccui/ui/tooltip/test/tooltip.test.ts b/packages/ccui/ui/tooltip/test/tooltip.test.ts
index 1a57b432..4bb770f7 100644
--- a/packages/ccui/ui/tooltip/test/tooltip.test.ts
+++ b/packages/ccui/ui/tooltip/test/tooltip.test.ts
@@ -3,11 +3,37 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { nextTick } from 'vue'
import { Tooltip } from '../index'
+// 测试辅助函数
+function createWrapper(props = {}, slots = {}) {
+ return mount(Tooltip, {
+ props: {
+ teleported: false,
+ ...props,
+ },
+ slots: {
+ default: '',
+ ...slots,
+ },
+ })
+}
+
+function createShallowWrapper(props = {}, slots = {}) {
+ return shallowMount(Tooltip, {
+ props: {
+ teleported: false,
+ ...props,
+ },
+ slots: {
+ default: '',
+ ...slots,
+ },
+ })
+}
+
describe('tooltip', () => {
let wrapper: any
beforeEach(() => {
- // 模拟 DOM 环境
Object.defineProperty(window, 'innerWidth', {
writable: true,
configurable: true,
@@ -28,280 +54,131 @@ describe('tooltip', () => {
})
describe('基础功能', () => {
- it('应该正确渲染组件', () => {
- wrapper = shallowMount(Tooltip, {
- props: {
- content: 'Test tooltip',
- },
- slots: {
- default: '',
- },
- })
-
+ it('正确渲染组件', () => {
+ wrapper = createShallowWrapper()
expect(wrapper.exists()).toBe(true)
expect(wrapper.find('.ccui-tooltip').exists()).toBe(true)
expect(wrapper.find('.ccui-tooltip__trigger').exists()).toBe(true)
})
- it('应该正确显示内容', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test tooltip content',
- visible: true,
- },
- slots: {
- default: '',
- },
+ it('显示内容', async () => {
+ wrapper = createWrapper({
+ content: 'Test tooltip content',
+ visible: true,
})
-
await nextTick()
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(true)
expect(wrapper.find('.ccui-tooltip__content').text()).toBe('Test tooltip content')
})
- it('应该支持插槽内容', async () => {
- wrapper = mount(Tooltip, {
- props: {
- visible: true,
- },
- slots: {
- default: '',
- content: 'Custom content
',
- },
- })
-
+ it('支持插槽内容', async () => {
+ wrapper = createWrapper(
+ { visible: true },
+ { content: 'Custom content
' },
+ )
await nextTick()
expect(wrapper.find('.custom-content').exists()).toBe(true)
expect(wrapper.find('.custom-content').text()).toBe('Custom content')
})
- it('应该支持 HTML 内容', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Bold text',
- rawContent: true,
- visible: true,
- },
- slots: {
- default: '',
- },
+ it('支持 HTML 内容', async () => {
+ wrapper = createWrapper({
+ content: 'Bold text',
+ rawContent: true,
+ visible: true,
})
-
await nextTick()
expect(wrapper.find('.ccui-tooltip__content strong').exists()).toBe(true)
})
})
- describe('主题和样式', () => {
- it('应该正确应用 dark 主题', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- effect: 'dark',
- visible: true,
- },
- slots: {
- default: '',
- },
- })
-
- await nextTick()
- expect(wrapper.find('.ccui-tooltip__popper--dark').exists()).toBe(true)
- })
-
- it('应该正确应用 light 主题', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- effect: 'light',
- visible: true,
- },
- slots: {
- default: '',
- },
+ describe('主题与样式', () => {
+ it.each([
+ ['dark', 'ccui-tooltip__popper--dark'],
+ ['light', 'ccui-tooltip__popper--light'],
+ ])('应用 %s 主题', async (effect, expectedClass) => {
+ wrapper = createWrapper({
+ content: 'Test',
+ effect: effect as any,
+ visible: true,
})
-
await nextTick()
- expect(wrapper.find('.ccui-tooltip__popper--light').exists()).toBe(true)
+ expect(wrapper.find(`.${expectedClass}`).exists()).toBe(true)
})
- it('应该正确应用位置样式', async () => {
+ it('应用位置样式', async () => {
const placements = ['top', 'bottom', 'left', 'right']
+ wrapper = createWrapper({
+ content: 'Test',
+ placement: 'top',
+ visible: true,
+ })
for (const placement of placements) {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- placement: placement as any,
- visible: true,
- },
- slots: {
- default: '',
- },
- })
-
+ await wrapper.setProps({ placement: placement as any })
await nextTick()
expect(wrapper.find(`.ccui-tooltip__popper--${placement}`).exists()).toBe(true)
- wrapper.unmount()
}
})
- it('应该显示箭头', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- showArrow: true,
- visible: true,
- },
- slots: {
- default: '',
- },
+ it.each([
+ [true, true],
+ [false, false],
+ ])('箭头显示状态: showArrow=%s', async (showArrow, shouldExist) => {
+ wrapper = createWrapper({
+ content: 'Test',
+ showArrow,
+ visible: true,
})
-
await nextTick()
- expect(wrapper.find('.ccui-tooltip__arrow').exists()).toBe(true)
- })
-
- it('应该隐藏箭头', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- showArrow: false,
- visible: true,
- },
- slots: {
- default: '',
- },
- })
-
- await nextTick()
- expect(wrapper.find('.ccui-tooltip__arrow').exists()).toBe(false)
+ expect(wrapper.find('.ccui-tooltip__arrow').exists()).toBe(shouldExist)
})
})
describe('交互功能', () => {
- it('应该在鼠标悬停时显示', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- trigger: 'hover',
- },
- slots: {
- default: '',
- },
- })
-
+ it('悬停时显示与隐藏', async () => {
+ wrapper = createWrapper({ content: 'Test', trigger: 'hover', hideAfter: 0 })
const trigger = wrapper.find('.ccui-tooltip__trigger')
await trigger.trigger('mouseenter')
await nextTick()
-
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(true)
- })
-
- it('应该在鼠标离开时隐藏', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- trigger: 'hover',
- hideAfter: 0,
- },
- slots: {
- default: '',
- },
- })
-
- const trigger = wrapper.find('.ccui-tooltip__trigger')
- await trigger.trigger('mouseenter')
- await nextTick()
-
await trigger.trigger('mouseleave')
await nextTick()
-
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(false)
})
- it('应该在点击时切换显示状态', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- trigger: 'click',
- },
- slots: {
- default: '',
- },
- })
-
+ it('点击时切换显示状态', async () => {
+ wrapper = createWrapper({ content: 'Test', trigger: 'click' })
const trigger = wrapper.find('.ccui-tooltip__trigger')
-
- // 第一次点击显示
await trigger.trigger('click')
await nextTick()
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(true)
-
- // 第二次点击隐藏
await trigger.trigger('click')
await nextTick()
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(false)
})
- it('应该在获得焦点时显示', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- trigger: 'focus',
- },
- slots: {
- default: '',
- },
- })
-
+ it('获得焦点时显示,失焦时隐藏', async () => {
+ wrapper = createWrapper(
+ { content: 'Test', trigger: 'focus', hideAfter: 0 },
+ { default: '' },
+ )
const trigger = wrapper.find('.ccui-tooltip__trigger')
await trigger.trigger('focus')
await nextTick()
-
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(true)
- })
-
- it('应该在失去焦点时隐藏', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- trigger: 'focus',
- hideAfter: 0,
- },
- slots: {
- default: '',
- },
- })
-
- const trigger = wrapper.find('.ccui-tooltip__trigger')
- await trigger.trigger('focus')
- await nextTick()
-
await trigger.trigger('blur')
await nextTick()
-
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(false)
})
})
describe('禁用状态', () => {
- it('禁用时不应该显示', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- disabled: true,
- trigger: 'hover',
- },
- slots: {
- default: '',
- },
- })
-
+ it('禁用时不显示', async () => {
+ wrapper = createWrapper({ content: 'Test', disabled: true, trigger: 'hover' })
const trigger = wrapper.find('.ccui-tooltip__trigger')
await trigger.trigger('mouseenter')
await nextTick()
-
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(false)
})
})
@@ -315,170 +192,65 @@ describe('tooltip', () => {
vi.useRealTimers()
})
- it('应该支持延迟显示', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- trigger: 'hover',
- showAfter: 100,
- },
- slots: {
- default: '',
- },
- })
-
+ it('延迟显示', async () => {
+ wrapper = createWrapper({ content: 'Test', trigger: 'hover', showAfter: 100 })
const trigger = wrapper.find('.ccui-tooltip__trigger')
await trigger.trigger('mouseenter')
await nextTick()
-
- // 延迟前不应该显示
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(false)
-
- // 等待延迟时间
vi.advanceTimersByTime(100)
await nextTick()
-
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(true)
})
- it('应该支持延迟隐藏', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- trigger: 'hover',
- hideAfter: 100,
- },
- slots: {
- default: '',
- },
- })
-
+ it('延迟隐藏', async () => {
+ wrapper = createWrapper({ content: 'Test', trigger: 'hover', hideAfter: 100 })
const trigger = wrapper.find('.ccui-tooltip__trigger')
await trigger.trigger('mouseenter')
await nextTick()
-
- // 先显示
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(true)
-
await trigger.trigger('mouseleave')
await nextTick()
-
- // 延迟前仍然显示
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(true)
-
- // 等待延迟时间
vi.advanceTimersByTime(100)
await nextTick()
-
expect(wrapper.find('.ccui-tooltip__popper').exists()).toBe(false)
})
})
describe('事件触发', () => {
- it('应该触发 before-show 事件', async () => {
+ it('触发事件', async () => {
const beforeShow = vi.fn()
- wrapper = mount(Tooltip, {
- props: {
- 'content': 'Test',
- 'trigger': 'hover',
- 'onBefore-show': beforeShow,
- },
- slots: {
- default: '',
- },
- })
-
- const trigger = wrapper.find('.ccui-tooltip__trigger')
- await trigger.trigger('mouseenter')
- await nextTick()
-
- expect(beforeShow).toHaveBeenCalled()
- })
-
- it('应该触发 show 事件', async () => {
const show = vi.fn()
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- trigger: 'hover',
- onShow: show,
- },
- slots: {
- default: '',
- },
- })
-
- const trigger = wrapper.find('.ccui-tooltip__trigger')
- await trigger.trigger('mouseenter')
- await nextTick()
-
- expect(show).toHaveBeenCalled()
- })
-
- it('应该触发 before-hide 事件', async () => {
const beforeHide = vi.fn()
- wrapper = mount(Tooltip, {
- props: {
- 'content': 'Test',
- 'trigger': 'hover',
- 'hideAfter': 0,
- 'onBefore-hide': beforeHide,
- },
- slots: {
- default: '',
- },
- })
-
- const trigger = wrapper.find('.ccui-tooltip__trigger')
- await trigger.trigger('mouseenter')
- await nextTick()
- await trigger.trigger('mouseleave')
- await nextTick()
-
- expect(beforeHide).toHaveBeenCalled()
- })
-
- it('应该触发 hide 事件', async () => {
const hide = vi.fn()
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- trigger: 'hover',
- hideAfter: 0,
- onHide: hide,
- },
- slots: {
- default: '',
- },
+ wrapper = createWrapper({
+ 'content': 'Test',
+ 'trigger': 'hover',
+ 'hideAfter': 0,
+ 'onBefore-show': beforeShow,
+ 'onShow': show,
+ 'onBefore-hide': beforeHide,
+ 'onHide': hide,
})
-
const trigger = wrapper.find('.ccui-tooltip__trigger')
await trigger.trigger('mouseenter')
await nextTick()
+ expect(beforeShow).toHaveBeenCalled()
+ expect(show).toHaveBeenCalled()
await trigger.trigger('mouseleave')
await nextTick()
-
+ expect(beforeHide).toHaveBeenCalled()
expect(hide).toHaveBeenCalled()
})
})
describe('可访问性', () => {
- it('应该设置正确的 ARIA 属性', async () => {
- wrapper = mount(Tooltip, {
- props: {
- content: 'Test',
- ariaLabel: 'Test tooltip',
- visible: true,
- },
- slots: {
- default: '',
- },
- })
-
+ it('aRIA 属性', async () => {
+ wrapper = createWrapper({ content: 'Test', ariaLabel: 'Test tooltip', visible: true })
await nextTick()
const trigger = wrapper.find('.ccui-tooltip__trigger')
const popper = wrapper.find('.ccui-tooltip__popper')
-
expect(trigger.attributes('aria-label')).toBe('Test tooltip')
expect(trigger.attributes('aria-describedby')).toBe('ccui-tooltip__popper')
expect(popper.attributes('role')).toBe('tooltip')