mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-05 15:40:10 +00:00
317 lines
10 KiB
TypeScript
317 lines
10 KiB
TypeScript
import { expect, mergeTests } from '@playwright/test'
|
|
|
|
import { comfyPageFixture } from '../fixtures/ComfyPage'
|
|
import { webSocketFixture } from '../fixtures/ws'
|
|
import {
|
|
BrowserTitleMonitor,
|
|
ExecutionTestHelper
|
|
} from '../helpers/ExecutionTestHelper'
|
|
|
|
const test = mergeTests(comfyPageFixture, webSocketFixture)
|
|
|
|
test.describe('Browser Tab Title - Multi-node Execution', () => {
|
|
test.describe.configure({ mode: 'serial' })
|
|
|
|
let executionHelper: ExecutionTestHelper
|
|
let titleMonitor: BrowserTitleMonitor
|
|
|
|
test.beforeEach(async ({ comfyPage }) => {
|
|
await comfyPage.setSetting('Comfy.UseNewMenu', 'Top')
|
|
executionHelper = new ExecutionTestHelper(comfyPage.page)
|
|
titleMonitor = new BrowserTitleMonitor(comfyPage.page)
|
|
})
|
|
|
|
test.afterEach(async () => {
|
|
// Clean up event listeners to avoid conflicts
|
|
if (executionHelper) {
|
|
await executionHelper.cleanup()
|
|
}
|
|
})
|
|
|
|
test('Shows multiple nodes running in tab title', async ({
|
|
comfyPage,
|
|
ws
|
|
}) => {
|
|
await comfyPage.loadWorkflow('execution/parallel_async_nodes')
|
|
|
|
// Wait for any existing execution to complete
|
|
await titleMonitor.waitForIdleTitle()
|
|
|
|
// Get initial title
|
|
const initialTitle = await comfyPage.page.title()
|
|
// Title might show execution state if other tests are running
|
|
// Just ensure we have a baseline to compare against
|
|
|
|
// Wait for the UI to be ready
|
|
await comfyPage.nextFrame()
|
|
|
|
// Check if workflow is valid and nodes are available
|
|
const workflowStatus = await comfyPage.page.evaluate(() => {
|
|
const graph = window['app'].graph
|
|
const missingNodeTypes: string[] = []
|
|
const nodeCount = graph.nodes.length
|
|
|
|
// Check for missing node types
|
|
graph.nodes.forEach((node: any) => {
|
|
if (node.type && !LiteGraph.registered_node_types[node.type]) {
|
|
missingNodeTypes.push(node.type)
|
|
}
|
|
})
|
|
|
|
return {
|
|
nodeCount,
|
|
missingNodeTypes,
|
|
hasErrors: missingNodeTypes.length > 0
|
|
}
|
|
})
|
|
|
|
if (workflowStatus.hasErrors) {
|
|
console.log('Missing node types:', workflowStatus.missingNodeTypes)
|
|
// Skip test if nodes are missing
|
|
test.skip()
|
|
return
|
|
}
|
|
|
|
// Set up tracking for progress events and errors
|
|
await executionHelper.setupEventTracking()
|
|
|
|
// Queue the workflow for real execution using the command
|
|
await comfyPage.executeCommand('Comfy.QueuePrompt')
|
|
|
|
// Wait a moment to see if there's an error
|
|
await comfyPage.page.waitForTimeout(1000)
|
|
|
|
// Check for execution errors
|
|
if (await executionHelper.hasExecutionError()) {
|
|
const error = await executionHelper.getExecutionError()
|
|
console.log('Execution error:', error)
|
|
}
|
|
|
|
// Wait for multiple nodes to be running (TestSleep nodes 2, 3 and TestAsyncProgressNode 4)
|
|
await executionHelper.waitForRunningNodes(2)
|
|
|
|
// Check title while we know multiple nodes are running
|
|
const testId = executionHelper.getTestId()
|
|
const titleDuringExecution = await comfyPage.page.evaluate((testId) => {
|
|
const states = window[`__progressStates_${testId}`]
|
|
if (!states || states.length === 0) return null
|
|
|
|
const latestState = states[states.length - 1]
|
|
if (!latestState.nodes) return null
|
|
|
|
const runningNodes = Object.values(latestState.nodes).filter(
|
|
(node: any) => node.state === 'running'
|
|
).length
|
|
|
|
return {
|
|
title: document.title,
|
|
runningCount: runningNodes
|
|
}
|
|
}, testId)
|
|
|
|
// Verify we captured the state with multiple nodes running
|
|
expect(titleDuringExecution).not.toBeNull()
|
|
expect(titleDuringExecution.runningCount).toBeGreaterThanOrEqual(2)
|
|
|
|
// The title should show multiple nodes running when we have 2+ nodes executing
|
|
if (titleDuringExecution.runningCount >= 2) {
|
|
expect(titleDuringExecution.title).toMatch(/\[\d+ nodes running\]/)
|
|
}
|
|
|
|
// Wait for some nodes to finish, leaving only one running
|
|
await executionHelper.waitForRunningNodes(1, 15000)
|
|
|
|
// Wait for title to show single node progress
|
|
await comfyPage.page.waitForFunction(
|
|
() => {
|
|
const title = document.title
|
|
return title.match(/\[\d+%\]/) && !title.match(/\[\d+ nodes running\]/)
|
|
},
|
|
{ timeout: 5000 }
|
|
)
|
|
|
|
// Check that title shows single node with progress
|
|
const titleWithSingleNode = await comfyPage.page.title()
|
|
expect(titleWithSingleNode).toMatch(/\[\d+%\]/)
|
|
expect(titleWithSingleNode).not.toMatch(/\[\d+ nodes running\]/)
|
|
})
|
|
|
|
test('Shows progress updates in title during execution', async ({
|
|
comfyPage,
|
|
ws
|
|
}) => {
|
|
await comfyPage.loadWorkflow('execution/parallel_async_nodes')
|
|
|
|
// Wait for the UI to be ready
|
|
await comfyPage.nextFrame()
|
|
|
|
// Set up tracking for progress events and title changes
|
|
await executionHelper.setupEventTracking()
|
|
await titleMonitor.setupTitleMonitoring()
|
|
|
|
// Queue the workflow for real execution using the command
|
|
await comfyPage.executeCommand('Comfy.QueuePrompt')
|
|
|
|
// Wait for TestAsyncProgressNode (node 4) to start showing progress
|
|
// This node reports progress from 0 to 10 with steps of 1
|
|
const testId2 = executionHelper.getTestId()
|
|
await comfyPage.page.waitForFunction(
|
|
(testId) => {
|
|
const states = window[`__progressStates_${testId}`]
|
|
if (!states || states.length === 0) return false
|
|
|
|
const latestState = states[states.length - 1]
|
|
if (!latestState.nodes || !latestState.nodes['4']) return false
|
|
|
|
const node4 = latestState.nodes['4']
|
|
if (node4.state === 'running' && node4.value > 0) {
|
|
window['__lastProgress'] = Math.round((node4.value / node4.max) * 100)
|
|
return true
|
|
}
|
|
return false
|
|
},
|
|
testId2,
|
|
{ timeout: 10000 }
|
|
)
|
|
|
|
// Wait for title to show progress percentage
|
|
await comfyPage.page.waitForFunction(
|
|
() => {
|
|
const title = document.title
|
|
console.log('Title check 1:', title)
|
|
return title.match(/\[\d+%\]/)
|
|
},
|
|
{ timeout: 5000 }
|
|
)
|
|
|
|
// Check that title shows a progress percentage
|
|
const titleWithProgress = await comfyPage.page.title()
|
|
expect(titleWithProgress).toMatch(/\[\d+%\]/)
|
|
|
|
// Wait for progress to update to a different value
|
|
const firstProgress = await comfyPage.page.evaluate(
|
|
() => window['__lastProgress']
|
|
)
|
|
|
|
const testId3 = executionHelper.getTestId()
|
|
await comfyPage.page.waitForFunction(
|
|
({ initialProgress, testId }) => {
|
|
const states = window[`__progressStates_${testId}`]
|
|
if (!states || states.length === 0) return false
|
|
|
|
const latestState = states[states.length - 1]
|
|
if (!latestState.nodes || !latestState.nodes['4']) return false
|
|
|
|
const node4 = latestState.nodes['4']
|
|
if (node4.state === 'running') {
|
|
const currentProgress = Math.round((node4.value / node4.max) * 100)
|
|
window['__lastProgress'] = currentProgress
|
|
return currentProgress > initialProgress
|
|
}
|
|
return false
|
|
},
|
|
{ initialProgress: firstProgress, testId: testId3 },
|
|
{ timeout: 10000 }
|
|
)
|
|
|
|
// Store the first progress for comparison
|
|
await comfyPage.page.evaluate((progress) => {
|
|
window['__firstProgress'] = progress
|
|
}, firstProgress)
|
|
|
|
// Check the title history to verify we captured progress updates
|
|
const finalCheck = await comfyPage.page.evaluate(() => {
|
|
const titleLog = window['__titleUpdateLog'] || []
|
|
const firstProgress = window['__firstProgress'] || 0
|
|
|
|
// Find titles with progress information
|
|
const titlesWithProgress = titleLog.filter((entry) => entry.hasProgress)
|
|
|
|
// Check if we saw different progress values or multi-node running state
|
|
const progressValues = new Set()
|
|
const hadMultiNodeRunning = titleLog.some((entry) =>
|
|
entry.title.includes('nodes running')
|
|
)
|
|
|
|
titleLog.forEach((entry) => {
|
|
const match = entry.title.match(/\[(\d+)%\]/)
|
|
if (match) {
|
|
progressValues.add(parseInt(match[1]))
|
|
}
|
|
})
|
|
|
|
return {
|
|
sawProgressUpdates: titlesWithProgress.length > 0,
|
|
uniqueProgressValues: Array.from(progressValues),
|
|
hadMultiNodeRunning,
|
|
firstProgress,
|
|
lastProgress: window['__lastProgress'],
|
|
totalTitleUpdates: titleLog.length,
|
|
sampleTitles: titleLog.slice(0, 5)
|
|
}
|
|
})
|
|
|
|
console.log('Title update check:', JSON.stringify(finalCheck, null, 2))
|
|
|
|
// Verify that we captured title updates showing execution progress
|
|
expect(finalCheck.sawProgressUpdates).toBe(true)
|
|
expect(finalCheck.totalTitleUpdates).toBeGreaterThan(0)
|
|
|
|
// We should have seen either:
|
|
// 1. Multiple unique progress values, OR
|
|
// 2. Multi-node running state, OR
|
|
// 3. Progress different from initial
|
|
const sawProgressChange =
|
|
finalCheck.uniqueProgressValues.length > 1 ||
|
|
finalCheck.hadMultiNodeRunning ||
|
|
finalCheck.lastProgress !== firstProgress
|
|
|
|
expect(sawProgressChange).toBe(true)
|
|
|
|
// Clean up interval
|
|
await titleMonitor.stopTitleMonitoring()
|
|
})
|
|
|
|
test('Clears execution status from title when all nodes finish', async ({
|
|
comfyPage,
|
|
ws
|
|
}) => {
|
|
await comfyPage.loadWorkflow('execution/parallel_async_nodes')
|
|
|
|
// Wait for any existing execution to complete
|
|
await titleMonitor.waitForIdleTitle()
|
|
|
|
// Wait for the UI to be ready
|
|
await comfyPage.nextFrame()
|
|
|
|
// Set up tracking for events
|
|
await executionHelper.setupEventTracking()
|
|
|
|
// Queue the workflow for real execution using the command
|
|
await comfyPage.executeCommand('Comfy.QueuePrompt')
|
|
|
|
// Wait for execution to show progress in title
|
|
await titleMonitor.waitForExecutionTitle()
|
|
|
|
// Verify execution shows in title
|
|
const executingTitle = await comfyPage.page.title()
|
|
expect(executingTitle).toMatch(/\[[\d%\s\w]+\]/)
|
|
|
|
// Wait for execution to complete (all nodes finished)
|
|
await executionHelper.waitForExecutionFinish()
|
|
|
|
// Give a moment for title to update after execution completes
|
|
await comfyPage.page.waitForTimeout(500)
|
|
|
|
// Wait for title to clear execution status
|
|
await titleMonitor.waitForIdleTitle()
|
|
|
|
// Check that execution status is cleared
|
|
const finishedTitle = await comfyPage.page.title()
|
|
expect(finishedTitle).toContain('ComfyUI')
|
|
expect(finishedTitle).not.toMatch(/\[\d+%\]/) // No percentage
|
|
expect(finishedTitle).not.toMatch(/\[\d+ nodes running\]/) // No running nodes
|
|
expect(finishedTitle).not.toContain('Executing')
|
|
})
|
|
})
|