refactor: eliminate unsafe type assertions from Group 2 test files (#8258)

## Summary
Improved type safety in test files by eliminating unsafe type assertions
and adopting official testing patterns. Reduced unsafe `as unknown as`
type assertions and eliminated all `null!` assertions.

## Changes
- **Adopted @pinia/testing patterns**
- Replaced manual Pinia store mocking with `createTestingPinia()` in
`useSelectionState.test.ts`
  - Eliminated ~120 lines of mock boilerplate
- Created `createMockSettingStore()` helper to replace duplicated store
mocks in `useCoreCommands.test.ts`

- **Eliminated unsafe null assertions**
- Created explicit `MockMaskEditorStore` interface with proper nullable
types in `useCanvasTools.test.ts`
- Replaced `null!` initializations with `null` and used `!` at point of
use or `?.` for optional chaining

- **Made partial mock intent explicit**
- Updated test utilities in `litegraphTestUtils.ts` to use explicit
`Partial<T>` typing
- Changed cast pattern from `as T` to `as Partial<T> as T` to show
incomplete mock intent
- Applied to `createMockLGraphNode()`, `createMockPositionable()`, and
`createMockLGraphGroup()`

- **Created centralized mock utilities** in
`src/utils/__tests__/litegraphTestUtils.ts`
- `createMockLGraphNode()`, `createMockPositionable()`,
`createMockLGraphGroup()`, `createMockSubgraphNode()`
  - Updated 8+ test files to use centralized utilities
- Used union types `Partial<T> | Record<string, unknown>` for flexible
mock creation

## Results
-  0 typecheck errors
-  0 lint errors  
-  All tests passing in modified files
-  Eliminated all `null!` assertions
-  Reduced unsafe double-cast patterns significantly

## Files Modified (18)
- `src/components/graph/SelectionToolbox.test.ts`
-
`src/components/graph/selectionToolbox/{BypassButton,ColorPickerButton,ExecuteButton}.test.ts`
- `src/components/sidebar/tabs/queue/ResultGallery.test.ts`
- `src/composables/canvas/useSelectedLiteGraphItems.test.ts`
- `src/composables/graph/{useGraphHierarchy,useSelectionState}.test.ts`
-
`src/composables/maskeditor/{useCanvasHistory,useCanvasManager,useCanvasTools,useCanvasTransform}.test.ts`
- `src/composables/node/{useNodePricing,useWatchWidget}.test.ts`
- `src/composables/{useBrowserTabTitle,useCoreCommands}.test.ts`
- `src/utils/__tests__/litegraphTestUtils.ts`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8258-refactor-eliminate-unsafe-type-assertions-from-Group-2-test-files-2f16d73d365081549c65fd546cc7c765)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: AustinMroz <austin@comfy.org>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com>
This commit is contained in:
Johnpaul Chiwetelu
2026-01-24 05:10:35 +01:00
committed by GitHub
parent 6b6b467e68
commit b1d8bf0b13
24 changed files with 785 additions and 658 deletions

View File

@@ -6,6 +6,9 @@ import type { LGraphNode, Positionable } from '@/lib/litegraph/src/litegraph'
import { LGraphEventMode, Reroute } from '@/lib/litegraph/src/litegraph'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { app } from '@/scripts/app'
import type { NodeId } from '@/renderer/core/layout/types'
import type { ReadOnlyRect } from '@/lib/litegraph/src/interfaces'
import { createMockSubgraphNode } from '@/utils/__tests__/litegraphTestUtils'
// Mock the app module
vi.mock('@/scripts/app', () => ({
@@ -29,10 +32,12 @@ vi.mock('@/lib/litegraph/src/litegraph', () => ({
}))
// Mock Positionable objects
// @ts-expect-error - Mock implementation for testing
class MockNode implements Positionable {
pos: [number, number]
size: [number, number]
id: NodeId
boundingRect: ReadOnlyRect
constructor(
pos: [number, number] = [0, 0],
@@ -40,6 +45,13 @@ class MockNode implements Positionable {
) {
this.pos = pos
this.size = size
this.id = 'mock-node'
this.boundingRect = [0, 0, 0, 0]
}
move(): void {}
snapToGrid(_: number): boolean {
return true
}
}
@@ -61,7 +73,7 @@ class MockReroute extends Reroute implements Positionable {
describe('useSelectedLiteGraphItems', () => {
let canvasStore: ReturnType<typeof useCanvasStore>
let mockCanvas: any
let mockCanvas: { selectedItems: Set<Positionable> }
beforeEach(() => {
setActivePinia(createPinia())
@@ -73,7 +85,9 @@ describe('useSelectedLiteGraphItems', () => {
}
// Mock getCanvas to return our mock canvas
vi.spyOn(canvasStore, 'getCanvas').mockReturnValue(mockCanvas)
vi.spyOn(canvasStore, 'getCanvas').mockReturnValue(
mockCanvas as ReturnType<typeof canvasStore.getCanvas>
)
})
describe('isIgnoredItem', () => {
@@ -86,7 +100,6 @@ describe('useSelectedLiteGraphItems', () => {
it('should return false for non-Reroute items', () => {
const { isIgnoredItem } = useSelectedLiteGraphItems()
const node = new MockNode()
// @ts-expect-error - Test mock
expect(isIgnoredItem(node)).toBe(false)
})
})
@@ -98,14 +111,11 @@ describe('useSelectedLiteGraphItems', () => {
const node2 = new MockNode([100, 100])
const reroute = new MockReroute([50, 50])
// @ts-expect-error - Test mocks
const items = new Set<Positionable>([node1, node2, reroute])
const filtered = filterSelectableItems(items)
expect(filtered.size).toBe(2)
// @ts-expect-error - Test mocks
expect(filtered.has(node1)).toBe(true)
// @ts-expect-error - Test mocks
expect(filtered.has(node2)).toBe(true)
expect(filtered.has(reroute)).toBe(false)
})
@@ -143,9 +153,7 @@ describe('useSelectedLiteGraphItems', () => {
const selectableItems = getSelectableItems()
expect(selectableItems.size).toBe(2)
// @ts-expect-error - Test mock
expect(selectableItems.has(node1)).toBe(true)
// @ts-expect-error - Test mock
expect(selectableItems.has(node2)).toBe(true)
expect(selectableItems.has(reroute)).toBe(false)
})
@@ -255,14 +263,7 @@ describe('useSelectedLiteGraphItems', () => {
const { getSelectedNodes } = useSelectedLiteGraphItems()
const subNode1 = { id: 11, mode: LGraphEventMode.ALWAYS } as LGraphNode
const subNode2 = { id: 12, mode: LGraphEventMode.NEVER } as LGraphNode
const subgraphNode = {
id: 1,
mode: LGraphEventMode.ALWAYS,
isSubgraphNode: () => true,
subgraph: {
nodes: [subNode1, subNode2]
}
} as unknown as LGraphNode
const subgraphNode = createMockSubgraphNode([subNode1, subNode2])
const regularNode = { id: 2, mode: LGraphEventMode.NEVER } as LGraphNode
app.canvas.selected_nodes = { '0': subgraphNode, '1': regularNode }
@@ -279,14 +280,7 @@ describe('useSelectedLiteGraphItems', () => {
const { toggleSelectedNodesMode } = useSelectedLiteGraphItems()
const subNode1 = { id: 11, mode: LGraphEventMode.ALWAYS } as LGraphNode
const subNode2 = { id: 12, mode: LGraphEventMode.NEVER } as LGraphNode
const subgraphNode = {
id: 1,
mode: LGraphEventMode.ALWAYS,
isSubgraphNode: () => true,
subgraph: {
nodes: [subNode1, subNode2]
}
} as unknown as LGraphNode
const subgraphNode = createMockSubgraphNode([subNode1, subNode2])
const regularNode = { id: 2, mode: LGraphEventMode.BYPASS } as LGraphNode
app.canvas.selected_nodes = { '0': subgraphNode, '1': regularNode }
@@ -310,14 +304,10 @@ describe('useSelectedLiteGraphItems', () => {
const { toggleSelectedNodesMode } = useSelectedLiteGraphItems()
const subNode1 = { id: 11, mode: LGraphEventMode.ALWAYS } as LGraphNode
const subNode2 = { id: 12, mode: LGraphEventMode.BYPASS } as LGraphNode
const subgraphNode = {
const subgraphNode = createMockSubgraphNode([subNode1, subNode2], {
id: 1,
mode: LGraphEventMode.NEVER, // Already in NEVER mode
isSubgraphNode: () => true,
subgraph: {
nodes: [subNode1, subNode2]
}
} as unknown as LGraphNode
mode: LGraphEventMode.NEVER // Already in NEVER mode
})
app.canvas.selected_nodes = { '0': subgraphNode }