mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-03 22:59:14 +00:00
## Summary - disable pan tracking in `useTransformSettling` so we stop wiring high-frequency pointer listeners during canvas drags - the post-navigation-interaction forced reflow is only necessary when zooming since it is for fixing pixel stretch that results from `scale` (which doesn't happen during panning/`translate`) - extend settle delay to 512ms to reduce unnecessary reflow while preserving post-zoom pixel fix After this PR, there should be 0 reflows when panning the graph. First PR in series to address: - https://github.com/Comfy-Org/ComfyUI_frontend/issues/6151 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6186-disable-transform-settling-reflow-when-panning-the-graph-2936d73d365081c2b357e3c72d711439) by [Unito](https://www.unito.io) --------- Co-authored-by: DrJKL <DrJKL@users.noreply.github.com>
168 lines
4.9 KiB
TypeScript
168 lines
4.9 KiB
TypeScript
import { mount } from '@vue/test-utils'
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { nextTick, ref } from 'vue'
|
|
|
|
import { useTransformSettling } from '@/renderer/core/layout/transform/useTransformSettling'
|
|
|
|
describe('useTransformSettling', () => {
|
|
let element: HTMLDivElement
|
|
|
|
beforeEach(() => {
|
|
vi.useFakeTimers()
|
|
element = document.createElement('div')
|
|
document.body.appendChild(element)
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers()
|
|
document.body.removeChild(element)
|
|
})
|
|
|
|
it('should track wheel events and settle after delay', async () => {
|
|
const { isTransforming } = useTransformSettling(element)
|
|
|
|
// Initially not transforming
|
|
expect(isTransforming.value).toBe(false)
|
|
|
|
// Dispatch wheel event
|
|
element.dispatchEvent(new WheelEvent('wheel', { bubbles: true }))
|
|
await nextTick()
|
|
|
|
// Should be transforming
|
|
expect(isTransforming.value).toBe(true)
|
|
|
|
// Advance time but not past settle delay
|
|
vi.advanceTimersByTime(100)
|
|
expect(isTransforming.value).toBe(true)
|
|
|
|
// Advance past settle delay (default 200ms)
|
|
vi.advanceTimersByTime(150)
|
|
expect(isTransforming.value).toBe(false)
|
|
})
|
|
|
|
it('should reset settle timer on subsequent wheel events', async () => {
|
|
const { isTransforming } = useTransformSettling(element, {
|
|
settleDelay: 300
|
|
})
|
|
|
|
// First wheel event
|
|
element.dispatchEvent(new WheelEvent('wheel', { bubbles: true }))
|
|
await nextTick()
|
|
expect(isTransforming.value).toBe(true)
|
|
|
|
// Advance time partially
|
|
vi.advanceTimersByTime(200)
|
|
expect(isTransforming.value).toBe(true)
|
|
|
|
// Another wheel event should reset the timer
|
|
element.dispatchEvent(new WheelEvent('wheel', { bubbles: true }))
|
|
await nextTick()
|
|
|
|
// Advance 200ms more - should still be transforming
|
|
vi.advanceTimersByTime(200)
|
|
expect(isTransforming.value).toBe(true)
|
|
|
|
// Need another 100ms to settle (300ms total from last event)
|
|
vi.advanceTimersByTime(100)
|
|
expect(isTransforming.value).toBe(false)
|
|
})
|
|
|
|
it('should not track pan events', async () => {
|
|
const { isTransforming } = useTransformSettling(element)
|
|
|
|
// Pointer events should not trigger transform
|
|
element.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true }))
|
|
element.dispatchEvent(new PointerEvent('pointermove', { bubbles: true }))
|
|
await nextTick()
|
|
|
|
expect(isTransforming.value).toBe(false)
|
|
})
|
|
|
|
it('should work with ref target', async () => {
|
|
const targetRef = ref<HTMLElement | null>(null)
|
|
const { isTransforming } = useTransformSettling(targetRef)
|
|
|
|
// No target yet
|
|
expect(isTransforming.value).toBe(false)
|
|
|
|
// Set target
|
|
targetRef.value = element
|
|
await nextTick()
|
|
|
|
// Now events should work
|
|
element.dispatchEvent(new WheelEvent('wheel', { bubbles: true }))
|
|
await nextTick()
|
|
expect(isTransforming.value).toBe(true)
|
|
|
|
vi.advanceTimersByTime(200)
|
|
expect(isTransforming.value).toBe(false)
|
|
})
|
|
|
|
it('should use capture phase for events', async () => {
|
|
const captureHandler = vi.fn()
|
|
const bubbleHandler = vi.fn()
|
|
|
|
// Add handlers to verify capture phase
|
|
element.addEventListener('wheel', captureHandler, true)
|
|
element.addEventListener('wheel', bubbleHandler, false)
|
|
|
|
const { isTransforming } = useTransformSettling(element)
|
|
|
|
// Create child element
|
|
const child = document.createElement('div')
|
|
element.appendChild(child)
|
|
|
|
// Dispatch event on child
|
|
child.dispatchEvent(new WheelEvent('wheel', { bubbles: true }))
|
|
await nextTick()
|
|
|
|
// Capture handler should be called before bubble handler
|
|
expect(captureHandler).toHaveBeenCalled()
|
|
expect(isTransforming.value).toBe(true)
|
|
|
|
element.removeEventListener('wheel', captureHandler, true)
|
|
element.removeEventListener('wheel', bubbleHandler, false)
|
|
})
|
|
|
|
it('should clean up event listeners when component unmounts', async () => {
|
|
const removeEventListenerSpy = vi.spyOn(element, 'removeEventListener')
|
|
|
|
// Create a test component
|
|
const TestComponent = {
|
|
setup() {
|
|
const { isTransforming } = useTransformSettling(element)
|
|
return { isTransforming }
|
|
},
|
|
template: '<div>{{ isTransforming }}</div>'
|
|
}
|
|
|
|
const wrapper = mount(TestComponent)
|
|
await nextTick()
|
|
|
|
// Unmount component
|
|
wrapper.unmount()
|
|
|
|
// Should have removed wheel event listener
|
|
expect(removeEventListenerSpy).toHaveBeenCalledWith(
|
|
'wheel',
|
|
expect.any(Function),
|
|
expect.objectContaining({ capture: true })
|
|
)
|
|
})
|
|
|
|
it('should use passive listeners when specified', async () => {
|
|
const addEventListenerSpy = vi.spyOn(element, 'addEventListener')
|
|
|
|
useTransformSettling(element, {
|
|
passive: true
|
|
})
|
|
|
|
// Check that passive option was used for wheel event
|
|
expect(addEventListenerSpy).toHaveBeenCalledWith(
|
|
'wheel',
|
|
expect.any(Function),
|
|
expect.objectContaining({ passive: true, capture: true })
|
|
)
|
|
})
|
|
})
|