mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
Compare commits
2 Commits
sno-qa-969
...
fix/elimin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eee49a221c | ||
|
|
017b26dfa8 |
@@ -34,7 +34,6 @@ import { SubgraphHelper } from './helpers/SubgraphHelper'
|
||||
import { ToastHelper } from './helpers/ToastHelper'
|
||||
import { WorkflowHelper } from './helpers/WorkflowHelper'
|
||||
import type { NodeReference } from './utils/litegraphUtils'
|
||||
import type { WorkspaceStore } from '../types/globals'
|
||||
|
||||
dotenv.config()
|
||||
|
||||
@@ -139,13 +138,9 @@ class ConfirmDialog {
|
||||
}
|
||||
|
||||
// Wait for workflow service to finish if it's busy
|
||||
await this.page.waitForFunction(
|
||||
() =>
|
||||
(window.app?.extensionManager as WorkspaceStore | undefined)?.workflow
|
||||
?.isBusy === false,
|
||||
undefined,
|
||||
{ timeout: 3000 }
|
||||
)
|
||||
await this.page.waitForFunction(() => !wss().workflow.isBusy, undefined, {
|
||||
timeout: 3000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,7 +385,7 @@ export class ComfyPage {
|
||||
|
||||
async setFocusMode(focusMode: boolean) {
|
||||
await this.page.evaluate((focusMode) => {
|
||||
;(window.app!.extensionManager as WorkspaceStore).focusMode = focusMode
|
||||
wss().focusMode = focusMode
|
||||
}, focusMode)
|
||||
await this.nextFrame()
|
||||
}
|
||||
@@ -436,6 +431,13 @@ export const comfyPageFixture = base.extend<{
|
||||
}
|
||||
|
||||
await comfyPage.setup()
|
||||
|
||||
// Inject workspace store helper for typed access in page.evaluate()
|
||||
await page.evaluate(() => {
|
||||
;(window as unknown as Record<string, unknown>).wss = () =>
|
||||
window.app!.extensionManager
|
||||
})
|
||||
|
||||
await use(comfyPage)
|
||||
},
|
||||
comfyMouse: async ({ comfyPage }, use) => {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { Locator, Page } from '@playwright/test'
|
||||
|
||||
import type { WorkspaceStore } from '../../types/globals'
|
||||
import { TestIds } from '../selectors'
|
||||
|
||||
class SidebarTab {
|
||||
@@ -152,13 +151,9 @@ export class WorkflowsSidebarTab extends SidebarTab {
|
||||
await this.page.keyboard.press('Enter')
|
||||
|
||||
// Wait for workflow service to finish renaming
|
||||
await this.page.waitForFunction(
|
||||
() =>
|
||||
!(window.app?.extensionManager as WorkspaceStore | undefined)?.workflow
|
||||
?.isBusy,
|
||||
undefined,
|
||||
{ timeout: 3000 }
|
||||
)
|
||||
await this.page.waitForFunction(() => !wss().workflow.isBusy, undefined, {
|
||||
timeout: 3000
|
||||
})
|
||||
}
|
||||
|
||||
async insertWorkflow(locator: Locator) {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import type { Locator, Page } from '@playwright/test'
|
||||
|
||||
import type { WorkspaceStore } from '../../types/globals'
|
||||
|
||||
export class Topbar {
|
||||
private readonly menuLocator: Locator
|
||||
private readonly menuTrigger: Locator
|
||||
@@ -86,11 +84,9 @@ export class Topbar {
|
||||
await this.page.keyboard.press('Enter')
|
||||
|
||||
// Wait for workflow service to finish saving
|
||||
await this.page.waitForFunction(
|
||||
() => !(window.app!.extensionManager as WorkspaceStore).workflow.isBusy,
|
||||
undefined,
|
||||
{ timeout: 3000 }
|
||||
)
|
||||
await this.page.waitForFunction(() => !wss().workflow.isBusy, undefined, {
|
||||
timeout: 3000
|
||||
})
|
||||
// Wait for the dialog to close.
|
||||
await this.getSaveDialog().waitFor({ state: 'hidden', timeout: 500 })
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import type {
|
||||
ComfyApiWorkflow,
|
||||
ComfyWorkflowJSON
|
||||
} from '../../../src/platform/workflow/validation/schemas/workflowSchema'
|
||||
import type { WorkspaceStore } from '../../types/globals'
|
||||
import type { ComfyPage } from '../ComfyPage'
|
||||
|
||||
type FolderStructure = {
|
||||
@@ -47,9 +46,7 @@ export class WorkflowHelper {
|
||||
}
|
||||
|
||||
await this.comfyPage.page.evaluate(async () => {
|
||||
await (
|
||||
window.app!.extensionManager as WorkspaceStore
|
||||
).workflow.syncWorkflows()
|
||||
await wss().workflow.syncWorkflows()
|
||||
})
|
||||
|
||||
// Wait for Vue to re-render the workflow list
|
||||
@@ -90,24 +87,19 @@ export class WorkflowHelper {
|
||||
|
||||
async getUndoQueueSize(): Promise<number | undefined> {
|
||||
return this.comfyPage.page.evaluate(() => {
|
||||
const workflow = (window.app!.extensionManager as WorkspaceStore).workflow
|
||||
.activeWorkflow
|
||||
return workflow?.changeTracker.undoQueue.length
|
||||
return wss().workflow.activeWorkflow?.changeTracker.undoQueue.length
|
||||
})
|
||||
}
|
||||
|
||||
async getRedoQueueSize(): Promise<number | undefined> {
|
||||
return this.comfyPage.page.evaluate(() => {
|
||||
const workflow = (window.app!.extensionManager as WorkspaceStore).workflow
|
||||
.activeWorkflow
|
||||
return workflow?.changeTracker.redoQueue.length
|
||||
return wss().workflow.activeWorkflow?.changeTracker.redoQueue.length
|
||||
})
|
||||
}
|
||||
|
||||
async isCurrentWorkflowModified(): Promise<boolean | undefined> {
|
||||
return this.comfyPage.page.evaluate(() => {
|
||||
return (window.app!.extensionManager as WorkspaceStore).workflow
|
||||
.activeWorkflow?.isModified
|
||||
return wss().workflow.activeWorkflow?.isModified
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { Locator, Page } from '@playwright/test'
|
||||
|
||||
import type { AutoQueueMode } from '../../src/stores/queueStore'
|
||||
import { TestIds } from '../fixtures/selectors'
|
||||
import type { WorkspaceStore } from '../types/globals'
|
||||
|
||||
export class ComfyActionbar {
|
||||
public readonly root: Locator
|
||||
@@ -44,14 +43,13 @@ class ComfyQueueButtonOptions {
|
||||
|
||||
public async setMode(mode: AutoQueueMode) {
|
||||
await this.page.evaluate((mode) => {
|
||||
;(window.app!.extensionManager as WorkspaceStore).queueSettings.mode =
|
||||
mode
|
||||
wss().queueSettings.mode = mode
|
||||
}, mode)
|
||||
}
|
||||
|
||||
public async getMode() {
|
||||
return await this.page.evaluate(() => {
|
||||
return (window.app!.extensionManager as WorkspaceStore).queueSettings.mode
|
||||
return wss().queueSettings.mode
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { expect, mergeTests } from '@playwright/test'
|
||||
import type { StatusWsMessage } from '../../src/schemas/apiSchema'
|
||||
import { comfyPageFixture } from '../fixtures/ComfyPage'
|
||||
import { webSocketFixture } from '../fixtures/ws'
|
||||
import type { WorkspaceStore } from '../types/globals'
|
||||
|
||||
const test = mergeTests(comfyPageFixture, webSocketFixture)
|
||||
|
||||
@@ -55,9 +54,7 @@ test.describe('Actionbar', { tag: '@ui' }, () => {
|
||||
)
|
||||
node!.widgets![0].value = value
|
||||
|
||||
;(
|
||||
window.app!.extensionManager as WorkspaceStore
|
||||
).workflow.activeWorkflow?.changeTracker.checkState()
|
||||
wss().workflow.activeWorkflow?.changeTracker.checkState()
|
||||
}, value)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
|
||||
import type { WorkspaceStore } from '../types/globals'
|
||||
|
||||
test.describe('Browser tab title', { tag: '@smoke' }, () => {
|
||||
test.describe('Beta Menu', () => {
|
||||
@@ -11,8 +10,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 WorkspaceStore).workflow
|
||||
.activeWorkflow?.filename
|
||||
return wss().workflow.activeWorkflow?.filename
|
||||
})
|
||||
expect(await comfyPage.page.title()).toBe(`*${workflowName} - ComfyUI`)
|
||||
})
|
||||
@@ -23,8 +21,7 @@ test.describe('Browser tab title', { tag: '@smoke' }, () => {
|
||||
comfyPage
|
||||
}) => {
|
||||
const workflowName = await comfyPage.page.evaluate(async () => {
|
||||
return (window.app!.extensionManager as WorkspaceStore).workflow
|
||||
.activeWorkflow?.filename
|
||||
return wss().workflow.activeWorkflow?.filename
|
||||
})
|
||||
expect(await comfyPage.page.title()).toBe(`${workflowName} - ComfyUI`)
|
||||
|
||||
@@ -38,9 +35,7 @@ test.describe('Browser tab title', { tag: '@smoke' }, () => {
|
||||
|
||||
// Delete the saved workflow for cleanup.
|
||||
await comfyPage.page.evaluate(async () => {
|
||||
return (
|
||||
window.app!.extensionManager as WorkspaceStore
|
||||
).workflow.activeWorkflow?.delete()
|
||||
return wss().workflow.activeWorkflow?.delete()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
|
||||
import type { WorkspaceStore } from '../types/globals'
|
||||
|
||||
test.beforeEach(async ({ comfyPage }) => {
|
||||
await comfyPage.settings.setSetting('Comfy.UseNewMenu', 'Disabled')
|
||||
@@ -179,9 +178,7 @@ test.describe('Color Palette', { tag: ['@screenshot', '@settings'] }, () => {
|
||||
|
||||
test('Can add custom color palette', async ({ comfyPage }) => {
|
||||
await comfyPage.page.evaluate(async (p) => {
|
||||
await (
|
||||
window.app!.extensionManager as WorkspaceStore
|
||||
).colorPalette.addCustomColorPalette(p)
|
||||
await wss().colorPalette.addCustomColorPalette(p)
|
||||
}, customColorPalettes.obsidian_dark)
|
||||
expect(await comfyPage.toast.getToastErrorCount()).toBe(0)
|
||||
|
||||
|
||||
45
browser_tests/types/globals.d.ts
vendored
45
browser_tests/types/globals.d.ts
vendored
@@ -4,6 +4,7 @@ import type { LGraphBadge } from '@/lib/litegraph/src/LGraphBadge'
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
|
||||
import type { LiteGraphGlobal } from '@/lib/litegraph/src/LiteGraphGlobal'
|
||||
import type { ComfyApp } from '@/scripts/app'
|
||||
import type { ExtensionManager } from '@/types/extensionTypes'
|
||||
import type { useWorkspaceStore } from '@/stores/workspaceStore'
|
||||
|
||||
/**
|
||||
@@ -25,6 +26,26 @@ interface CapturedMessages {
|
||||
serverFeatureFlags: unknown
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal store type for browser test access.
|
||||
* At runtime, `app.extensionManager` is assigned `useWorkspaceStore()`, which
|
||||
* implements the public `ExtensionManager` interface plus internal store properties.
|
||||
*
|
||||
* Use the `wss()` helper function to access store properties in page.evaluate():
|
||||
* @example
|
||||
* ```ts
|
||||
* await page.evaluate(() => wss().workflow.syncWorkflows())
|
||||
* ```
|
||||
*/
|
||||
export type WorkspaceStore = ReturnType<typeof useWorkspaceStore>
|
||||
|
||||
/**
|
||||
* Test-only extension manager type that exposes both the public API and
|
||||
* internal store properties. This intersection accurately reflects the
|
||||
* runtime reality where extensionManager is the workspace store.
|
||||
*/
|
||||
export type TestExtensionManager = ExtensionManager & WorkspaceStore
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
app?: ComfyApp
|
||||
@@ -49,21 +70,19 @@ declare global {
|
||||
__ws__?: Record<string, WebSocket>
|
||||
}
|
||||
|
||||
/**
|
||||
* WorkspaceStore shorthand - returns the workspace store with full typing.
|
||||
* Centralizes the type assertion in one place.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* await page.evaluate(() => wss().workflow.syncWorkflows())
|
||||
* ```
|
||||
*/
|
||||
function wss(): TestExtensionManager
|
||||
|
||||
const app: ComfyApp | undefined
|
||||
const graph: LGraph | undefined
|
||||
const LiteGraph: LiteGraphGlobal | undefined
|
||||
const LGraphBadge: typeof LGraphBadge | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal store type for browser test access.
|
||||
* Used to access properties not exposed via the public ExtensionManager interface.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* await page.evaluate(() => {
|
||||
* ;(window.app!.extensionManager as WorkspaceStore).workflow.syncWorkflows()
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export type WorkspaceStore = ReturnType<typeof useWorkspaceStore>
|
||||
|
||||
@@ -65,12 +65,20 @@ data as unknown as SomeType // Avoid; prefer explicit typings or helpers
|
||||
When tests need internal store properties (e.g., `.workflow`, `.focusMode`):
|
||||
|
||||
```typescript
|
||||
// ✅ Access stores directly in page.evaluate
|
||||
// ✅ Use the wss() helper to access workspace store with full typing
|
||||
await page.evaluate(() => {
|
||||
const store = useWorkflowStore()
|
||||
return store.activeWorkflow
|
||||
return wss().workflow.activeWorkflow?.filename
|
||||
})
|
||||
|
||||
// ✅ wss() provides typed access to:
|
||||
// - workflow (activeWorkflow, syncWorkflows, isBusy)
|
||||
// - focusMode
|
||||
// - queueSettings
|
||||
// - colorPalette
|
||||
|
||||
// ❌ Don't use `as WorkspaceStore` casts
|
||||
;(window.app!.extensionManager as WorkspaceStore).workflow // Bad
|
||||
|
||||
// ❌ Don't change public API types to expose internals
|
||||
// Keep app.extensionManager typed as ExtensionManager, not WorkspaceStore
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user