diff --git a/src/utils/fuseUtil.ts b/src/utils/fuseUtil.ts index 6969bbe06..ddfbaa9a4 100644 --- a/src/utils/fuseUtil.ts +++ b/src/utils/fuseUtil.ts @@ -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 + ) } /** diff --git a/src/utils/graphTraversalUtil.test.ts b/src/utils/graphTraversalUtil.test.ts index 2b3f1bfbc..604ba8138 100644 --- a/src/utils/graphTraversalUtil.test.ts +++ b/src/utils/graphTraversalUtil.test.ts @@ -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 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 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 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') diff --git a/src/utils/linkFixer.ts b/src/utils/linkFixer.ts index 64fdd598f..065934224 100644 --- a/src/utils/linkFixer.ts +++ b/src/utils/linkFixer.ts @@ -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 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]}`) diff --git a/src/utils/litegraphUtil.test.ts b/src/utils/litegraphUtil.test.ts index 36a6692ee..50a6ef821 100644 --- a/src/utils/litegraphUtil.test.ts +++ b/src/utils/litegraphUtil.test.ts @@ -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[] 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 = {} 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[] 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 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 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 as ISerialisedGraph compressWidgetInputSlots(graph) diff --git a/src/utils/syncUtil.ts b/src/utils/syncUtil.ts index c60583b9b..f69474603 100644 --- a/src/utils/syncUtil.ts +++ b/src/utils/syncUtil.ts @@ -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( dir: string, entityByPath: Record, - 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) => ({ diff --git a/src/utils/typeGuardUtil.test.ts b/src/utils/typeGuardUtil.test.ts index 9c0689271..9a58655b2 100644 --- a/src/utils/typeGuardUtil.test.ts +++ b/src/utils/typeGuardUtil.test.ts @@ -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 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) }) diff --git a/src/workbench/extensions/manager/composables/nodePack/useMissingNodes.test.ts b/src/workbench/extensions/manager/composables/nodePack/useMissingNodes.test.ts index a467bf098..371d36b0b 100644 --- a/src/workbench/extensions/manager/composables/nodePack/useMissingNodes.test.ts +++ b/src/workbench/extensions/manager/composables/nodePack/useMissingNodes.test.ts @@ -2,17 +2,22 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { nextTick, ref } from 'vue' import type { LGraphNode, LGraph } from '@/lib/litegraph/src/litegraph' +import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore' import { useNodeDefStore } from '@/stores/nodeDefStore' import { collectAllNodes } from '@/utils/graphTraversalUtil' import { useMissingNodes } from '@/workbench/extensions/manager/composables/nodePack/useMissingNodes' import { useWorkflowPacks } from '@/workbench/extensions/manager/composables/nodePack/useWorkflowPacks' +import type { WorkflowPack } from '@/workbench/extensions/manager/composables/nodePack/useWorkflowPacks' import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore' +import { createMockLGraphNode } from '@/utils/__tests__/litegraphTestUtils' vi.mock('@vueuse/core', async () => { const actual = await vi.importActual('@vueuse/core') return { ...actual, - createSharedComposable: any>(fn: Fn) => fn + createSharedComposable: unknown>( + fn: Fn + ) => fn } }) @@ -81,11 +86,11 @@ describe('useMissingNodes', () => { // Default setup: pack-3 is installed, others are not mockIsPackInstalled.mockImplementation((id: string) => id === 'pack-3') - // @ts-expect-error - Mocking partial ComfyManagerStore for testing. - // We only need isPackInstalled method for these tests. mockUseComfyManagerStore.mockReturnValue({ isPackInstalled: mockIsPackInstalled - }) + } as Partial> as ReturnType< + typeof useComfyManagerStore + >) mockUseWorkflowPacks.mockReturnValue({ workflowPacks: ref([]), @@ -97,11 +102,11 @@ describe('useMissingNodes', () => { }) // Reset node def store mock - // @ts-expect-error - Mocking partial NodeDefStore for testing. - // We only need nodeDefsByName for these tests. mockUseNodeDefStore.mockReturnValue({ nodeDefsByName: {} - }) + } as Partial> as ReturnType< + typeof useNodeDefStore + >) // Reset app.rootGraph.nodes mockApp.rootGraph = { nodes: [] } @@ -249,7 +254,7 @@ describe('useMissingNodes', () => { describe('reactivity', () => { it('updates when workflow packs change', async () => { - const workflowPacksRef = ref([]) + const workflowPacksRef = ref([]) mockUseWorkflowPacks.mockReturnValue({ workflowPacks: workflowPacksRef, isLoading: ref(false), @@ -265,8 +270,8 @@ describe('useMissingNodes', () => { expect(missingNodePacks.value).toEqual([]) // Update workflow packs - // @ts-expect-error - mockWorkflowPacks is a simplified version without full WorkflowPack interface. - workflowPacksRef.value = mockWorkflowPacks + + workflowPacksRef.value = mockWorkflowPacks as unknown as WorkflowPack[] await nextTick() // Should update missing packs (2 missing since pack-3 is installed) @@ -302,7 +307,7 @@ describe('useMissingNodes', () => { describe('missing core nodes detection', () => { const createMockNode = (type: string, packId?: string, version?: string) => - ({ + createMockLGraphNode({ type, properties: { cnr_id: packId, ver: version }, id: 1, @@ -314,7 +319,7 @@ describe('useMissingNodes', () => { mode: 0, inputs: [], outputs: [] - }) as unknown as LGraphNode + }) it('identifies missing core nodes not in nodeDefStore', () => { const coreNode1 = createMockNode('CoreNode1', 'comfy-core', '1.2.0') @@ -323,13 +328,16 @@ describe('useMissingNodes', () => { // Mock collectAllNodes to return only the filtered nodes (missing core nodes) mockCollectAllNodes.mockReturnValue([coreNode1, coreNode2]) + const namedNode = { + name: 'RegisteredNode' + } as Partial as ComfyNodeDefImpl mockUseNodeDefStore.mockReturnValue({ nodeDefsByName: { - // @ts-expect-error - Creating minimal mock of ComfyNodeDefImpl for testing. - // Only including required properties for our test assertions. - RegisteredNode: { name: 'RegisteredNode' } + RegisteredNode: namedNode } - }) + } as Partial> as ReturnType< + typeof useNodeDefStore + >) const { missingCoreNodes } = useMissingNodes() @@ -347,10 +355,11 @@ describe('useMissingNodes', () => { // Mock collectAllNodes to return these nodes mockCollectAllNodes.mockReturnValue([node120, node130, nodeNoVer]) - // @ts-expect-error - Mocking partial NodeDefStore for testing. mockUseNodeDefStore.mockReturnValue({ nodeDefsByName: {} - }) + } as Partial> as ReturnType< + typeof useNodeDefStore + >) const { missingCoreNodes } = useMissingNodes() @@ -366,10 +375,11 @@ describe('useMissingNodes', () => { // Mock collectAllNodes to return only the filtered nodes (core nodes only) mockCollectAllNodes.mockReturnValue([coreNode]) - // @ts-expect-error - Mocking partial NodeDefStore for testing. mockUseNodeDefStore.mockReturnValue({ nodeDefsByName: {} - }) + } as Partial> as ReturnType< + typeof useNodeDefStore + >) const { missingCoreNodes } = useMissingNodes() @@ -384,13 +394,16 @@ describe('useMissingNodes', () => { mockUseNodeDefStore.mockReturnValue({ nodeDefsByName: { - // @ts-expect-error - Creating minimal mock of ComfyNodeDefImpl for testing. - // Only including required properties for our test assertions. - RegisteredNode1: { name: 'RegisteredNode1' }, - // @ts-expect-error - Creating minimal mock of ComfyNodeDefImpl for testing. - RegisteredNode2: { name: 'RegisteredNode2' } + RegisteredNode1: { + name: 'RegisteredNode1' + } as Partial as ComfyNodeDefImpl, + RegisteredNode2: { + name: 'RegisteredNode2' + } as Partial as ComfyNodeDefImpl } - }) + } as Partial> as ReturnType< + typeof useNodeDefStore + >) const { missingCoreNodes } = useMissingNodes() @@ -404,9 +417,7 @@ describe('useMissingNodes', () => { packId?: string, version?: string ): LGraphNode => - // @ts-expect-error - Creating a partial mock of LGraphNode for testing. - // We only need specific properties for our tests, not the full LGraphNode interface. - ({ + createMockLGraphNode({ type, properties: { cnr_id: packId, ver: version }, id: 1, @@ -441,10 +452,11 @@ describe('useMissingNodes', () => { ]) // Mock none of the nodes as registered - // @ts-expect-error - Mocking partial NodeDefStore for testing. mockUseNodeDefStore.mockReturnValue({ nodeDefsByName: {} - }) + } as Partial> as ReturnType< + typeof useNodeDefStore + >) const { missingCoreNodes } = useMissingNodes() @@ -482,10 +494,13 @@ describe('useMissingNodes', () => { mockUseNodeDefStore.mockReturnValue({ nodeDefsByName: { - // @ts-expect-error - Creating minimal mock of ComfyNodeDefImpl for testing. - RegisteredCore: { name: 'RegisteredCore' } + RegisteredCore: { + name: 'RegisteredCore' + } as Partial as ComfyNodeDefImpl } - }) + } as Partial> as ReturnType< + typeof useNodeDefStore + >) let capturedFilterFunction: ((node: LGraphNode) => boolean) | undefined @@ -561,12 +576,12 @@ describe('useMissingNodes', () => { nodes: [subgraphMissingNode, subgraphRegisteredNode] } - const mockSubgraphNode = { + const mockSubgraphNode = createMockLGraphNode({ isSubgraphNode: () => true, subgraph: mockSubgraph, type: 'SubgraphContainer', properties: { cnr_id: 'custom-pack' } - } as unknown as LGraphNode + }) const mockMainGraph = { nodes: [mainMissingNode, mockSubgraphNode] @@ -576,10 +591,13 @@ describe('useMissingNodes', () => { mockUseNodeDefStore.mockReturnValue({ nodeDefsByName: { - // @ts-expect-error - Creating minimal mock of ComfyNodeDefImpl for testing. - SubgraphRegistered: { name: 'SubgraphRegistered' } + SubgraphRegistered: { + name: 'SubgraphRegistered' + } as Partial as ComfyNodeDefImpl } - }) + } as Partial> as ReturnType< + typeof useNodeDefStore + >) const { missingCoreNodes } = useMissingNodes() diff --git a/src/workbench/extensions/manager/composables/nodePack/usePacksSelection.test.ts b/src/workbench/extensions/manager/composables/nodePack/usePacksSelection.test.ts index 3a17a1ba1..807cbeb38 100644 --- a/src/workbench/extensions/manager/composables/nodePack/usePacksSelection.test.ts +++ b/src/workbench/extensions/manager/composables/nodePack/usePacksSelection.test.ts @@ -324,7 +324,7 @@ describe('usePacksSelection', () => { describe('edge cases', () => { it('should handle packs with undefined ids', () => { const nodePacks = ref([ - { ...createMockPack('pack1'), id: undefined as any }, + { ...createMockPack('pack1'), id: undefined }, createMockPack('pack2') ]) diff --git a/src/workbench/extensions/manager/composables/nodePack/usePacksStatus.test.ts b/src/workbench/extensions/manager/composables/nodePack/usePacksStatus.test.ts index 5977196ce..d630e5eb8 100644 --- a/src/workbench/extensions/manager/composables/nodePack/usePacksStatus.test.ts +++ b/src/workbench/extensions/manager/composables/nodePack/usePacksStatus.test.ts @@ -108,7 +108,7 @@ describe('usePacksStatus', () => { it('should handle packs without ids', () => { const nodePacks = ref([ - { ...createMockPack('pack1'), id: undefined as any }, + { ...createMockPack('pack1'), id: undefined }, createMockPack('pack2') ]) diff --git a/src/workbench/extensions/manager/composables/nodePack/useWorkflowPacks.ts b/src/workbench/extensions/manager/composables/nodePack/useWorkflowPacks.ts index a56c908ef..5fa3fcf38 100644 --- a/src/workbench/extensions/manager/composables/nodePack/useWorkflowPacks.ts +++ b/src/workbench/extensions/manager/composables/nodePack/useWorkflowPacks.ts @@ -11,7 +11,7 @@ import type { components } from '@/types/comfyRegistryTypes' import { mapAllNodes } from '@/utils/graphTraversalUtil' import { useNodePacks } from '@/workbench/extensions/manager/composables/nodePack/useNodePacks' -type WorkflowPack = { +export type WorkflowPack = { id: | ComfyWorkflowJSON['nodes'][number]['properties']['cnr_id'] | ComfyWorkflowJSON['nodes'][number]['properties']['aux_id'] diff --git a/src/workbench/extensions/manager/composables/useConflictAcknowledgment.ts b/src/workbench/extensions/manager/composables/useConflictAcknowledgment.ts index 0abec73e4..d79b5086e 100644 --- a/src/workbench/extensions/manager/composables/useConflictAcknowledgment.ts +++ b/src/workbench/extensions/manager/composables/useConflictAcknowledgment.ts @@ -15,7 +15,7 @@ const STORAGE_KEYS = { /** * Interface for conflict acknowledgment state */ -interface ConflictAcknowledgmentState { +export interface ConflictAcknowledgmentState { modal_dismissed: boolean red_dot_dismissed: boolean warning_banner_dismissed: boolean diff --git a/src/workbench/extensions/manager/composables/useConflictDetection.test.ts b/src/workbench/extensions/manager/composables/useConflictDetection.test.ts index 46aec9d2c..fca5e7de6 100644 --- a/src/workbench/extensions/manager/composables/useConflictDetection.test.ts +++ b/src/workbench/extensions/manager/composables/useConflictDetection.test.ts @@ -8,6 +8,7 @@ import { useSystemStatsStore } from '@/stores/systemStatsStore' import type { components } from '@/types/comfyRegistryTypes' import { useInstalledPacks } from '@/workbench/extensions/manager/composables/nodePack/useInstalledPacks' import { useConflictAcknowledgment } from '@/workbench/extensions/manager/composables/useConflictAcknowledgment' +import type { ConflictAcknowledgmentState } from '@/workbench/extensions/manager/composables/useConflictAcknowledgment' import { useConflictDetection } from '@/workbench/extensions/manager/composables/useConflictDetection' import { useComfyManagerService } from '@/workbench/extensions/manager/services/comfyManagerService' import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore' @@ -121,13 +122,17 @@ describe('useConflictDetection', () => { getImportFailInfoBulk: vi.fn(), isLoading: ref(false), error: ref(null) - } as unknown as ReturnType + } as Partial> as ReturnType< + typeof useComfyManagerService + > const mockRegistryService = { getBulkNodeVersions: vi.fn(), isLoading: ref(false), error: ref(null) - } as unknown as ReturnType + } as Partial> as ReturnType< + typeof useComfyRegistryService + > // Create a ref that can be modified in tests const mockInstalledPacksWithVersions = ref<{ id: string; version: string }[]>( @@ -143,35 +148,43 @@ describe('useConflictDetection', () => { isReady: ref(false), isLoading: ref(false), error: ref(null) - } as unknown as ReturnType + } as Partial> as ReturnType< + typeof useInstalledPacks + > const mockManagerStore = { isPackEnabled: vi.fn() - } as unknown as ReturnType + } as Partial> as ReturnType< + typeof useComfyManagerStore + > // Create refs that can be used to control computed properties - const mockConflictedPackages = ref([]) + let mockConflictedPackages: ConflictDetectionResult[] = [] const mockConflictStore = { - hasConflicts: computed(() => - mockConflictedPackages.value.some((p) => p.has_conflict) - ), - conflictedPackages: mockConflictedPackages, - bannedPackages: computed(() => - mockConflictedPackages.value.filter((p) => + get hasConflicts() { + return mockConflictedPackages.some((p) => p.has_conflict) + }, + get conflictedPackages() { + return mockConflictedPackages + }, + get bannedPackages() { + return mockConflictedPackages.filter((p) => p.conflicts?.some((c) => c.type === 'banned') ) - ), - securityPendingPackages: computed(() => - mockConflictedPackages.value.filter((p) => + }, + get securityPendingPackages() { + return mockConflictedPackages.filter((p) => p.conflicts?.some((c) => c.type === 'pending') ) - ), + }, setConflictedPackages: vi.fn(), clearConflicts: vi.fn() - } as unknown as ReturnType + } as Partial> as ReturnType< + typeof useConflictDetectionStore + > - const mockIsInitialized = ref(true) + const mockIsInitialized = true const mockSystemStatsStore = { systemStats: { system: { @@ -199,26 +212,26 @@ describe('useConflictDetection', () => { ] }, isInitialized: mockIsInitialized, - $state: {} as never, - $patch: vi.fn(), - $reset: vi.fn(), - $subscribe: vi.fn(), - $onAction: vi.fn(), - $dispose: vi.fn(), - $id: 'systemStats', + _customProperties: new Set() - } as unknown as ReturnType + } as Partial> as ReturnType< + typeof useSystemStatsStore + > const mockAcknowledgment = { checkComfyUIVersionChange: vi.fn(), - acknowledgmentState: computed(() => ({})), + acknowledgmentState: computed( + () => ({}) as Partial + ), shouldShowConflictModal: computed(() => false), shouldShowRedDot: computed(() => false), shouldShowManagerBanner: computed(() => false), dismissRedDotNotification: vi.fn(), dismissWarningBanner: vi.fn(), markConflictsAsSeen: vi.fn() - } as unknown as ReturnType + } as Partial> as ReturnType< + typeof useConflictAcknowledgment + > beforeEach(() => { vi.clearAllMocks() @@ -249,7 +262,7 @@ describe('useConflictDetection', () => { // Reset the installedPacksWithVersions data mockInstalledPacksWithVersions.value = [] // Reset conflicted packages - mockConflictedPackages.value = [] + mockConflictedPackages = [] }) afterEach(() => { @@ -414,7 +427,7 @@ describe('useConflictDetection', () => { error: 'Import error', name: 'fail-pack', path: '/path/to/pack' - } as any // The actual API returns different structure than types + } as { error?: string; traceback?: string } | null // The actual API returns different structure than types }) // Mock registry response for the package @@ -437,7 +450,7 @@ describe('useConflictDetection', () => { describe('computed properties', () => { it('should expose conflict status from store', () => { - mockConflictedPackages.value = [ + mockConflictedPackages = [ { package_id: 'test', package_name: 'Test', @@ -450,8 +463,8 @@ describe('useConflictDetection', () => { useConflictDetection() // The hasConflicts computed should be true since we have a conflict - expect(mockConflictedPackages.value).toHaveLength(1) - expect(mockConflictedPackages.value[0].has_conflict).toBe(true) + expect(mockConflictedPackages).toHaveLength(1) + expect(mockConflictedPackages[0].has_conflict).toBe(true) }) }) diff --git a/src/workbench/extensions/manager/composables/useManagerQueue.test.ts b/src/workbench/extensions/manager/composables/useManagerQueue.test.ts index 740a1e5cf..67a2f19e4 100644 --- a/src/workbench/extensions/manager/composables/useManagerQueue.test.ts +++ b/src/workbench/extensions/manager/composables/useManagerQueue.test.ts @@ -1,4 +1,5 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import type { Ref } from 'vue' import { ref } from 'vue' import { useManagerQueue } from '@/workbench/extensions/manager/composables/useManagerQueue' @@ -22,9 +23,11 @@ type ManagerTaskHistory = Record< type ManagerTaskQueue = components['schemas']['TaskStateMessage'] describe('useManagerQueue', () => { - let taskHistory: any - let taskQueue: any - let installedPacks: any + let taskHistory: Ref + let taskQueue: Ref + let installedPacks: Ref< + Record + > const createManagerQueue = () => { taskHistory = ref({}) @@ -67,14 +70,28 @@ describe('useManagerQueue', () => { { ui_id: 'task1', client_id: 'test-client-id', - task_name: 'Installing pack1' + kind: 'install', + params: { + id: 'pack1', + version: '1.0.0', + selected_version: '1.0.0', + mode: 'remote' as const, + channel: 'default' as const + } } ] taskQueue.value.pending_queue = [ { ui_id: 'task2', client_id: 'test-client-id', - task_name: 'Installing pack2' + kind: 'install', + params: { + id: 'pack2', + version: '1.0.0', + selected_version: '1.0.0', + mode: 'remote' as const, + channel: 'default' as const + } } ] @@ -101,12 +118,18 @@ describe('useManagerQueue', () => { task1: { ui_id: 'task1', client_id: 'test-client-id', - status: { status_str: 'success', completed: true } + kind: 'install', + timestamp: '2024-01-01T00:00:00Z', + result: 'success', + status: { status_str: 'success', completed: true, messages: [] } }, task2: { ui_id: 'task2', client_id: 'test-client-id', - status: { status_str: 'success', completed: true } + kind: 'install', + timestamp: '2024-01-01T00:00:00Z', + result: 'success', + status: { status_str: 'success', completed: true, messages: [] } } } @@ -198,12 +221,12 @@ describe('useManagerQueue', () => { it('handles empty installed_packs gracefully', () => { const queue = createManagerQueue() - const mockState: any = { + const mockState = { history: {}, running_queue: [], pending_queue: [], - installed_packs: undefined - } + installed_packs: undefined! + } satisfies Partial as ManagerTaskQueue // Just call the function - if it throws, the test will fail automatically queue.updateTaskState(mockState) diff --git a/src/workbench/extensions/manager/composables/useManagerState.test.ts b/src/workbench/extensions/manager/composables/useManagerState.test.ts index 1ba41d107..710ea6d32 100644 --- a/src/workbench/extensions/manager/composables/useManagerState.test.ts +++ b/src/workbench/extensions/manager/composables/useManagerState.test.ts @@ -1,45 +1,45 @@ +import { createTestingPinia } from '@pinia/testing' +import { setActivePinia } from 'pinia' import { beforeEach, describe, expect, it, vi } from 'vitest' -import { ref } from 'vue' -import { useFeatureFlags } from '@/composables/useFeatureFlags' import { api } from '@/scripts/api' -import { useExtensionStore } from '@/stores/extensionStore' import { useSystemStatsStore } from '@/stores/systemStatsStore' import { ManagerUIState, useManagerState } from '@/workbench/extensions/manager/composables/useManagerState' -// Mock dependencies +// Mock dependencies that are not stores vi.mock('@/scripts/api', () => ({ api: { getClientFeatureFlags: vi.fn(), - getServerFeature: vi.fn() + getServerFeature: vi.fn(), + getSystemStats: vi.fn() } })) -vi.mock('@/composables/useFeatureFlags', () => ({ - useFeatureFlags: vi.fn(() => ({ - flags: { supportsManagerV4: false }, - featureFlag: vi.fn() - })) -})) +vi.mock('@/composables/useFeatureFlags', () => { + const featureFlag = vi.fn() + return { + useFeatureFlags: vi.fn(() => ({ + flags: { supportsManagerV4: false }, + featureFlag + })) + } +}) -vi.mock('@/stores/extensionStore', () => ({ - useExtensionStore: vi.fn() -})) - -vi.mock('@/stores/systemStatsStore', () => ({ - useSystemStatsStore: vi.fn() -})) - -vi.mock('@/services/dialogService', () => ({ - useDialogService: vi.fn(() => ({ - showManagerPopup: vi.fn(), - showLegacyManagerPopup: vi.fn(), - showSettingsDialog: vi.fn() - })) -})) +vi.mock('@/services/dialogService', () => { + const showManagerPopup = vi.fn() + const showLegacyManagerPopup = vi.fn() + const showSettingsDialog = vi.fn() + return { + useDialogService: vi.fn(() => ({ + showManagerPopup, + showLegacyManagerPopup, + showSettingsDialog + })) + } +}) vi.mock('@/stores/commandStore', () => ({ useCommandStore: vi.fn(() => ({ @@ -47,198 +47,223 @@ vi.mock('@/stores/commandStore', () => ({ })) })) -vi.mock('@/stores/toastStore', () => ({ - useToastStore: vi.fn(() => ({ - add: vi.fn() - })) -})) +vi.mock('@/platform/updates/common/toastStore', () => { + const add = vi.fn() + return { + useToastStore: vi.fn(() => ({ + add + })) + } +}) -vi.mock('@/workbench/extensions/manager/composables/useManagerDialog', () => ({ - useManagerDialog: vi.fn(() => ({ - show: vi.fn(), - hide: vi.fn() - })) -})) +vi.mock('@/workbench/extensions/manager/composables/useManagerDialog', () => { + const show = vi.fn() + const hide = vi.fn() + return { + useManagerDialog: vi.fn(() => ({ + show, + hide + })) + } +}) describe('useManagerState', () => { + let systemStatsStore: ReturnType + beforeEach(() => { - vi.clearAllMocks() + // Create a fresh testing pinia and activate it for each test + setActivePinia( + createTestingPinia({ + stubActions: false, + createSpy: vi.fn + }) + ) + + // Initialize stores + systemStatsStore = useSystemStatsStore() + + // Reset all mocks + vi.resetAllMocks() + + // Set default mock returns + vi.mocked(api.getClientFeatureFlags).mockReturnValue({}) + vi.mocked(api.getServerFeature).mockReturnValue(undefined) }) describe('managerUIState property', () => { it('should return DISABLED state when --enable-manager is NOT present', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ - system: { argv: ['python', 'main.py'] } // No --enable-manager flag - }), - isInitialized: ref(true) - } as any) - vi.mocked(api.getClientFeatureFlags).mockReturnValue({}) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) + // Set up store state + systemStatsStore.$patch({ + systemStats: { + system: { + os: 'Test OS', + python_version: '3.10', + embedded_python: false, + comfyui_version: '1.0.0', + pytorch_version: '2.0.0', + argv: ['python', 'main.py'], // No --enable-manager flag + ram_total: 16000000000, + ram_free: 8000000000 + }, + devices: [] + }, + isInitialized: true + }) const managerState = useManagerState() - expect(managerState.managerUIState.value).toBe(ManagerUIState.DISABLED) }) it('should return LEGACY_UI state when --enable-manager-legacy-ui is present', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ + // Set up store state + systemStatsStore.$patch({ + systemStats: { system: { + os: 'Test OS', + python_version: '3.10', + embedded_python: false, + comfyui_version: '1.0.0', + pytorch_version: '2.0.0', argv: [ 'python', 'main.py', '--enable-manager', '--enable-manager-legacy-ui' - ] - } // Both flags needed - }), - isInitialized: ref(true) - } as any) - vi.mocked(api.getClientFeatureFlags).mockReturnValue({}) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) + ], + ram_total: 16000000000, + ram_free: 8000000000 + }, + devices: [] + }, + isInitialized: true + }) const managerState = useManagerState() - expect(managerState.managerUIState.value).toBe(ManagerUIState.LEGACY_UI) }) it('should return NEW_UI state when client and server both support v4', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ - system: { argv: ['python', 'main.py', '--enable-manager'] } - }), // Need --enable-manager - isInitialized: ref(true) - } as any) + // Set up store state + systemStatsStore.$patch({ + systemStats: { + system: { + os: 'Test OS', + python_version: '3.10', + embedded_python: false, + comfyui_version: '1.0.0', + pytorch_version: '2.0.0', + argv: ['python', 'main.py', '--enable-manager'], + ram_total: 16000000000, + ram_free: 8000000000 + }, + devices: [] + }, + isInitialized: true + }) + vi.mocked(api.getClientFeatureFlags).mockReturnValue({ supports_manager_v4_ui: true }) vi.mocked(api.getServerFeature).mockReturnValue(true) - vi.mocked(useFeatureFlags).mockReturnValue({ - flags: { supportsManagerV4: true }, - featureFlag: vi.fn() - } as any) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) const managerState = useManagerState() - expect(managerState.managerUIState.value).toBe(ManagerUIState.NEW_UI) }) it('should return LEGACY_UI state when server supports v4 but client does not', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ - system: { argv: ['python', 'main.py', '--enable-manager'] } - }), // Need --enable-manager - isInitialized: ref(true) - } as any) + // Set up store state + systemStatsStore.$patch({ + systemStats: { + system: { + os: 'Test OS', + python_version: '3.10', + embedded_python: false, + comfyui_version: '1.0.0', + pytorch_version: '2.0.0', + argv: ['python', 'main.py', '--enable-manager'], + ram_total: 16000000000, + ram_free: 8000000000 + }, + devices: [] + }, + isInitialized: true + }) + vi.mocked(api.getClientFeatureFlags).mockReturnValue({ supports_manager_v4_ui: false }) vi.mocked(api.getServerFeature).mockReturnValue(true) - vi.mocked(useFeatureFlags).mockReturnValue({ - flags: { supportsManagerV4: true }, - featureFlag: vi.fn() - } as any) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) const managerState = useManagerState() - expect(managerState.managerUIState.value).toBe(ManagerUIState.LEGACY_UI) }) - it('should return LEGACY_UI state when legacy manager extension exists', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ - system: { argv: ['python', 'main.py', '--enable-manager'] } - }), // Need --enable-manager - isInitialized: ref(true) - } as any) + it('should return LEGACY_UI state when server does not support v4', () => { + // Set up store state + systemStatsStore.$patch({ + systemStats: { + system: { + os: 'Test OS', + python_version: '3.10', + embedded_python: false, + comfyui_version: '1.0.0', + pytorch_version: '2.0.0', + argv: ['python', 'main.py', '--enable-manager'], + ram_total: 16000000000, + ram_free: 8000000000 + }, + devices: [] + }, + isInitialized: true + }) + vi.mocked(api.getClientFeatureFlags).mockReturnValue({}) - vi.mocked(useFeatureFlags).mockReturnValue({ - flags: { supportsManagerV4: false }, - featureFlag: vi.fn() - } as any) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [{ name: 'Comfy.CustomNodesManager' }] - } as any) + vi.mocked(api.getServerFeature).mockReturnValue(false) const managerState = useManagerState() - expect(managerState.managerUIState.value).toBe(ManagerUIState.LEGACY_UI) }) it('should return NEW_UI state when server feature flags are undefined', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ - system: { argv: ['python', 'main.py', '--enable-manager'] } - }), // Need --enable-manager - isInitialized: ref(true) - } as any) + // Set up store state + systemStatsStore.$patch({ + systemStats: { + system: { + os: 'Test OS', + python_version: '3.10', + embedded_python: false, + comfyui_version: '1.0.0', + pytorch_version: '2.0.0', + argv: ['python', 'main.py', '--enable-manager'], + ram_total: 16000000000, + ram_free: 8000000000 + }, + devices: [] + }, + isInitialized: true + }) + vi.mocked(api.getClientFeatureFlags).mockReturnValue({}) vi.mocked(api.getServerFeature).mockReturnValue(undefined) - vi.mocked(useFeatureFlags).mockReturnValue({ - flags: { supportsManagerV4: undefined }, - featureFlag: vi.fn() - } as any) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) const managerState = useManagerState() - + // When server feature flags haven't loaded yet, default to NEW_UI expect(managerState.managerUIState.value).toBe(ManagerUIState.NEW_UI) }) - it('should return LEGACY_UI state when server does not support v4', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ - system: { argv: ['python', 'main.py', '--enable-manager'] } - }), // Need --enable-manager - isInitialized: ref(true) - } as any) - vi.mocked(api.getClientFeatureFlags).mockReturnValue({}) - vi.mocked(api.getServerFeature).mockReturnValue(false) - vi.mocked(useFeatureFlags).mockReturnValue({ - flags: { supportsManagerV4: false }, - featureFlag: vi.fn() - } as any) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) - - const managerState = useManagerState() - - expect(managerState.managerUIState.value).toBe(ManagerUIState.LEGACY_UI) - }) - it('should handle null systemStats gracefully', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref(null), - isInitialized: ref(true) - } as any) + // Set up store state + systemStatsStore.$patch({ + systemStats: null, + isInitialized: true + }) + vi.mocked(api.getClientFeatureFlags).mockReturnValue({ supports_manager_v4_ui: true }) vi.mocked(api.getServerFeature).mockReturnValue(true) - vi.mocked(useFeatureFlags).mockReturnValue({ - flags: { supportsManagerV4: true }, - featureFlag: vi.fn() - } as any) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) const managerState = useManagerState() - // When systemStats is null, we can't check for --enable-manager flag, so manager is disabled expect(managerState.managerUIState.value).toBe(ManagerUIState.DISABLED) }) @@ -246,115 +271,163 @@ describe('useManagerState', () => { describe('helper properties', () => { it('isManagerEnabled should return true when state is not DISABLED', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ - system: { argv: ['python', 'main.py', '--enable-manager'] } - }), // Need --enable-manager - isInitialized: ref(true) - } as any) + // Set up store state + systemStatsStore.$patch({ + systemStats: { + system: { + os: 'Test OS', + python_version: '3.10', + embedded_python: false, + comfyui_version: '1.0.0', + pytorch_version: '2.0.0', + argv: ['python', 'main.py', '--enable-manager'], + ram_total: 16000000000, + ram_free: 8000000000 + }, + devices: [] + }, + isInitialized: true + }) + vi.mocked(api.getClientFeatureFlags).mockReturnValue({ supports_manager_v4_ui: true }) vi.mocked(api.getServerFeature).mockReturnValue(true) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) const managerState = useManagerState() expect(managerState.isManagerEnabled.value).toBe(true) }) it('isManagerEnabled should return false when state is DISABLED', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ - system: { argv: ['python', 'main.py'] } // No --enable-manager flag means disabled - }), - isInitialized: ref(true) - } as any) - vi.mocked(api.getClientFeatureFlags).mockReturnValue({}) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) + // Set up store state + systemStatsStore.$patch({ + systemStats: { + system: { + os: 'Test OS', + python_version: '3.10', + embedded_python: false, + comfyui_version: '1.0.0', + pytorch_version: '2.0.0', + argv: ['python', 'main.py'], // No --enable-manager flag + ram_total: 16000000000, + ram_free: 8000000000 + }, + devices: [] + }, + isInitialized: true + }) const managerState = useManagerState() expect(managerState.isManagerEnabled.value).toBe(false) }) it('isNewManagerUI should return true when state is NEW_UI', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ - system: { argv: ['python', 'main.py', '--enable-manager'] } - }), // Need --enable-manager - isInitialized: ref(true) - } as any) + // Set up store state + systemStatsStore.$patch({ + systemStats: { + system: { + os: 'Test OS', + python_version: '3.10', + embedded_python: false, + comfyui_version: '1.0.0', + pytorch_version: '2.0.0', + argv: ['python', 'main.py', '--enable-manager'], + ram_total: 16000000000, + ram_free: 8000000000 + }, + devices: [] + }, + isInitialized: true + }) + vi.mocked(api.getClientFeatureFlags).mockReturnValue({ supports_manager_v4_ui: true }) vi.mocked(api.getServerFeature).mockReturnValue(true) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) const managerState = useManagerState() expect(managerState.isNewManagerUI.value).toBe(true) }) it('isLegacyManagerUI should return true when state is LEGACY_UI', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ + // Set up store state + systemStatsStore.$patch({ + systemStats: { system: { + os: 'Test OS', + python_version: '3.10', + embedded_python: false, + comfyui_version: '1.0.0', + pytorch_version: '2.0.0', argv: [ 'python', 'main.py', '--enable-manager', '--enable-manager-legacy-ui' - ] - } // Both flags needed - }), - isInitialized: ref(true) - } as any) - vi.mocked(api.getClientFeatureFlags).mockReturnValue({}) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) + ], + ram_total: 16000000000, + ram_free: 8000000000 + }, + devices: [] + }, + isInitialized: true + }) const managerState = useManagerState() expect(managerState.isLegacyManagerUI.value).toBe(true) }) it('shouldShowInstallButton should return true only for NEW_UI', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ - system: { argv: ['python', 'main.py', '--enable-manager'] } - }), // Need --enable-manager - isInitialized: ref(true) - } as any) + // Set up store state + systemStatsStore.$patch({ + systemStats: { + system: { + os: 'Test OS', + python_version: '3.10', + embedded_python: false, + comfyui_version: '1.0.0', + pytorch_version: '2.0.0', + argv: ['python', 'main.py', '--enable-manager'], + ram_total: 16000000000, + ram_free: 8000000000 + }, + devices: [] + }, + isInitialized: true + }) + vi.mocked(api.getClientFeatureFlags).mockReturnValue({ supports_manager_v4_ui: true }) vi.mocked(api.getServerFeature).mockReturnValue(true) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) const managerState = useManagerState() expect(managerState.shouldShowInstallButton.value).toBe(true) }) it('shouldShowManagerButtons should return true when not DISABLED', () => { - vi.mocked(useSystemStatsStore).mockReturnValue({ - systemStats: ref({ - system: { argv: ['python', 'main.py', '--enable-manager'] } - }), // Need --enable-manager - isInitialized: ref(true) - } as any) + // Set up store state + systemStatsStore.$patch({ + systemStats: { + system: { + os: 'Test OS', + python_version: '3.10', + embedded_python: false, + comfyui_version: '1.0.0', + pytorch_version: '2.0.0', + argv: ['python', 'main.py', '--enable-manager'], + ram_total: 16000000000, + ram_free: 8000000000 + }, + devices: [] + }, + isInitialized: true + }) + vi.mocked(api.getClientFeatureFlags).mockReturnValue({ supports_manager_v4_ui: true }) vi.mocked(api.getServerFeature).mockReturnValue(true) - vi.mocked(useExtensionStore).mockReturnValue({ - extensions: [] - } as any) const managerState = useManagerState() expect(managerState.shouldShowManagerButtons.value).toBe(true) diff --git a/src/workbench/extensions/manager/utils/versionUtil.test.ts b/src/workbench/extensions/manager/utils/versionUtil.test.ts index a9eacfc9d..c0d6270d9 100644 --- a/src/workbench/extensions/manager/utils/versionUtil.test.ts +++ b/src/workbench/extensions/manager/utils/versionUtil.test.ts @@ -27,7 +27,7 @@ describe('versionUtil', () => { it('should return null when current version is null', () => { const result = checkVersionCompatibility( 'comfyui_version', - null as any, + null!, '>=1.0.0' ) expect(result).toBeNull() @@ -51,7 +51,7 @@ describe('versionUtil', () => { const result = checkVersionCompatibility( 'comfyui_version', '1.0.0', - null as any + null! ) expect(result).toBeNull() })