20260913231607
This commit is contained in:
1 parent
f3ad727f1c
commit
c31329d387
179 files changed
+10846
-2684
No files matched your search
@@ -158,3 +158,50 @@ describe('Popover 零包裹交互', () => {
|
||||
wrapper.unmount()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Popover 浮层宽度跟随触发器', () => {
|
||||
/** jsdom 里 offsetWidth 恒为 0,覆写成真实宽度才能断言下发值 */
|
||||
function stubTriggerWidth(wrapper, width) {
|
||||
const trigger = wrapper.find('span.popover-trigger').element
|
||||
Object.defineProperty(trigger, 'offsetWidth', { value: width, configurable: true })
|
||||
}
|
||||
|
||||
it('开启时触发器宽作为 min-width 下发,而非写死 width(内容更宽仍可撑开)', async () => {
|
||||
const wrapper = mount(Popover, {
|
||||
props: { trigger: 'click', followTriggerWidth: true },
|
||||
slots: {
|
||||
trigger: '<button class="t-btn">触发</button>',
|
||||
content: '<div class="t-content">内容</div>',
|
||||
},
|
||||
})
|
||||
stubTriggerWidth(wrapper, 240)
|
||||
await wrapper.find('button.t-btn').trigger('click')
|
||||
await flush()
|
||||
|
||||
const float = bodyPopover()
|
||||
expect(float.style.minWidth).toBe('240px')
|
||||
// 关键:不写死宽度,浮层才能被更宽的内容撑开;内容靠 CSS 铺满浮层
|
||||
expect(float.style.width).toBe('')
|
||||
expect(float.classList.contains('popover-follow-trigger-width')).toBe(true)
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('未开启时不下发任何宽度约束(完全由内容撑开)', async () => {
|
||||
const wrapper = mount(Popover, {
|
||||
props: { trigger: 'click' },
|
||||
slots: {
|
||||
trigger: '<button class="t-btn">触发</button>',
|
||||
content: '<div class="t-content">内容</div>',
|
||||
},
|
||||
})
|
||||
stubTriggerWidth(wrapper, 240)
|
||||
await wrapper.find('button.t-btn').trigger('click')
|
||||
await flush()
|
||||
|
||||
const float = bodyPopover()
|
||||
expect(float.style.minWidth).toBe('')
|
||||
expect(float.style.width).toBe('')
|
||||
expect(float.classList.contains('popover-follow-trigger-width')).toBe(false)
|
||||
wrapper.unmount()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,74 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { nextTick } from 'vue'
|
||||
import Select from '@/components/ui/select/select.vue'
|
||||
|
||||
/** 下拉浮层 Teleport 到 body,需从 body 查 */
|
||||
function popoverContent() {
|
||||
return document.body.querySelector('.popover-content')
|
||||
}
|
||||
|
||||
describe('Select 下拉浮层宽度上限', () => {
|
||||
it('浮层内容盒带 select-popover-content 锚点类(:has() 定位浮层加 max-width 用)', async () => {
|
||||
// 浮层由 Popover 渲染、Teleport 到 body,不在 Select 的 scoped 作用域内,
|
||||
// 只能靠 content-class 传递锚点类,再由全局样式 .popover:has(> .select-popover-content)
|
||||
// 把 max-width 上限压到浮层上;锚点类丢失等于宽度上限静默失效
|
||||
const wrapper = mount(Select, {
|
||||
props: { options: [{ value: 'a', label: '选项' }] },
|
||||
})
|
||||
await wrapper.find('.select-trigger').trigger('click')
|
||||
await nextTick()
|
||||
|
||||
const content = popoverContent()
|
||||
expect(content).not.toBeNull()
|
||||
expect(content.classList.contains('select-popover-content')).toBe(true)
|
||||
wrapper.unmount()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Select 远程分页增强(visible-change / load-more)', () => {
|
||||
it('展开时 emit visible-change(true),供远程选择在打开时加载首页', async () => {
|
||||
const wrapper = mount(Select, { props: { options: [{ value: 'a', label: '甲' }] } })
|
||||
await wrapper.find('.select-trigger').trigger('click')
|
||||
await nextTick()
|
||||
|
||||
expect(wrapper.emitted('visible-change')?.at(-1)).toEqual([true])
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('选项列表滚动触底 emit load-more', async () => {
|
||||
const options = Array.from({ length: 30 }, (_, i) => ({ value: String(i), label: `项${i}` }))
|
||||
const wrapper = mount(Select, { props: { options }, attachTo: document.body })
|
||||
await wrapper.find('.select-trigger').trigger('click')
|
||||
await nextTick()
|
||||
|
||||
const list = document.body.querySelector('.select-list')
|
||||
expect(list).not.toBeNull()
|
||||
// jsdom 不做布局,手动造出"已滚到触底"的度量:scrollTop + clientHeight >= scrollHeight - 24
|
||||
Object.defineProperty(list, 'scrollHeight', { value: 300, configurable: true })
|
||||
Object.defineProperty(list, 'clientHeight', { value: 200, configurable: true })
|
||||
Object.defineProperty(list, 'scrollTop', { value: 100, configurable: true })
|
||||
list.dispatchEvent(new Event('scroll'))
|
||||
await nextTick()
|
||||
|
||||
expect(wrapper.emitted('load-more')).toBeTruthy()
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('loading 中滚动触底不重复 emit load-more', async () => {
|
||||
const options = Array.from({ length: 30 }, (_, i) => ({ value: String(i), label: `项${i}` }))
|
||||
const wrapper = mount(Select, { props: { options, loading: true }, attachTo: document.body })
|
||||
await wrapper.find('.select-trigger').trigger('click')
|
||||
await nextTick()
|
||||
|
||||
const list = document.body.querySelector('.select-list')
|
||||
Object.defineProperty(list, 'scrollHeight', { value: 300, configurable: true })
|
||||
Object.defineProperty(list, 'clientHeight', { value: 200, configurable: true })
|
||||
Object.defineProperty(list, 'scrollTop', { value: 100, configurable: true })
|
||||
list.dispatchEvent(new Event('scroll'))
|
||||
await nextTick()
|
||||
|
||||
expect(wrapper.emitted('load-more')).toBeFalsy()
|
||||
wrapper.unmount()
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user