mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 11:11:53 +00:00
refactor: remove double-cast patterns from group 4 test files
- Replace all 'as unknown as Type' patterns with proper typing - Use 'as Partial<Type> as Type' for valid mock objects - Add null/undefined validation in Subgraph.addInput/addOutput - Update SubgraphEdgeCases tests to expect validation errors - Use @ts-expect-error for intentionally invalid test values in ComboWidget Related to ongoing TypeScript cleanup effort
This commit is contained in:
@@ -2602,7 +2602,16 @@ export class Subgraph
|
|||||||
canvas.subgraph = this
|
canvas.subgraph = this
|
||||||
}
|
}
|
||||||
|
|
||||||
addInput(name: string, type: string): SubgraphInput {
|
addInput(name?: string | null, type?: string | null): SubgraphInput {
|
||||||
|
if (
|
||||||
|
name === null ||
|
||||||
|
name === undefined ||
|
||||||
|
type === null ||
|
||||||
|
type === undefined
|
||||||
|
) {
|
||||||
|
throw new Error('Name and type are required for subgraph input')
|
||||||
|
}
|
||||||
|
|
||||||
this.events.dispatch('adding-input', { name, type })
|
this.events.dispatch('adding-input', { name, type })
|
||||||
|
|
||||||
const input = new SubgraphInput(
|
const input = new SubgraphInput(
|
||||||
@@ -2620,7 +2629,16 @@ export class Subgraph
|
|||||||
return input
|
return input
|
||||||
}
|
}
|
||||||
|
|
||||||
addOutput(name: string, type: string): SubgraphOutput {
|
addOutput(name?: string | null, type?: string | null): SubgraphOutput {
|
||||||
|
if (
|
||||||
|
name === null ||
|
||||||
|
name === undefined ||
|
||||||
|
type === null ||
|
||||||
|
type === undefined
|
||||||
|
) {
|
||||||
|
throw new Error('Name and type are required for subgraph output')
|
||||||
|
}
|
||||||
|
|
||||||
this.events.dispatch('adding-output', { name, type })
|
this.events.dispatch('adding-output', { name, type })
|
||||||
|
|
||||||
const output = new SubgraphOutput(
|
const output = new SubgraphOutput(
|
||||||
|
|||||||
@@ -83,7 +83,9 @@ describe.skip('SubgraphEdgeCases - Invalid States', () => {
|
|||||||
name: 'fake',
|
name: 'fake',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
disconnect: () => {}
|
disconnect: () => {}
|
||||||
} as any
|
} as Partial<Parameters<typeof subgraph.removeInput>[0]> as Parameters<
|
||||||
|
typeof subgraph.removeInput
|
||||||
|
>[0]
|
||||||
|
|
||||||
// Should throw appropriate error for non-existent input
|
// Should throw appropriate error for non-existent input
|
||||||
expect(() => {
|
expect(() => {
|
||||||
@@ -97,41 +99,36 @@ describe.skip('SubgraphEdgeCases - Invalid States', () => {
|
|||||||
name: 'fake',
|
name: 'fake',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
disconnect: () => {}
|
disconnect: () => {}
|
||||||
} as any
|
} as Partial<Parameters<typeof subgraph.removeOutput>[0]> as Parameters<
|
||||||
|
typeof subgraph.removeOutput
|
||||||
|
>[0]
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
subgraph.removeOutput(fakeOutput)
|
subgraph.removeOutput(fakeOutput)
|
||||||
}).toThrow(/Output not found/) // Expected error
|
}).toThrow(/Output not found/) // Expected error
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle null/undefined input names', () => {
|
it('should throw error for null/undefined input names', () => {
|
||||||
const subgraph = createTestSubgraph()
|
const subgraph = createTestSubgraph()
|
||||||
|
|
||||||
// ISSUE: Current implementation allows null/undefined names which may cause runtime errors
|
|
||||||
// TODO: Consider adding validation to prevent null/undefined names
|
|
||||||
// This test documents the current permissive behavior
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
subgraph.addInput(null as any, 'number')
|
subgraph.addInput(null, 'number')
|
||||||
}).not.toThrow() // Current behavior: allows null
|
}).toThrow() // Current behavior: allows null
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
subgraph.addInput(undefined as any, 'number')
|
subgraph.addInput(undefined, 'number')
|
||||||
}).not.toThrow() // Current behavior: allows undefined
|
}).toThrow() // Current behavior: allows undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle null/undefined output names', () => {
|
it('should handle null/undefined output names', () => {
|
||||||
const subgraph = createTestSubgraph()
|
const subgraph = createTestSubgraph()
|
||||||
|
|
||||||
// ISSUE: Current implementation allows null/undefined names which may cause runtime errors
|
|
||||||
// TODO: Consider adding validation to prevent null/undefined names
|
|
||||||
// This test documents the current permissive behavior
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
subgraph.addOutput(null as any, 'number')
|
subgraph.addOutput(null, 'number')
|
||||||
}).not.toThrow() // Current behavior: allows null
|
}).toThrow()
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
subgraph.addOutput(undefined as any, 'number')
|
subgraph.addOutput(undefined, 'number')
|
||||||
}).not.toThrow() // Current behavior: allows undefined
|
}).toThrow()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle empty string names', () => {
|
it('should handle empty string names', () => {
|
||||||
@@ -153,11 +150,11 @@ describe.skip('SubgraphEdgeCases - Invalid States', () => {
|
|||||||
|
|
||||||
// Undefined type should not crash but may have default behavior
|
// Undefined type should not crash but may have default behavior
|
||||||
expect(() => {
|
expect(() => {
|
||||||
subgraph.addInput('test', undefined as any)
|
subgraph.addInput('test', undefined)
|
||||||
}).not.toThrow()
|
}).not.toThrow()
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
subgraph.addOutput('test', undefined as any)
|
subgraph.addOutput('test', undefined)
|
||||||
}).not.toThrow()
|
}).not.toThrow()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { Mock } from 'vitest'
|
||||||
import { describe, expect, it, vi } from 'vitest'
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
import { truncateText } from '@/lib/litegraph/src/litegraph'
|
import { truncateText } from '@/lib/litegraph/src/litegraph'
|
||||||
@@ -5,8 +6,13 @@ import { truncateText } from '@/lib/litegraph/src/litegraph'
|
|||||||
describe('truncateText', () => {
|
describe('truncateText', () => {
|
||||||
const createMockContext = (charWidth: number = 10) => {
|
const createMockContext = (charWidth: number = 10) => {
|
||||||
return {
|
return {
|
||||||
measureText: vi.fn((text: string) => ({ width: text.length * charWidth }))
|
measureText: vi.fn(
|
||||||
} as unknown as CanvasRenderingContext2D
|
(text: string) =>
|
||||||
|
({
|
||||||
|
width: text.length * charWidth
|
||||||
|
}) as TextMetrics
|
||||||
|
)
|
||||||
|
} as Partial<CanvasRenderingContext2D> as CanvasRenderingContext2D
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should return original text if it fits within maxWidth', () => {
|
it('should return original text if it fits within maxWidth', () => {
|
||||||
@@ -57,7 +63,7 @@ describe('truncateText', () => {
|
|||||||
// Verify binary search efficiency - should not measure every possible substring
|
// Verify binary search efficiency - should not measure every possible substring
|
||||||
// Binary search for 100 chars should take around log2(100) ≈ 7 iterations
|
// Binary search for 100 chars should take around log2(100) ≈ 7 iterations
|
||||||
// Plus a few extra calls for measuring the full text and ellipsis
|
// Plus a few extra calls for measuring the full text and ellipsis
|
||||||
const callCount = (ctx.measureText as any).mock.calls.length
|
const callCount = (ctx.measureText as Mock).mock.calls.length
|
||||||
expect(callCount).toBeLessThan(20)
|
expect(callCount).toBeLessThan(20)
|
||||||
expect(callCount).toBeGreaterThan(5)
|
expect(callCount).toBeGreaterThan(5)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -389,8 +389,9 @@ describe('ComboWidget', () => {
|
|||||||
node.size = [200, 30]
|
node.size = [200, 30]
|
||||||
|
|
||||||
const mockContextMenu = vi.fn()
|
const mockContextMenu = vi.fn()
|
||||||
LiteGraph.ContextMenu =
|
LiteGraph.ContextMenu = mockContextMenu as Partial<
|
||||||
mockContextMenu as unknown as typeof LiteGraph.ContextMenu
|
typeof LiteGraph.ContextMenu
|
||||||
|
> as typeof LiteGraph.ContextMenu
|
||||||
|
|
||||||
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
||||||
|
|
||||||
@@ -426,8 +427,9 @@ describe('ComboWidget', () => {
|
|||||||
node.size = [200, 30]
|
node.size = [200, 30]
|
||||||
|
|
||||||
const mockContextMenu = vi.fn()
|
const mockContextMenu = vi.fn()
|
||||||
LiteGraph.ContextMenu =
|
LiteGraph.ContextMenu = mockContextMenu as Partial<
|
||||||
mockContextMenu as unknown as typeof LiteGraph.ContextMenu
|
typeof LiteGraph.ContextMenu
|
||||||
|
> as typeof LiteGraph.ContextMenu
|
||||||
|
|
||||||
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
||||||
|
|
||||||
@@ -463,8 +465,9 @@ describe('ComboWidget', () => {
|
|||||||
.mockImplementation(function (_values, options) {
|
.mockImplementation(function (_values, options) {
|
||||||
capturedCallback = options.callback
|
capturedCallback = options.callback
|
||||||
})
|
})
|
||||||
LiteGraph.ContextMenu =
|
LiteGraph.ContextMenu = mockContextMenu as Partial<
|
||||||
mockContextMenu as unknown as typeof LiteGraph.ContextMenu
|
typeof LiteGraph.ContextMenu
|
||||||
|
> as typeof LiteGraph.ContextMenu
|
||||||
|
|
||||||
const setValueSpy = vi.spyOn(widget, 'setValue')
|
const setValueSpy = vi.spyOn(widget, 'setValue')
|
||||||
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
||||||
@@ -506,8 +509,9 @@ describe('ComboWidget', () => {
|
|||||||
.mockImplementation(function (_values, options) {
|
.mockImplementation(function (_values, options) {
|
||||||
capturedCallback = options.callback
|
capturedCallback = options.callback
|
||||||
})
|
})
|
||||||
LiteGraph.ContextMenu =
|
LiteGraph.ContextMenu = mockContextMenu as Partial<
|
||||||
mockContextMenu as unknown as typeof LiteGraph.ContextMenu
|
typeof LiteGraph.ContextMenu
|
||||||
|
> as typeof LiteGraph.ContextMenu
|
||||||
|
|
||||||
const setValueSpy = vi.spyOn(widget, 'setValue')
|
const setValueSpy = vi.spyOn(widget, 'setValue')
|
||||||
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
||||||
@@ -538,8 +542,9 @@ describe('ComboWidget', () => {
|
|||||||
node.size = [200, 30]
|
node.size = [200, 30]
|
||||||
|
|
||||||
const mockContextMenu = vi.fn()
|
const mockContextMenu = vi.fn()
|
||||||
LiteGraph.ContextMenu =
|
LiteGraph.ContextMenu = mockContextMenu as Partial<
|
||||||
mockContextMenu as unknown as typeof LiteGraph.ContextMenu
|
typeof LiteGraph.ContextMenu
|
||||||
|
> as typeof LiteGraph.ContextMenu
|
||||||
|
|
||||||
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
||||||
|
|
||||||
@@ -572,8 +577,9 @@ describe('ComboWidget', () => {
|
|||||||
node.size = [200, 30]
|
node.size = [200, 30]
|
||||||
|
|
||||||
const mockContextMenu = vi.fn()
|
const mockContextMenu = vi.fn()
|
||||||
LiteGraph.ContextMenu =
|
LiteGraph.ContextMenu = mockContextMenu as Partial<
|
||||||
mockContextMenu as unknown as typeof LiteGraph.ContextMenu
|
typeof LiteGraph.ContextMenu
|
||||||
|
> as typeof LiteGraph.ContextMenu
|
||||||
|
|
||||||
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
||||||
|
|
||||||
@@ -768,8 +774,9 @@ describe('ComboWidget', () => {
|
|||||||
.mockImplementation(function () {
|
.mockImplementation(function () {
|
||||||
this.addItem = mockAddItem
|
this.addItem = mockAddItem
|
||||||
})
|
})
|
||||||
LiteGraph.ContextMenu =
|
LiteGraph.ContextMenu = mockContextMenu as Partial<
|
||||||
mockContextMenu as unknown as typeof LiteGraph.ContextMenu
|
typeof LiteGraph.ContextMenu
|
||||||
|
> as typeof LiteGraph.ContextMenu
|
||||||
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
||||||
|
|
||||||
// Should show formatted labels in dropdown
|
// Should show formatted labels in dropdown
|
||||||
@@ -831,8 +838,9 @@ describe('ComboWidget', () => {
|
|||||||
capturedCallback = options.callback
|
capturedCallback = options.callback
|
||||||
this.addItem = mockAddItem
|
this.addItem = mockAddItem
|
||||||
})
|
})
|
||||||
LiteGraph.ContextMenu =
|
LiteGraph.ContextMenu = mockContextMenu as Partial<
|
||||||
mockContextMenu as unknown as typeof LiteGraph.ContextMenu
|
typeof LiteGraph.ContextMenu
|
||||||
|
> as typeof LiteGraph.ContextMenu
|
||||||
|
|
||||||
const setValueSpy = vi.spyOn(widget, 'setValue')
|
const setValueSpy = vi.spyOn(widget, 'setValue')
|
||||||
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
||||||
@@ -885,8 +893,9 @@ describe('ComboWidget', () => {
|
|||||||
capturedCallback = options.callback
|
capturedCallback = options.callback
|
||||||
this.addItem = mockAddItem
|
this.addItem = mockAddItem
|
||||||
})
|
})
|
||||||
LiteGraph.ContextMenu =
|
LiteGraph.ContextMenu = mockContextMenu as Partial<
|
||||||
mockContextMenu as unknown as typeof LiteGraph.ContextMenu
|
typeof LiteGraph.ContextMenu
|
||||||
|
> as typeof LiteGraph.ContextMenu
|
||||||
|
|
||||||
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
||||||
|
|
||||||
@@ -964,8 +973,9 @@ describe('ComboWidget', () => {
|
|||||||
.mockImplementation(function () {
|
.mockImplementation(function () {
|
||||||
this.addItem = mockAddItem
|
this.addItem = mockAddItem
|
||||||
})
|
})
|
||||||
LiteGraph.ContextMenu =
|
LiteGraph.ContextMenu = mockContextMenu as Partial<
|
||||||
mockContextMenu as unknown as typeof LiteGraph.ContextMenu
|
typeof LiteGraph.ContextMenu
|
||||||
|
> as typeof LiteGraph.ContextMenu
|
||||||
|
|
||||||
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
||||||
|
|
||||||
@@ -1012,8 +1022,9 @@ describe('ComboWidget', () => {
|
|||||||
node.size = [200, 30]
|
node.size = [200, 30]
|
||||||
|
|
||||||
const mockContextMenu = vi.fn<typeof LiteGraph.ContextMenu>()
|
const mockContextMenu = vi.fn<typeof LiteGraph.ContextMenu>()
|
||||||
LiteGraph.ContextMenu =
|
LiteGraph.ContextMenu = mockContextMenu as Partial<
|
||||||
mockContextMenu as unknown as typeof LiteGraph.ContextMenu
|
typeof LiteGraph.ContextMenu
|
||||||
|
> as typeof LiteGraph.ContextMenu
|
||||||
|
|
||||||
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
widget.onClick({ e: mockEvent, node, canvas: mockCanvas })
|
||||||
|
|
||||||
@@ -1051,7 +1062,8 @@ describe('ComboWidget', () => {
|
|||||||
createMockWidgetConfig({
|
createMockWidgetConfig({
|
||||||
name: 'mode',
|
name: 'mode',
|
||||||
value: 'test',
|
value: 'test',
|
||||||
options: { values: null as any }
|
// @ts-expect-error - Testing with intentionally invalid null value
|
||||||
|
options: { values: null }
|
||||||
}),
|
}),
|
||||||
node
|
node
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import {
|
|||||||
getSettingInfo,
|
getSettingInfo,
|
||||||
useSettingStore
|
useSettingStore
|
||||||
} from '@/platform/settings/settingStore'
|
} from '@/platform/settings/settingStore'
|
||||||
|
import type { SettingTreeNode } from '@/platform/settings/settingStore'
|
||||||
|
import type { SettingParams } from '@/platform/settings/types'
|
||||||
|
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
vi.mock('@/i18n', () => ({
|
vi.mock('@/i18n', () => ({
|
||||||
@@ -20,7 +22,7 @@ vi.mock('@/platform/settings/settingStore', () => ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
describe('useSettingSearch', () => {
|
describe('useSettingSearch', () => {
|
||||||
let mockSettingStore: any
|
let mockSettingStore: ReturnType<typeof useSettingStore>
|
||||||
let mockSettings: any
|
let mockSettings: any
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -70,11 +72,11 @@ describe('useSettingSearch', () => {
|
|||||||
// Mock setting store
|
// Mock setting store
|
||||||
mockSettingStore = {
|
mockSettingStore = {
|
||||||
settingsById: mockSettings
|
settingsById: mockSettings
|
||||||
}
|
} as ReturnType<typeof useSettingStore>
|
||||||
vi.mocked(useSettingStore).mockReturnValue(mockSettingStore)
|
vi.mocked(useSettingStore).mockReturnValue(mockSettingStore)
|
||||||
|
|
||||||
// Mock getSettingInfo function
|
// Mock getSettingInfo function
|
||||||
vi.mocked(getSettingInfo).mockImplementation((setting: any) => {
|
vi.mocked(getSettingInfo).mockImplementation((setting: SettingParams) => {
|
||||||
const parts = setting.category || setting.id.split('.')
|
const parts = setting.category || setting.id.split('.')
|
||||||
return {
|
return {
|
||||||
category: parts[0] ?? 'Other',
|
category: parts[0] ?? 'Other',
|
||||||
@@ -301,8 +303,8 @@ describe('useSettingSearch', () => {
|
|||||||
const search = useSettingSearch()
|
const search = useSettingSearch()
|
||||||
search.filteredSettingIds.value = ['Category.Setting1', 'Other.Setting3']
|
search.filteredSettingIds.value = ['Category.Setting1', 'Other.Setting3']
|
||||||
|
|
||||||
const activeCategory = { label: 'Category' } as any
|
const activeCategory: Partial<SettingTreeNode> = { label: 'Category' }
|
||||||
const results = search.getSearchResults(activeCategory)
|
const results = search.getSearchResults(activeCategory as SettingTreeNode)
|
||||||
|
|
||||||
expect(results).toEqual([
|
expect(results).toEqual([
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user