cleanup: remove useCanvasTransformSync composables. (#5742)

No I am not proud of the new placeholder arguments.

## Summary

Small change to unify the two composables before updating the logic.
Edit: Now unifies them both into the **void**.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5742-cleanup-unify-useCanvasTransformSync-composables-2776d73d36508147ad39d11de8588b2e)
by [Unito](https://www.unito.io)
This commit is contained in:
Alexander Brown
2025-09-23 21:36:29 -07:00
committed by GitHub
parent 80cabc61ee
commit 6449d26cee
9 changed files with 29 additions and 649 deletions

View File

@@ -1,129 +0,0 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { nextTick } from 'vue'
import { useCanvasTransformSync } from '@/composables/canvas/useCanvasTransformSync'
// Mock canvas store
let mockGetCanvas = vi.fn()
vi.mock('@/renderer/core/canvas/canvasStore', () => ({
useCanvasStore: vi.fn(() => ({
getCanvas: mockGetCanvas
}))
}))
describe('useCanvasTransformSync', () => {
let mockCanvas: { ds: { scale: number; offset: [number, number] } }
let syncFn: ReturnType<typeof vi.fn>
beforeEach(() => {
mockCanvas = {
ds: {
scale: 1,
offset: [0, 0]
}
}
syncFn = vi.fn()
mockGetCanvas = vi.fn(() => mockCanvas)
vi.clearAllMocks()
})
it('should not call syncFn when transform has not changed', async () => {
const { startSync } = useCanvasTransformSync(syncFn, { autoStart: false })
startSync()
await nextTick()
// Should call once initially
expect(syncFn).toHaveBeenCalledTimes(1)
// Wait for next RAF cycle
await new Promise((resolve) => requestAnimationFrame(resolve))
// Should not call again since transform didn't change
expect(syncFn).toHaveBeenCalledTimes(1)
})
it('should call syncFn when scale changes', async () => {
const { startSync } = useCanvasTransformSync(syncFn, { autoStart: false })
startSync()
await nextTick()
expect(syncFn).toHaveBeenCalledTimes(1)
// Change scale
mockCanvas.ds.scale = 2
// Wait for next RAF cycle
await new Promise((resolve) => requestAnimationFrame(resolve))
expect(syncFn).toHaveBeenCalledTimes(2)
})
it('should call syncFn when offset changes', async () => {
const { startSync } = useCanvasTransformSync(syncFn, { autoStart: false })
startSync()
await nextTick()
expect(syncFn).toHaveBeenCalledTimes(1)
// Change offset
mockCanvas.ds.offset = [10, 20]
// Wait for next RAF cycles
await new Promise((resolve) => requestAnimationFrame(resolve))
expect(syncFn).toHaveBeenCalledTimes(2)
})
it('should stop calling syncFn after stopSync is called', async () => {
const { startSync, stopSync } = useCanvasTransformSync(syncFn, {
autoStart: false
})
startSync()
await nextTick()
expect(syncFn).toHaveBeenCalledTimes(1)
stopSync()
// Change transform after stopping
mockCanvas.ds.scale = 2
// Wait for RAF cycle
await new Promise((resolve) => requestAnimationFrame(resolve))
// Should not call again
expect(syncFn).toHaveBeenCalledTimes(1)
})
it('should handle null canvas gracefully', async () => {
mockGetCanvas.mockReturnValue(null)
const { startSync } = useCanvasTransformSync(syncFn, { autoStart: false })
startSync()
await nextTick()
// Should not call syncFn with null canvas
expect(syncFn).not.toHaveBeenCalled()
})
it('should call onStart and onStop callbacks', () => {
const onStart = vi.fn()
const onStop = vi.fn()
const { startSync, stopSync } = useCanvasTransformSync(syncFn, {
autoStart: false,
onStart,
onStop
})
startSync()
expect(onStart).toHaveBeenCalledTimes(1)
stopSync()
expect(onStop).toHaveBeenCalledTimes(1)
})
})

View File

@@ -1,240 +0,0 @@
import { mount } from '@vue/test-utils'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { nextTick } from 'vue'
import { useCanvasTransformSync } from '@/renderer/core/layout/transform/useCanvasTransformSync'
import type { LGraphCanvas } from '../../../../src/lib/litegraph/src/litegraph'
// Mock LiteGraph canvas
const createMockCanvas = (): Partial<LGraphCanvas> => ({
canvas: document.createElement('canvas'),
ds: {
offset: [0, 0],
scale: 1
} as any // Mock the DragAndScale type
})
describe('useCanvasTransformSync', () => {
let mockCanvas: LGraphCanvas
let syncFn: ReturnType<typeof vi.fn>
let callbacks: {
onStart: ReturnType<typeof vi.fn>
onUpdate: ReturnType<typeof vi.fn>
onStop: ReturnType<typeof vi.fn>
}
beforeEach(() => {
vi.useFakeTimers()
mockCanvas = createMockCanvas() as LGraphCanvas
syncFn = vi.fn()
callbacks = {
onStart: vi.fn(),
onUpdate: vi.fn(),
onStop: vi.fn()
}
// Mock requestAnimationFrame
global.requestAnimationFrame = vi.fn((cb) => {
setTimeout(cb, 16) // Simulate 60fps
return 1
})
global.cancelAnimationFrame = vi.fn()
})
afterEach(() => {
vi.useRealTimers()
vi.restoreAllMocks()
})
it('should auto-start sync when canvas is provided', async () => {
const { isActive } = useCanvasTransformSync(mockCanvas, syncFn, callbacks)
await nextTick()
expect(isActive.value).toBe(true)
expect(callbacks.onStart).toHaveBeenCalledOnce()
expect(syncFn).toHaveBeenCalledWith(mockCanvas)
})
it('should not auto-start when autoStart is false', async () => {
const { isActive } = useCanvasTransformSync(mockCanvas, syncFn, callbacks, {
autoStart: false
})
await nextTick()
expect(isActive.value).toBe(false)
expect(callbacks.onStart).not.toHaveBeenCalled()
expect(syncFn).not.toHaveBeenCalled()
})
it('should not start when canvas is null', async () => {
const { isActive } = useCanvasTransformSync(null, syncFn, callbacks)
await nextTick()
expect(isActive.value).toBe(false)
expect(callbacks.onStart).not.toHaveBeenCalled()
})
it('should manually start and stop sync', async () => {
const { isActive, startSync, stopSync } = useCanvasTransformSync(
mockCanvas,
syncFn,
callbacks,
{ autoStart: false }
)
// Start manually
startSync()
await nextTick()
expect(isActive.value).toBe(true)
expect(callbacks.onStart).toHaveBeenCalledOnce()
// Stop manually
stopSync()
await nextTick()
expect(isActive.value).toBe(false)
expect(callbacks.onStop).toHaveBeenCalledOnce()
})
it('should call sync function on each frame', async () => {
useCanvasTransformSync(mockCanvas, syncFn, callbacks)
await nextTick()
// Advance timers to trigger additional frames (initial call + 3 more = 4 total)
vi.advanceTimersByTime(48) // 3 additional frames at 16ms each
await nextTick()
expect(syncFn).toHaveBeenCalledTimes(4) // Initial call + 3 timed calls
expect(syncFn).toHaveBeenCalledWith(mockCanvas)
})
it('should provide timing information in onUpdate callback', async () => {
// Mock performance.now to return predictable values
const mockNow = vi.spyOn(performance, 'now')
mockNow.mockReturnValueOnce(0).mockReturnValueOnce(5) // 5ms duration
useCanvasTransformSync(mockCanvas, syncFn, callbacks)
await nextTick()
expect(callbacks.onUpdate).toHaveBeenCalledWith(5)
})
it('should handle sync function that throws errors', async () => {
const errorSyncFn = vi.fn().mockImplementation(() => {
throw new Error('Sync failed')
})
// Creating the composable should not throw
expect(() => {
useCanvasTransformSync(mockCanvas, errorSyncFn, callbacks)
}).not.toThrow()
await nextTick()
// Even though sync function throws, the composable should handle it gracefully
expect(errorSyncFn).toHaveBeenCalled()
expect(callbacks.onStart).toHaveBeenCalled()
})
it('should not start if already active', async () => {
const { startSync } = useCanvasTransformSync(mockCanvas, syncFn, callbacks)
await nextTick()
// Try to start again
startSync()
await nextTick()
// Should only be called once from auto-start
expect(callbacks.onStart).toHaveBeenCalledOnce()
})
it('should not stop if already inactive', async () => {
const { stopSync } = useCanvasTransformSync(mockCanvas, syncFn, callbacks, {
autoStart: false
})
// Try to stop when not started
stopSync()
await nextTick()
expect(callbacks.onStop).not.toHaveBeenCalled()
})
it('should clean up on component unmount', async () => {
const TestComponent = {
setup() {
const { isActive } = useCanvasTransformSync(
mockCanvas,
syncFn,
callbacks
)
return { isActive }
},
template: '<div>{{ isActive }}</div>'
}
const wrapper = mount(TestComponent)
await nextTick()
expect(callbacks.onStart).toHaveBeenCalled()
// Unmount component
wrapper.unmount()
await nextTick()
expect(callbacks.onStop).toHaveBeenCalled()
expect(global.cancelAnimationFrame).toHaveBeenCalled()
})
it('should work without callbacks', async () => {
const { isActive } = useCanvasTransformSync(mockCanvas, syncFn)
await nextTick()
expect(isActive.value).toBe(true)
expect(syncFn).toHaveBeenCalledWith(mockCanvas)
})
it('should stop sync when canvas becomes null during sync', async () => {
let currentCanvas: any = mockCanvas
const dynamicSyncFn = vi.fn(() => {
// Simulate canvas becoming null during sync
currentCanvas = null
})
const { isActive } = useCanvasTransformSync(
currentCanvas,
dynamicSyncFn,
callbacks
)
await nextTick()
expect(isActive.value).toBe(true)
// Advance time to trigger sync
vi.advanceTimersByTime(16)
await nextTick()
// Should handle null canvas gracefully
expect(dynamicSyncFn).toHaveBeenCalled()
})
it('should use cancelAnimationFrame when stopping', async () => {
const { stopSync } = useCanvasTransformSync(mockCanvas, syncFn, callbacks)
await nextTick()
stopSync()
expect(global.cancelAnimationFrame).toHaveBeenCalledWith(1)
})
})