From f622ff5622fd54e0221ecdc170198f26280a1199 Mon Sep 17 00:00:00 2001 From: vae <18137693952@163.com> Date: Mon, 24 Nov 2025 10:35:31 +0800 Subject: [PATCH 1/5] =?UTF-8?q?refactor(test):=20=E4=BC=98=E5=8C=96=20popo?= =?UTF-8?q?ver.test.ts=20=E6=89=A7=E8=A1=8C=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ccui/ui/popover/test/popover.test.ts | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/ccui/ui/popover/test/popover.test.ts b/packages/ccui/ui/popover/test/popover.test.ts index ae98a486..ded4adaf 100644 --- a/packages/ccui/ui/popover/test/popover.test.ts +++ b/packages/ccui/ui/popover/test/popover.test.ts @@ -142,21 +142,22 @@ describe('popover', () => { it('应用位置样式', async () => { const placements = ['top', 'bottom', 'left', 'right'] + wrapper = mount(Popover, { + props: { + content: 'Test', + placement: 'top', + visible: true, + teleported: false, // 测试中禁用 teleport,以便在组件内部查找元素 + }, + slots: { + default: '', + }, + }) + 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() } }) From 0e6575f7c8f6777b527ba46ba60a3c0bbbc248d8 Mon Sep 17 00:00:00 2001 From: vae <18137693952@163.com> Date: Mon, 24 Nov 2025 10:49:48 +0800 Subject: [PATCH 2/5] =?UTF-8?q?refactor(test):=20=E4=BC=98=E5=8C=96=20slid?= =?UTF-8?q?er.test=20=E6=89=A7=E8=A1=8C=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ccui/ui/slider/test/slider.test.ts | 70 +++++---------------- 1 file changed, 17 insertions(+), 53 deletions(-) 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() From ae7d7fa78c253504f76f576c86762071d157a6e8 Mon Sep 17 00:00:00 2001 From: vae <18137693952@163.com> Date: Mon, 24 Nov 2025 11:00:34 +0800 Subject: [PATCH 3/5] =?UTF-8?q?refactor(test):=20=E4=BC=98=E5=8C=96=20popo?= =?UTF-8?q?ver.test.ts=20=E6=89=A7=E8=A1=8C=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ccui/ui/popover/test/popover.test.ts | 281 +++++++----------- 1 file changed, 100 insertions(+), 181 deletions(-) diff --git a/packages/ccui/ui/popover/test/popover.test.ts b/packages/ccui/ui/popover/test/popover.test.ts index ded4adaf..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,101 +74,59 @@ 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: '', - }, - }) - 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: '', - }, + 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--dark').exists()).toBe(true) + expect(wrapper.find(`.${expectedClass}`).exists()).toBe(true) }) it('应用位置样式', async () => { const placements = ['top', 'bottom', 'left', 'right'] - wrapper = mount(Popover, { - props: { - content: 'Test', - placement: 'top', - visible: true, - teleported: false, // 测试中禁用 teleport,以便在组件内部查找元素 - }, - slots: { - default: '', - }, + wrapper = createWrapper({ + content: 'Test', + placement: 'top', + visible: true, }) for (const placement of placements) { @@ -161,45 +136,23 @@ describe('popover', () => { } }) - 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() @@ -210,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() @@ -224,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() @@ -240,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() @@ -258,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() @@ -271,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() @@ -295,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') @@ -319,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') @@ -384,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() @@ -417,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() @@ -433,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 @@ -488,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') @@ -526,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) @@ -538,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') From d3c149dd273298417713a279a17dc1fd2a4a04a7 Mon Sep 17 00:00:00 2001 From: vae <18137693952@163.com> Date: Mon, 24 Nov 2025 11:10:12 +0800 Subject: [PATCH 4/5] =?UTF-8?q?refactor(test):=20=E4=BC=98=E5=8C=96=20tool?= =?UTF-8?q?tip.test.ts=20=E6=89=A7=E8=A1=8C=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ccui/ui/tooltip/test/tooltip.test.ts | 424 ++++-------------- 1 file changed, 98 insertions(+), 326 deletions(-) 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') From 9656c62fd4aa15be2891553abe40530bc893a473 Mon Sep 17 00:00:00 2001 From: vae <18137693952@163.com> Date: Mon, 24 Nov 2025 13:15:22 +0800 Subject: [PATCH 5/5] =?UTF-8?q?refactor(test):=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ccui/ui/button/test/button.test.ts | 199 +++++----------- .../ccui/ui/calendar/test/calendar.test.ts | 212 ++++-------------- .../ui/input-number/test/input-number.test.ts | 171 +++----------- packages/ccui/ui/input/test/input.test.ts | 124 +++------- packages/ccui/ui/rate/test/rate.test.ts | 89 ++------ .../ccui/ui/timeline/test/timeline.test.ts | 162 ++++--------- 6 files changed, 225 insertions(+), 732 deletions(-) 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: `