mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-26 01:34:07 +00:00
Road to No explicit any: Group 8 (part 8) test files (#8496)
## Summary
This PR removes unsafe type assertions ("as unknown as Type") from test
files and improves type safety across the codebase.
### Key Changes
#### Type Safety Improvements
- Removed improper `as unknown as Type` patterns from test files in
Group 8 part 8
- Replaced with proper TypeScript patterns using Pinia store testing
patterns
- Fixed parameter shadowing issue in typeGuardUtil.test.ts (constructor
→ nodeConstructor)
- Fixed stale mock values in useConflictDetection.test.ts using getter
functions
- Refactored useManagerState tests to follow proper Pinia store testing
patterns with createTestingPinia
### Files Changed
Test files (Group 8 part 8 - utils and manager composables):
- src/utils/typeGuardUtil.test.ts - Fixed parameter shadowing
- src/utils/graphTraversalUtil.test.ts - Removed unsafe type assertions
- src/utils/litegraphUtil.test.ts - Improved type handling
- src/workbench/extensions/manager/composables/useManagerState.test.ts -
Complete rewrite using Pinia testing patterns
-
src/workbench/extensions/manager/composables/useConflictDetection.test.ts
- Fixed stale mock values with getters
- src/workbench/extensions/manager/composables/useManagerQueue.test.ts -
Type safety improvements
-
src/workbench/extensions/manager/composables/nodePack/useMissingNodes.test.ts
- Removed unsafe casts
-
src/workbench/extensions/manager/composables/nodePack/usePacksSelection.test.ts
- Type improvements
-
src/workbench/extensions/manager/composables/nodePack/usePacksStatus.test.ts
- Type improvements
- src/workbench/extensions/manager/utils/versionUtil.test.ts - Type
safety fixes
Source files (minor type fixes):
- src/utils/fuseUtil.ts - Type improvements
- src/utils/linkFixer.ts - Type safety fixes
- src/utils/syncUtil.ts - Type improvements
-
src/workbench/extensions/manager/composables/nodePack/useWorkflowPacks.ts
- Type fix
-
src/workbench/extensions/manager/composables/useConflictAcknowledgment.ts
- Type fix
### Testing
- All TypeScript type checking passes (`pnpm typecheck`)
- All affected test files pass (`pnpm test:unit`)
- Linting passes without errors (`pnpm lint`)
- Code formatting applied (`pnpm format`)
Part of the "Road to No Explicit Any" initiative, cleaning up type
casting issues from branch `fix/remove-any-types-part8`.
### Previous PRs in this series:
- Part 2: #7401
- Part 3: #7935
- Part 4: #7970
- Part 5: #8064
- Part 6: #8083
- Part 7: #8092
- Part 8 Group 1: #8253
- Part 8 Group 2: #8258
- Part 8 Group 3: #8304
- Part 8 Group 4: #8314
- Part 8 Group 5: #8329
- Part 8 Group 6: #8344
- Part 8 Group 7: #8459
- Part 8 Group 8: #8496 (this PR)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8496-Road-to-No-explicit-any-Group-8-part-8-test-files-2f86d73d365081f3afdcf8d01fba81e1)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
committed by
GitHub
parent
59c58379fe
commit
a64c561a5f
@@ -75,8 +75,12 @@ export interface FuseSearchable {
|
||||
postProcessSearchScores: (scores: SearchAuxScore) => SearchAuxScore
|
||||
}
|
||||
|
||||
function isFuseSearchable(item: any): item is FuseSearchable {
|
||||
return 'postProcessSearchScores' in item
|
||||
function isFuseSearchable(item: unknown): item is FuseSearchable {
|
||||
return (
|
||||
typeof item === 'object' &&
|
||||
item !== null &&
|
||||
'postProcessSearchScores' in item
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
triggerCallbackOnAllNodes,
|
||||
visitGraphNodes
|
||||
} from '@/utils/graphTraversalUtil'
|
||||
import { createMockLGraphNode } from './__tests__/litegraphTestUtils'
|
||||
|
||||
// Mock node factory
|
||||
function createMockNode(
|
||||
@@ -39,13 +40,13 @@ function createMockNode(
|
||||
graph?: LGraph
|
||||
} = {}
|
||||
): LGraphNode {
|
||||
const node = {
|
||||
const node = createMockLGraphNode({
|
||||
id,
|
||||
isSubgraphNode: options.isSubgraph ? () => true : undefined,
|
||||
subgraph: options.subgraph,
|
||||
onExecutionStart: options.callback,
|
||||
graph: options.graph
|
||||
} as unknown as LGraphNode
|
||||
}) satisfies Partial<LGraphNode> as LGraphNode
|
||||
options.graph?.nodes?.push(node)
|
||||
return node
|
||||
}
|
||||
@@ -58,7 +59,7 @@ function createMockGraph(nodes: LGraphNode[]): LGraph {
|
||||
isRootGraph: true,
|
||||
getNodeById: (id: string | number) =>
|
||||
nodes.find((n) => String(n.id) === String(id)) || null
|
||||
} as unknown as LGraph
|
||||
} satisfies Partial<LGraph> as LGraph
|
||||
}
|
||||
|
||||
// Mock subgraph factory
|
||||
@@ -75,7 +76,7 @@ function createMockSubgraph(
|
||||
rootGraph,
|
||||
getNodeById: (nodeId: string | number) =>
|
||||
nodes.find((n) => String(n.id) === String(nodeId)) || null
|
||||
} as unknown as Subgraph
|
||||
} satisfies Partial<Subgraph> as Subgraph
|
||||
return graph
|
||||
}
|
||||
|
||||
@@ -96,8 +97,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!)).toBeNull()
|
||||
expect(parseExecutionId(undefined!)).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -415,7 +416,7 @@ describe('graphTraversalUtil', () => {
|
||||
|
||||
// Add a title property to each node
|
||||
forEachNode(graph, (node) => {
|
||||
;(node as any).title = `Node ${node.id}`
|
||||
node.title = `Node ${node.id}`
|
||||
})
|
||||
|
||||
expect(nodes[0]).toHaveProperty('title', 'Node 1')
|
||||
@@ -653,7 +654,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)
|
||||
})
|
||||
@@ -662,9 +663,10 @@ describe('graphTraversalUtil', () => {
|
||||
const rootGraph = createMockGraph([])
|
||||
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.title = 'Updated Title'
|
||||
})
|
||||
|
||||
expect(nodes[0]).toHaveProperty('title', 'Updated Title')
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import type { INodeOutputSlot } from '@/lib/litegraph/src/interfaces'
|
||||
import type { NodeId } from '@/lib/litegraph/src/LGraphNode'
|
||||
import type { SerialisedLLinkArray } from '@/lib/litegraph/src/LLink'
|
||||
import type { LGraph, LGraphNode, LLink } from '@/lib/litegraph/src/litegraph'
|
||||
@@ -79,12 +80,12 @@ export function fixBadLinks(
|
||||
options: {
|
||||
fix?: boolean
|
||||
silent?: boolean
|
||||
logger?: { log: (...args: any[]) => void }
|
||||
logger?: { log: (...args: unknown[]) => void }
|
||||
} = {}
|
||||
): BadLinksData {
|
||||
const { fix = false, silent = false, logger: _logger = console } = options
|
||||
const logger = {
|
||||
log: (...args: any[]) => {
|
||||
log: (...args: unknown[]) => {
|
||||
if (!silent) {
|
||||
_logger.log(...args)
|
||||
}
|
||||
@@ -166,7 +167,9 @@ export function fixBadLinks(
|
||||
patchedNode['outputs']![slot]!['links'].push(linkId)
|
||||
if (fix) {
|
||||
node.outputs = node.outputs || []
|
||||
node.outputs[slot] = node.outputs[slot] || ({} as any)
|
||||
node.outputs[slot] =
|
||||
node.outputs[slot] ||
|
||||
({} satisfies Partial<INodeOutputSlot> as INodeOutputSlot)
|
||||
node.outputs[slot]!.links = node.outputs[slot]!.links || []
|
||||
node.outputs[slot]!.links!.push(linkId)
|
||||
}
|
||||
@@ -428,7 +431,7 @@ export function fixBadLinks(
|
||||
(l) =>
|
||||
l &&
|
||||
(l[0] === data.deletedLinks[i] ||
|
||||
(l as any).id === data.deletedLinks[i])
|
||||
('id' in l && l.id === data.deletedLinks[i]))
|
||||
)
|
||||
if (idx === -1) {
|
||||
logger.log(`INDEX NOT FOUND for #${data.deletedLinks[i]}`)
|
||||
|
||||
@@ -26,10 +26,10 @@ describe('migrateWidgetsValues', () => {
|
||||
}
|
||||
}
|
||||
|
||||
const widgets: IWidget[] = [
|
||||
const widgets = [
|
||||
{ name: 'normalInput', type: 'number' },
|
||||
{ name: 'anotherNormal', type: 'number' }
|
||||
] as unknown as IWidget[]
|
||||
] as Partial<IWidget>[] as IWidget[]
|
||||
|
||||
const widgetValues = [42, 'dummy value', 3.14]
|
||||
|
||||
@@ -56,7 +56,7 @@ describe('migrateWidgetsValues', () => {
|
||||
it('should handle empty widgets and values', () => {
|
||||
const inputDefs: Record<string, InputSpec> = {}
|
||||
const widgets: IWidget[] = []
|
||||
const widgetValues: any[] = []
|
||||
const widgetValues: unknown[] = []
|
||||
|
||||
const result = migrateWidgetsValues(inputDefs, widgets, widgetValues)
|
||||
expect(result).toEqual([])
|
||||
@@ -79,10 +79,10 @@ describe('migrateWidgetsValues', () => {
|
||||
}
|
||||
}
|
||||
|
||||
const widgets: IWidget[] = [
|
||||
const widgets = [
|
||||
{ name: 'first', type: 'number' },
|
||||
{ name: 'last', type: 'number' }
|
||||
] as unknown as IWidget[]
|
||||
] as Partial<IWidget>[] as IWidget[]
|
||||
|
||||
const widgetValues = ['first value', 'dummy', 'last value']
|
||||
|
||||
@@ -93,7 +93,8 @@ describe('migrateWidgetsValues', () => {
|
||||
|
||||
describe('compressWidgetInputSlots', () => {
|
||||
it('should remove unconnected widget input slots', () => {
|
||||
const graph: ISerialisedGraph = {
|
||||
// Using partial mock - only including properties needed for test
|
||||
const graph = {
|
||||
nodes: [
|
||||
{
|
||||
id: 1,
|
||||
@@ -112,7 +113,7 @@ describe('compressWidgetInputSlots', () => {
|
||||
}
|
||||
],
|
||||
links: [[2, 1, 0, 1, 0, 'INT']]
|
||||
} as unknown as ISerialisedGraph
|
||||
} as Partial<ISerialisedGraph> as ISerialisedGraph
|
||||
|
||||
compressWidgetInputSlots(graph)
|
||||
|
||||
@@ -122,7 +123,7 @@ describe('compressWidgetInputSlots', () => {
|
||||
})
|
||||
|
||||
it('should update link target slots correctly', () => {
|
||||
const graph: ISerialisedGraph = {
|
||||
const graph = {
|
||||
nodes: [
|
||||
{
|
||||
id: 1,
|
||||
@@ -144,7 +145,7 @@ describe('compressWidgetInputSlots', () => {
|
||||
[2, 1, 0, 1, 1, 'INT'],
|
||||
[3, 1, 0, 1, 2, 'INT']
|
||||
]
|
||||
} as unknown as ISerialisedGraph
|
||||
} as Partial<ISerialisedGraph> as ISerialisedGraph
|
||||
|
||||
compressWidgetInputSlots(graph)
|
||||
|
||||
@@ -160,10 +161,11 @@ describe('compressWidgetInputSlots', () => {
|
||||
})
|
||||
|
||||
it('should handle graphs with no nodes gracefully', () => {
|
||||
const graph: ISerialisedGraph = {
|
||||
// Using partial mock - only including properties needed for test
|
||||
const graph = {
|
||||
nodes: [],
|
||||
links: []
|
||||
} as unknown as ISerialisedGraph
|
||||
} as Partial<ISerialisedGraph> as ISerialisedGraph
|
||||
|
||||
compressWidgetInputSlots(graph)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { api } from '@/scripts/api'
|
||||
import type { UserDataFullInfo } from '@/schemas/apiSchema'
|
||||
|
||||
/**
|
||||
* Sync entities from the API to the entityByPath map.
|
||||
@@ -11,8 +12,8 @@ import { api } from '@/scripts/api'
|
||||
export async function syncEntities<T>(
|
||||
dir: string,
|
||||
entityByPath: Record<string, T>,
|
||||
createEntity: (file: any) => T,
|
||||
updateEntity: (entity: T, file: any) => void,
|
||||
createEntity: (file: UserDataFullInfo & { path: string }) => T,
|
||||
updateEntity: (entity: T, file: UserDataFullInfo & { path: string }) => void,
|
||||
exclude: (file: T) => boolean = () => false
|
||||
) {
|
||||
const files = (await api.listUserDataFullInfo(dir)).map((file) => ({
|
||||
|
||||
@@ -1,43 +1,42 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import { isSubgraphIoNode } from '@/utils/typeGuardUtil'
|
||||
|
||||
type NodeConstructor = { comfyClass?: string }
|
||||
|
||||
function createMockNode(nodeConstructor?: NodeConstructor): LGraphNode {
|
||||
return { constructor: nodeConstructor } as Partial<LGraphNode> as LGraphNode
|
||||
}
|
||||
|
||||
describe('typeGuardUtil', () => {
|
||||
describe('isSubgraphIoNode', () => {
|
||||
it('should identify SubgraphInputNode as IO node', () => {
|
||||
const node = {
|
||||
constructor: { comfyClass: 'SubgraphInputNode' }
|
||||
} as any
|
||||
const node = createMockNode({ comfyClass: 'SubgraphInputNode' })
|
||||
|
||||
expect(isSubgraphIoNode(node)).toBe(true)
|
||||
})
|
||||
|
||||
it('should identify SubgraphOutputNode as IO node', () => {
|
||||
const node = {
|
||||
constructor: { comfyClass: 'SubgraphOutputNode' }
|
||||
} as any
|
||||
const node = createMockNode({ comfyClass: 'SubgraphOutputNode' })
|
||||
|
||||
expect(isSubgraphIoNode(node)).toBe(true)
|
||||
})
|
||||
|
||||
it('should not identify regular nodes as IO nodes', () => {
|
||||
const node = {
|
||||
constructor: { comfyClass: 'CLIPTextEncode' }
|
||||
} as any
|
||||
const node = createMockNode({ comfyClass: 'CLIPTextEncode' })
|
||||
|
||||
expect(isSubgraphIoNode(node)).toBe(false)
|
||||
})
|
||||
|
||||
it('should handle nodes without constructor', () => {
|
||||
const node = {} as any
|
||||
const node = createMockNode(undefined)
|
||||
|
||||
expect(isSubgraphIoNode(node)).toBe(false)
|
||||
})
|
||||
|
||||
it('should handle nodes without comfyClass', () => {
|
||||
const node = {
|
||||
constructor: {}
|
||||
} as any
|
||||
const node = createMockNode({})
|
||||
|
||||
expect(isSubgraphIoNode(node)).toBe(false)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user