feat: Add more Storybook stories for UI components

This commit is contained in:
snomiao
2025-09-22 21:10:30 +00:00
parent e5d4d07d32
commit ce71c2c529
521 changed files with 8078 additions and 22384 deletions

View File

@@ -1,82 +1,79 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { computed, shallowRef } from 'vue'
import { ref } from 'vue'
import {
type GraphNodeManager,
type VueNodeData,
useGraphNodeManager
} from '@/composables/graph/useGraphNodeManager'
import { useVueNodeLifecycle } from '@/composables/graph/useVueNodeLifecycle'
import type {
LGraph,
LGraphCanvas,
LGraphNode
} from '@/lib/litegraph/src/litegraph'
import type { VueNodeData } from '@/composables/graph/useGraphNodeManager'
import { useGraphNodeManager } from '@/composables/graph/useGraphNodeManager'
import type { LGraphCanvas, LGraphNode } from '@/lib/litegraph/src/litegraph'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useLayoutMutations } from '@/renderer/core/layout/operations/layoutMutations'
import { useNodeEventHandlers } from '@/renderer/extensions/vueNodes/composables/useNodeEventHandlers'
vi.mock('@/renderer/core/canvas/canvasStore', () => {
const canvas: Partial<LGraphCanvas> = {
vi.mock('@/renderer/core/canvas/canvasStore', () => ({
useCanvasStore: vi.fn()
}))
vi.mock('@/renderer/core/layout/operations/layoutMutations', () => ({
useLayoutMutations: vi.fn()
}))
function createMockCanvas(): Pick<
LGraphCanvas,
'select' | 'deselect' | 'deselectAll'
> {
return {
select: vi.fn(),
deselect: vi.fn(),
deselectAll: vi.fn()
}
const updateSelectedItems = vi.fn()
}
function createMockNode(): Pick<LGraphNode, 'id' | 'selected' | 'flags'> {
return {
useCanvasStore: vi.fn(() => ({
canvas: canvas as LGraphCanvas,
updateSelectedItems,
selectedItems: []
}))
}
})
vi.mock('@/renderer/core/canvas/useCanvasInteractions', () => ({
useCanvasInteractions: vi.fn(() => ({
shouldHandleNodePointerEvents: computed(() => true) // Default to allowing pointer events
}))
}))
vi.mock('@/renderer/core/layout/operations/layoutMutations', () => {
const setSource = vi.fn()
const bringNodeToFront = vi.fn()
return {
useLayoutMutations: vi.fn(() => ({
setSource,
bringNodeToFront
}))
}
})
vi.mock('@/composables/graph/useGraphNodeManager', () => {
const mockNode = {
id: 'node-1',
selected: false,
flags: { pinned: false }
}
const nodeManager = shallowRef({
getNode: vi.fn(() => mockNode as Partial<LGraphNode> as LGraphNode)
} as Partial<GraphNodeManager> as GraphNodeManager)
return {
useGraphNodeManager: vi.fn(() => nodeManager)
}
})
}
vi.mock('@/composables/graph/useVueNodeLifecycle', () => {
const nodeManager = useGraphNodeManager(undefined as unknown as LGraph)
function createMockNodeManager(
node: Pick<LGraphNode, 'id' | 'selected' | 'flags'>
) {
return {
useVueNodeLifecycle: vi.fn(() => ({
nodeManager
}))
getNode: vi.fn().mockReturnValue(node) as ReturnType<
typeof useGraphNodeManager
>['getNode']
}
})
}
function createMockCanvasStore(
canvas: Pick<LGraphCanvas, 'select' | 'deselect' | 'deselectAll'>
): Pick<
ReturnType<typeof useCanvasStore>,
'canvas' | 'selectedItems' | 'updateSelectedItems'
> {
return {
canvas: canvas as LGraphCanvas,
selectedItems: [],
updateSelectedItems: vi.fn()
}
}
function createMockLayoutMutations(): Pick<
ReturnType<typeof useLayoutMutations>,
'setSource' | 'bringNodeToFront'
> {
return {
setSource: vi.fn(),
bringNodeToFront: vi.fn()
}
}
describe('useNodeEventHandlers', () => {
const { nodeManager: mockNodeManager } = useVueNodeLifecycle()
const mockNode = mockNodeManager.value!.getNode('fake_id')
const mockLayoutMutations = useLayoutMutations()
let mockCanvas: ReturnType<typeof createMockCanvas>
let mockNode: ReturnType<typeof createMockNode>
let mockNodeManager: ReturnType<typeof createMockNodeManager>
let mockCanvasStore: ReturnType<typeof createMockCanvasStore>
let mockLayoutMutations: ReturnType<typeof createMockLayoutMutations>
const testNodeData: VueNodeData = {
id: 'node-1',
@@ -88,13 +85,24 @@ describe('useNodeEventHandlers', () => {
}
beforeEach(async () => {
vi.restoreAllMocks()
mockNode = createMockNode()
mockCanvas = createMockCanvas()
mockNodeManager = createMockNodeManager(mockNode)
mockCanvasStore = createMockCanvasStore(mockCanvas)
mockLayoutMutations = createMockLayoutMutations()
vi.mocked(useCanvasStore).mockReturnValue(
mockCanvasStore as ReturnType<typeof useCanvasStore>
)
vi.mocked(useLayoutMutations).mockReturnValue(
mockLayoutMutations as ReturnType<typeof useLayoutMutations>
)
})
describe('handleNodeSelect', () => {
it('should select single node on regular click', () => {
const { handleNodeSelect } = useNodeEventHandlers()
const { canvas, updateSelectedItems } = useCanvasStore()
const nodeManager = ref(mockNodeManager)
const { handleNodeSelect } = useNodeEventHandlers(nodeManager)
const event = new PointerEvent('pointerdown', {
bubbles: true,
@@ -104,17 +112,17 @@ describe('useNodeEventHandlers', () => {
handleNodeSelect(event, testNodeData, false)
expect(canvas?.deselectAll).toHaveBeenCalledOnce()
expect(canvas?.select).toHaveBeenCalledWith(mockNode)
expect(updateSelectedItems).toHaveBeenCalledOnce()
expect(mockCanvas.deselectAll).toHaveBeenCalledOnce()
expect(mockCanvas.select).toHaveBeenCalledWith(mockNode)
expect(mockCanvasStore.updateSelectedItems).toHaveBeenCalledOnce()
})
it('should toggle selection on ctrl+click', () => {
const { handleNodeSelect } = useNodeEventHandlers()
const { canvas } = useCanvasStore()
const nodeManager = ref(mockNodeManager)
const { handleNodeSelect } = useNodeEventHandlers(nodeManager)
// Test selecting unselected node with ctrl
mockNode!.selected = false
mockNode.selected = false
const ctrlClickEvent = new PointerEvent('pointerdown', {
bubbles: true,
@@ -124,16 +132,16 @@ describe('useNodeEventHandlers', () => {
handleNodeSelect(ctrlClickEvent, testNodeData, false)
expect(canvas?.deselectAll).not.toHaveBeenCalled()
expect(canvas?.select).toHaveBeenCalledWith(mockNode)
expect(mockCanvas.deselectAll).not.toHaveBeenCalled()
expect(mockCanvas.select).toHaveBeenCalledWith(mockNode)
})
it('should deselect on ctrl+click of selected node', () => {
const { handleNodeSelect } = useNodeEventHandlers()
const { canvas } = useCanvasStore()
const nodeManager = ref(mockNodeManager)
const { handleNodeSelect } = useNodeEventHandlers(nodeManager)
// Test deselecting selected node with ctrl
mockNode!.selected = true
mockNode.selected = true
const ctrlClickEvent = new PointerEvent('pointerdown', {
bubbles: true,
@@ -143,15 +151,15 @@ describe('useNodeEventHandlers', () => {
handleNodeSelect(ctrlClickEvent, testNodeData, false)
expect(canvas?.deselect).toHaveBeenCalledWith(mockNode)
expect(canvas?.select).not.toHaveBeenCalled()
expect(mockCanvas.deselect).toHaveBeenCalledWith(mockNode)
expect(mockCanvas.select).not.toHaveBeenCalled()
})
it('should handle meta key (Cmd) on Mac', () => {
const { handleNodeSelect } = useNodeEventHandlers()
const { canvas } = useCanvasStore()
const nodeManager = ref(mockNodeManager)
const { handleNodeSelect } = useNodeEventHandlers(nodeManager)
mockNode!.selected = false
mockNode.selected = false
const metaClickEvent = new PointerEvent('pointerdown', {
bubbles: true,
@@ -161,14 +169,15 @@ describe('useNodeEventHandlers', () => {
handleNodeSelect(metaClickEvent, testNodeData, false)
expect(canvas?.select).toHaveBeenCalledWith(mockNode)
expect(canvas?.deselectAll).not.toHaveBeenCalled()
expect(mockCanvas.select).toHaveBeenCalledWith(mockNode)
expect(mockCanvas.deselectAll).not.toHaveBeenCalled()
})
it('should bring node to front when not pinned', () => {
const { handleNodeSelect } = useNodeEventHandlers()
const nodeManager = ref(mockNodeManager)
const { handleNodeSelect } = useNodeEventHandlers(nodeManager)
mockNode!.flags.pinned = false
mockNode.flags.pinned = false
const event = new PointerEvent('pointerdown')
handleNodeSelect(event, testNodeData, false)
@@ -179,14 +188,49 @@ describe('useNodeEventHandlers', () => {
})
it('should not bring pinned node to front', () => {
const { handleNodeSelect } = useNodeEventHandlers()
const nodeManager = ref(mockNodeManager)
const { handleNodeSelect } = useNodeEventHandlers(nodeManager)
mockNode!.flags.pinned = true
mockNode.flags.pinned = true
const event = new PointerEvent('pointerdown')
handleNodeSelect(event, testNodeData, false)
expect(mockLayoutMutations.bringNodeToFront).not.toHaveBeenCalled()
})
it('should handle missing canvas gracefully', () => {
const nodeManager = ref(mockNodeManager)
const { handleNodeSelect } = useNodeEventHandlers(nodeManager)
mockCanvasStore.canvas = null
const event = new PointerEvent('pointerdown')
expect(() => {
handleNodeSelect(event, testNodeData, false)
}).not.toThrow()
expect(mockCanvas.select).not.toHaveBeenCalled()
})
it('should handle missing node gracefully', () => {
const nodeManager = ref(mockNodeManager)
const { handleNodeSelect } = useNodeEventHandlers(nodeManager)
vi.mocked(mockNodeManager.getNode).mockReturnValue(undefined)
const event = new PointerEvent('pointerdown')
const nodeData = {
id: 'missing-node',
title: 'Missing Node',
type: 'test'
} as any
expect(() => {
handleNodeSelect(event, nodeData, false)
}).not.toThrow()
expect(mockCanvas.select).not.toHaveBeenCalled()
})
})
})