mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-03 04:31:58 +00:00
[backport cloud/1.32] Feat: Alt+Drag to clone - Vue Nodes (#6861)
Backport of #6789 to `cloud/1.32` Automatically created by backport workflow. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6861-backport-cloud-1-32-Feat-Alt-Drag-to-clone-Vue-Nodes-2b46d73d3650819e83e7f55bb16fdf9d) by [Unito](https://www.unito.io) Co-authored-by: Alexander Brown <drjkl@comfy.org> Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { nextTick, ref } from 'vue'
|
||||
|
||||
import type { VueNodeData } from '@/composables/graph/useGraphNodeManager'
|
||||
import { useNodePointerInteractions } from '@/renderer/extensions/vueNodes/composables/useNodePointerInteractions'
|
||||
import { useNodeEventHandlers } from '@/renderer/extensions/vueNodes/composables/useNodeEventHandlers'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
|
||||
import type { NodeLayout } from '@/renderer/core/layout/types'
|
||||
import { useNodeDrag } from '@/renderer/extensions/vueNodes/layout/useNodeDrag'
|
||||
|
||||
const forwardEventToCanvasMock = vi.fn()
|
||||
const deselectNodeMock = vi.fn()
|
||||
const selectNodesMock = vi.fn()
|
||||
const toggleNodeSelectionAfterPointerUpMock = vi.fn()
|
||||
const ensureNodeSelectedForShiftDragMock = vi.fn()
|
||||
const selectedItemsState: { items: Array<{ id?: string }> } = { items: [] }
|
||||
|
||||
// Mock the dependencies
|
||||
@@ -20,19 +20,18 @@ vi.mock('@/renderer/core/canvas/useCanvasInteractions', () => ({
|
||||
})
|
||||
}))
|
||||
|
||||
vi.mock('@/renderer/extensions/vueNodes/layout/useNodeLayout', () => ({
|
||||
useNodeLayout: () => ({
|
||||
startDrag: vi.fn(),
|
||||
endDrag: vi.fn().mockResolvedValue(undefined),
|
||||
handleDrag: vi.fn().mockResolvedValue(undefined)
|
||||
})
|
||||
}))
|
||||
|
||||
vi.mock('@/renderer/core/layout/store/layoutStore', () => ({
|
||||
layoutStore: {
|
||||
isDraggingVueNodes: ref(false)
|
||||
vi.mock('@/renderer/extensions/vueNodes/layout/useNodeDrag', () => {
|
||||
const startDrag = vi.fn()
|
||||
const handleDrag = vi.fn()
|
||||
const endDrag = vi.fn()
|
||||
return {
|
||||
useNodeDrag: () => ({
|
||||
startDrag,
|
||||
handleDrag,
|
||||
endDrag
|
||||
})
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
vi.mock('@/renderer/core/canvas/canvasStore', () => ({
|
||||
useCanvasStore: () => ({
|
||||
@@ -44,14 +43,23 @@ vi.mock('@/renderer/core/canvas/canvasStore', () => ({
|
||||
|
||||
vi.mock(
|
||||
'@/renderer/extensions/vueNodes/composables/useNodeEventHandlers',
|
||||
() => ({
|
||||
useNodeEventHandlers: () => ({
|
||||
deselectNode: deselectNodeMock,
|
||||
selectNodes: selectNodesMock,
|
||||
toggleNodeSelectionAfterPointerUp: toggleNodeSelectionAfterPointerUpMock,
|
||||
ensureNodeSelectedForShiftDrag: ensureNodeSelectedForShiftDragMock
|
||||
})
|
||||
})
|
||||
() => {
|
||||
const handleNodeSelect = vi.fn()
|
||||
const deselectNode = vi.fn()
|
||||
const selectNodes = vi.fn()
|
||||
const toggleNodeSelectionAfterPointerUp = vi.fn()
|
||||
const ensureNodeSelectedForShiftDrag = vi.fn()
|
||||
|
||||
return {
|
||||
useNodeEventHandlers: () => ({
|
||||
handleNodeSelect,
|
||||
deselectNode,
|
||||
selectNodes,
|
||||
toggleNodeSelectionAfterPointerUp,
|
||||
ensureNodeSelectedForShiftDrag
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
vi.mock('@/composables/graph/useVueNodeLifecycle', () => ({
|
||||
@@ -65,19 +73,35 @@ vi.mock('@/composables/graph/useVueNodeLifecycle', () => ({
|
||||
})
|
||||
}))
|
||||
|
||||
const createMockVueNodeData = (
|
||||
overrides: Partial<VueNodeData> = {}
|
||||
): VueNodeData => ({
|
||||
id: 'test-node-123',
|
||||
title: 'Test Node',
|
||||
type: 'TestNodeType',
|
||||
mode: 0,
|
||||
selected: false,
|
||||
executing: false,
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
widgets: [],
|
||||
...overrides
|
||||
const mockData = vi.hoisted(() => {
|
||||
const fakeNodeLayout: NodeLayout = {
|
||||
id: '',
|
||||
position: { x: 0, y: 0 },
|
||||
size: { width: 100, height: 100 },
|
||||
zIndex: 1,
|
||||
visible: true,
|
||||
bounds: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
}
|
||||
return { fakeNodeLayout }
|
||||
})
|
||||
|
||||
vi.mock('@/renderer/core/layout/store/layoutStore', () => {
|
||||
const isDraggingVueNodes = ref(false)
|
||||
const fakeNodeLayoutRef = ref(mockData.fakeNodeLayout)
|
||||
const getNodeLayoutRef = vi.fn(() => fakeNodeLayoutRef)
|
||||
const setSource = vi.fn()
|
||||
return {
|
||||
layoutStore: {
|
||||
isDraggingVueNodes,
|
||||
getNodeLayoutRef,
|
||||
setSource
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const createPointerEvent = (
|
||||
@@ -107,46 +131,34 @@ const createMouseEvent = (
|
||||
|
||||
describe('useNodePointerInteractions', () => {
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks()
|
||||
vi.restoreAllMocks()
|
||||
selectedItemsState.items = []
|
||||
setActivePinia(createPinia())
|
||||
// Reset layout store state between tests
|
||||
const { layoutStore } = await import(
|
||||
'@/renderer/core/layout/store/layoutStore'
|
||||
)
|
||||
layoutStore.isDraggingVueNodes.value = false
|
||||
setActivePinia(createTestingPinia())
|
||||
})
|
||||
|
||||
it('should only start drag on left-click', async () => {
|
||||
const mockNodeData = createMockVueNodeData()
|
||||
const mockOnNodeSelect = vi.fn()
|
||||
const { handleNodeSelect } = useNodeEventHandlers()
|
||||
const { startDrag } = useNodeDrag()
|
||||
|
||||
const { pointerHandlers } = useNodePointerInteractions(
|
||||
ref(mockNodeData),
|
||||
mockOnNodeSelect
|
||||
)
|
||||
const { pointerHandlers } = useNodePointerInteractions('test-node-123')
|
||||
|
||||
// Right-click should not trigger selection
|
||||
const rightClickEvent = createPointerEvent('pointerdown', { button: 2 })
|
||||
pointerHandlers.onPointerdown(rightClickEvent)
|
||||
|
||||
expect(mockOnNodeSelect).not.toHaveBeenCalled()
|
||||
expect(handleNodeSelect).not.toHaveBeenCalled()
|
||||
|
||||
// Left-click should trigger selection on pointer down
|
||||
const leftClickEvent = createPointerEvent('pointerdown', { button: 0 })
|
||||
pointerHandlers.onPointerdown(leftClickEvent)
|
||||
|
||||
expect(mockOnNodeSelect).toHaveBeenCalledWith(leftClickEvent, mockNodeData)
|
||||
expect(startDrag).toHaveBeenCalledWith(leftClickEvent, 'test-node-123')
|
||||
})
|
||||
|
||||
it('should call onNodeSelect on pointer down', async () => {
|
||||
const mockNodeData = createMockVueNodeData()
|
||||
const mockOnNodeSelect = vi.fn()
|
||||
it.skip('should call onNodeSelect on pointer down', async () => {
|
||||
const { handleNodeSelect } = useNodeEventHandlers()
|
||||
|
||||
const { pointerHandlers } = useNodePointerInteractions(
|
||||
ref(mockNodeData),
|
||||
mockOnNodeSelect
|
||||
)
|
||||
const { pointerHandlers } = useNodePointerInteractions('test-node-123')
|
||||
|
||||
// Selection should happen on pointer down
|
||||
const downEvent = createPointerEvent('pointerdown', {
|
||||
@@ -155,9 +167,9 @@ describe('useNodePointerInteractions', () => {
|
||||
})
|
||||
pointerHandlers.onPointerdown(downEvent)
|
||||
|
||||
expect(mockOnNodeSelect).toHaveBeenCalledWith(downEvent, mockNodeData)
|
||||
expect(handleNodeSelect).toHaveBeenCalledWith(downEvent, 'test-node-123')
|
||||
|
||||
mockOnNodeSelect.mockClear()
|
||||
vi.mocked(handleNodeSelect).mockClear()
|
||||
|
||||
// Even if we drag, selection already happened on pointer down
|
||||
pointerHandlers.onPointerup(
|
||||
@@ -165,35 +177,36 @@ describe('useNodePointerInteractions', () => {
|
||||
)
|
||||
|
||||
// onNodeSelect should not be called again on pointer up
|
||||
expect(mockOnNodeSelect).not.toHaveBeenCalled()
|
||||
expect(handleNodeSelect).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should handle drag termination via cancel and context menu', async () => {
|
||||
const mockNodeData = createMockVueNodeData()
|
||||
const mockOnNodeSelect = vi.fn()
|
||||
const { handleNodeSelect } = useNodeEventHandlers()
|
||||
|
||||
const { pointerHandlers } = useNodePointerInteractions(
|
||||
ref(mockNodeData),
|
||||
mockOnNodeSelect
|
||||
)
|
||||
const { pointerHandlers } = useNodePointerInteractions('test-node-123')
|
||||
|
||||
// Test pointer cancel - selection happens on pointer down
|
||||
pointerHandlers.onPointerdown(
|
||||
createPointerEvent('pointerdown', { clientX: 100, clientY: 100 })
|
||||
)
|
||||
expect(mockOnNodeSelect).toHaveBeenCalledTimes(1)
|
||||
|
||||
// Simulate drag by moving pointer beyond threshold
|
||||
pointerHandlers.onPointermove(
|
||||
createPointerEvent('pointermove', { clientX: 110, clientY: 110 })
|
||||
createPointerEvent('pointermove', {
|
||||
clientX: 110,
|
||||
clientY: 110,
|
||||
buttons: 1
|
||||
})
|
||||
)
|
||||
|
||||
expect(handleNodeSelect).toHaveBeenCalledTimes(1)
|
||||
|
||||
pointerHandlers.onPointercancel(createPointerEvent('pointercancel'))
|
||||
|
||||
// Selection should have been called on pointer down only
|
||||
expect(mockOnNodeSelect).toHaveBeenCalledTimes(1)
|
||||
expect(handleNodeSelect).toHaveBeenCalledTimes(1)
|
||||
|
||||
mockOnNodeSelect.mockClear()
|
||||
vi.mocked(handleNodeSelect).mockClear()
|
||||
|
||||
// Test context menu during drag prevents default
|
||||
pointerHandlers.onPointerdown(
|
||||
@@ -201,7 +214,11 @@ describe('useNodePointerInteractions', () => {
|
||||
)
|
||||
// Simulate drag by moving pointer beyond threshold
|
||||
pointerHandlers.onPointermove(
|
||||
createPointerEvent('pointermove', { clientX: 110, clientY: 110 })
|
||||
createPointerEvent('pointermove', {
|
||||
clientX: 110,
|
||||
clientY: 110,
|
||||
buttons: 1
|
||||
})
|
||||
)
|
||||
|
||||
const contextMenuEvent = createMouseEvent('contextmenu')
|
||||
@@ -212,36 +229,8 @@ describe('useNodePointerInteractions', () => {
|
||||
expect(preventDefaultSpy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not call onNodeSelect when nodeData is null', async () => {
|
||||
const mockNodeData = createMockVueNodeData()
|
||||
const mockOnNodeSelect = vi.fn()
|
||||
const nodeDataRef = ref<VueNodeData | null>(mockNodeData)
|
||||
|
||||
const { pointerHandlers } = useNodePointerInteractions(
|
||||
nodeDataRef,
|
||||
mockOnNodeSelect
|
||||
)
|
||||
|
||||
// Clear nodeData before pointer down
|
||||
nodeDataRef.value = null
|
||||
await nextTick()
|
||||
|
||||
pointerHandlers.onPointerdown(createPointerEvent('pointerdown'))
|
||||
|
||||
expect(mockOnNodeSelect).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should integrate with layout store dragging state', async () => {
|
||||
const mockNodeData = createMockVueNodeData()
|
||||
const mockOnNodeSelect = vi.fn()
|
||||
const { layoutStore } = await import(
|
||||
'@/renderer/core/layout/store/layoutStore'
|
||||
)
|
||||
|
||||
const { pointerHandlers } = useNodePointerInteractions(
|
||||
ref(mockNodeData),
|
||||
mockOnNodeSelect
|
||||
)
|
||||
const { pointerHandlers } = useNodePointerInteractions('test-node-123')
|
||||
|
||||
// Pointer down alone shouldn't set dragging state
|
||||
pointerHandlers.onPointerdown(
|
||||
@@ -251,7 +240,11 @@ describe('useNodePointerInteractions', () => {
|
||||
|
||||
// Move pointer beyond threshold to start drag
|
||||
pointerHandlers.onPointermove(
|
||||
createPointerEvent('pointermove', { clientX: 110, clientY: 110 })
|
||||
createPointerEvent('pointermove', {
|
||||
clientX: 110,
|
||||
clientY: 110,
|
||||
buttons: 1
|
||||
})
|
||||
)
|
||||
await nextTick()
|
||||
expect(layoutStore.isDraggingVueNodes.value).toBe(true)
|
||||
@@ -262,63 +255,8 @@ describe('useNodePointerInteractions', () => {
|
||||
expect(layoutStore.isDraggingVueNodes.value).toBe(false)
|
||||
})
|
||||
|
||||
it('should select node on pointer down with ctrl key for multi-select', async () => {
|
||||
const mockNodeData = createMockVueNodeData()
|
||||
const mockOnNodeSelect = vi.fn()
|
||||
|
||||
const { pointerHandlers } = useNodePointerInteractions(
|
||||
ref(mockNodeData),
|
||||
mockOnNodeSelect
|
||||
)
|
||||
|
||||
// Pointer down with ctrl key should pass the event with ctrl key set
|
||||
const ctrlDownEvent = createPointerEvent('pointerdown', {
|
||||
ctrlKey: true,
|
||||
clientX: 100,
|
||||
clientY: 100
|
||||
})
|
||||
pointerHandlers.onPointerdown(ctrlDownEvent)
|
||||
|
||||
expect(mockOnNodeSelect).toHaveBeenCalledWith(ctrlDownEvent, mockNodeData)
|
||||
expect(mockOnNodeSelect).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('should select pinned node on pointer down but not start drag', async () => {
|
||||
const mockNodeData = createMockVueNodeData({
|
||||
flags: { pinned: true }
|
||||
})
|
||||
const mockOnNodeSelect = vi.fn()
|
||||
const { layoutStore } = await import(
|
||||
'@/renderer/core/layout/store/layoutStore'
|
||||
)
|
||||
|
||||
const { pointerHandlers } = useNodePointerInteractions(
|
||||
ref(mockNodeData),
|
||||
mockOnNodeSelect
|
||||
)
|
||||
|
||||
// Pointer down on pinned node
|
||||
const downEvent = createPointerEvent('pointerdown')
|
||||
pointerHandlers.onPointerdown(downEvent)
|
||||
|
||||
// Should select the node
|
||||
expect(mockOnNodeSelect).toHaveBeenCalledWith(downEvent, mockNodeData)
|
||||
|
||||
// But should not start dragging
|
||||
expect(layoutStore.isDraggingVueNodes.value).toBe(false)
|
||||
})
|
||||
|
||||
it('should select node immediately when drag starts', async () => {
|
||||
const mockNodeData = createMockVueNodeData()
|
||||
const mockOnNodeSelect = vi.fn()
|
||||
const { layoutStore } = await import(
|
||||
'@/renderer/core/layout/store/layoutStore'
|
||||
)
|
||||
|
||||
const { pointerHandlers } = useNodePointerInteractions(
|
||||
ref(mockNodeData),
|
||||
mockOnNodeSelect
|
||||
)
|
||||
const { pointerHandlers } = useNodePointerInteractions('test-node-123')
|
||||
|
||||
// Pointer down should select node immediately
|
||||
const downEvent = createPointerEvent('pointerdown', {
|
||||
@@ -326,24 +264,25 @@ describe('useNodePointerInteractions', () => {
|
||||
clientY: 100
|
||||
})
|
||||
pointerHandlers.onPointerdown(downEvent)
|
||||
|
||||
// Selection should happen on pointer down (before move)
|
||||
expect(mockOnNodeSelect).toHaveBeenCalledWith(downEvent, mockNodeData)
|
||||
expect(mockOnNodeSelect).toHaveBeenCalledTimes(1)
|
||||
const { handleNodeSelect } = useNodeEventHandlers()
|
||||
|
||||
// Dragging state should NOT be active yet
|
||||
expect(layoutStore.isDraggingVueNodes.value).toBe(false)
|
||||
|
||||
const pointerMove = createPointerEvent('pointermove', {
|
||||
clientX: 150,
|
||||
clientY: 150,
|
||||
buttons: 1
|
||||
})
|
||||
// Move the pointer beyond threshold (start dragging)
|
||||
pointerHandlers.onPointermove(
|
||||
createPointerEvent('pointermove', { clientX: 150, clientY: 150 })
|
||||
)
|
||||
pointerHandlers.onPointermove(pointerMove)
|
||||
|
||||
// Now dragging state should be active
|
||||
expect(layoutStore.isDraggingVueNodes.value).toBe(true)
|
||||
|
||||
// Selection should still only have been called once (on pointer down)
|
||||
expect(mockOnNodeSelect).toHaveBeenCalledTimes(1)
|
||||
// Selection should happen on pointer down (before move)
|
||||
expect(handleNodeSelect).toHaveBeenCalledWith(pointerMove, 'test-node-123')
|
||||
expect(handleNodeSelect).toHaveBeenCalledTimes(1)
|
||||
|
||||
// End drag
|
||||
pointerHandlers.onPointerup(
|
||||
@@ -351,17 +290,12 @@ describe('useNodePointerInteractions', () => {
|
||||
)
|
||||
|
||||
// Selection should still only have been called once
|
||||
expect(mockOnNodeSelect).toHaveBeenCalledTimes(1)
|
||||
expect(handleNodeSelect).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('on ctrl+click: calls toggleNodeSelectionAfterPointerUp on pointer up (not pointer down)', async () => {
|
||||
const mockNodeData = createMockVueNodeData()
|
||||
const mockOnNodeSelect = vi.fn()
|
||||
|
||||
const { pointerHandlers } = useNodePointerInteractions(
|
||||
ref(mockNodeData),
|
||||
mockOnNodeSelect
|
||||
)
|
||||
const { pointerHandlers } = useNodePointerInteractions('test-node-123')
|
||||
const { toggleNodeSelectionAfterPointerUp } = useNodeEventHandlers()
|
||||
|
||||
// Pointer down with ctrl
|
||||
const downEvent = createPointerEvent('pointerdown', {
|
||||
@@ -372,7 +306,7 @@ describe('useNodePointerInteractions', () => {
|
||||
pointerHandlers.onPointerdown(downEvent)
|
||||
|
||||
// On pointer down: toggle handler should NOT be called yet
|
||||
expect(toggleNodeSelectionAfterPointerUpMock).not.toHaveBeenCalled()
|
||||
expect(toggleNodeSelectionAfterPointerUp).not.toHaveBeenCalled()
|
||||
|
||||
// Pointer up with ctrl (no drag - same position)
|
||||
const upEvent = createPointerEvent('pointerup', {
|
||||
@@ -383,116 +317,9 @@ describe('useNodePointerInteractions', () => {
|
||||
pointerHandlers.onPointerup(upEvent)
|
||||
|
||||
// On pointer up: toggle handler IS called with correct params
|
||||
expect(toggleNodeSelectionAfterPointerUpMock).toHaveBeenCalledWith(
|
||||
mockNodeData.id,
|
||||
{
|
||||
wasSelectedAtPointerDown: false,
|
||||
multiSelect: true
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('on ctrl+drag: does NOT call toggleNodeSelectionAfterPointerUp', async () => {
|
||||
const mockNodeData = createMockVueNodeData()
|
||||
const mockOnNodeSelect = vi.fn()
|
||||
|
||||
const { pointerHandlers } = useNodePointerInteractions(
|
||||
ref(mockNodeData),
|
||||
mockOnNodeSelect
|
||||
)
|
||||
|
||||
// Pointer down with ctrl
|
||||
const downEvent = createPointerEvent('pointerdown', {
|
||||
ctrlKey: true,
|
||||
clientX: 100,
|
||||
clientY: 100
|
||||
})
|
||||
pointerHandlers.onPointerdown(downEvent)
|
||||
|
||||
// Move beyond drag threshold
|
||||
pointerHandlers.onPointermove(
|
||||
createPointerEvent('pointermove', {
|
||||
ctrlKey: true,
|
||||
clientX: 110,
|
||||
clientY: 110
|
||||
})
|
||||
)
|
||||
|
||||
// Pointer up after drag
|
||||
const upEvent = createPointerEvent('pointerup', {
|
||||
ctrlKey: true,
|
||||
clientX: 110,
|
||||
clientY: 110
|
||||
})
|
||||
pointerHandlers.onPointerup(upEvent)
|
||||
|
||||
// When dragging: toggle handler should NOT be called
|
||||
expect(toggleNodeSelectionAfterPointerUpMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('selects node when shift drag starts without multi selection', async () => {
|
||||
selectedItemsState.items = []
|
||||
const mockNodeData = createMockVueNodeData()
|
||||
const mockOnNodeSelect = vi.fn()
|
||||
|
||||
const { pointerHandlers } = useNodePointerInteractions(
|
||||
ref(mockNodeData),
|
||||
mockOnNodeSelect
|
||||
)
|
||||
|
||||
const pointerDownEvent = createPointerEvent('pointerdown', {
|
||||
clientX: 0,
|
||||
clientY: 0,
|
||||
shiftKey: true
|
||||
})
|
||||
|
||||
pointerHandlers.onPointerdown(pointerDownEvent)
|
||||
|
||||
const pointerMoveEvent = createPointerEvent('pointermove', {
|
||||
clientX: 10,
|
||||
clientY: 10,
|
||||
shiftKey: true
|
||||
})
|
||||
|
||||
pointerHandlers.onPointermove(pointerMoveEvent)
|
||||
|
||||
expect(ensureNodeSelectedForShiftDragMock).toHaveBeenCalledWith(
|
||||
pointerMoveEvent,
|
||||
mockNodeData,
|
||||
false
|
||||
)
|
||||
})
|
||||
|
||||
it('still ensures selection when shift drag starts with existing multi select', async () => {
|
||||
selectedItemsState.items = [{ id: 'a' }, { id: 'b' }]
|
||||
const mockNodeData = createMockVueNodeData()
|
||||
const mockOnNodeSelect = vi.fn()
|
||||
|
||||
const { pointerHandlers } = useNodePointerInteractions(
|
||||
ref(mockNodeData),
|
||||
mockOnNodeSelect
|
||||
)
|
||||
|
||||
const pointerDownEvent = createPointerEvent('pointerdown', {
|
||||
clientX: 0,
|
||||
clientY: 0,
|
||||
shiftKey: true
|
||||
})
|
||||
|
||||
pointerHandlers.onPointerdown(pointerDownEvent)
|
||||
|
||||
const pointerMoveEvent = createPointerEvent('pointermove', {
|
||||
clientX: 10,
|
||||
clientY: 10,
|
||||
shiftKey: true
|
||||
})
|
||||
|
||||
pointerHandlers.onPointermove(pointerMoveEvent)
|
||||
|
||||
expect(ensureNodeSelectedForShiftDragMock).toHaveBeenCalledWith(
|
||||
pointerMoveEvent,
|
||||
mockNodeData,
|
||||
false
|
||||
expect(toggleNodeSelectionAfterPointerUp).toHaveBeenCalledWith(
|
||||
'test-node-123',
|
||||
true
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user