From 02e926471fbe74b76b99f13343aa8a4f1263e4c6 Mon Sep 17 00:00:00 2001 From: Johnpaul Chiwetelu <49923152+Myestery@users.noreply.github.com> Date: Mon, 23 Feb 2026 05:46:12 +0100 Subject: [PATCH] fix: replace as-unknown-as casts with safer patterns (#9107) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Replace 83 `as unknown as` double casts with safer alternatives across 33 files - Use `as Partial as X` pattern where TypeScript allows it - Create/reuse factory functions from `litegraphTestUtils.ts` for mock objects - Widen `getWorkflowDataFromFile` return type to include `ComfyMetadata` directly - Reduce total `as unknown as` count from ~153 to 71 The remaining 71 occurrences are genuinely necessary due to cross-schema casts, generic variance, missing index signatures, Float64Array-to-tuple conversions, and DOM type incompatibilities. ## Test plan - [x] `pnpm typecheck` passes - [x] `pnpm lint` passes - [x] All affected unit tests pass ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9107-fix-replace-as-unknown-as-casts-with-safer-patterns-3106d73d3650815cb5bcd613ad635bd7) by [Unito](https://www.unito.io) --- .../src/views/MaintenanceView.stories.ts | 2 +- .../fixtures/helpers/SubgraphHelper.ts | 6 +- docs/guidance/playwright.md | 2 +- scripts/collect-i18n-general.ts | 6 +- src/base/common/downloadUtil.test.ts | 2 +- .../queue/QueueInlineProgress.test.ts | 4 +- .../queue/job/useJobErrorReporting.test.ts | 2 +- .../searchbox/v2/NodeSearchInput.test.ts | 10 +- .../node/useNodePreviewAndDrag.test.ts | 12 +- .../queue/useQueueNotificationBanners.test.ts | 9 +- src/composables/usePaste.test.ts | 65 +-- src/lib/litegraph/src/LGraphButton.test.ts | 8 +- .../src/LGraphCanvas.slotHitDetection.test.ts | 2 +- .../src/LGraphCanvas.titleButtons.test.ts | 2 +- src/lib/litegraph/src/LGraphCanvas.ts | 2 +- .../src/LGraphNode.titleButtons.test.ts | 10 +- .../src/infrastructure/Rectangle.test.ts | 4 +- .../__tests__/checkoutAttribution.test.ts | 4 +- .../core/services/workflowService.test.ts | 7 +- .../core/canvas/useCanvasInteractions.test.ts | 2 +- .../layout/__tests__/TransformPane.test.ts | 26 +- .../composables/useNodeEventHandlers.test.ts | 8 +- .../interactions/resize/useNodeResize.test.ts | 2 +- src/scripts/metadata/parser.ts | 14 +- src/services/audioService.test.ts | 6 +- src/services/colorPaletteService.ts | 3 +- src/stores/imagePreviewStore.test.ts | 2 +- src/stores/workspace/searchBoxStore.test.ts | 10 +- src/utils/__tests__/litegraphTestUtils.ts | 4 +- src/utils/litegraphUtil.test.ts | 2 +- .../nodePack/useMissingNodes.test.ts | 3 +- .../nodePack/useUpdateAvailableNodes.test.ts | 382 ++++++++---------- .../utils/graphHasMissingNodes.test.ts | 5 +- 33 files changed, 282 insertions(+), 346 deletions(-) diff --git a/apps/desktop-ui/src/views/MaintenanceView.stories.ts b/apps/desktop-ui/src/views/MaintenanceView.stories.ts index 5dee7106b..4a8a4b012 100644 --- a/apps/desktop-ui/src/views/MaintenanceView.stories.ts +++ b/apps/desktop-ui/src/views/MaintenanceView.stories.ts @@ -77,7 +77,7 @@ const createMockElectronAPI = () => { } const ensureElectronAPI = () => { - const globalWindow = window as unknown as { electronAPI?: unknown } + const globalWindow = window as { electronAPI?: unknown } if (!globalWindow.electronAPI) { globalWindow.electronAPI = createMockElectronAPI() } diff --git a/browser_tests/fixtures/helpers/SubgraphHelper.ts b/browser_tests/fixtures/helpers/SubgraphHelper.ts index eb74c2fb5..645c05448 100644 --- a/browser_tests/fixtures/helpers/SubgraphHelper.ts +++ b/browser_tests/fixtures/helpers/SubgraphHelper.ts @@ -88,7 +88,7 @@ export class SubgraphHelper { if (node.onPointerDown) { node.onPointerDown( - event as unknown as CanvasPointerEvent, + event as Partial as CanvasPointerEvent, app.canvas.pointer, app.canvas.linkConnector ) @@ -121,7 +121,7 @@ export class SubgraphHelper { if (node.onPointerDown) { node.onPointerDown( - event as unknown as CanvasPointerEvent, + event as Partial as CanvasPointerEvent, app.canvas.pointer, app.canvas.linkConnector ) @@ -129,7 +129,7 @@ export class SubgraphHelper { // Trigger double-click if (app.canvas.pointer.onDoubleClick) { app.canvas.pointer.onDoubleClick( - event as unknown as CanvasPointerEvent + event as Partial as CanvasPointerEvent ) } } diff --git a/docs/guidance/playwright.md b/docs/guidance/playwright.md index 4eefbc08d..9e30a1e3a 100644 --- a/docs/guidance/playwright.md +++ b/docs/guidance/playwright.md @@ -57,7 +57,7 @@ settings: testData as any // Don't add test settings to src/schemas/apiSchema.ts // ❌ Don't chain through unknown to bypass types -data as unknown as SomeType // Avoid; prefer explicit typings or helpers +data as unknown as SomeType // Avoid; prefer `as Partial as SomeType` or explicit typings ``` ### Accessing Internal State diff --git a/scripts/collect-i18n-general.ts b/scripts/collect-i18n-general.ts index 5165e89be..42ca568a8 100644 --- a/scripts/collect-i18n-general.ts +++ b/scripts/collect-i18n-general.ts @@ -11,7 +11,7 @@ import { } from '../packages/shared-frontend-utils/src/formatUtil' import { CORE_MENU_COMMANDS } from '../src/constants/coreMenuCommands' import { SERVER_CONFIG_ITEMS } from '../src/constants/serverConfig' -import type { FormItem, SettingParams } from '../src/platform/settings/types' +import type { SettingParams } from '../src/platform/settings/types' import type { ComfyCommandImpl } from '../src/stores/commandStore' const localePath = './src/locales/en/main.json' @@ -123,8 +123,8 @@ test('collect-i18n-general', async ({ comfyPage }) => { SERVER_CONFIG_ITEMS.map((config) => [ normalizeI18nKey(config.id), { - name: (config as unknown as FormItem).name, - tooltip: (config as unknown as FormItem).tooltip + name: config.name, + tooltip: config.tooltip } ]) ) diff --git a/src/base/common/downloadUtil.test.ts b/src/base/common/downloadUtil.test.ts index 7ab107f39..fc5c32a86 100644 --- a/src/base/common/downloadUtil.test.ts +++ b/src/base/common/downloadUtil.test.ts @@ -190,7 +190,7 @@ describe('downloadUtil', () => { ok: false, status: 404, blob: vi.fn() - } as unknown as Response) + } as Partial as Response) downloadFile(testUrl) diff --git a/src/components/queue/QueueInlineProgress.test.ts b/src/components/queue/QueueInlineProgress.test.ts index d63dc430e..a065789f3 100644 --- a/src/components/queue/QueueInlineProgress.test.ts +++ b/src/components/queue/QueueInlineProgress.test.ts @@ -6,8 +6,8 @@ import type { Ref } from 'vue' import QueueInlineProgress from '@/components/queue/QueueInlineProgress.vue' const mockProgress = vi.hoisted(() => ({ - totalPercent: null as unknown as Ref, - currentNodePercent: null as unknown as Ref + totalPercent: null! as Ref, + currentNodePercent: null! as Ref })) vi.mock('@/composables/queue/useQueueProgress', () => ({ diff --git a/src/components/queue/job/useJobErrorReporting.test.ts b/src/components/queue/job/useJobErrorReporting.test.ts index 16bf80243..32f8c2172 100644 --- a/src/components/queue/job/useJobErrorReporting.test.ts +++ b/src/components/queue/job/useJobErrorReporting.test.ts @@ -39,7 +39,7 @@ describe('useJobErrorReporting', () => { dialog = { showErrorDialog, showExecutionErrorDialog - } as unknown as JobErrorDialogService + } as Partial as JobErrorDialogService composable = useJobErrorReporting({ taskForJob, copyToClipboard: copyToClipboard as ( diff --git a/src/components/searchbox/v2/NodeSearchInput.test.ts b/src/components/searchbox/v2/NodeSearchInput.test.ts index 5b5a187af..5bc875466 100644 --- a/src/components/searchbox/v2/NodeSearchInput.test.ts +++ b/src/components/searchbox/v2/NodeSearchInput.test.ts @@ -31,7 +31,10 @@ function createFilter( filterDef: { id, matches: vi.fn(() => true) - } as unknown as FuseFilter, + } as Partial> as FuseFilter< + ComfyNodeDefImpl, + string + >, value } } @@ -43,7 +46,10 @@ function createActiveFilter(label: string): FilterChip { filter: { id: label.toLowerCase(), matches: vi.fn(() => true) - } as unknown as FuseFilter + } as Partial> as FuseFilter< + ComfyNodeDefImpl, + string + > } } diff --git a/src/composables/node/useNodePreviewAndDrag.test.ts b/src/composables/node/useNodePreviewAndDrag.test.ts index b493d6bc8..bad6d3d7f 100644 --- a/src/composables/node/useNodePreviewAndDrag.test.ts +++ b/src/composables/node/useNodePreviewAndDrag.test.ts @@ -72,7 +72,9 @@ describe('useNodePreviewAndDrag', () => { toJSON: () => ({}) }) - const mockEvent = { currentTarget: mockElement } as unknown as MouseEvent + const mockEvent = { + currentTarget: mockElement + } as Partial as MouseEvent result.handleMouseEnter(mockEvent) expect(result.isHovered.value).toBe(true) @@ -83,7 +85,9 @@ describe('useNodePreviewAndDrag', () => { const result = useNodePreviewAndDrag(nodeDef) const mockElement = document.createElement('div') - const mockEvent = { currentTarget: mockElement } as unknown as MouseEvent + const mockEvent = { + currentTarget: mockElement + } as Partial as MouseEvent result.handleMouseEnter(mockEvent) expect(result.isHovered.value).toBe(false) @@ -150,7 +154,7 @@ describe('useNodePreviewAndDrag', () => { const mockEvent = { clientX: 100, clientY: 200 - } as unknown as DragEvent + } as Partial as DragEvent result.handleDragEnd(mockEvent) @@ -168,7 +172,7 @@ describe('useNodePreviewAndDrag', () => { dataTransfer: { dropEffect: 'none' }, clientX: 300, clientY: 400 - } as unknown as DragEvent + } as Partial as DragEvent result.handleDragEnd(mockEvent) diff --git a/src/composables/queue/useQueueNotificationBanners.test.ts b/src/composables/queue/useQueueNotificationBanners.test.ts index 73eb557ff..6b51e1e57 100644 --- a/src/composables/queue/useQueueNotificationBanners.test.ts +++ b/src/composables/queue/useQueueNotificationBanners.test.ts @@ -3,7 +3,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { nextTick, reactive } from 'vue' import { useQueueNotificationBanners } from '@/composables/queue/useQueueNotificationBanners' -import { api } from '@/scripts/api' import { useExecutionStore } from '@/stores/executionStore' import { useQueueStore } from '@/stores/queueStore' @@ -135,7 +134,7 @@ describe(useQueueNotificationBanners, () => { const { wrapper, composable } = mountComposable() try { - ;(api as unknown as EventTarget).dispatchEvent( + mockApi.dispatchEvent( new CustomEvent('promptQueued', { detail: { batchCount: 4 } }) ) await nextTick() @@ -157,7 +156,7 @@ describe(useQueueNotificationBanners, () => { const { wrapper, composable } = mountComposable() try { - ;(api as unknown as EventTarget).dispatchEvent( + mockApi.dispatchEvent( new CustomEvent('promptQueueing', { detail: { requestId: 1, batchCount: 2 } }) @@ -170,7 +169,7 @@ describe(useQueueNotificationBanners, () => { requestId: 1 }) - ;(api as unknown as EventTarget).dispatchEvent( + mockApi.dispatchEvent( new CustomEvent('promptQueued', { detail: { requestId: 1, batchCount: 2 } }) @@ -191,7 +190,7 @@ describe(useQueueNotificationBanners, () => { const { wrapper, composable } = mountComposable() try { - ;(api as unknown as EventTarget).dispatchEvent( + mockApi.dispatchEvent( new CustomEvent('promptQueued', { detail: { batchCount: 0 } }) ) await nextTick() diff --git a/src/composables/usePaste.test.ts b/src/composables/usePaste.test.ts index 0c36ff009..9842ba664 100644 --- a/src/composables/usePaste.test.ts +++ b/src/composables/usePaste.test.ts @@ -7,6 +7,7 @@ import type { } from '@/lib/litegraph/src/litegraph' import { LiteGraph } from '@/lib/litegraph/src/litegraph' import { app } from '@/scripts/app' +import { createMockLGraphNode } from '@/utils/__tests__/litegraphTestUtils' import { createNode, isImageNode } from '@/utils/litegraphUtil' import { cloneDataTransfer, @@ -15,12 +16,12 @@ import { usePaste } from './usePaste' -function createMockNode() { - return { +function createMockNode(): LGraphNode { + return createMockLGraphNode({ pos: [0, 0], pasteFile: vi.fn(), pasteFiles: vi.fn() - } + }) } function createImageFile( @@ -84,7 +85,8 @@ vi.mock('@/scripts/app', () => ({ } })) -vi.mock('@/lib/litegraph/src/litegraph', () => ({ +vi.mock('@/lib/litegraph/src/litegraph', async (importOriginal) => ({ + ...(await importOriginal()), LiteGraph: { createNode: vi.fn() } @@ -111,15 +113,12 @@ describe('pasteImageNode', () => { it('should create new LoadImage node when no image node provided', async () => { const mockNode = createMockNode() - vi.mocked(createNode).mockResolvedValue(mockNode as unknown as LGraphNode) + vi.mocked(createNode).mockResolvedValue(mockNode) const file = createImageFile() const dataTransfer = createDataTransfer([file]) - await pasteImageNode( - mockCanvas as unknown as LGraphCanvas, - dataTransfer.items - ) + await pasteImageNode(mockCanvas, dataTransfer.items) expect(createNode).toHaveBeenCalledWith(mockCanvas, 'LoadImage') expect(mockNode.pasteFile).toHaveBeenCalledWith(file) @@ -130,11 +129,7 @@ describe('pasteImageNode', () => { const file = createImageFile() const dataTransfer = createDataTransfer([file]) - await pasteImageNode( - mockCanvas as unknown as LGraphCanvas, - dataTransfer.items, - mockNode as unknown as LGraphNode - ) + await pasteImageNode(mockCanvas, dataTransfer.items, mockNode) expect(mockNode.pasteFile).toHaveBeenCalledWith(file) expect(mockNode.pasteFiles).toHaveBeenCalledWith([file]) @@ -146,11 +141,7 @@ describe('pasteImageNode', () => { const file2 = createImageFile('test2.jpg', 'image/jpeg') const dataTransfer = createDataTransfer([file1, file2]) - await pasteImageNode( - mockCanvas as unknown as LGraphCanvas, - dataTransfer.items, - mockNode as unknown as LGraphNode - ) + await pasteImageNode(mockCanvas, dataTransfer.items, mockNode) expect(mockNode.pasteFile).toHaveBeenCalledWith(file1) expect(mockNode.pasteFiles).toHaveBeenCalledWith([file1, file2]) @@ -160,11 +151,7 @@ describe('pasteImageNode', () => { const mockNode = createMockNode() const dataTransfer = createDataTransfer() - await pasteImageNode( - mockCanvas as unknown as LGraphCanvas, - dataTransfer.items, - mockNode as unknown as LGraphNode - ) + await pasteImageNode(mockCanvas, dataTransfer.items, mockNode) expect(mockNode.pasteFile).not.toHaveBeenCalled() expect(mockNode.pasteFiles).not.toHaveBeenCalled() @@ -176,11 +163,7 @@ describe('pasteImageNode', () => { const textFile = new File([''], 'test.txt', { type: 'text/plain' }) const dataTransfer = createDataTransfer([textFile, imageFile]) - await pasteImageNode( - mockCanvas as unknown as LGraphCanvas, - dataTransfer.items, - mockNode as unknown as LGraphNode - ) + await pasteImageNode(mockCanvas, dataTransfer.items, mockNode) expect(mockNode.pasteFile).toHaveBeenCalledWith(imageFile) expect(mockNode.pasteFiles).toHaveBeenCalledWith([imageFile]) @@ -196,16 +179,13 @@ describe('pasteImageNodes', () => { const mockNode1 = createMockNode() const mockNode2 = createMockNode() vi.mocked(createNode) - .mockResolvedValueOnce(mockNode1 as unknown as LGraphNode) - .mockResolvedValueOnce(mockNode2 as unknown as LGraphNode) + .mockResolvedValueOnce(mockNode1) + .mockResolvedValueOnce(mockNode2) const file1 = createImageFile('test1.png') const file2 = createImageFile('test2.jpg', 'image/jpeg') - const result = await pasteImageNodes( - mockCanvas as unknown as LGraphCanvas, - [file1, file2] - ) + const result = await pasteImageNodes(mockCanvas, [file1, file2]) expect(createNode).toHaveBeenCalledTimes(2) expect(createNode).toHaveBeenNthCalledWith(1, mockCanvas, 'LoadImage') @@ -216,10 +196,7 @@ describe('pasteImageNodes', () => { }) it('should handle empty file list', async () => { - const result = await pasteImageNodes( - mockCanvas as unknown as LGraphCanvas, - [] - ) + const result = await pasteImageNodes(mockCanvas, []) expect(createNode).not.toHaveBeenCalled() expect(result).toEqual([]) @@ -238,7 +215,7 @@ describe('usePaste', () => { it('should handle image paste', async () => { const mockNode = createMockNode() - vi.mocked(createNode).mockResolvedValue(mockNode as unknown as LGraphNode) + vi.mocked(createNode).mockResolvedValue(mockNode) usePaste() @@ -255,9 +232,7 @@ describe('usePaste', () => { it('should handle audio paste', async () => { const mockNode = createMockNode() - vi.mocked(LiteGraph.createNode).mockReturnValue( - mockNode as unknown as LGraphNode - ) + vi.mocked(LiteGraph.createNode).mockReturnValue(mockNode) usePaste() @@ -302,11 +277,11 @@ describe('usePaste', () => { }) it('should use existing image node when selected', () => { - const mockNode = { + const mockNode = createMockLGraphNode({ is_selected: true, pasteFile: vi.fn(), pasteFiles: vi.fn() - } as unknown as Partial as LGraphNode + }) mockCanvas.current_node = mockNode vi.mocked(isImageNode).mockReturnValue(true) diff --git a/src/lib/litegraph/src/LGraphButton.test.ts b/src/lib/litegraph/src/LGraphButton.test.ts index 923dd4778..7490a2d0a 100644 --- a/src/lib/litegraph/src/LGraphButton.test.ts +++ b/src/lib/litegraph/src/LGraphButton.test.ts @@ -36,7 +36,7 @@ describe('LGraphButton', () => { const button = new LGraphButton({ text: '' }) // Empty text makes it invisible const ctx = { measureText: vi.fn().mockReturnValue({ width: 100 }) - } as unknown as CanvasRenderingContext2D + } as Partial as CanvasRenderingContext2D const superDrawSpy = vi.spyOn( Object.getPrototypeOf(Object.getPrototypeOf(button)), @@ -66,7 +66,7 @@ describe('LGraphButton', () => { font: '', fillStyle: '', globalAlpha: 1 - } as unknown as CanvasRenderingContext2D + } as Partial as CanvasRenderingContext2D const mockGetWidth = vi.fn().mockReturnValue(80) button.getWidth = mockGetWidth @@ -98,7 +98,7 @@ describe('LGraphButton', () => { font: '', fillStyle: '', globalAlpha: 1 - } as unknown as CanvasRenderingContext2D + } as Partial as CanvasRenderingContext2D const mockGetWidth = vi.fn().mockReturnValue(50) button.getWidth = mockGetWidth @@ -172,7 +172,7 @@ describe('LGraphButton', () => { font: '', fillStyle: '', globalAlpha: 1 - } as unknown as CanvasRenderingContext2D + } as Partial as CanvasRenderingContext2D // Draw the button button.draw(ctx, 100, 50) diff --git a/src/lib/litegraph/src/LGraphCanvas.slotHitDetection.test.ts b/src/lib/litegraph/src/LGraphCanvas.slotHitDetection.test.ts index faf878b0c..c43f9bf56 100644 --- a/src/lib/litegraph/src/LGraphCanvas.slotHitDetection.test.ts +++ b/src/lib/litegraph/src/LGraphCanvas.slotHitDetection.test.ts @@ -63,7 +63,7 @@ describe('LGraphCanvas slot hit detection', () => { globalAlpha: 1, textAlign: 'left' as CanvasTextAlign, textBaseline: 'alphabetic' as CanvasTextBaseline - } as unknown as CanvasRenderingContext2D + } as Partial as CanvasRenderingContext2D canvasElement.getContext = vi.fn().mockReturnValue(ctx) canvasElement.getBoundingClientRect = vi.fn().mockReturnValue({ diff --git a/src/lib/litegraph/src/LGraphCanvas.titleButtons.test.ts b/src/lib/litegraph/src/LGraphCanvas.titleButtons.test.ts index 6202bb33d..c444f0a94 100644 --- a/src/lib/litegraph/src/LGraphCanvas.titleButtons.test.ts +++ b/src/lib/litegraph/src/LGraphCanvas.titleButtons.test.ts @@ -43,7 +43,7 @@ describe('LGraphCanvas Title Button Rendering', () => { globalAlpha: 1, textAlign: 'left' as CanvasTextAlign, textBaseline: 'alphabetic' as CanvasTextBaseline - } as unknown as CanvasRenderingContext2D + } as Partial as CanvasRenderingContext2D canvasElement.getContext = vi.fn().mockReturnValue(ctx) diff --git a/src/lib/litegraph/src/LGraphCanvas.ts b/src/lib/litegraph/src/LGraphCanvas.ts index 84f5a17ab..08b6ef7c1 100644 --- a/src/lib/litegraph/src/LGraphCanvas.ts +++ b/src/lib/litegraph/src/LGraphCanvas.ts @@ -863,7 +863,7 @@ export class LGraphCanvas implements CustomEventDispatcher if ('shiftKey' in e && e.shiftKey) { if (this.allow_searchbox) { this.showSearchBox( - e as unknown as MouseEvent, + e as MouseEvent, linkReleaseContext as IShowSearchOptions ) } diff --git a/src/lib/litegraph/src/LGraphNode.titleButtons.test.ts b/src/lib/litegraph/src/LGraphNode.titleButtons.test.ts index 9d2a45992..f2fa8c183 100644 --- a/src/lib/litegraph/src/LGraphNode.titleButtons.test.ts +++ b/src/lib/litegraph/src/LGraphNode.titleButtons.test.ts @@ -65,7 +65,7 @@ describe('LGraphNode Title Buttons', () => { const canvas = { ctx: {} as CanvasRenderingContext2D, dispatch: vi.fn() - } as unknown as LGraphCanvas + } as Partial as LGraphCanvas // Mock the node's onTitleButtonClick method to verify it gets called const onTitleButtonClickSpy = vi.spyOn(node, 'onTitleButtonClick') @@ -119,7 +119,7 @@ describe('LGraphNode Title Buttons', () => { const canvas = { ctx: {} as CanvasRenderingContext2D, dispatch: vi.fn() - } as unknown as LGraphCanvas + } as Partial as LGraphCanvas // Calculate node-relative position const clickPosRelativeToNode: [number, number] = [ @@ -177,7 +177,7 @@ describe('LGraphNode Title Buttons', () => { const canvas = { ctx: {} as CanvasRenderingContext2D, dispatch: vi.fn() - } as unknown as LGraphCanvas + } as Partial as LGraphCanvas // Mock the node's onTitleButtonClick method const onTitleButtonClickSpy = vi.spyOn(node, 'onTitleButtonClick') @@ -242,7 +242,7 @@ describe('LGraphNode Title Buttons', () => { const canvas = { ctx: {} as CanvasRenderingContext2D, dispatch: vi.fn() - } as unknown as LGraphCanvas + } as Partial as LGraphCanvas // Mock the node's onTitleButtonClick method const onTitleButtonClickSpy = vi.spyOn(node, 'onTitleButtonClick') @@ -292,7 +292,7 @@ describe('LGraphNode Title Buttons', () => { const canvas = { dispatch: vi.fn() - } as unknown as LGraphCanvas + } as Partial as LGraphCanvas node.onTitleButtonClick(button, canvas) diff --git a/src/lib/litegraph/src/infrastructure/Rectangle.test.ts b/src/lib/litegraph/src/infrastructure/Rectangle.test.ts index b4fc56091..cb4245e26 100644 --- a/src/lib/litegraph/src/infrastructure/Rectangle.test.ts +++ b/src/lib/litegraph/src/infrastructure/Rectangle.test.ts @@ -510,7 +510,7 @@ describe('Rectangle', () => { lineWidth: 1, beginPath: vi.fn(), strokeRect: vi.fn() - } as unknown as CanvasRenderingContext2D + } as Partial as CanvasRenderingContext2D rect._drawDebug(mockCtx, 'blue') @@ -533,7 +533,7 @@ describe('Rectangle', () => { lineWidth: 1, beginPath: vi.fn(), strokeRect: vi.fn() - } as unknown as CanvasRenderingContext2D + } as Partial as CanvasRenderingContext2D rect._drawDebug(mockCtx) // Check if strokeStyle was "red" at the time of strokeRect // This requires a more complex mock or observing calls. diff --git a/src/platform/telemetry/utils/__tests__/checkoutAttribution.test.ts b/src/platform/telemetry/utils/__tests__/checkoutAttribution.test.ts index eb9409318..a17522c04 100644 --- a/src/platform/telemetry/utils/__tests__/checkoutAttribution.test.ts +++ b/src/platform/telemetry/utils/__tests__/checkoutAttribution.test.ts @@ -38,7 +38,7 @@ describe('getCheckoutAttribution', () => { callback(valueByField[fieldName]) } ) - window.gtag = gtagSpy as unknown as Window['gtag'] + window.gtag = gtagSpy as Partial as Window['gtag'] window.history.pushState( {}, @@ -108,7 +108,7 @@ describe('getCheckoutAttribution', () => { callback(valueByField[fieldName]) } ) - window.gtag = gtagSpy as unknown as Window['gtag'] + window.gtag = gtagSpy as Partial as Window['gtag'] const attribution = await getCheckoutAttribution() diff --git a/src/platform/workflow/core/services/workflowService.test.ts b/src/platform/workflow/core/services/workflowService.test.ts index f27ff7683..6ac7f41c5 100644 --- a/src/platform/workflow/core/services/workflowService.test.ts +++ b/src/platform/workflow/core/services/workflowService.test.ts @@ -91,7 +91,7 @@ function createWorkflow( activeState: { nodes: [], links: [] }, changeTracker: { reset: vi.fn(), restore: vi.fn() } }) - } as unknown as ComfyWorkflow + } as Partial as ComfyWorkflow } function enableWarningSettings() { @@ -181,7 +181,10 @@ describe('useWorkflowService', () => { vi.mocked(app.loadGraphData).mockImplementation( async (_data, _clean, _restore, wf) => { ;( - workflowStore as unknown as Record + workflowStore as Partial> as Record< + string, + unknown + > ).activeWorkflow = wf } ) diff --git a/src/renderer/core/canvas/useCanvasInteractions.test.ts b/src/renderer/core/canvas/useCanvasInteractions.test.ts index cce86a037..f73d717b7 100644 --- a/src/renderer/core/canvas/useCanvasInteractions.test.ts +++ b/src/renderer/core/canvas/useCanvasInteractions.test.ts @@ -104,7 +104,7 @@ describe('useCanvasInteractions', () => { it('should return early when canvas is null', () => { const { getCanvas } = useCanvasStore() - vi.mocked(getCanvas).mockReturnValue(null as unknown as LGraphCanvas) // TODO: Fix misaligned types + vi.mocked(getCanvas).mockReturnValue(null!) const { handlePointer } = useCanvasInteractions() const mockEvent = createMockPointerEvent(1) diff --git a/src/renderer/core/layout/__tests__/TransformPane.test.ts b/src/renderer/core/layout/__tests__/TransformPane.test.ts index 64952a629..b51c05e23 100644 --- a/src/renderer/core/layout/__tests__/TransformPane.test.ts +++ b/src/renderer/core/layout/__tests__/TransformPane.test.ts @@ -2,8 +2,8 @@ import { mount } from '@vue/test-utils' import { beforeEach, describe, expect, it, vi } from 'vitest' import { computed, nextTick } from 'vue' -import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas' import { useTransformState } from '@/renderer/core/layout/transform/useTransformState' +import { createMockCanvas } from '@/utils/__tests__/litegraphTestUtils' import TransformPane from '../transform/TransformPane.vue' @@ -29,8 +29,8 @@ vi.mock('@/renderer/core/layout/transform/useTransformState', () => { } }) -function createMockCanvas(): LGraphCanvas { - return { +function createMockLGraphCanvas() { + return createMockCanvas({ canvas: { addEventListener: vi.fn(), removeEventListener: vi.fn() @@ -39,7 +39,7 @@ function createMockCanvas(): LGraphCanvas { offset: [0, 0], scale: 1 } - } as unknown as LGraphCanvas + }) } describe('TransformPane', () => { @@ -52,7 +52,7 @@ describe('TransformPane', () => { describe('component mounting', () => { it('should mount successfully with minimal props', () => { - const mockCanvas = createMockCanvas() + const mockCanvas = createMockLGraphCanvas() const wrapper = mount(TransformPane, { props: { canvas: mockCanvas @@ -69,7 +69,7 @@ describe('TransformPane', () => { transformOrigin: '0 0' } - const mockCanvas = createMockCanvas() + const mockCanvas = createMockLGraphCanvas() const wrapper = mount(TransformPane, { props: { canvas: mockCanvas @@ -83,7 +83,7 @@ describe('TransformPane', () => { }) it('should render slot content', () => { - const mockCanvas = createMockCanvas() + const mockCanvas = createMockLGraphCanvas() const wrapper = mount(TransformPane, { props: { canvas: mockCanvas @@ -100,7 +100,7 @@ describe('TransformPane', () => { describe('RAF synchronization', () => { it('should call syncWithCanvas during RAF updates', async () => { - const mockCanvas = createMockCanvas() + const mockCanvas = createMockLGraphCanvas() mount(TransformPane, { props: { canvas: mockCanvas @@ -119,7 +119,7 @@ describe('TransformPane', () => { describe('canvas event listeners', () => { it('should add event listeners to canvas on mount', async () => { - const mockCanvas = createMockCanvas() + const mockCanvas = createMockLGraphCanvas() mount(TransformPane, { props: { canvas: mockCanvas @@ -151,7 +151,7 @@ describe('TransformPane', () => { }) it('should remove event listeners on unmount', async () => { - const mockCanvas = createMockCanvas() + const mockCanvas = createMockLGraphCanvas() const wrapper = mount(TransformPane, { props: { canvas: mockCanvas @@ -186,7 +186,7 @@ describe('TransformPane', () => { describe('interaction state management', () => { it('should apply interacting class during interactions', async () => { - const mockCanvas = createMockCanvas() + const mockCanvas = createMockLGraphCanvas() const wrapper = mount(TransformPane, { props: { canvas: mockCanvas @@ -204,7 +204,7 @@ describe('TransformPane', () => { }) it('should handle pointer events for node delegation', async () => { - const mockCanvas = createMockCanvas() + const mockCanvas = createMockLGraphCanvas() const wrapper = mount(TransformPane, { props: { canvas: mockCanvas @@ -225,7 +225,7 @@ describe('TransformPane', () => { describe('transform state integration', () => { it('should provide transform utilities to child components', () => { - const mockCanvas = createMockCanvas() + const mockCanvas = createMockLGraphCanvas() mount(TransformPane, { props: { canvas: mockCanvas diff --git a/src/renderer/extensions/vueNodes/composables/useNodeEventHandlers.test.ts b/src/renderer/extensions/vueNodes/composables/useNodeEventHandlers.test.ts index 5ddc6f227..7973d1f5e 100644 --- a/src/renderer/extensions/vueNodes/composables/useNodeEventHandlers.test.ts +++ b/src/renderer/extensions/vueNodes/composables/useNodeEventHandlers.test.ts @@ -4,11 +4,7 @@ import { computed, shallowRef } from 'vue' import { useGraphNodeManager } from '@/composables/graph/useGraphNodeManager' import type { GraphNodeManager } from '@/composables/graph/useGraphNodeManager' import { useVueNodeLifecycle } from '@/composables/graph/useVueNodeLifecycle' -import type { - LGraph, - LGraphCanvas, - LGraphNode -} from '@/lib/litegraph/src/litegraph' +import type { LGraphCanvas, LGraphNode } from '@/lib/litegraph/src/litegraph' import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' import { useLayoutMutations } from '@/renderer/core/layout/operations/layoutMutations' import { useNodeEventHandlers } from '@/renderer/extensions/vueNodes/composables/useNodeEventHandlers' @@ -64,7 +60,7 @@ vi.mock('@/composables/graph/useGraphNodeManager', () => { }) vi.mock('@/composables/graph/useVueNodeLifecycle', () => { - const nodeManager = useGraphNodeManager(undefined as unknown as LGraph) + const nodeManager = useGraphNodeManager(null!) return { useVueNodeLifecycle: vi.fn(() => ({ nodeManager diff --git a/src/renderer/extensions/vueNodes/interactions/resize/useNodeResize.test.ts b/src/renderer/extensions/vueNodes/interactions/resize/useNodeResize.test.ts index 1b99ae8fa..f33aaa3cc 100644 --- a/src/renderer/extensions/vueNodes/interactions/resize/useNodeResize.test.ts +++ b/src/renderer/extensions/vueNodes/interactions/resize/useNodeResize.test.ts @@ -108,7 +108,7 @@ function createPointerEvent( preventDefault: vi.fn(), stopPropagation: vi.fn(), ...overrides - } as unknown as PointerEvent + } as Partial as PointerEvent } function startResizeAt( diff --git a/src/scripts/metadata/parser.ts b/src/scripts/metadata/parser.ts index f11b9bef7..ee4f881b6 100644 --- a/src/scripts/metadata/parser.ts +++ b/src/scripts/metadata/parser.ts @@ -5,6 +5,7 @@ import { getDataFromJSON } from '@/scripts/metadata/json' import { getMp3Metadata } from '@/scripts/metadata/mp3' import { getOggMetadata } from '@/scripts/metadata/ogg' import { getSvgMetadata } from '@/scripts/metadata/svg' +import type { ComfyMetadata } from '@/types/metadataTypes' import { getAvifMetadata, getWebpMetadata, @@ -15,7 +16,7 @@ import { export async function getWorkflowDataFromFile( file: File -): Promise | undefined> { +): Promise | undefined> { if (file.type === 'image/png') { return await getPngMetadata(file) } @@ -43,7 +44,7 @@ export async function getWorkflowDataFromFile( return { workflow, prompt } } if (file.type === 'video/webm') { - return (await getFromWebmFile(file)) as unknown as Record + return await getFromWebmFile(file) } if ( file.name?.endsWith('.mp4') || @@ -53,16 +54,13 @@ export async function getWorkflowDataFromFile( file.type === 'video/quicktime' || file.type === 'video/x-m4v' ) { - return (await getFromIsobmffFile(file)) as unknown as Record + return await getFromIsobmffFile(file) } if (file.type === 'image/svg+xml' || file.name?.endsWith('.svg')) { - return (await getSvgMetadata(file)) as unknown as Record + return await getSvgMetadata(file) } if (file.type === 'model/gltf-binary' || file.name?.endsWith('.glb')) { - return (await getGltfBinaryMetadata(file)) as unknown as Record< - string, - object - > + return await getGltfBinaryMetadata(file) } if (file.name?.endsWith('.latent') || file.name?.endsWith('.safetensors')) { return await getLatentMetadata(file) diff --git a/src/services/audioService.test.ts b/src/services/audioService.test.ts index f26b60244..b5bf672c3 100644 --- a/src/services/audioService.test.ts +++ b/src/services/audioService.test.ts @@ -104,7 +104,7 @@ describe('useAudioService', () => { const mockTrack2 = { stop: vi.fn() } const mockStream = { getTracks: vi.fn().mockReturnValue([mockTrack1, mockTrack2]) - } as unknown as MediaStream + } as Partial as MediaStream service.stopAllTracks(mockStream) @@ -120,7 +120,7 @@ describe('useAudioService', () => { it('should handle stream with no tracks', () => { const mockStream = { getTracks: vi.fn().mockReturnValue([]) - } as unknown as MediaStream + } as Partial as MediaStream expect(() => service.stopAllTracks(mockStream)).not.toThrow() expect(mockStream.getTracks).toHaveBeenCalledTimes(1) @@ -135,7 +135,7 @@ describe('useAudioService', () => { } const mockStream = { getTracks: vi.fn().mockReturnValue([mockTrack1, mockTrack2]) - } as unknown as MediaStream + } as Partial as MediaStream expect(() => service.stopAllTracks(mockStream)).toThrow() expect(mockTrack1.stop).toHaveBeenCalledTimes(1) diff --git a/src/services/colorPaletteService.ts b/src/services/colorPaletteService.ts index 533488471..cf0c1e0bc 100644 --- a/src/services/colorPaletteService.ts +++ b/src/services/colorPaletteService.ts @@ -107,8 +107,7 @@ export const useColorPaletteService = () => { for (const dataType of nodeDefStore.nodeDataTypes) { const cssVar = `color-datatype-${dataType}` - const valueMaybe = - linkColorPalette[dataType as unknown as keyof Colors['node_slot']] + const valueMaybe = linkColorPalette[dataType as keyof Colors['node_slot']] if (valueMaybe) { rootStyle.setProperty(`--${cssVar}`, valueMaybe) } else { diff --git a/src/stores/imagePreviewStore.test.ts b/src/stores/imagePreviewStore.test.ts index ff358c48b..a6397c554 100644 --- a/src/stores/imagePreviewStore.test.ts +++ b/src/stores/imagePreviewStore.test.ts @@ -32,7 +32,7 @@ const createMockNode = (overrides: Record = {}): LGraphNode => id: 1, type: 'TestNode', ...overrides - }) as unknown as LGraphNode + }) as Partial as LGraphNode const createMockOutputs = ( images?: ExecutedWsMessage['output']['images'] diff --git a/src/stores/workspace/searchBoxStore.test.ts b/src/stores/workspace/searchBoxStore.test.ts index e8ea010bb..022c8fc72 100644 --- a/src/stores/workspace/searchBoxStore.test.ts +++ b/src/stores/workspace/searchBoxStore.test.ts @@ -20,17 +20,17 @@ vi.mock('@/platform/settings/settingStore', () => ({ })) function createMockPopover(): InstanceType { - return { showSearchBox: vi.fn() } satisfies Partial< + return { showSearchBox: vi.fn() } as Partial< InstanceType - > as unknown as InstanceType + > as InstanceType } function createMockSettingStore(): ReturnType { return { get: vi.fn() - } satisfies Partial< - ReturnType - > as unknown as ReturnType + } as Partial> as ReturnType< + typeof useSettingStore + > } describe('useSearchBoxStore', () => { diff --git a/src/utils/__tests__/litegraphTestUtils.ts b/src/utils/__tests__/litegraphTestUtils.ts index c5d241b5c..22d7e7a9a 100644 --- a/src/utils/__tests__/litegraphTestUtils.ts +++ b/src/utils/__tests__/litegraphTestUtils.ts @@ -82,14 +82,14 @@ export function createMockSubgraphNode( * Creates a mock LGraphCanvas with minimal required properties for testing */ export function createMockCanvas( - overrides: Partial = {} + overrides: Partial | Record = {} ): LGraphCanvas { return { setDirty: vi.fn(), state: { selectionChanged: false }, - ...overrides + ...(overrides as Partial) } as LGraphCanvas } diff --git a/src/utils/litegraphUtil.test.ts b/src/utils/litegraphUtil.test.ts index 462005b96..bed098037 100644 --- a/src/utils/litegraphUtil.test.ts +++ b/src/utils/litegraphUtil.test.ts @@ -40,7 +40,7 @@ function createMockCanvas(overrides: Partial = {}): LGraphCanvas { const mockGraph = { add: vi.fn((node) => node), change: vi.fn() - } satisfies Partial as unknown as LGraph + } as Partial as LGraph const mockCanvas: Partial = { graph_mouse: [100, 200], graph: mockGraph, diff --git a/src/workbench/extensions/manager/composables/nodePack/useMissingNodes.test.ts b/src/workbench/extensions/manager/composables/nodePack/useMissingNodes.test.ts index 371d36b0b..a5da7d524 100644 --- a/src/workbench/extensions/manager/composables/nodePack/useMissingNodes.test.ts +++ b/src/workbench/extensions/manager/composables/nodePack/useMissingNodes.test.ts @@ -271,7 +271,8 @@ describe('useMissingNodes', () => { // Update workflow packs - workflowPacksRef.value = mockWorkflowPacks as unknown as WorkflowPack[] + workflowPacksRef.value = + mockWorkflowPacks as Partial[] as WorkflowPack[] await nextTick() // Should update missing packs (2 missing since pack-3 is installed) diff --git a/src/workbench/extensions/manager/composables/nodePack/useUpdateAvailableNodes.test.ts b/src/workbench/extensions/manager/composables/nodePack/useUpdateAvailableNodes.test.ts index c15b96ef6..6d8e11de0 100644 --- a/src/workbench/extensions/manager/composables/nodePack/useUpdateAvailableNodes.test.ts +++ b/src/workbench/extensions/manager/composables/nodePack/useUpdateAvailableNodes.test.ts @@ -39,6 +39,32 @@ const mockUseComfyManagerStore = vi.mocked(useComfyManagerStore) const mockSemverCompare = vi.mocked(compare) const mockSemverValid = vi.mocked(valid) +type InstalledPacksReturn = ReturnType +type ManagerStoreReturn = ReturnType + +function createMockInstalledPacksReturn( + overrides: Partial = {} +): InstalledPacksReturn { + return { + installedPacks: ref([]), + isLoading: ref(false), + isReady: ref(false), + error: ref(null), + startFetchInstalled: vi.fn(), + installedPacksWithVersions: ref([]), + filterInstalledPack: vi.fn(), + ...overrides + } as Partial as InstalledPacksReturn +} + +function createMockManagerStoreReturn( + overrides: Partial = {} +): ManagerStoreReturn { + return { + ...overrides + } as Partial as ManagerStoreReturn +} + describe('useUpdateAvailableNodes', () => { const mockInstalledPacks = [ { @@ -103,34 +129,29 @@ describe('useUpdateAvailableNodes', () => { return 0 }) - mockUseComfyManagerStore.mockReturnValue({ - isPackInstalled: mockIsPackInstalled, - getInstalledPackVersion: mockGetInstalledPackVersion, - isPackEnabled: mockIsPackEnabled - } as unknown as ReturnType) + mockUseComfyManagerStore.mockReturnValue( + createMockManagerStoreReturn({ + isPackInstalled: mockIsPackInstalled, + getInstalledPackVersion: mockGetInstalledPackVersion, + isPackEnabled: mockIsPackEnabled + }) + ) - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([]), - isLoading: ref(false), - isReady: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + startFetchInstalled: mockStartFetchInstalled + }) + ) }) describe('core filtering logic', () => { it('identifies outdated packs correctly', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref(mockInstalledPacks), - isLoading: ref(false), - isReady: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref(mockInstalledPacks), + startFetchInstalled: mockStartFetchInstalled + }) + ) const { updateAvailableNodePacks } = useUpdateAvailableNodes() @@ -140,15 +161,12 @@ describe('useUpdateAvailableNodes', () => { }) it('excludes up-to-date packs', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[1]]), // pack-2: up to date - isLoading: ref(false), - isReady: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[1]]), // pack-2: up to date + startFetchInstalled: mockStartFetchInstalled + }) + ) const { updateAvailableNodePacks } = useUpdateAvailableNodes() @@ -156,15 +174,12 @@ describe('useUpdateAvailableNodes', () => { }) it('excludes nightly packs from updates', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[2]]), // pack-3: nightly - isLoading: ref(false), - isReady: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[2]]), // pack-3: nightly + startFetchInstalled: mockStartFetchInstalled + }) + ) const { updateAvailableNodePacks } = useUpdateAvailableNodes() @@ -172,15 +187,12 @@ describe('useUpdateAvailableNodes', () => { }) it('excludes packs with no latest version', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[3]]), // pack-4: no latest version - isLoading: ref(false), - isReady: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[3]]), // pack-4: no latest version + startFetchInstalled: mockStartFetchInstalled + }) + ) const { updateAvailableNodePacks } = useUpdateAvailableNodes() @@ -189,15 +201,12 @@ describe('useUpdateAvailableNodes', () => { it('excludes uninstalled packs', () => { mockIsPackInstalled.mockReturnValue(false) - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref(mockInstalledPacks), - isLoading: ref(false), - isReady: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref(mockInstalledPacks), + startFetchInstalled: mockStartFetchInstalled + }) + ) const { updateAvailableNodePacks } = useUpdateAvailableNodes() @@ -213,15 +222,12 @@ describe('useUpdateAvailableNodes', () => { describe('hasUpdateAvailable computed', () => { it('returns true when updates are available', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated - isLoading: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - isReady: ref(false), - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated + startFetchInstalled: mockStartFetchInstalled + }) + ) const { hasUpdateAvailable } = useUpdateAvailableNodes() @@ -229,15 +235,12 @@ describe('useUpdateAvailableNodes', () => { }) it('returns false when no updates are available', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[1]]), // pack-2: up to date - isLoading: ref(false), - isReady: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[1]]), // pack-2: up to date + startFetchInstalled: mockStartFetchInstalled + }) + ) const { hasUpdateAvailable } = useUpdateAvailableNodes() @@ -253,15 +256,12 @@ describe('useUpdateAvailableNodes', () => { }) it('does not fetch when packs already exist', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref(mockInstalledPacks), - isLoading: ref(false), - isReady: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref(mockInstalledPacks), + startFetchInstalled: mockStartFetchInstalled + }) + ) useUpdateAvailableNodes() @@ -269,15 +269,12 @@ describe('useUpdateAvailableNodes', () => { }) it('does not fetch when already loading', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([]), - isLoading: ref(true), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - isReady: ref(false), - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + isLoading: ref(true), + startFetchInstalled: mockStartFetchInstalled + }) + ) useUpdateAvailableNodes() @@ -287,15 +284,12 @@ describe('useUpdateAvailableNodes', () => { describe('state management', () => { it('exposes loading state from useInstalledPacks', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([]), - isLoading: ref(true), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - isReady: ref(false), - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + isLoading: ref(true), + startFetchInstalled: mockStartFetchInstalled + }) + ) const { isLoading } = useUpdateAvailableNodes() @@ -304,15 +298,12 @@ describe('useUpdateAvailableNodes', () => { it('exposes error state from useInstalledPacks', () => { const testError = 'Failed to fetch installed packs' - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([]), - isLoading: ref(false), - error: ref(testError), - startFetchInstalled: mockStartFetchInstalled, - isReady: ref(false), - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + error: ref(testError), + startFetchInstalled: mockStartFetchInstalled + }) + ) const { error } = useUpdateAvailableNodes() @@ -323,15 +314,12 @@ describe('useUpdateAvailableNodes', () => { describe('reactivity', () => { it('updates when installed packs change', async () => { const installedPacksRef = ref([]) - mockUseInstalledPacks.mockReturnValue({ - installedPacks: installedPacksRef, - isLoading: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - isReady: ref(false), - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: installedPacksRef, + startFetchInstalled: mockStartFetchInstalled + }) + ) const { updateAvailableNodePacks, hasUpdateAvailable } = useUpdateAvailableNodes() @@ -352,15 +340,12 @@ describe('useUpdateAvailableNodes', () => { describe('version comparison logic', () => { it('calls compareVersions with correct parameters', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[0]]), // pack-1 - isLoading: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - isReady: ref(false), - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[0]]), // pack-1 + startFetchInstalled: mockStartFetchInstalled + }) + ) const { updateAvailableNodePacks } = useUpdateAvailableNodes() @@ -371,15 +356,12 @@ describe('useUpdateAvailableNodes', () => { }) it('calls semver.valid to check nightly versions', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[2]]), // pack-3: nightly - isLoading: ref(false), - isReady: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[2]]), // pack-3: nightly + startFetchInstalled: mockStartFetchInstalled + }) + ) const { updateAvailableNodePacks } = useUpdateAvailableNodes() @@ -390,15 +372,12 @@ describe('useUpdateAvailableNodes', () => { }) it('calls isPackInstalled for each pack', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref(mockInstalledPacks), - isLoading: ref(false), - isReady: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref(mockInstalledPacks), + startFetchInstalled: mockStartFetchInstalled + }) + ) const { updateAvailableNodePacks } = useUpdateAvailableNodes() @@ -419,15 +398,12 @@ describe('useUpdateAvailableNodes', () => { return id !== 'pack-1' }) - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[0], mockInstalledPacks[1]]), - isLoading: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - isReady: ref(false), - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[0], mockInstalledPacks[1]]), + startFetchInstalled: mockStartFetchInstalled + }) + ) const { updateAvailableNodePacks, enabledUpdateAvailableNodePacks } = useUpdateAvailableNodes() @@ -441,15 +417,12 @@ describe('useUpdateAvailableNodes', () => { }) it('returns all packs when all are enabled', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated - isLoading: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - isReady: ref(false), - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated + startFetchInstalled: mockStartFetchInstalled + }) + ) const { updateAvailableNodePacks, enabledUpdateAvailableNodePacks } = useUpdateAvailableNodes() @@ -467,15 +440,12 @@ describe('useUpdateAvailableNodes', () => { return id !== 'pack-1' }) - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated - isLoading: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - isReady: ref(false), - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated + startFetchInstalled: mockStartFetchInstalled + }) + ) const { hasDisabledUpdatePacks } = useUpdateAvailableNodes() @@ -483,15 +453,12 @@ describe('useUpdateAvailableNodes', () => { }) it('returns false when all packs with updates are enabled', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated - isLoading: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - isReady: ref(false), - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated + startFetchInstalled: mockStartFetchInstalled + }) + ) const { hasDisabledUpdatePacks } = useUpdateAvailableNodes() @@ -499,15 +466,12 @@ describe('useUpdateAvailableNodes', () => { }) it('returns false when no packs have updates', () => { - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[1]]), // pack-2: up to date - isLoading: ref(false), - isReady: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[1]]), // pack-2: up to date + startFetchInstalled: mockStartFetchInstalled + }) + ) const { hasDisabledUpdatePacks } = useUpdateAvailableNodes() @@ -519,15 +483,12 @@ describe('useUpdateAvailableNodes', () => { it('returns false when only disabled packs have updates', () => { mockIsPackEnabled.mockReturnValue(false) // All packs disabled - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated - isLoading: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - isReady: ref(false), - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated + startFetchInstalled: mockStartFetchInstalled + }) + ) const { hasUpdateAvailable } = useUpdateAvailableNodes() @@ -540,15 +501,12 @@ describe('useUpdateAvailableNodes', () => { return id === 'pack-1' }) - mockUseInstalledPacks.mockReturnValue({ - installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated - isLoading: ref(false), - error: ref(null), - startFetchInstalled: mockStartFetchInstalled, - isReady: ref(false), - installedPacksWithVersions: ref([]), - filterInstalledPack: vi.fn() - } as unknown as ReturnType) + mockUseInstalledPacks.mockReturnValue( + createMockInstalledPacksReturn({ + installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated + startFetchInstalled: mockStartFetchInstalled + }) + ) const { hasUpdateAvailable } = useUpdateAvailableNodes() diff --git a/src/workbench/extensions/manager/utils/graphHasMissingNodes.test.ts b/src/workbench/extensions/manager/utils/graphHasMissingNodes.test.ts index 2badaa7cc..d987e7231 100644 --- a/src/workbench/extensions/manager/utils/graphHasMissingNodes.test.ts +++ b/src/workbench/extensions/manager/utils/graphHasMissingNodes.test.ts @@ -86,10 +86,7 @@ describe('graphHasMissingNodes', () => { }) it('ignores nodes without a type', () => { - const graph = createGraph([ - createNode(undefined), - createNode(null as unknown as string) - ]) + const graph = createGraph([createNode(undefined), createNode(null!)]) expect(graphHasMissingNodes(graph, {})).toBe(false) })