diff --git a/browser_tests/fixtures/ComfyPage.ts b/browser_tests/fixtures/ComfyPage.ts index 6ba477c9d..2d9028a35 100644 --- a/browser_tests/fixtures/ComfyPage.ts +++ b/browser_tests/fixtures/ComfyPage.ts @@ -139,7 +139,7 @@ class ConfirmDialog { // Wait for workflow service to finish if it's busy await this.page.waitForFunction( - () => (window.app?.extensionManager as any)?.workflow?.isBusy === false, + () => window.app?.extensionManager?.workflow?.isBusy === false, undefined, { timeout: 3000 } ) @@ -387,7 +387,7 @@ export class ComfyPage { async setFocusMode(focusMode: boolean) { await this.page.evaluate((focusMode) => { - ;(window.app!.extensionManager as any).focusMode = focusMode + window.app!.extensionManager.focusMode = focusMode }, focusMode) await this.nextFrame() } diff --git a/browser_tests/fixtures/components/SidebarTab.ts b/browser_tests/fixtures/components/SidebarTab.ts index 80a948b7a..0c64f0fe0 100644 --- a/browser_tests/fixtures/components/SidebarTab.ts +++ b/browser_tests/fixtures/components/SidebarTab.ts @@ -154,7 +154,7 @@ export class WorkflowsSidebarTab extends SidebarTab { // Wait for workflow service to finish renaming await this.page.waitForFunction( - () => !(window.app?.extensionManager as any)?.workflow?.isBusy, + () => !window.app?.extensionManager?.workflow?.isBusy, undefined, { timeout: 3000 } ) diff --git a/browser_tests/fixtures/components/Topbar.ts b/browser_tests/fixtures/components/Topbar.ts index 7d4a5f39d..e53bf4264 100644 --- a/browser_tests/fixtures/components/Topbar.ts +++ b/browser_tests/fixtures/components/Topbar.ts @@ -85,7 +85,7 @@ export class Topbar { // Wait for workflow service to finish saving await this.page.waitForFunction( - () => !(window.app!.extensionManager as any).workflow.isBusy, + () => !window.app!.extensionManager.workflow.isBusy, undefined, { timeout: 3000 } ) diff --git a/browser_tests/fixtures/helpers/WorkflowHelper.ts b/browser_tests/fixtures/helpers/WorkflowHelper.ts index 72b4679be..61ea974e8 100644 --- a/browser_tests/fixtures/helpers/WorkflowHelper.ts +++ b/browser_tests/fixtures/helpers/WorkflowHelper.ts @@ -45,7 +45,7 @@ export class WorkflowHelper { } await this.comfyPage.page.evaluate(async () => { - await (window.app!.extensionManager as any).workflow.syncWorkflows() + await window.app!.extensionManager.workflow.syncWorkflows() }) // Wait for Vue to re-render the workflow list diff --git a/browser_tests/fixtures/utils/litegraphUtils.ts b/browser_tests/fixtures/utils/litegraphUtils.ts index 4a0b511e7..fc8185c65 100644 --- a/browser_tests/fixtures/utils/litegraphUtils.ts +++ b/browser_tests/fixtures/utils/litegraphUtils.ts @@ -25,24 +25,22 @@ export class SubgraphSlotReference { ([type, slotName]) => { const currentGraph = window.app!.canvas.graph! - // Check if we're in a subgraph - if (currentGraph.constructor.name !== 'Subgraph') { + // Check if we're in a subgraph (subgraphs have inputNode property) + if (!('inputNode' in currentGraph)) { throw new Error( 'Not in a subgraph - this method only works inside subgraphs' ) } const slots = - type === 'input' - ? (currentGraph as any).inputs - : (currentGraph as any).outputs + type === 'input' ? currentGraph.inputs : currentGraph.outputs if (!slots || slots.length === 0) { throw new Error(`No ${type} slots found in subgraph`) } // Find the specific slot or use the first one if no name specified const slot = slotName - ? slots.find((s: any) => s.name === slotName) + ? slots.find((s) => s.name === slotName) : slots[0] if (!slot) { @@ -74,16 +72,15 @@ export class SubgraphSlotReference { ([type]) => { const currentGraph = window.app!.canvas.graph! - if (currentGraph.constructor.name !== 'Subgraph') { + // Check if we're in a subgraph (subgraphs have inputNode property) + if (!('inputNode' in currentGraph)) { throw new Error( 'Not in a subgraph - this method only works inside subgraphs' ) } const node = - type === 'input' - ? (currentGraph as any).inputNode - : (currentGraph as any).outputNode + type === 'input' ? currentGraph.inputNode : currentGraph.outputNode if (!node) { throw new Error(`No ${type} node found in subgraph`) diff --git a/browser_tests/fixtures/ws.ts b/browser_tests/fixtures/ws.ts index f1ab1a538..92a5ef89a 100644 --- a/browser_tests/fixtures/ws.ts +++ b/browser_tests/fixtures/ws.ts @@ -10,7 +10,7 @@ export const webSocketFixture = base.extend<{ await page.evaluate(function () { // Create a wrapper for WebSocket that stores them globally // so we can look it up to trigger messages - const store: Record = ((window as any).__ws__ = {}) + const store: Record = (window.__ws__ = {}) window.WebSocket = class extends window.WebSocket { constructor( ...rest: ConstructorParameters @@ -34,7 +34,7 @@ export const webSocketFixture = base.extend<{ u.pathname = '/' url = u.toString() + 'ws' } - const ws: WebSocket = (window as any).__ws__[url] + const ws: WebSocket = window.__ws__![url] ws.dispatchEvent( new MessageEvent('message', { data diff --git a/browser_tests/helpers/actionbar.ts b/browser_tests/helpers/actionbar.ts index b4d1d342b..be128ba90 100644 --- a/browser_tests/helpers/actionbar.ts +++ b/browser_tests/helpers/actionbar.ts @@ -42,13 +42,13 @@ class ComfyQueueButtonOptions { public async setMode(mode: AutoQueueMode) { await this.page.evaluate((mode) => { - ;(window.app!.extensionManager as any).queueSettings.mode = mode + window.app!.extensionManager.queueSettings.mode = mode }, mode) } public async getMode() { return await this.page.evaluate(() => { - return (window.app!.extensionManager as any).queueSettings.mode + return window.app!.extensionManager.queueSettings.mode }) } } diff --git a/browser_tests/helpers/subgraphTestUtils.ts b/browser_tests/helpers/subgraphTestUtils.ts new file mode 100644 index 000000000..0eae24651 --- /dev/null +++ b/browser_tests/helpers/subgraphTestUtils.ts @@ -0,0 +1,16 @@ +import type { LGraph, Subgraph } from '../../src/lib/litegraph/src/litegraph' +import { isSubgraph } from '../../src/utils/typeGuardUtil' + +/** + * Assertion helper for tests where being in a subgraph is a precondition. + * Throws a clear error if the graph is not a Subgraph. + */ +export function assertSubgraph( + graph: LGraph | Subgraph | null | undefined +): asserts graph is Subgraph { + if (!isSubgraph(graph)) { + throw new Error( + 'Expected to be in a subgraph context, but graph is not a Subgraph' + ) + } +} diff --git a/browser_tests/tests/actionbar.spec.ts b/browser_tests/tests/actionbar.spec.ts index 224284b98..dbbf08ce4 100644 --- a/browser_tests/tests/actionbar.spec.ts +++ b/browser_tests/tests/actionbar.spec.ts @@ -54,9 +54,7 @@ test.describe('Actionbar', { tag: '@ui' }, () => { ) node!.widgets![0].value = value - ;( - window.app!.extensionManager as any - ).workflow.activeWorkflow.changeTracker.checkState() + window.app!.extensionManager.workflow.activeWorkflow?.changeTracker.checkState() }, value) } diff --git a/browser_tests/tests/browserTabTitle.spec.ts b/browser_tests/tests/browserTabTitle.spec.ts index cd8cc37f8..af75555f0 100644 --- a/browser_tests/tests/browserTabTitle.spec.ts +++ b/browser_tests/tests/browserTabTitle.spec.ts @@ -11,8 +11,7 @@ test.describe('Browser tab title', { tag: '@smoke' }, () => { test('Can display workflow name', async ({ comfyPage }) => { const workflowName = await comfyPage.page.evaluate(async () => { - return (window.app!.extensionManager as any).workflow.activeWorkflow - .filename + return window.app!.extensionManager.workflow.activeWorkflow?.filename }) expect(await comfyPage.page.title()).toBe(`*${workflowName} - ComfyUI`) }) @@ -23,8 +22,7 @@ test.describe('Browser tab title', { tag: '@smoke' }, () => { comfyPage }) => { const workflowName = await comfyPage.page.evaluate(async () => { - return (window.app!.extensionManager as any).workflow.activeWorkflow - .filename + return window.app!.extensionManager.workflow.activeWorkflow?.filename }) expect(await comfyPage.page.title()).toBe(`${workflowName} - ComfyUI`) @@ -40,9 +38,7 @@ test.describe('Browser tab title', { tag: '@smoke' }, () => { // Delete the saved workflow for cleanup. await comfyPage.page.evaluate(async () => { - return ( - window.app!.extensionManager as any - ).workflow.activeWorkflow.delete() + return window.app!.extensionManager.workflow.activeWorkflow?.delete() }) }) }) diff --git a/browser_tests/tests/colorPalette.spec.ts b/browser_tests/tests/colorPalette.spec.ts index 4fd029fe8..703bea722 100644 --- a/browser_tests/tests/colorPalette.spec.ts +++ b/browser_tests/tests/colorPalette.spec.ts @@ -178,9 +178,7 @@ test.describe('Color Palette', { tag: ['@screenshot', '@settings'] }, () => { test('Can add custom color palette', async ({ comfyPage }) => { await comfyPage.page.evaluate((p) => { - ;(window.app!.extensionManager as any).colorPalette.addCustomColorPalette( - p - ) + window.app!.extensionManager.colorPalette.addCustomColorPalette(p) }, customColorPalettes.obsidian_dark) expect(await comfyPage.toast.getToastErrorCount()).toBe(0) diff --git a/browser_tests/tests/extensionAPI.spec.ts b/browser_tests/tests/extensionAPI.spec.ts index c0df2aa25..2487815c0 100644 --- a/browser_tests/tests/extensionAPI.spec.ts +++ b/browser_tests/tests/extensionAPI.spec.ts @@ -87,7 +87,7 @@ test.describe('Topbar commands', () => { name: 'TestExtension1', settings: [ { - id: 'TestSetting' as any, + id: 'TestSetting', name: 'Test Setting', type: 'text', defaultValue: 'Hello, world!', @@ -117,7 +117,7 @@ test.describe('Topbar commands', () => { name: 'TestExtension1', settings: [ { - id: 'Comfy.TestSetting' as any, + id: 'Comfy.TestSetting', name: 'Test Setting', type: 'boolean', defaultValue: false, @@ -144,7 +144,8 @@ test.describe('Topbar commands', () => { test.describe('Passing through attrs to setting components', () => { const testCases: Array<{ - config: Partial> + config: Pick & + Partial> selector: string }> = [ { @@ -201,11 +202,11 @@ test.describe('Topbar commands', () => { name: 'TestExtension1', settings: [ { - id: 'Comfy.TestSetting' as any, + id: 'Comfy.TestSetting', name: 'Test', attrs: { disabled: true }, ...config - } as any + } ] }) }, config) diff --git a/browser_tests/tests/groupNode.spec.ts b/browser_tests/tests/groupNode.spec.ts index f55acb017..e91327ce7 100644 --- a/browser_tests/tests/groupNode.spec.ts +++ b/browser_tests/tests/groupNode.spec.ts @@ -1,5 +1,7 @@ import { expect } from '@playwright/test' +import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema' + import type { ComfyPage } from '../fixtures/ComfyPage' import { comfyPageFixture as test } from '../fixtures/ComfyPage' import type { NodeLibrarySidebarTab } from '../fixtures/components/SidebarTab' @@ -313,7 +315,8 @@ test.describe('Group Node', { tag: '@node' }, () => { await test.step('Load workflow containing a group node pasted from a different workflow', async () => { await comfyPage.page.evaluate( - (workflow) => window.app!.loadGraphData(workflow as any), + (workflow) => + window.app!.loadGraphData(workflow as ComfyWorkflowJSON), currentGraphState ) await comfyPage.nextFrame() diff --git a/browser_tests/tests/nodeSearchBox.spec.ts b/browser_tests/tests/nodeSearchBox.spec.ts index 01ba64e98..89bfe4a5e 100644 --- a/browser_tests/tests/nodeSearchBox.spec.ts +++ b/browser_tests/tests/nodeSearchBox.spec.ts @@ -1,5 +1,8 @@ -import { comfyExpect as expect, comfyPageFixture as test } from '../fixtures/ComfyPage'; -import type { ComfyPage } from '../fixtures/ComfyPage'; +import { + comfyExpect as expect, + comfyPageFixture as test +} from '../fixtures/ComfyPage' +import type { ComfyPage } from '../fixtures/ComfyPage' test.beforeEach(async ({ comfyPage }) => { await comfyPage.settings.setSetting('Comfy.UseNewMenu', 'Disabled') diff --git a/browser_tests/tests/subgraph-rename-dialog.spec.ts b/browser_tests/tests/subgraph-rename-dialog.spec.ts index 957152804..6812e5408 100644 --- a/browser_tests/tests/subgraph-rename-dialog.spec.ts +++ b/browser_tests/tests/subgraph-rename-dialog.spec.ts @@ -26,12 +26,13 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => { // Get initial slot label const initialInputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.inputs?.[0]?.label || graph?.inputs?.[0]?.name || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.inputs?.[0]?.label || graph.inputs?.[0]?.name || null }) // First rename - await comfyPage.subgraph.rightClickInputSlot(initialInputLabel) + await comfyPage.subgraph.rightClickInputSlot(initialInputLabel!) await comfyPage.contextMenu.clickLitegraphMenuItem('Rename Slot') await comfyPage.nextFrame() @@ -55,8 +56,10 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => { // Verify the rename worked const afterFirstRename = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - const slot = graph?.inputs?.[0] + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) + return { label: null, name: null, displayName: null } + const slot = graph.inputs?.[0] return { label: slot?.label || null, name: slot?.name || null, @@ -98,8 +101,9 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => { // Verify the second rename worked const afterSecondRename = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.inputs?.[0]?.label || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.inputs?.[0]?.label || null }) expect(afterSecondRename).toBe(SECOND_RENAMED_NAME) }) @@ -114,12 +118,13 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => { // Get initial output slot label const initialOutputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.outputs?.[0]?.label || graph?.outputs?.[0]?.name || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.outputs?.[0]?.label || graph.outputs?.[0]?.name || null }) // First rename - await comfyPage.subgraph.rightClickOutputSlot(initialOutputLabel) + await comfyPage.subgraph.rightClickOutputSlot(initialOutputLabel!) await comfyPage.contextMenu.clickLitegraphMenuItem('Rename Slot') await comfyPage.nextFrame() diff --git a/browser_tests/tests/subgraph.spec.ts b/browser_tests/tests/subgraph.spec.ts index e6fc4c8dc..a6f6e20b4 100644 --- a/browser_tests/tests/subgraph.spec.ts +++ b/browser_tests/tests/subgraph.spec.ts @@ -27,7 +27,10 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { type: 'inputs' | 'outputs' ): Promise { return await comfyPage.page.evaluate((slotType: 'inputs' | 'outputs') => { - return (window.app!.canvas.graph as any)?.[slotType]?.length || 0 + const graph = window.app!.canvas.graph + // isSubgraph check: subgraphs have isRootGraph === false + if (!graph || !('inputNode' in graph)) return 0 + return graph[slotType]?.length || 0 }, type) } @@ -132,11 +135,12 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await subgraphNode.navigateIntoSubgraph() const initialInputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.inputs?.[0]?.label || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.inputs?.[0]?.label || null }) - await comfyPage.subgraph.rightClickInputSlot(initialInputLabel) + await comfyPage.subgraph.rightClickInputSlot(initialInputLabel!) await comfyPage.contextMenu.clickLitegraphMenuItem('Rename Slot') await comfyPage.nextFrame() @@ -151,8 +155,9 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await comfyPage.nextFrame() const newInputName = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.inputs?.[0]?.label || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.inputs?.[0]?.label || null }) expect(newInputName).toBe(RENAMED_INPUT_NAME) @@ -166,11 +171,12 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await subgraphNode.navigateIntoSubgraph() const initialInputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.inputs?.[0]?.label || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.inputs?.[0]?.label || null }) - await comfyPage.subgraph.doubleClickInputSlot(initialInputLabel) + await comfyPage.subgraph.doubleClickInputSlot(initialInputLabel!) await comfyPage.page.waitForSelector(SELECTORS.promptDialog, { state: 'visible' @@ -183,8 +189,9 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await comfyPage.nextFrame() const newInputName = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.inputs?.[0]?.label || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.inputs?.[0]?.label || null }) expect(newInputName).toBe(RENAMED_INPUT_NAME) @@ -198,11 +205,12 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await subgraphNode.navigateIntoSubgraph() const initialOutputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.outputs?.[0]?.label || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.outputs?.[0]?.label || null }) - await comfyPage.subgraph.doubleClickOutputSlot(initialOutputLabel) + await comfyPage.subgraph.doubleClickOutputSlot(initialOutputLabel!) await comfyPage.page.waitForSelector(SELECTORS.promptDialog, { state: 'visible' @@ -216,8 +224,9 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await comfyPage.nextFrame() const newOutputName = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.outputs?.[0]?.label || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.outputs?.[0]?.label || null }) expect(newOutputName).toBe(renamedOutputName) @@ -233,12 +242,13 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await subgraphNode.navigateIntoSubgraph() const initialInputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.inputs?.[0]?.label || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.inputs?.[0]?.label || null }) // Test that right-click still works for renaming - await comfyPage.subgraph.rightClickInputSlot(initialInputLabel) + await comfyPage.subgraph.rightClickInputSlot(initialInputLabel!) await comfyPage.contextMenu.clickLitegraphMenuItem('Rename Slot') await comfyPage.nextFrame() @@ -254,8 +264,9 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await comfyPage.nextFrame() const newInputName = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.inputs?.[0]?.label || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.inputs?.[0]?.label || null }) expect(newInputName).toBe(rightClickRenamedName) @@ -271,16 +282,20 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await subgraphNode.navigateIntoSubgraph() const initialInputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.inputs?.[0]?.label || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.inputs?.[0]?.label || null }) // Use direct pointer event approach to double-click on label await comfyPage.page.evaluate(() => { const app = window.app! - const graph = app.canvas.graph as any - const input = graph?.inputs?.[0] + const graph = app.canvas.graph + if (!graph || !('inputNode' in graph)) { + throw new Error('Expected to be in subgraph') + } + const input = graph.inputs?.[0] if (!input?.labelPos) { throw new Error('Could not get label position for testing') @@ -290,25 +305,27 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { const testX = input.labelPos[0] const testY = input.labelPos[1] + // Create a minimal mock event with required properties + // Full PointerEvent creation is unnecessary for this test const leftClickEvent = { canvasX: testX, canvasY: testY, - button: 0, // Left mouse button + button: 0, preventDefault: () => {}, stopPropagation: () => {} - } + } as Parameters[0] - const inputNode = graph?.inputNode + const inputNode = graph.inputNode if (inputNode?.onPointerDown) { inputNode.onPointerDown( - leftClickEvent as any, + leftClickEvent, app.canvas.pointer, app.canvas.linkConnector ) // Trigger double-click if pointer has the handler if (app.canvas.pointer.onDoubleClick) { - app.canvas.pointer.onDoubleClick(leftClickEvent as any) + app.canvas.pointer.onDoubleClick(leftClickEvent) } } }) @@ -327,8 +344,9 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await comfyPage.nextFrame() const newInputName = await comfyPage.page.evaluate(() => { - const graph = window.app!.canvas.graph as any - return graph?.inputs?.[0]?.label || null + const graph = window.app!.canvas.graph + if (!graph || !('inputNode' in graph)) return null + return graph.inputs?.[0]?.label || null }) expect(newInputName).toBe(labelClickRenamedName) diff --git a/browser_tests/tests/useSettingSearch.spec.ts b/browser_tests/tests/useSettingSearch.spec.ts index 8942425e7..bd8373fc1 100644 --- a/browser_tests/tests/useSettingSearch.spec.ts +++ b/browser_tests/tests/useSettingSearch.spec.ts @@ -14,14 +14,14 @@ test.describe('Settings Search functionality', { tag: '@settings' }, () => { name: 'TestSettingsExtension', settings: [ { - id: 'TestHiddenSetting' as any, + id: 'TestHiddenSetting', name: 'Test Hidden Setting', type: 'hidden', defaultValue: 'hidden_value', category: ['Test', 'Hidden'] }, { - id: 'TestDeprecatedSetting' as any, + id: 'TestDeprecatedSetting', name: 'Test Deprecated Setting', type: 'text', defaultValue: 'deprecated_value', @@ -29,7 +29,7 @@ test.describe('Settings Search functionality', { tag: '@settings' }, () => { category: ['Test', 'Deprecated'] }, { - id: 'TestVisibleSetting' as any, + id: 'TestVisibleSetting', name: 'Test Visible Setting', type: 'text', defaultValue: 'visible_value', diff --git a/browser_tests/tests/widget.spec.ts b/browser_tests/tests/widget.spec.ts index a632d8200..fd8afb06a 100644 --- a/browser_tests/tests/widget.spec.ts +++ b/browser_tests/tests/widget.spec.ts @@ -251,7 +251,7 @@ test.describe('Image widget', { tag: ['@screenshot', '@widget'] }, () => { image1.src = src const image2 = new Image() image2.src = src - const targetNode = graph.nodes[6] + const targetNode = graph!.nodes[6] targetNode.imgs = [image1, image2] targetNode.imageIndex = 1 app!.canvas.setDirty(true) diff --git a/browser_tests/types.d.ts b/browser_tests/types.d.ts new file mode 100644 index 000000000..4bdc398ae --- /dev/null +++ b/browser_tests/types.d.ts @@ -0,0 +1,16 @@ +/** + * Type declarations for browser tests. + * Augments global types with test-specific properties. + */ + +declare global { + interface Window { + /** + * WebSocket store used by test fixtures for mocking WebSocket connections. + * @see browser_tests/fixtures/ws.ts + */ + __ws__?: Record + } +} + +export {} diff --git a/browser_tests/types/globals.d.ts b/browser_tests/types/globals.d.ts index 03f770cef..bde4fb7e2 100644 --- a/browser_tests/types/globals.d.ts +++ b/browser_tests/types/globals.d.ts @@ -1,5 +1,5 @@ import type { ComfyApp } from '@/scripts/app' -import type { LGraph } from '@/lib/litegraph' +import type { LGraph } from '@/lib/litegraph/src/LGraph' import type { LiteGraphGlobal } from '@/lib/litegraph/src/LiteGraphGlobal' interface AppReadiness { diff --git a/src/schemas/apiSchema.ts b/src/schemas/apiSchema.ts index b75942a55..2c0d9dbf5 100644 --- a/src/schemas/apiSchema.ts +++ b/src/schemas/apiSchema.ts @@ -427,6 +427,11 @@ const zSettings = z.object({ 'test.setting': z.any(), 'main.sub.setting.name': z.any(), 'single.setting': z.any(), + TestSetting: z.any(), + TestHiddenSetting: z.any(), + TestDeprecatedSetting: z.any(), + TestVisibleSetting: z.any(), + 'Comfy.TestSetting': z.any(), 'LiteGraph.Node.DefaultPadding': z.boolean(), 'LiteGraph.Pointer.TrackpadGestures': z.boolean(), 'Comfy.VersionCompatibility.DisableWarnings': z.boolean(), diff --git a/src/scripts/app.ts b/src/scripts/app.ts index 067b6177d..eddae324d 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -65,9 +65,8 @@ import { useModelStore } from '@/stores/modelStore' import { SYSTEM_NODE_DEFS, useNodeDefStore } from '@/stores/nodeDefStore' import { useSubgraphStore } from '@/stores/subgraphStore' import { useWidgetStore } from '@/stores/widgetStore' -import { useWorkspaceStore } from '@/stores/workspaceStore' +import { useWorkspaceStore, type WorkspaceStore } from '@/stores/workspaceStore' import type { ComfyExtension, MissingNodeType } from '@/types/comfy' -import { type ExtensionManager } from '@/types/extensionTypes' import type { NodeExecutionId } from '@/types/nodeIdentification' import { graphToPrompt } from '@/utils/executionUtil' import { anyItemOverlapsRect } from '@/utils/mathUtil' @@ -155,7 +154,7 @@ export class ComfyApp { vueAppReady: boolean api: ComfyApi ui: ComfyUI - extensionManager!: ExtensionManager + extensionManager!: WorkspaceStore private _nodeOutputs!: Record nodePreviewImages: Record diff --git a/src/stores/workspaceStore.ts b/src/stores/workspaceStore.ts index 94c85f555..26cc0262f 100644 --- a/src/stores/workspaceStore.ts +++ b/src/stores/workspaceStore.ts @@ -17,7 +17,7 @@ import { useQueueSettingsStore } from './queueStore' import { useBottomPanelStore } from './workspace/bottomPanelStore' import { useSidebarTabStore } from './workspace/sidebarTabStore' -export const useWorkspaceStore = defineStore('workspace', () => { +const workspaceStoreSetup = () => { const spinner = ref(false) const { shift: shiftDown } = useMagicKeys() /** @@ -37,7 +37,8 @@ export const useWorkspaceStore = defineStore('workspace', () => { settings: useSettingStore().settingsById, // Allow generic key access to settings as custom nodes may add their // own settings which is not tracked by the `Setting` schema. - get: (key: string) => useSettingStore().get(key as keyof Settings), + get: (key: string): T | undefined => + useSettingStore().get(key as keyof Settings) as T | undefined, set: (key: string, value: unknown) => useSettingStore().set(key as keyof Settings, value) })) @@ -107,4 +108,8 @@ export const useWorkspaceStore = defineStore('workspace', () => { unregisterSidebarTab, getSidebarTabs } -}) +} + +export const useWorkspaceStore = defineStore('workspace', workspaceStoreSetup) + +export type WorkspaceStore = ReturnType