Road to No explicit any Part 8 (Group 3): Improve type safety in Group 3 test mocks (#8304)

## Summary

- Eliminated all `as unknown as` type assertions from Group 3 test files
- Created reusable factory functions in `litegraphTestUtils.ts` for
better type safety
- Improved test mock composition using `Partial` types with single `as`
casts
- Fixed LGraphNode tests to use proper API methods instead of direct
property assignment

## Changes by Category

### New Factory Functions in `litegraphTestUtils.ts`

- `createMockLGraphNodeWithArrayBoundingRect()` - Creates LGraphNode
with proper boundingRect for position tests
- `createMockFileList()` - Creates mock FileList with proper structure
including `item()` method

### Test File Improvements

**Composables:**
- `useLoad3dDrag.test.ts` - Used `createMockFileList` factory
- `useLoad3dViewer.test.ts` - Created local `MockSceneManager` interface
with proper typing

**LiteGraph Tests:**
- `LGraphNode.test.ts` - Replaced direct `boundingRect` assignments with
`updateArea()` calls
- `LinkConnector.test.ts` - Improved mock composition with proper
Partial types
- `ToOutputRenderLink.test.ts` - Added `MockEvents` interface for
type-safe event mocking
- Updated integration and core tests to use new factory functions

**Extension Tests:**
- `contextMenuFilter.test.ts` - Updated menu factories to accept
`(IContextMenuValue | null)[]`

## Type Safety Improvements

- Zero `as unknown as` instances (was: multiple instances across 17
files)
- All mocks use proper `Partial<T>` composition with single `as T` casts
- Improved IntelliSense and type checking in test files
- Centralized mock creation reduces duplication and improves
maintainability

## Test Plan

-  All TypeScript type checks pass
-  ESLint passes with no new errors  
-  Pre-commit hooks (format, lint, typecheck) all pass
-  Knip unused export check passes
-  No behavioral changes to actual tests (only type improvements)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8304-Road-to-No-explicit-any-Improve-type-safety-in-Group-3-test-mocks-2f36d73d365081ab841de96e5f01306d)
by [Unito](https://www.unito.io)
This commit is contained in:
Johnpaul Chiwetelu
2026-01-26 18:13:18 +01:00
committed by GitHub
parent ba5380395d
commit 29220f6562
17 changed files with 606 additions and 355 deletions

View File

@@ -1,11 +1,17 @@
import type { Positionable } from '@/lib/litegraph/src/interfaces'
import type {
INodeInputSlot,
INodeOutputSlot,
Positionable
} from '@/lib/litegraph/src/interfaces'
import { Rectangle } from '@/lib/litegraph/src/infrastructure/Rectangle'
import type {
CanvasPointerEvent,
LGraph,
LGraphCanvas,
LGraphGroup,
LGraphNode
LinkNetwork
} from '@/lib/litegraph/src/litegraph'
import { LGraphEventMode } from '@/lib/litegraph/src/litegraph'
import { LGraphEventMode, LGraphNode } from '@/lib/litegraph/src/litegraph'
import { vi } from 'vitest'
/**
@@ -84,3 +90,114 @@ export function createMockCanvas(
...overrides
} as LGraphCanvas
}
/**
* Creates a mock LGraph with trigger function
*/
export function createMockLGraph(overrides: Partial<LGraph> = {}): LGraph {
return {
trigger: vi.fn(),
...overrides
} as LGraph
}
/**
* Creates a mock CanvasPointerEvent
*/
export function createMockCanvasPointerEvent(
canvasX: number,
canvasY: number,
overrides: Partial<CanvasPointerEvent> = {}
): CanvasPointerEvent {
return {
canvasX,
canvasY,
...overrides
} as CanvasPointerEvent
}
/**
* Creates a mock CanvasRenderingContext2D
*/
export function createMockCanvasRenderingContext2D(
overrides: Partial<CanvasRenderingContext2D> = {}
): CanvasRenderingContext2D {
const partial: Partial<CanvasRenderingContext2D> = {
measureText: vi.fn(() => ({ width: 10 }) as TextMetrics),
...overrides
}
return partial as CanvasRenderingContext2D
}
/**
* Creates a mock LinkNetwork
*/
export function createMockLinkNetwork(
overrides: Partial<LinkNetwork> = {}
): LinkNetwork {
return {
...overrides
} as LinkNetwork
}
/**
* Creates a mock INodeInputSlot
*/
export function createMockNodeInputSlot(
overrides: Partial<INodeInputSlot> = {}
): INodeInputSlot {
return {
...overrides
} as INodeInputSlot
}
/**
* Creates a mock INodeOutputSlot
*/
export function createMockNodeOutputSlot(
overrides: Partial<INodeOutputSlot> = {}
): 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 = {
...files,
length: files.length,
item: (index: number) => files[index] ?? null,
[Symbol.iterator]: function* () {
yield* files
}
}
return fileList as FileList
}