mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-24 00:34:09 +00:00
fix: replace as-unknown-as casts with safer patterns (#9107)
## Summary - Replace 83 `as unknown as` double casts with safer alternatives across 33 files - Use `as Partial<X> 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)
This commit is contained in:
committed by
GitHub
parent
8998d92e1b
commit
02e926471f
@@ -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()
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ export class SubgraphHelper {
|
||||
|
||||
if (node.onPointerDown) {
|
||||
node.onPointerDown(
|
||||
event as unknown as CanvasPointerEvent,
|
||||
event as Partial<CanvasPointerEvent> 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<CanvasPointerEvent> 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<CanvasPointerEvent> as CanvasPointerEvent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<SomeType> as SomeType` or explicit typings
|
||||
```
|
||||
|
||||
### Accessing Internal State
|
||||
|
||||
@@ -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
|
||||
}
|
||||
])
|
||||
)
|
||||
|
||||
@@ -190,7 +190,7 @@ describe('downloadUtil', () => {
|
||||
ok: false,
|
||||
status: 404,
|
||||
blob: vi.fn()
|
||||
} as unknown as Response)
|
||||
} as Partial<Response> as Response)
|
||||
|
||||
downloadFile(testUrl)
|
||||
|
||||
|
||||
@@ -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<number>,
|
||||
currentNodePercent: null as unknown as Ref<number>
|
||||
totalPercent: null! as Ref<number>,
|
||||
currentNodePercent: null! as Ref<number>
|
||||
}))
|
||||
|
||||
vi.mock('@/composables/queue/useQueueProgress', () => ({
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('useJobErrorReporting', () => {
|
||||
dialog = {
|
||||
showErrorDialog,
|
||||
showExecutionErrorDialog
|
||||
} as unknown as JobErrorDialogService
|
||||
} as Partial<JobErrorDialogService> as JobErrorDialogService
|
||||
composable = useJobErrorReporting({
|
||||
taskForJob,
|
||||
copyToClipboard: copyToClipboard as (
|
||||
|
||||
@@ -31,7 +31,10 @@ function createFilter(
|
||||
filterDef: {
|
||||
id,
|
||||
matches: vi.fn(() => true)
|
||||
} as unknown as FuseFilter<ComfyNodeDefImpl, string>,
|
||||
} as Partial<FuseFilter<ComfyNodeDefImpl, string>> 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<ComfyNodeDefImpl, string>
|
||||
} as Partial<FuseFilter<ComfyNodeDefImpl, string>> as FuseFilter<
|
||||
ComfyNodeDefImpl,
|
||||
string
|
||||
>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,9 @@ describe('useNodePreviewAndDrag', () => {
|
||||
toJSON: () => ({})
|
||||
})
|
||||
|
||||
const mockEvent = { currentTarget: mockElement } as unknown as MouseEvent
|
||||
const mockEvent = {
|
||||
currentTarget: mockElement
|
||||
} as Partial<MouseEvent> 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<MouseEvent> 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<DragEvent> as DragEvent
|
||||
|
||||
result.handleDragEnd(mockEvent)
|
||||
|
||||
@@ -168,7 +172,7 @@ describe('useNodePreviewAndDrag', () => {
|
||||
dataTransfer: { dropEffect: 'none' },
|
||||
clientX: 300,
|
||||
clientY: 400
|
||||
} as unknown as DragEvent
|
||||
} as Partial<DragEvent> as DragEvent
|
||||
|
||||
result.handleDragEnd(mockEvent)
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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<LGraphNode> as LGraphNode
|
||||
})
|
||||
mockCanvas.current_node = mockNode
|
||||
vi.mocked(isImageNode).mockReturnValue(true)
|
||||
|
||||
|
||||
@@ -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<CanvasRenderingContext2D> 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<CanvasRenderingContext2D> 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<CanvasRenderingContext2D> 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<CanvasRenderingContext2D> as CanvasRenderingContext2D
|
||||
|
||||
// Draw the button
|
||||
button.draw(ctx, 100, 50)
|
||||
|
||||
@@ -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<CanvasRenderingContext2D> as CanvasRenderingContext2D
|
||||
|
||||
canvasElement.getContext = vi.fn().mockReturnValue(ctx)
|
||||
canvasElement.getBoundingClientRect = vi.fn().mockReturnValue({
|
||||
|
||||
@@ -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<CanvasRenderingContext2D> as CanvasRenderingContext2D
|
||||
|
||||
canvasElement.getContext = vi.fn().mockReturnValue(ctx)
|
||||
|
||||
|
||||
@@ -863,7 +863,7 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
|
||||
if ('shiftKey' in e && e.shiftKey) {
|
||||
if (this.allow_searchbox) {
|
||||
this.showSearchBox(
|
||||
e as unknown as MouseEvent,
|
||||
e as MouseEvent,
|
||||
linkReleaseContext as IShowSearchOptions
|
||||
)
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ describe('LGraphNode Title Buttons', () => {
|
||||
const canvas = {
|
||||
ctx: {} as CanvasRenderingContext2D,
|
||||
dispatch: vi.fn()
|
||||
} as unknown as LGraphCanvas
|
||||
} as Partial<LGraphCanvas> 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<LGraphCanvas> 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<LGraphCanvas> 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<LGraphCanvas> 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<LGraphCanvas> as LGraphCanvas
|
||||
|
||||
node.onTitleButtonClick(button, canvas)
|
||||
|
||||
|
||||
@@ -510,7 +510,7 @@ describe('Rectangle', () => {
|
||||
lineWidth: 1,
|
||||
beginPath: vi.fn(),
|
||||
strokeRect: vi.fn()
|
||||
} as unknown as CanvasRenderingContext2D
|
||||
} as Partial<CanvasRenderingContext2D> 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<CanvasRenderingContext2D> as CanvasRenderingContext2D
|
||||
rect._drawDebug(mockCtx)
|
||||
// Check if strokeStyle was "red" at the time of strokeRect
|
||||
// This requires a more complex mock or observing calls.
|
||||
|
||||
@@ -38,7 +38,7 @@ describe('getCheckoutAttribution', () => {
|
||||
callback(valueByField[fieldName])
|
||||
}
|
||||
)
|
||||
window.gtag = gtagSpy as unknown as Window['gtag']
|
||||
window.gtag = gtagSpy as Partial<Window['gtag']> 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<Window['gtag']> as Window['gtag']
|
||||
|
||||
const attribution = await getCheckoutAttribution()
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ function createWorkflow(
|
||||
activeState: { nodes: [], links: [] },
|
||||
changeTracker: { reset: vi.fn(), restore: vi.fn() }
|
||||
})
|
||||
} as unknown as ComfyWorkflow
|
||||
} as Partial<ComfyWorkflow> 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<string, unknown>
|
||||
workflowStore as Partial<Record<string, unknown>> as Record<
|
||||
string,
|
||||
unknown
|
||||
>
|
||||
).activeWorkflow = wf
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -108,7 +108,7 @@ function createPointerEvent(
|
||||
preventDefault: vi.fn(),
|
||||
stopPropagation: vi.fn(),
|
||||
...overrides
|
||||
} as unknown as PointerEvent
|
||||
} as Partial<PointerEvent> as PointerEvent
|
||||
}
|
||||
|
||||
function startResizeAt(
|
||||
|
||||
@@ -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<Record<string, string | object> | undefined> {
|
||||
): Promise<ComfyMetadata | Record<string, string | object> | 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<string, object>
|
||||
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<string, object>
|
||||
return await getFromIsobmffFile(file)
|
||||
}
|
||||
if (file.type === 'image/svg+xml' || file.name?.endsWith('.svg')) {
|
||||
return (await getSvgMetadata(file)) as unknown as Record<string, object>
|
||||
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)
|
||||
|
||||
@@ -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<MediaStream> 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<MediaStream> 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<MediaStream> as MediaStream
|
||||
|
||||
expect(() => service.stopAllTracks(mockStream)).toThrow()
|
||||
expect(mockTrack1.stop).toHaveBeenCalledTimes(1)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -32,7 +32,7 @@ const createMockNode = (overrides: Record<string, unknown> = {}): LGraphNode =>
|
||||
id: 1,
|
||||
type: 'TestNode',
|
||||
...overrides
|
||||
}) as unknown as LGraphNode
|
||||
}) as Partial<LGraphNode> as LGraphNode
|
||||
|
||||
const createMockOutputs = (
|
||||
images?: ExecutedWsMessage['output']['images']
|
||||
|
||||
@@ -20,17 +20,17 @@ vi.mock('@/platform/settings/settingStore', () => ({
|
||||
}))
|
||||
|
||||
function createMockPopover(): InstanceType<typeof NodeSearchBoxPopover> {
|
||||
return { showSearchBox: vi.fn() } satisfies Partial<
|
||||
return { showSearchBox: vi.fn() } as Partial<
|
||||
InstanceType<typeof NodeSearchBoxPopover>
|
||||
> as unknown as InstanceType<typeof NodeSearchBoxPopover>
|
||||
> as InstanceType<typeof NodeSearchBoxPopover>
|
||||
}
|
||||
|
||||
function createMockSettingStore(): ReturnType<typeof useSettingStore> {
|
||||
return {
|
||||
get: vi.fn()
|
||||
} satisfies Partial<
|
||||
ReturnType<typeof useSettingStore>
|
||||
> as unknown as ReturnType<typeof useSettingStore>
|
||||
} as Partial<ReturnType<typeof useSettingStore>> as ReturnType<
|
||||
typeof useSettingStore
|
||||
>
|
||||
}
|
||||
|
||||
describe('useSearchBoxStore', () => {
|
||||
|
||||
@@ -82,14 +82,14 @@ export function createMockSubgraphNode(
|
||||
* Creates a mock LGraphCanvas with minimal required properties for testing
|
||||
*/
|
||||
export function createMockCanvas(
|
||||
overrides: Partial<LGraphCanvas> = {}
|
||||
overrides: Partial<LGraphCanvas> | Record<string, unknown> = {}
|
||||
): LGraphCanvas {
|
||||
return {
|
||||
setDirty: vi.fn(),
|
||||
state: {
|
||||
selectionChanged: false
|
||||
},
|
||||
...overrides
|
||||
...(overrides as Partial<LGraphCanvas>)
|
||||
} as LGraphCanvas
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ function createMockCanvas(overrides: Partial<LGraphCanvas> = {}): LGraphCanvas {
|
||||
const mockGraph = {
|
||||
add: vi.fn((node) => node),
|
||||
change: vi.fn()
|
||||
} satisfies Partial<LGraph> as unknown as LGraph
|
||||
} as Partial<LGraph> as LGraph
|
||||
const mockCanvas: Partial<LGraphCanvas> = {
|
||||
graph_mouse: [100, 200],
|
||||
graph: mockGraph,
|
||||
|
||||
@@ -271,7 +271,8 @@ describe('useMissingNodes', () => {
|
||||
|
||||
// Update workflow packs
|
||||
|
||||
workflowPacksRef.value = mockWorkflowPacks as unknown as WorkflowPack[]
|
||||
workflowPacksRef.value =
|
||||
mockWorkflowPacks as Partial<WorkflowPack>[] as WorkflowPack[]
|
||||
await nextTick()
|
||||
|
||||
// Should update missing packs (2 missing since pack-3 is installed)
|
||||
|
||||
@@ -39,6 +39,32 @@ const mockUseComfyManagerStore = vi.mocked(useComfyManagerStore)
|
||||
const mockSemverCompare = vi.mocked(compare)
|
||||
const mockSemverValid = vi.mocked(valid)
|
||||
|
||||
type InstalledPacksReturn = ReturnType<typeof useInstalledPacks>
|
||||
type ManagerStoreReturn = ReturnType<typeof useComfyManagerStore>
|
||||
|
||||
function createMockInstalledPacksReturn(
|
||||
overrides: Partial<InstalledPacksReturn> = {}
|
||||
): InstalledPacksReturn {
|
||||
return {
|
||||
installedPacks: ref([]),
|
||||
isLoading: ref(false),
|
||||
isReady: ref(false),
|
||||
error: ref(null),
|
||||
startFetchInstalled: vi.fn(),
|
||||
installedPacksWithVersions: ref([]),
|
||||
filterInstalledPack: vi.fn(),
|
||||
...overrides
|
||||
} as Partial<InstalledPacksReturn> as InstalledPacksReturn
|
||||
}
|
||||
|
||||
function createMockManagerStoreReturn(
|
||||
overrides: Partial<ManagerStoreReturn> = {}
|
||||
): ManagerStoreReturn {
|
||||
return {
|
||||
...overrides
|
||||
} as Partial<ManagerStoreReturn> 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<typeof useComfyManagerStore>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<components['schemas']['Node'][]>([])
|
||||
mockUseInstalledPacks.mockReturnValue({
|
||||
installedPacks: installedPacksRef,
|
||||
isLoading: ref(false),
|
||||
error: ref(null),
|
||||
startFetchInstalled: mockStartFetchInstalled,
|
||||
isReady: ref(false),
|
||||
installedPacksWithVersions: ref([]),
|
||||
filterInstalledPack: vi.fn()
|
||||
} as unknown as ReturnType<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
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<typeof useInstalledPacks>)
|
||||
mockUseInstalledPacks.mockReturnValue(
|
||||
createMockInstalledPacksReturn({
|
||||
installedPacks: ref([mockInstalledPacks[0]]), // pack-1: outdated
|
||||
startFetchInstalled: mockStartFetchInstalled
|
||||
})
|
||||
)
|
||||
|
||||
const { hasUpdateAvailable } = useUpdateAvailableNodes()
|
||||
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user