From e9e4780aba486ada1449eb5050a4983806cc51c8 Mon Sep 17 00:00:00 2001 From: Johnpaul Date: Mon, 26 Jan 2026 01:17:45 +0100 Subject: [PATCH] refactor: remove double-cast patterns from group 4 test files - Replace all 'as unknown as Type' patterns with proper typing - Use 'as Partial 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 --- src/lib/litegraph/src/LGraph.ts | 22 ++++++- .../src/subgraph/SubgraphEdgeCases.test.ts | 37 ++++++------ src/lib/litegraph/src/utils/textUtils.test.ts | 12 +++- .../litegraph/src/widgets/ComboWidget.test.ts | 58 +++++++++++-------- .../composables/useSettingSearch.test.ts | 12 ++-- 5 files changed, 88 insertions(+), 53 deletions(-) diff --git a/src/lib/litegraph/src/LGraph.ts b/src/lib/litegraph/src/LGraph.ts index 49ad35101..3a457ddac 100644 --- a/src/lib/litegraph/src/LGraph.ts +++ b/src/lib/litegraph/src/LGraph.ts @@ -2602,7 +2602,16 @@ export class Subgraph 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 }) const input = new SubgraphInput( @@ -2620,7 +2629,16 @@ export class Subgraph 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 }) const output = new SubgraphOutput( diff --git a/src/lib/litegraph/src/subgraph/SubgraphEdgeCases.test.ts b/src/lib/litegraph/src/subgraph/SubgraphEdgeCases.test.ts index b161467e2..4cf70c14e 100644 --- a/src/lib/litegraph/src/subgraph/SubgraphEdgeCases.test.ts +++ b/src/lib/litegraph/src/subgraph/SubgraphEdgeCases.test.ts @@ -83,7 +83,9 @@ describe.skip('SubgraphEdgeCases - Invalid States', () => { name: 'fake', type: 'number', disconnect: () => {} - } as any + } as Partial[0]> as Parameters< + typeof subgraph.removeInput + >[0] // Should throw appropriate error for non-existent input expect(() => { @@ -97,41 +99,36 @@ describe.skip('SubgraphEdgeCases - Invalid States', () => { name: 'fake', type: 'number', disconnect: () => {} - } as any + } as Partial[0]> as Parameters< + typeof subgraph.removeOutput + >[0] expect(() => { subgraph.removeOutput(fakeOutput) }).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() - // 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(() => { - subgraph.addInput(null as any, 'number') - }).not.toThrow() // Current behavior: allows null + subgraph.addInput(null, 'number') + }).toThrow() // Current behavior: allows null expect(() => { - subgraph.addInput(undefined as any, 'number') - }).not.toThrow() // Current behavior: allows undefined + subgraph.addInput(undefined, 'number') + }).toThrow() // Current behavior: allows undefined }) it('should handle null/undefined output names', () => { 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(() => { - subgraph.addOutput(null as any, 'number') - }).not.toThrow() // Current behavior: allows null + subgraph.addOutput(null, 'number') + }).toThrow() expect(() => { - subgraph.addOutput(undefined as any, 'number') - }).not.toThrow() // Current behavior: allows undefined + subgraph.addOutput(undefined, 'number') + }).toThrow() }) 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 expect(() => { - subgraph.addInput('test', undefined as any) + subgraph.addInput('test', undefined) }).not.toThrow() expect(() => { - subgraph.addOutput('test', undefined as any) + subgraph.addOutput('test', undefined) }).not.toThrow() }) diff --git a/src/lib/litegraph/src/utils/textUtils.test.ts b/src/lib/litegraph/src/utils/textUtils.test.ts index 8ca101f61..4d2bbbca0 100644 --- a/src/lib/litegraph/src/utils/textUtils.test.ts +++ b/src/lib/litegraph/src/utils/textUtils.test.ts @@ -1,3 +1,4 @@ +import type { Mock } from 'vitest' import { describe, expect, it, vi } from 'vitest' import { truncateText } from '@/lib/litegraph/src/litegraph' @@ -5,8 +6,13 @@ import { truncateText } from '@/lib/litegraph/src/litegraph' describe('truncateText', () => { const createMockContext = (charWidth: number = 10) => { return { - measureText: vi.fn((text: string) => ({ width: text.length * charWidth })) - } as unknown as CanvasRenderingContext2D + measureText: vi.fn( + (text: string) => + ({ + width: text.length * charWidth + }) as TextMetrics + ) + } as Partial as CanvasRenderingContext2D } 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 // Binary search for 100 chars should take around log2(100) ≈ 7 iterations // 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).toBeGreaterThan(5) }) diff --git a/src/lib/litegraph/src/widgets/ComboWidget.test.ts b/src/lib/litegraph/src/widgets/ComboWidget.test.ts index f080dbab7..e58a61cc8 100644 --- a/src/lib/litegraph/src/widgets/ComboWidget.test.ts +++ b/src/lib/litegraph/src/widgets/ComboWidget.test.ts @@ -389,8 +389,9 @@ describe('ComboWidget', () => { node.size = [200, 30] const mockContextMenu = vi.fn() - LiteGraph.ContextMenu = - mockContextMenu as unknown as typeof LiteGraph.ContextMenu + LiteGraph.ContextMenu = mockContextMenu as Partial< + typeof LiteGraph.ContextMenu + > as typeof LiteGraph.ContextMenu widget.onClick({ e: mockEvent, node, canvas: mockCanvas }) @@ -426,8 +427,9 @@ describe('ComboWidget', () => { node.size = [200, 30] const mockContextMenu = vi.fn() - LiteGraph.ContextMenu = - mockContextMenu as unknown as typeof LiteGraph.ContextMenu + LiteGraph.ContextMenu = mockContextMenu as Partial< + typeof LiteGraph.ContextMenu + > as typeof LiteGraph.ContextMenu widget.onClick({ e: mockEvent, node, canvas: mockCanvas }) @@ -463,8 +465,9 @@ describe('ComboWidget', () => { .mockImplementation(function (_values, options) { capturedCallback = options.callback }) - LiteGraph.ContextMenu = - mockContextMenu as unknown as typeof LiteGraph.ContextMenu + LiteGraph.ContextMenu = mockContextMenu as Partial< + typeof LiteGraph.ContextMenu + > as typeof LiteGraph.ContextMenu const setValueSpy = vi.spyOn(widget, 'setValue') widget.onClick({ e: mockEvent, node, canvas: mockCanvas }) @@ -506,8 +509,9 @@ describe('ComboWidget', () => { .mockImplementation(function (_values, options) { capturedCallback = options.callback }) - LiteGraph.ContextMenu = - mockContextMenu as unknown as typeof LiteGraph.ContextMenu + LiteGraph.ContextMenu = mockContextMenu as Partial< + typeof LiteGraph.ContextMenu + > as typeof LiteGraph.ContextMenu const setValueSpy = vi.spyOn(widget, 'setValue') widget.onClick({ e: mockEvent, node, canvas: mockCanvas }) @@ -538,8 +542,9 @@ describe('ComboWidget', () => { node.size = [200, 30] const mockContextMenu = vi.fn() - LiteGraph.ContextMenu = - mockContextMenu as unknown as typeof LiteGraph.ContextMenu + LiteGraph.ContextMenu = mockContextMenu as Partial< + typeof LiteGraph.ContextMenu + > as typeof LiteGraph.ContextMenu widget.onClick({ e: mockEvent, node, canvas: mockCanvas }) @@ -572,8 +577,9 @@ describe('ComboWidget', () => { node.size = [200, 30] const mockContextMenu = vi.fn() - LiteGraph.ContextMenu = - mockContextMenu as unknown as typeof LiteGraph.ContextMenu + LiteGraph.ContextMenu = mockContextMenu as Partial< + typeof LiteGraph.ContextMenu + > as typeof LiteGraph.ContextMenu widget.onClick({ e: mockEvent, node, canvas: mockCanvas }) @@ -768,8 +774,9 @@ describe('ComboWidget', () => { .mockImplementation(function () { this.addItem = mockAddItem }) - LiteGraph.ContextMenu = - mockContextMenu as unknown as typeof LiteGraph.ContextMenu + LiteGraph.ContextMenu = mockContextMenu as Partial< + typeof LiteGraph.ContextMenu + > as typeof LiteGraph.ContextMenu widget.onClick({ e: mockEvent, node, canvas: mockCanvas }) // Should show formatted labels in dropdown @@ -831,8 +838,9 @@ describe('ComboWidget', () => { capturedCallback = options.callback this.addItem = mockAddItem }) - LiteGraph.ContextMenu = - mockContextMenu as unknown as typeof LiteGraph.ContextMenu + LiteGraph.ContextMenu = mockContextMenu as Partial< + typeof LiteGraph.ContextMenu + > as typeof LiteGraph.ContextMenu const setValueSpy = vi.spyOn(widget, 'setValue') widget.onClick({ e: mockEvent, node, canvas: mockCanvas }) @@ -885,8 +893,9 @@ describe('ComboWidget', () => { capturedCallback = options.callback this.addItem = mockAddItem }) - LiteGraph.ContextMenu = - mockContextMenu as unknown as typeof LiteGraph.ContextMenu + LiteGraph.ContextMenu = mockContextMenu as Partial< + typeof LiteGraph.ContextMenu + > as typeof LiteGraph.ContextMenu widget.onClick({ e: mockEvent, node, canvas: mockCanvas }) @@ -964,8 +973,9 @@ describe('ComboWidget', () => { .mockImplementation(function () { this.addItem = mockAddItem }) - LiteGraph.ContextMenu = - mockContextMenu as unknown as typeof LiteGraph.ContextMenu + LiteGraph.ContextMenu = mockContextMenu as Partial< + typeof LiteGraph.ContextMenu + > as typeof LiteGraph.ContextMenu widget.onClick({ e: mockEvent, node, canvas: mockCanvas }) @@ -1012,8 +1022,9 @@ describe('ComboWidget', () => { node.size = [200, 30] const mockContextMenu = vi.fn() - LiteGraph.ContextMenu = - mockContextMenu as unknown as typeof LiteGraph.ContextMenu + LiteGraph.ContextMenu = mockContextMenu as Partial< + typeof LiteGraph.ContextMenu + > as typeof LiteGraph.ContextMenu widget.onClick({ e: mockEvent, node, canvas: mockCanvas }) @@ -1051,7 +1062,8 @@ describe('ComboWidget', () => { createMockWidgetConfig({ name: 'mode', value: 'test', - options: { values: null as any } + // @ts-expect-error - Testing with intentionally invalid null value + options: { values: null } }), node ) diff --git a/src/platform/settings/composables/useSettingSearch.test.ts b/src/platform/settings/composables/useSettingSearch.test.ts index ba63256e8..239dec846 100644 --- a/src/platform/settings/composables/useSettingSearch.test.ts +++ b/src/platform/settings/composables/useSettingSearch.test.ts @@ -8,6 +8,8 @@ import { getSettingInfo, useSettingStore } from '@/platform/settings/settingStore' +import type { SettingTreeNode } from '@/platform/settings/settingStore' +import type { SettingParams } from '@/platform/settings/types' // Mock dependencies vi.mock('@/i18n', () => ({ @@ -20,7 +22,7 @@ vi.mock('@/platform/settings/settingStore', () => ({ })) describe('useSettingSearch', () => { - let mockSettingStore: any + let mockSettingStore: ReturnType let mockSettings: any beforeEach(() => { @@ -70,11 +72,11 @@ describe('useSettingSearch', () => { // Mock setting store mockSettingStore = { settingsById: mockSettings - } + } as ReturnType vi.mocked(useSettingStore).mockReturnValue(mockSettingStore) // Mock getSettingInfo function - vi.mocked(getSettingInfo).mockImplementation((setting: any) => { + vi.mocked(getSettingInfo).mockImplementation((setting: SettingParams) => { const parts = setting.category || setting.id.split('.') return { category: parts[0] ?? 'Other', @@ -301,8 +303,8 @@ describe('useSettingSearch', () => { const search = useSettingSearch() search.filteredSettingIds.value = ['Category.Setting1', 'Other.Setting3'] - const activeCategory = { label: 'Category' } as any - const results = search.getSearchResults(activeCategory) + const activeCategory: Partial = { label: 'Category' } + const results = search.getSearchResults(activeCategory as SettingTreeNode) expect(results).toEqual([ {