mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-14 17:37:46 +00:00
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:
committed by
GitHub
parent
ba5380395d
commit
29220f6562
@@ -47,8 +47,9 @@ export class ClipspaceDialog extends ComfyDialog {
|
||||
if (ClipspaceDialog.instance) {
|
||||
const self = ClipspaceDialog.instance
|
||||
// allow reconstruct controls when copying from non-image to image content.
|
||||
const imgSettings = self.createImgSettings()
|
||||
const children = $el('div.comfy-modal-content', [
|
||||
self.createImgSettings(),
|
||||
...(imgSettings ? [imgSettings] : []),
|
||||
...self.createButtons()
|
||||
])
|
||||
|
||||
@@ -103,7 +104,7 @@ export class ClipspaceDialog extends ComfyDialog {
|
||||
return buttons
|
||||
}
|
||||
|
||||
createImgSettings() {
|
||||
createImgSettings(): HTMLTableElement | null {
|
||||
if (ComfyApp.clipspace?.imgs) {
|
||||
const combo_items = []
|
||||
const imgs = ComfyApp.clipspace.imgs
|
||||
@@ -167,14 +168,14 @@ export class ClipspaceDialog extends ComfyDialog {
|
||||
|
||||
return $el('table', {}, [row1, row2, row3])
|
||||
} else {
|
||||
return []
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
createImgPreview() {
|
||||
createImgPreview(): HTMLImageElement | null {
|
||||
if (ComfyApp.clipspace?.imgs) {
|
||||
return $el('img', { id: 'clipspace_preview', ondragstart: () => false })
|
||||
} else return []
|
||||
} else return null
|
||||
}
|
||||
|
||||
override show() {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { legacyMenuCompat } from '@/lib/litegraph/src/contextMenuCompat'
|
||||
import type {
|
||||
IContextMenuValue,
|
||||
LGraphNode
|
||||
} from '@/lib/litegraph/src/litegraph'
|
||||
import { LGraphCanvas } from '@/lib/litegraph/src/litegraph'
|
||||
|
||||
/**
|
||||
@@ -18,11 +22,12 @@ describe('Context Menu Extension Name in Warnings', () => {
|
||||
|
||||
// Extension monkey-patches the method
|
||||
const original = LGraphCanvas.prototype.getCanvasMenuOptions
|
||||
LGraphCanvas.prototype.getCanvasMenuOptions = function (...args: any[]) {
|
||||
const items = (original as any).apply(this, args)
|
||||
items.push({ content: 'My Custom Menu Item', callback: () => {} })
|
||||
return items
|
||||
}
|
||||
LGraphCanvas.prototype.getCanvasMenuOptions =
|
||||
function (): (IContextMenuValue | null)[] {
|
||||
const items = original.call(this)
|
||||
items.push({ content: 'My Custom Menu Item', callback: () => {} })
|
||||
return items
|
||||
}
|
||||
|
||||
// Clear extension (happens after setup completes)
|
||||
legacyMenuCompat.setCurrentExtension(null)
|
||||
@@ -49,8 +54,8 @@ describe('Context Menu Extension Name in Warnings', () => {
|
||||
|
||||
// Extension monkey-patches the method
|
||||
const original = LGraphCanvas.prototype.getNodeMenuOptions
|
||||
LGraphCanvas.prototype.getNodeMenuOptions = function (...args: any[]) {
|
||||
const items = (original as any).apply(this, args)
|
||||
LGraphCanvas.prototype.getNodeMenuOptions = function (node: LGraphNode) {
|
||||
const items = original.call(this, node)
|
||||
items.push({ content: 'My Node Menu Item', callback: () => {} })
|
||||
return items
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ import type { LGraphCanvas, LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import { useExtensionService } from '@/services/extensionService'
|
||||
import { useExtensionStore } from '@/stores/extensionStore'
|
||||
import type { ComfyExtension } from '@/types/comfy'
|
||||
import {
|
||||
createMockCanvas,
|
||||
createMockLGraphNode
|
||||
} from '@/utils/__tests__/litegraphTestUtils'
|
||||
|
||||
describe('Context Menu Extension API', () => {
|
||||
let mockCanvas: LGraphCanvas
|
||||
@@ -35,7 +39,7 @@ describe('Context Menu Extension API', () => {
|
||||
// Mock extensions
|
||||
const createCanvasMenuExtension = (
|
||||
name: string,
|
||||
items: IContextMenuValue[]
|
||||
items: (IContextMenuValue | null)[]
|
||||
): ComfyExtension => ({
|
||||
name,
|
||||
getCanvasMenuItems: () => items
|
||||
@@ -54,16 +58,16 @@ describe('Context Menu Extension API', () => {
|
||||
extensionStore = useExtensionStore()
|
||||
extensionService = useExtensionService()
|
||||
|
||||
mockCanvas = {
|
||||
mockCanvas = createMockCanvas({
|
||||
graph_mouse: [100, 100],
|
||||
selectedItems: new Set()
|
||||
} as unknown as LGraphCanvas
|
||||
})
|
||||
|
||||
mockNode = {
|
||||
mockNode = createMockLGraphNode({
|
||||
id: 1,
|
||||
type: 'TestNode',
|
||||
pos: [0, 0]
|
||||
} as unknown as LGraphNode
|
||||
})
|
||||
})
|
||||
|
||||
describe('collectCanvasMenuItems', () => {
|
||||
@@ -79,7 +83,7 @@ describe('Context Menu Extension API', () => {
|
||||
|
||||
const items: IContextMenuValue[] = extensionService
|
||||
.invokeExtensions('getCanvasMenuItems', mockCanvas)
|
||||
.flat()
|
||||
.flat() as IContextMenuValue[]
|
||||
|
||||
expect(items).toHaveLength(3)
|
||||
expect(items[0]).toMatchObject({ content: 'Canvas Item 1' })
|
||||
@@ -99,7 +103,7 @@ describe('Context Menu Extension API', () => {
|
||||
]
|
||||
}
|
||||
},
|
||||
null as unknown as IContextMenuValue,
|
||||
null,
|
||||
{ content: 'After Separator', callback: () => {} }
|
||||
])
|
||||
|
||||
@@ -107,7 +111,7 @@ describe('Context Menu Extension API', () => {
|
||||
|
||||
const items: IContextMenuValue[] = extensionService
|
||||
.invokeExtensions('getCanvasMenuItems', mockCanvas)
|
||||
.flat()
|
||||
.flat() as IContextMenuValue[]
|
||||
|
||||
expect(items).toHaveLength(3)
|
||||
expect(items[0].content).toBe('Menu with Submenu')
|
||||
@@ -129,7 +133,7 @@ describe('Context Menu Extension API', () => {
|
||||
|
||||
const items: IContextMenuValue[] = extensionService
|
||||
.invokeExtensions('getCanvasMenuItems', mockCanvas)
|
||||
.flat()
|
||||
.flat() as IContextMenuValue[]
|
||||
|
||||
expect(items).toHaveLength(1)
|
||||
expect(items[0].content).toBe('Canvas Item 1')
|
||||
@@ -146,11 +150,11 @@ describe('Context Menu Extension API', () => {
|
||||
// Collect items multiple times (simulating repeated menu opens)
|
||||
const items1: IContextMenuValue[] = extensionService
|
||||
.invokeExtensions('getCanvasMenuItems', mockCanvas)
|
||||
.flat()
|
||||
.flat() as IContextMenuValue[]
|
||||
|
||||
const items2: IContextMenuValue[] = extensionService
|
||||
.invokeExtensions('getCanvasMenuItems', mockCanvas)
|
||||
.flat()
|
||||
.flat() as IContextMenuValue[]
|
||||
|
||||
// Both collections should have the same items (no duplication)
|
||||
expect(items1).toHaveLength(2)
|
||||
@@ -180,7 +184,7 @@ describe('Context Menu Extension API', () => {
|
||||
|
||||
const items: IContextMenuValue[] = extensionService
|
||||
.invokeExtensions('getNodeMenuItems', mockNode)
|
||||
.flat()
|
||||
.flat() as IContextMenuValue[]
|
||||
|
||||
expect(items).toHaveLength(3)
|
||||
expect(items[0]).toMatchObject({ content: 'Node Item 1' })
|
||||
@@ -205,7 +209,7 @@ describe('Context Menu Extension API', () => {
|
||||
|
||||
const items: IContextMenuValue[] = extensionService
|
||||
.invokeExtensions('getNodeMenuItems', mockNode)
|
||||
.flat()
|
||||
.flat() as IContextMenuValue[]
|
||||
|
||||
expect(items[0].content).toBe('Node Menu with Submenu')
|
||||
expect(items[0].submenu?.options).toHaveLength(2)
|
||||
@@ -222,7 +226,7 @@ describe('Context Menu Extension API', () => {
|
||||
|
||||
const items: IContextMenuValue[] = extensionService
|
||||
.invokeExtensions('getNodeMenuItems', mockNode)
|
||||
.flat()
|
||||
.flat() as IContextMenuValue[]
|
||||
|
||||
expect(items).toHaveLength(1)
|
||||
expect(items[0].content).toBe('Node Item 1')
|
||||
|
||||
@@ -32,9 +32,13 @@ import { GroupNodeConfig, GroupNodeHandler } from './groupNode'
|
||||
const id = 'Comfy.NodeTemplates'
|
||||
const file = 'comfy.templates.json'
|
||||
|
||||
interface NodeTemplate {
|
||||
name: string
|
||||
data: string
|
||||
}
|
||||
|
||||
class ManageTemplates extends ComfyDialog {
|
||||
// @ts-expect-error fixme ts strict error
|
||||
templates: any[]
|
||||
templates: NodeTemplate[] = []
|
||||
draggedEl: HTMLElement | null
|
||||
saveVisualCue: number | null
|
||||
emptyImg: HTMLImageElement
|
||||
|
||||
Reference in New Issue
Block a user