import type { INodeInputSlot, INodeOutputSlot, Positionable } from '@/lib/litegraph/src/interfaces' import { Rectangle } from '@/lib/litegraph/src/infrastructure/Rectangle' import type { CanvasPointerEvent, LGraph, LGraphCanvas, LGraphGroup, LinkNetwork } from '@/lib/litegraph/src/litegraph' import { LGraphEventMode, LGraphNode } from '@/lib/litegraph/src/litegraph' import { vi } from 'vitest' /** * Creates a mock LGraphNode with minimal required properties */ export function createMockLGraphNode( overrides: Partial | Record = {} ): LGraphNode { const partial: Partial = { id: 1, pos: [0, 0], size: [100, 100], title: 'Test Node', mode: LGraphEventMode.ALWAYS, ...(overrides as Partial) } return partial as Partial as LGraphNode } /** * Creates a mock Positionable object */ export function createMockPositionable( overrides: Partial = {} ): Positionable { const partial: Partial = { id: 1, pos: [0, 0], ...overrides } return partial as Partial as Positionable } /** * Creates a mock LGraphGroup with minimal required properties */ export function createMockLGraphGroup( overrides: Partial = {} ): LGraphGroup { const partial: Partial = { id: 1, pos: [0, 0], boundingRect: new Rectangle(0, 0, 100, 100), ...overrides } return partial as Partial as LGraphGroup } /** * Creates a mock SubgraphNode with sub-nodes */ export function createMockSubgraphNode( subNodes: LGraphNode[], overrides: Partial | Record = {} ): LGraphNode { const baseNode = createMockLGraphNode(overrides) return Object.assign(baseNode, { isSubgraphNode: () => true, subgraph: { nodes: subNodes } }) } /** * Creates a mock LGraphCanvas with minimal required properties for testing */ export function createMockCanvas( overrides: Partial = {} ): LGraphCanvas { return { setDirty: vi.fn(), state: { selectionChanged: false }, ...overrides } as LGraphCanvas } /** * Creates a mock LGraph with trigger function */ export function createMockLGraph(overrides: Partial = {}): LGraph { return { trigger: vi.fn(), ...overrides } as LGraph } /** * Creates a mock CanvasPointerEvent */ export function createMockCanvasPointerEvent( canvasX: number, canvasY: number, overrides: Partial = {} ): CanvasPointerEvent { return { canvasX, canvasY, ...overrides } as CanvasPointerEvent } /** * Creates a mock CanvasRenderingContext2D */ export function createMockCanvasRenderingContext2D( overrides: Partial = {} ): CanvasRenderingContext2D { const partial: Partial = { measureText: vi.fn(() => ({ width: 10 }) as TextMetrics), ...overrides } return partial as CanvasRenderingContext2D } /** * Creates a mock LinkNetwork */ export function createMockLinkNetwork( overrides: Partial = {} ): LinkNetwork { return { ...overrides } as LinkNetwork } /** * Creates a mock INodeInputSlot */ export function createMockNodeInputSlot( overrides: Partial = {} ): INodeInputSlot { return { ...overrides } as INodeInputSlot } /** * Creates a mock INodeOutputSlot */ export function createMockNodeOutputSlot( overrides: Partial = {} ): INodeOutputSlot { return { ...overrides } as INodeOutputSlot } /** * Creates a real LGraphNode instance (not a lightweight mock) with its boundingRect * property represented as a Float64Array for testing position methods. * * Use createMockLGraphNodeWithArrayBoundingRect when: * - Tests rely on Float64Array boundingRect behavior * - Tests call position-related methods like updateArea() * - Tests need actual LGraphNode implementation details * * Use createMockLGraphNode when: * - Tests only need simple/mock-only behavior * - Tests don't depend on boundingRect being a Float64Array * - A lightweight mock with minimal properties is sufficient * * @param name - The node name/type to pass to the LGraphNode constructor * @returns A fully constructed LGraphNode instance with Float64Array boundingRect */ export function createMockLGraphNodeWithArrayBoundingRect( name: string ): LGraphNode { const node = new LGraphNode(name) // The actual node has a Float64Array boundingRect, we just need to type it correctly return node } /** * Creates a mock FileList from an array of files */ export function createMockFileList(files: File[]): FileList { const fileList = Object.assign( { length: files.length, item: (index: number) => files[index] ?? null, [Symbol.iterator]: function* () { yield* files } }, files ) return fileList as FileList }