mirror of https://github.com/allinssl/allinssl
213 lines
6.2 KiB
JavaScript
213 lines
6.2 KiB
JavaScript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
import { ref, nextTick } from 'vue'
|
|
import useResizeObserver from '../src/resize-observer'
|
|
import { mount } from '@vue/test-utils'
|
|
describe('useResizeObserver', () => {
|
|
// 保存原始的ResizeObserver
|
|
const originalResizeObserver = global.ResizeObserver
|
|
// 模拟ResizeObserver
|
|
class MockResizeObserver {
|
|
callback
|
|
observedElements
|
|
constructor(callback) {
|
|
this.callback = callback
|
|
this.observedElements = new Set()
|
|
}
|
|
observe = vi.fn((el) => {
|
|
this.observedElements.add(el)
|
|
// 模拟元素大小变化
|
|
setTimeout(() => {
|
|
this.callback([
|
|
{
|
|
target: el,
|
|
contentRect: { width: 100, height: 100 },
|
|
},
|
|
])
|
|
}, 0)
|
|
})
|
|
unobserve = vi.fn((el) => {
|
|
this.observedElements.delete(el)
|
|
})
|
|
disconnect = vi.fn(() => {
|
|
this.observedElements.clear()
|
|
})
|
|
// 模拟大小变化
|
|
simulateResize(el, width, height) {
|
|
if (this.observedElements.has(el)) {
|
|
this.callback([
|
|
{
|
|
target: el,
|
|
contentRect: { width, height },
|
|
},
|
|
])
|
|
}
|
|
}
|
|
}
|
|
// 全局mock对象
|
|
let mockObserver
|
|
beforeEach(() => {
|
|
// 安装模拟的ResizeObserver
|
|
global.ResizeObserver = vi.fn((callback) => {
|
|
mockObserver = new MockResizeObserver(callback)
|
|
return mockObserver
|
|
})
|
|
// 监视console.warn
|
|
vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
})
|
|
afterEach(() => {
|
|
// 恢复原始的ResizeObserver
|
|
global.ResizeObserver = originalResizeObserver
|
|
vi.restoreAllMocks()
|
|
})
|
|
it('应该返回元素的宽高', async () => {
|
|
const div = document.createElement('div')
|
|
const { width, height } = useResizeObserver(div)
|
|
await nextTick()
|
|
expect(width.value).toBe(100)
|
|
expect(height.value).toBe(100)
|
|
})
|
|
it('应该支持使用Ref包装的元素', async () => {
|
|
const div = document.createElement('div')
|
|
const elementRef = ref(div)
|
|
const { width, height } = useResizeObserver(elementRef)
|
|
await nextTick()
|
|
expect(width.value).toBe(100)
|
|
expect(height.value).toBe(100)
|
|
// 改变引用
|
|
const newDiv = document.createElement('div')
|
|
elementRef.value = newDiv
|
|
await nextTick()
|
|
// 验证新元素被监听,旧元素被取消监听
|
|
expect(mockObserver.observe).toHaveBeenCalledWith(newDiv)
|
|
expect(mockObserver.unobserve).toHaveBeenCalledWith(div)
|
|
})
|
|
it('应该在元素变化时调用回调函数', async () => {
|
|
const div = document.createElement('div')
|
|
const callback = vi.fn()
|
|
useResizeObserver(div, callback)
|
|
await nextTick()
|
|
// 验证回调被调用
|
|
expect(callback).toHaveBeenCalledTimes(1)
|
|
expect(callback).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
target: div,
|
|
contentRect: { width: 100, height: 100 },
|
|
}),
|
|
)
|
|
// 模拟元素大小变化
|
|
mockObserver.simulateResize(div, 200, 150)
|
|
// 验证回调再次被调用,且参数正确
|
|
expect(callback).toHaveBeenCalledTimes(2)
|
|
expect(callback).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
target: div,
|
|
contentRect: { width: 200, height: 150 },
|
|
}),
|
|
)
|
|
})
|
|
it('应该在组件卸载时断开观察', async () => {
|
|
// 挂载组件
|
|
const wrapper = mount({
|
|
template: '<div></div>',
|
|
setup() {
|
|
const el = ref(null)
|
|
return {
|
|
el,
|
|
...useResizeObserver(el),
|
|
}
|
|
},
|
|
})
|
|
await nextTick()
|
|
// 卸载组件
|
|
wrapper.unmount()
|
|
// 验证断开连接
|
|
expect(mockObserver.disconnect).toHaveBeenCalled()
|
|
})
|
|
it('在ResizeObserver不存在时应该使用fallback', async () => {
|
|
// 临时删除ResizeObserver
|
|
global.ResizeObserver = undefined
|
|
const div = document.createElement('div')
|
|
// 模拟元素的getBoundingClientRect方法
|
|
div.getBoundingClientRect = vi.fn().mockReturnValue({
|
|
width: 200,
|
|
height: 150,
|
|
})
|
|
const { width, height } = useResizeObserver(div)
|
|
await nextTick()
|
|
// 验证fallback获取了正确的尺寸
|
|
expect(width.value).toBe(200)
|
|
expect(height.value).toBe(150)
|
|
// 验证警告信息
|
|
expect(console.warn).toHaveBeenCalledWith('ResizeObserver is not supported, using window resize fallback.')
|
|
// 触发window resize事件
|
|
div.getBoundingClientRect = vi.fn().mockReturnValue({
|
|
width: 300,
|
|
height: 250,
|
|
})
|
|
window.dispatchEvent(new Event('resize'))
|
|
await nextTick()
|
|
// 验证尺寸更新
|
|
expect(width.value).toBe(300)
|
|
expect(height.value).toBe(250)
|
|
})
|
|
it('fallback应该在元素引用变化时更新尺寸', async () => {
|
|
// 临时删除ResizeObserver
|
|
global.ResizeObserver = undefined
|
|
const div = document.createElement('div')
|
|
div.getBoundingClientRect = vi.fn().mockReturnValue({
|
|
width: 200,
|
|
height: 150,
|
|
})
|
|
const elementRef = ref(div)
|
|
const { width, height } = useResizeObserver(elementRef)
|
|
await nextTick()
|
|
expect(width.value).toBe(200)
|
|
expect(height.value).toBe(150)
|
|
// 改变引用
|
|
const newDiv = document.createElement('div')
|
|
newDiv.getBoundingClientRect = vi.fn().mockReturnValue({
|
|
width: 400,
|
|
height: 300,
|
|
})
|
|
elementRef.value = newDiv
|
|
await nextTick()
|
|
// 验证尺寸更新
|
|
expect(width.value).toBe(400)
|
|
expect(height.value).toBe(300)
|
|
})
|
|
it('当Ref元素为null时应该正确处理', async () => {
|
|
const elementRef = ref(null)
|
|
const { width, height } = useResizeObserver(elementRef)
|
|
// 初始值应为0
|
|
expect(width.value).toBe(0)
|
|
expect(height.value).toBe(0)
|
|
// 设置有效元素
|
|
const div = document.createElement('div')
|
|
elementRef.value = div
|
|
await nextTick()
|
|
// 验证元素被观察
|
|
expect(mockObserver.observe).toHaveBeenCalledWith(div)
|
|
// 再次设为null
|
|
elementRef.value = null
|
|
await nextTick()
|
|
// 验证元素被取消观察
|
|
expect(mockObserver.unobserve).toHaveBeenCalledWith(div)
|
|
})
|
|
it('当多个尺寸变化同时发生时应正确处理', async () => {
|
|
const div1 = document.createElement('div')
|
|
const div2 = document.createElement('div')
|
|
const { width: width1, height: height1 } = useResizeObserver(div1)
|
|
const { width: width2, height: height2 } = useResizeObserver(div2)
|
|
await nextTick()
|
|
// 模拟多个元素同时变化
|
|
mockObserver.simulateResize(div1, 150, 120)
|
|
mockObserver.simulateResize(div2, 250, 220)
|
|
// 验证每个元素的尺寸正确更新
|
|
expect(width1.value).toBe(150)
|
|
expect(height1.value).toBe(120)
|
|
expect(width2.value).toBe(250)
|
|
expect(height2.value).toBe(220)
|
|
})
|
|
})
|
|
//# sourceMappingURL=resize-observer.spec.js.map
|