test: stabilize flaky Playwright tests (#10817)

Stabilize flaky Playwright tests by improving test reliability.

This PR aims to identify and fix flaky e2e tests.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10817-test-stabilize-flaky-Playwright-tests-3366d73d365081ada40de73ce11af625)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Alexander Brown
2026-04-07 19:47:27 -07:00
committed by GitHub
parent d73c4406ed
commit 4cb83353cb
29 changed files with 760 additions and 536 deletions

View File

@@ -4,6 +4,7 @@ import {
} from '../fixtures/ComfyPage'
import type { ComfyPage } from '../fixtures/ComfyPage'
import { fitToViewInstant } from '../helpers/fitToView'
import type { WorkspaceStore } from '../types/globals'
import type { NodeReference } from '../fixtures/utils/litegraphUtils'
// TODO: there might be a better solution for this
@@ -23,6 +24,67 @@ async function selectNodeWithPan(comfyPage: ComfyPage, nodeRef: NodeReference) {
await nodeRef.click('title')
}
async function openSelectionToolboxHelp(comfyPage: ComfyPage) {
await expect(comfyPage.selectionToolbox).toBeVisible()
const helpButton = comfyPage.selectionToolbox.getByTestId('info-button')
await expect(helpButton).toBeVisible()
await helpButton.click({ force: true })
await comfyPage.nextFrame()
return comfyPage.page.getByTestId('properties-panel')
}
async function setLocaleAndWaitForWorkflowReload(
comfyPage: ComfyPage,
locale: string
) {
await comfyPage.page.evaluate(async (targetLocale) => {
const workflow = (window.app!.extensionManager as WorkspaceStore).workflow
.activeWorkflow
if (!workflow) {
throw new Error('No active workflow while waiting for locale reload')
}
const changeTracker = workflow.changeTracker.constructor as unknown as {
isLoadingGraph: boolean
}
let sawLoading = false
const waitForReload = new Promise<void>((resolve, reject) => {
const timeoutAt = performance.now() + 5000
const tick = () => {
if (changeTracker.isLoadingGraph) {
sawLoading = true
}
if (sawLoading && !changeTracker.isLoadingGraph) {
resolve()
return
}
if (performance.now() > timeoutAt) {
reject(
new Error(
`Timed out waiting for workflow reload after setting locale to ${targetLocale}`
)
)
return
}
requestAnimationFrame(tick)
}
tick()
})
await window.app!.extensionManager.setting.set('Comfy.Locale', targetLocale)
await waitForReload
}, locale)
}
test.describe('Node Help', { tag: ['@slow', '@ui'] }, () => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setup()
@@ -46,20 +108,8 @@ test.describe('Node Help', { tag: ['@slow', '@ui'] }, () => {
// Select the node with panning to ensure toolbox is visible
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
// Wait for selection toolbox to appear
await expect(comfyPage.selectionToolbox).toBeVisible()
// Click the help button in the selection toolbox
const helpButton = comfyPage.selectionToolbox.locator(
'button[data-testid="info-button"]'
)
await expect(helpButton).toBeVisible()
await helpButton.click()
// Verify that the help page is shown for the correct node
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
const helpPage = await openSelectionToolboxHelp(comfyPage)
await expect(helpPage).toContainText('KSampler')
await expect(helpPage.locator('.node-help-content')).toBeVisible()
})
@@ -168,16 +218,8 @@ test.describe('Node Help', { tag: ['@slow', '@ui'] }, () => {
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
// Click help button
const helpButton = comfyPage.page.locator(
'.selection-toolbox button[data-testid="info-button"]'
)
await helpButton.click()
// Verify loading spinner is shown
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
const helpPage = await openSelectionToolboxHelp(comfyPage)
await expect(helpPage.locator('.p-progressspinner')).toBeVisible()
// Wait for content to load
@@ -201,16 +243,8 @@ test.describe('Node Help', { tag: ['@slow', '@ui'] }, () => {
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
// Click help button
const helpButton = comfyPage.page.locator(
'.selection-toolbox button[data-testid="info-button"]'
)
await helpButton.click()
// Verify fallback content is shown (description, inputs, outputs)
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
const helpPage = await openSelectionToolboxHelp(comfyPage)
await expect(helpPage).toContainText('Description')
await expect(helpPage).toContainText('Inputs')
await expect(helpPage).toContainText('Outputs')
@@ -239,14 +273,7 @@ test.describe('Node Help', { tag: ['@slow', '@ui'] }, () => {
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
const helpButton = comfyPage.page.locator(
'.selection-toolbox button[data-testid="info-button"]'
)
await helpButton.click()
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
const helpPage = await openSelectionToolboxHelp(comfyPage)
await expect(helpPage).toContainText('KSampler Documentation')
// Check that relative image paths are prefixed correctly
@@ -290,14 +317,7 @@ test.describe('Node Help', { tag: ['@slow', '@ui'] }, () => {
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
const helpButton = comfyPage.page.locator(
'.selection-toolbox button[data-testid="info-button"]'
)
await helpButton.click()
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
const helpPage = await openSelectionToolboxHelp(comfyPage)
// Check relative video paths are prefixed
const relativeVideo = helpPage.locator('video[src*="demo.mp4"]')
@@ -364,15 +384,9 @@ This is documentation for a custom node.
await selectNodeWithPan(comfyPage, firstNode)
}
const helpButton = comfyPage.page.locator(
'.selection-toolbox button[data-testid="info-button"]'
)
const helpButton = comfyPage.selectionToolbox.getByTestId('info-button')
if (await helpButton.isVisible()) {
await helpButton.click()
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
const helpPage = await openSelectionToolboxHelp(comfyPage)
await expect(helpPage).toContainText('Custom Node Documentation')
// Check image path for custom nodes
@@ -408,14 +422,7 @@ This is documentation for a custom node.
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
const helpButton = comfyPage.page.locator(
'.selection-toolbox button[data-testid="info-button"]'
)
await helpButton.click()
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
const helpPage = await openSelectionToolboxHelp(comfyPage)
// Dangerous elements should be removed
await expect(helpPage.locator('script')).toHaveCount(0)
@@ -471,27 +478,20 @@ This is English documentation.
})
// Set locale to Japanese
await comfyPage.settings.setSetting('Comfy.Locale', 'ja')
await setLocaleAndWaitForWorkflowReload(comfyPage, 'ja')
await comfyPage.workflow.loadWorkflow('default')
const ksamplerNodes =
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
try {
await comfyPage.workflow.loadWorkflow('default')
const ksamplerNodes =
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
const helpButton = comfyPage.page.locator(
'.selection-toolbox button[data-testid="info-button"]'
)
await helpButton.waitFor({ state: 'visible', timeout: 10_000 })
await helpButton.click()
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
await expect(helpPage).toContainText('KSamplerード')
await expect(helpPage).toContainText('これは日本語のドキュメントです')
// Reset locale
await comfyPage.settings.setSetting('Comfy.Locale', 'en')
const helpPage = await openSelectionToolboxHelp(comfyPage)
await expect(helpPage).toContainText('KSamplerード')
await expect(helpPage).toContainText('これは日本語のドキュメントです')
} finally {
await setLocaleAndWaitForWorkflowReload(comfyPage, 'en')
}
})
test('Should handle network errors gracefully', async ({ comfyPage }) => {
@@ -505,14 +505,7 @@ This is English documentation.
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
const helpButton = comfyPage.page.locator(
'.selection-toolbox button[data-testid="info-button"]'
)
await helpButton.click()
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
const helpPage = await openSelectionToolboxHelp(comfyPage)
// Should show fallback content (node description)
await expect(helpPage).toBeVisible()
@@ -552,14 +545,7 @@ This is English documentation.
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
const helpButton = comfyPage.page.locator(
'.selection-toolbox button[data-testid="info-button"]'
)
await helpButton.click()
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
const helpPage = await openSelectionToolboxHelp(comfyPage)
await expect(helpPage).toContainText('KSampler Help')
await expect(helpPage).toContainText('This is KSampler documentation')