refactor: remove as any from 5 test files (batch 12)

Fixed 31 instances across:
- typeGuardUtil.test.ts: Use Parameters utility type for partial mocks
- graphTraversalUtil.test.ts: Use proper type assertions for property mutations and invalid input testing
- subgraphNavigationStore.viewport.test.ts: Import Subgraph type, fix mock canvas typing
- useCanvasManager.test.ts: Use as unknown as Type for mutable mock store properties
- useCanvasTools.test.ts: Use as unknown as Type for mutable mock store properties

The canvas mock store pattern now uses as unknown as HTMLCanvasElement/CanvasRenderingContext2D
at both declaration and assignment points to allow partial mocks while maintaining type safety.
This commit is contained in:
Johnpaul
2026-01-22 22:09:19 +01:00
parent 981394830c
commit 87c01c9819
5 changed files with 67 additions and 58 deletions

View File

@@ -3,13 +3,13 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
import { MaskBlendMode } from '@/extensions/core/maskeditor/types'
import { useCanvasManager } from '@/composables/maskeditor/useCanvasManager'
const mockStore = {
imgCanvas: null as any,
maskCanvas: null as any,
rgbCanvas: null as any,
imgCtx: null as any,
maskCtx: null as any,
rgbCtx: null as any,
canvasBackground: null as any,
imgCanvas: null as unknown as HTMLCanvasElement,
maskCanvas: null as unknown as HTMLCanvasElement,
rgbCanvas: null as unknown as HTMLCanvasElement,
imgCtx: null as unknown as CanvasRenderingContext2D,
maskCtx: null as unknown as CanvasRenderingContext2D,
rgbCtx: null as unknown as CanvasRenderingContext2D,
canvasBackground: null as unknown as HTMLElement,
maskColor: { r: 0, g: 0, b: 0 },
maskBlendMode: MaskBlendMode.Black,
maskOpacity: 0.8
@@ -40,7 +40,7 @@ describe('useCanvasManager', () => {
mockStore.imgCtx = {
drawImage: vi.fn()
}
} as unknown as CanvasRenderingContext2D
mockStore.maskCtx = {
drawImage: vi.fn(),
@@ -48,16 +48,16 @@ describe('useCanvasManager', () => {
putImageData: vi.fn(),
globalCompositeOperation: 'source-over',
fillStyle: ''
}
} as unknown as CanvasRenderingContext2D
mockStore.rgbCtx = {
drawImage: vi.fn()
}
} as unknown as CanvasRenderingContext2D
mockStore.imgCanvas = {
width: 0,
height: 0
}
} as unknown as HTMLCanvasElement
mockStore.maskCanvas = {
width: 0,
@@ -66,18 +66,18 @@ describe('useCanvasManager', () => {
mixBlendMode: '',
opacity: ''
}
}
} as unknown as HTMLCanvasElement
mockStore.rgbCanvas = {
width: 0,
height: 0
}
} as unknown as HTMLCanvasElement
mockStore.canvasBackground = {
style: {
backgroundColor: ''
}
}
} as unknown as HTMLElement
mockStore.maskColor = { r: 0, g: 0, b: 0 }
mockStore.maskBlendMode = MaskBlendMode.Black
@@ -163,7 +163,7 @@ describe('useCanvasManager', () => {
it('should throw error when canvas missing', async () => {
const manager = useCanvasManager()
mockStore.imgCanvas = null
mockStore.imgCanvas = null as unknown as HTMLCanvasElement
const origImage = createMockImage(512, 512)
const maskImage = createMockImage(512, 512)
@@ -176,7 +176,7 @@ describe('useCanvasManager', () => {
it('should throw error when context missing', async () => {
const manager = useCanvasManager()
mockStore.imgCtx = null
mockStore.imgCtx = null as unknown as CanvasRenderingContext2D
const origImage = createMockImage(512, 512)
const maskImage = createMockImage(512, 512)
@@ -259,7 +259,7 @@ describe('useCanvasManager', () => {
it('should return early when canvas missing', async () => {
const manager = useCanvasManager()
mockStore.maskCanvas = null
mockStore.maskCanvas = null as unknown as HTMLCanvasElement
await manager.updateMaskColor()
@@ -269,7 +269,7 @@ describe('useCanvasManager', () => {
it('should return early when context missing', async () => {
const manager = useCanvasManager()
mockStore.maskCtx = null
mockStore.maskCtx = null as unknown as CanvasRenderingContext2D
await manager.updateMaskColor()

View File

@@ -9,12 +9,12 @@ const mockCanvasHistory = {
}
const mockStore = {
maskCtx: null as any,
imgCtx: null as any,
maskCanvas: null as any,
imgCanvas: null as any,
rgbCtx: null as any,
rgbCanvas: null as any,
maskCtx: null as unknown as CanvasRenderingContext2D,
imgCtx: null as unknown as CanvasRenderingContext2D,
maskCanvas: null as unknown as HTMLCanvasElement,
imgCanvas: null as unknown as HTMLCanvasElement,
rgbCtx: null as unknown as CanvasRenderingContext2D,
rgbCanvas: null as unknown as HTMLCanvasElement,
maskColor: { r: 255, g: 255, b: 255 },
paintBucketTolerance: 10,
fillOpacity: 100,
@@ -61,30 +61,30 @@ describe('useCanvasTools', () => {
getImageData: vi.fn(() => mockMaskImageData),
putImageData: vi.fn(),
clearRect: vi.fn()
}
} as unknown as CanvasRenderingContext2D
mockStore.imgCtx = {
getImageData: vi.fn(() => mockImgImageData)
}
} as unknown as CanvasRenderingContext2D
mockStore.rgbCtx = {
clearRect: vi.fn()
}
} as unknown as CanvasRenderingContext2D
mockStore.maskCanvas = {
width: 100,
height: 100
}
} as unknown as HTMLCanvasElement
mockStore.imgCanvas = {
width: 100,
height: 100
}
} as unknown as HTMLCanvasElement
mockStore.rgbCanvas = {
width: 100,
height: 100
}
} as unknown as HTMLCanvasElement
mockStore.maskColor = { r: 255, g: 255, b: 255 }
mockStore.paintBucketTolerance = 10
@@ -158,7 +158,7 @@ describe('useCanvasTools', () => {
})
it('should return early when canvas missing', () => {
mockStore.maskCanvas = null
mockStore.maskCanvas = null as unknown as HTMLCanvasElement
const tools = useCanvasTools()
@@ -243,7 +243,7 @@ describe('useCanvasTools', () => {
})
it('should return early when canvas missing', async () => {
mockStore.imgCanvas = null
mockStore.imgCanvas = null as unknown as HTMLCanvasElement
const tools = useCanvasTools()
@@ -363,7 +363,7 @@ describe('useCanvasTools', () => {
})
it('should return early when canvas missing', () => {
mockStore.maskCanvas = null
mockStore.maskCanvas = null as unknown as HTMLCanvasElement
const tools = useCanvasTools()
@@ -373,7 +373,7 @@ describe('useCanvasTools', () => {
})
it('should return early when context missing', () => {
mockStore.maskCtx = null
mockStore.maskCtx = null as unknown as CanvasRenderingContext2D
const tools = useCanvasTools()
@@ -395,7 +395,7 @@ describe('useCanvasTools', () => {
})
it('should handle missing mask canvas', () => {
mockStore.maskCanvas = null
mockStore.maskCanvas = null as unknown as HTMLCanvasElement
const tools = useCanvasTools()
@@ -406,7 +406,7 @@ describe('useCanvasTools', () => {
})
it('should handle missing rgb canvas', () => {
mockStore.rgbCanvas = null
mockStore.rgbCanvas = null as unknown as HTMLCanvasElement
const tools = useCanvasTools()

View File

@@ -2,11 +2,14 @@ import { createPinia, setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { nextTick } from 'vue'
import type { Subgraph } from '@/lib/litegraph/src/litegraph'
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
import type { ComfyWorkflow } from '@/platform/workflow/management/stores/workflowStore'
import { app } from '@/scripts/app'
import { useSubgraphNavigationStore } from '@/stores/subgraphNavigationStore'
const mockSetDirty = vi.fn()
vi.mock('@/scripts/app', () => {
const mockCanvas = {
subgraph: null,
@@ -18,7 +21,7 @@ vi.mock('@/scripts/app', () => {
offset: [0, 0]
}
},
setDirty: vi.fn()
setDirty: mockSetDirty
}
return {
@@ -37,12 +40,12 @@ vi.mock('@/scripts/app', () => {
// Mock canvasStore
vi.mock('@/renderer/core/canvas/canvasStore', () => ({
useCanvasStore: () => ({
getCanvas: () => (app as any).canvas
getCanvas: () => app.canvas
})
}))
// Get reference to mock canvas
const mockCanvas = app.canvas as any
const mockCanvas = app.canvas
describe('useSubgraphNavigationStore - Viewport Persistence', () => {
beforeEach(() => {
@@ -52,7 +55,7 @@ describe('useSubgraphNavigationStore - Viewport Persistence', () => {
mockCanvas.ds.offset = [0, 0]
mockCanvas.ds.state.scale = 1
mockCanvas.ds.state.offset = [0, 0]
mockCanvas.setDirty.mockClear()
mockSetDirty.mockClear()
})
describe('saveViewport', () => {
@@ -98,7 +101,7 @@ describe('useSubgraphNavigationStore - Viewport Persistence', () => {
// Mock being in a subgraph
const mockSubgraph = { id: 'sub-456' }
workflowStore.activeSubgraph = mockSubgraph as any
workflowStore.activeSubgraph = mockSubgraph as unknown as Subgraph
// Set viewport state
mockCanvas.ds.state.scale = 3
@@ -158,7 +161,7 @@ describe('useSubgraphNavigationStore - Viewport Persistence', () => {
// Reset canvas
mockCanvas.ds.scale = 1
mockCanvas.ds.offset = [0, 0]
mockCanvas.setDirty.mockClear()
mockSetDirty.mockClear()
// Try to restore non-existent viewport
navigationStore.restoreViewport('non-existent')
@@ -166,7 +169,7 @@ describe('useSubgraphNavigationStore - Viewport Persistence', () => {
// Canvas should not change
expect(mockCanvas.ds.scale).toBe(1)
expect(mockCanvas.ds.offset).toEqual([0, 0])
expect(mockCanvas.setDirty).not.toHaveBeenCalled()
expect(mockSetDirty).not.toHaveBeenCalled()
})
})
@@ -194,7 +197,7 @@ describe('useSubgraphNavigationStore - Viewport Persistence', () => {
mockCanvas.ds.state.offset = [100, 100]
// Navigate to subgraph
workflowStore.activeSubgraph = subgraph1 as any
workflowStore.activeSubgraph = subgraph1 as unknown as Subgraph
await nextTick()
// Root viewport should have been saved automatically
@@ -239,10 +242,14 @@ describe('useSubgraphNavigationStore - Viewport Persistence', () => {
const workflow1 = { path: 'workflow1.json' } as ComfyWorkflow
const workflow2 = { path: 'workflow2.json' } as ComfyWorkflow
workflowStore.activeWorkflow = workflow1 as any
workflowStore.activeWorkflow = workflow1 as unknown as ReturnType<
typeof useWorkflowStore
>['activeWorkflow']
await nextTick()
workflowStore.activeWorkflow = workflow2 as any
workflowStore.activeWorkflow = workflow2 as unknown as ReturnType<
typeof useWorkflowStore
>['activeWorkflow']
await nextTick()
// Cache should be preserved (LRU will manage memory)

View File

@@ -96,8 +96,8 @@ describe('graphTraversalUtil', () => {
it('should return null for invalid input', () => {
expect(parseExecutionId('')).toBeNull()
expect(parseExecutionId(null as any)).toBeNull()
expect(parseExecutionId(undefined as any)).toBeNull()
expect(parseExecutionId(null as unknown as string)).toBeNull()
expect(parseExecutionId(undefined as unknown as string)).toBeNull()
})
})
@@ -415,7 +415,7 @@ describe('graphTraversalUtil', () => {
// Add a title property to each node
forEachNode(graph, (node) => {
;(node as any).title = `Node ${node.id}`
;(node as unknown as { title: string }).title = `Node ${node.id}`
})
expect(nodes[0]).toHaveProperty('title', 'Node 1')
@@ -653,7 +653,7 @@ describe('graphTraversalUtil', () => {
it('should return root graph from subgraph', () => {
const rootGraph = createMockGraph([])
const subgraph = createMockSubgraph('sub-uuid', [])
;(subgraph as any).rootGraph = rootGraph
;(subgraph as Subgraph & { rootGraph: LGraph }).rootGraph = rootGraph
expect(getRootGraph(subgraph)).toBe(rootGraph)
})
@@ -663,8 +663,10 @@ describe('graphTraversalUtil', () => {
const midSubgraph = createMockSubgraph('mid-uuid', [])
const deepSubgraph = createMockSubgraph('deep-uuid', [])
;(midSubgraph as any).rootGraph = rootGraph
;(deepSubgraph as any).rootGraph = midSubgraph
;(midSubgraph as Subgraph & { rootGraph: LGraph }).rootGraph = rootGraph
;(
deepSubgraph as Subgraph & { rootGraph: LGraph | Subgraph }
).rootGraph = midSubgraph
expect(getRootGraph(deepSubgraph)).toBe(rootGraph)
})
@@ -726,7 +728,7 @@ describe('graphTraversalUtil', () => {
const graph = createMockGraph(nodes)
forEachSubgraphNode(graph, subgraphId, (node) => {
;(node as any).title = 'Updated Title'
;(node as unknown as { title: string }).title = 'Updated Title'
})
expect(nodes[0]).toHaveProperty('title', 'Updated Title')

View File

@@ -7,7 +7,7 @@ describe('typeGuardUtil', () => {
it('should identify SubgraphInputNode as IO node', () => {
const node = {
constructor: { comfyClass: 'SubgraphInputNode' }
} as any
} as unknown as Parameters<typeof isSubgraphIoNode>[0]
expect(isSubgraphIoNode(node)).toBe(true)
})
@@ -15,7 +15,7 @@ describe('typeGuardUtil', () => {
it('should identify SubgraphOutputNode as IO node', () => {
const node = {
constructor: { comfyClass: 'SubgraphOutputNode' }
} as any
} as unknown as Parameters<typeof isSubgraphIoNode>[0]
expect(isSubgraphIoNode(node)).toBe(true)
})
@@ -23,13 +23,13 @@ describe('typeGuardUtil', () => {
it('should not identify regular nodes as IO nodes', () => {
const node = {
constructor: { comfyClass: 'CLIPTextEncode' }
} as any
} as unknown as Parameters<typeof isSubgraphIoNode>[0]
expect(isSubgraphIoNode(node)).toBe(false)
})
it('should handle nodes without constructor', () => {
const node = {} as any
const node = {} as unknown as Parameters<typeof isSubgraphIoNode>[0]
expect(isSubgraphIoNode(node)).toBe(false)
})
@@ -37,7 +37,7 @@ describe('typeGuardUtil', () => {
it('should handle nodes without comfyClass', () => {
const node = {
constructor: {}
} as any
} as unknown as Parameters<typeof isSubgraphIoNode>[0]
expect(isSubgraphIoNode(node)).toBe(false)
})