Files
ComfyUI_frontend/browser_tests/tests/builderReorder.spec.ts
Alexander Brown f1bb756929 fix: remove redundant and counterproductive e2e timeout overrides (#11110)
## Summary

Alright, alright, alright. These e2e tests have been runnin' around like
they're late for somethin', settin' tight little timeouts like the
world's gonna end in 250 milliseconds. Man, you gotta *breathe*. Let the
framework do its thing. Go slow to go fast, that's what I always say.

## Changes

- **What**: Removed ~120 redundant timeout overrides from auto-retrying
Playwright assertions (`toBeVisible`, `toBeHidden`, `toHaveCount`,
`toBeEnabled`, `toHaveAttribute`, `toContainText`, `expect.poll`) where
5000ms is already the default. Also removed sub-5s timeouts (1s, 2s, 3s)
that were just *begging* for flaky failures — like wearin' a belt and
suspenders and also holdin' your pants up with both hands. Raised the
absurdly short timeouts in `customMatchers.ts` (250ms `toPass` → 5000ms,
256ms poll → default). Kept `timeout: 5000` on `.toPass()` calls
(defaults to 0), `.waitFor()`, `waitForRequest`, `waitForFunction`,
intentionally-short timeouts inside retry loops, and conditional
`.isVisible()/.catch()` checks — those fellas actually need the help.

## Review Focus

Every remaining timeout in the diff is there for a *reason*. The ones on
`.toPass()` stay because that API defaults to zero — it won't retry at
all without one. The ones on `.waitFor()` and `waitForRequest` stay
because those are locator actions, not auto-retrying assertions. The
intentionally-short ones inside `toPass` retry loops
(`interaction.spec.ts`) and the negative assertions (`actionbar.spec.ts`
confirming no response arrives) — those are *supposed* to be tight.

The short timeouts on regular assertions were actively *encouragin'*
flaky failures. That's like settin' your alarm for 4 AM and then gettin'
mad you're tired. Just... don't do that, man. Let things take the time
they need.

38 files, net -115 lines. Less code, more chill. That's livin'.

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-04-10 19:47:20 +00:00

206 lines
6.0 KiB
TypeScript

import {
comfyPageFixture as test,
comfyExpect as expect
} from '@e2e/fixtures/ComfyPage'
import type { ComfyPage } from '@e2e/fixtures/ComfyPage'
import type { AppModeHelper } from '@e2e/fixtures/helpers/AppModeHelper'
import {
builderSaveAs,
createAndSaveApp,
openWorkflowFromSidebar,
setupBuilder
} from '@e2e/helpers/builderTestUtils'
const WIDGETS = ['seed', 'steps', 'cfg']
/** Save as app, close it by loading default, reopen from sidebar, enter app mode. */
async function saveCloseAndReopenAsApp(
comfyPage: ComfyPage,
appMode: AppModeHelper,
workflowName: string
) {
await appMode.steps.goToPreview()
await builderSaveAs(appMode, workflowName)
await appMode.saveAs.closeButton.click()
await expect(appMode.saveAs.successDialog).not.toBeVisible()
await appMode.footer.exitBuilder()
await openWorkflowFromSidebar(comfyPage, workflowName)
await appMode.toggleAppMode()
}
test.describe('Builder input reordering', { tag: '@ui' }, () => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.appMode.enableLinearMode()
await comfyPage.settings.setSetting(
'Comfy.AppBuilder.VueNodeSwitchDismissed',
true
)
})
test('Drag first input to last position', async ({ comfyPage }) => {
const { appMode } = comfyPage
await setupBuilder(comfyPage, undefined, WIDGETS)
await appMode.steps.goToInputs()
await expect(appMode.select.inputItemTitles).toHaveText(WIDGETS)
await appMode.select.dragInputItem(0, 2)
await expect(appMode.select.inputItemTitles).toHaveText([
'steps',
'cfg',
'seed'
])
await appMode.steps.goToPreview()
await expect(appMode.select.previewWidgetLabels).toHaveText([
'steps',
'cfg',
'seed'
])
})
test('Drag last input to first position', async ({ comfyPage }) => {
const { appMode } = comfyPage
await setupBuilder(comfyPage, undefined, WIDGETS)
await appMode.steps.goToInputs()
await expect(appMode.select.inputItemTitles).toHaveText(WIDGETS)
await appMode.select.dragInputItem(2, 0)
await expect(appMode.select.inputItemTitles).toHaveText([
'cfg',
'seed',
'steps'
])
await appMode.steps.goToPreview()
await expect(appMode.select.previewWidgetLabels).toHaveText([
'cfg',
'seed',
'steps'
])
})
test('Drag input to middle position', async ({ comfyPage }) => {
const { appMode } = comfyPage
await setupBuilder(comfyPage, undefined, WIDGETS)
await appMode.steps.goToInputs()
await expect(appMode.select.inputItemTitles).toHaveText(WIDGETS)
await appMode.select.dragInputItem(0, 1)
await expect(appMode.select.inputItemTitles).toHaveText([
'steps',
'seed',
'cfg'
])
await appMode.steps.goToPreview()
await expect(appMode.select.previewWidgetLabels).toHaveText([
'steps',
'seed',
'cfg'
])
})
test('Reorder in preview step reflects in app mode after save', async ({
comfyPage
}) => {
const { appMode } = comfyPage
await setupBuilder(comfyPage, undefined, WIDGETS)
await appMode.steps.goToPreview()
await expect(appMode.select.previewWidgetLabels).toHaveText(WIDGETS)
await appMode.select.dragPreviewItem(0, 2)
await expect(appMode.select.previewWidgetLabels).toHaveText([
'steps',
'cfg',
'seed'
])
const workflowName = `${Date.now()} reorder-preview`
await saveCloseAndReopenAsApp(comfyPage, appMode, workflowName)
await expect(appMode.linearWidgets).toBeVisible()
await expect(appMode.select.previewWidgetLabels).toHaveText([
'steps',
'cfg',
'seed'
])
})
test('Reorder inputs persists after save and reload', async ({
comfyPage
}) => {
const { appMode } = comfyPage
await setupBuilder(comfyPage, undefined, WIDGETS)
await appMode.steps.goToInputs()
await appMode.select.dragInputItem(0, 2)
await expect(appMode.select.inputItemTitles).toHaveText([
'steps',
'cfg',
'seed'
])
const workflowName = `${Date.now()} reorder-persist`
await saveCloseAndReopenAsApp(comfyPage, appMode, workflowName)
await expect(appMode.linearWidgets).toBeVisible()
await expect(appMode.select.previewWidgetLabels).toHaveText([
'steps',
'cfg',
'seed'
])
})
test('Reordering inputs in one app does not corrupt another app', async ({
comfyPage
}) => {
const { appMode } = comfyPage
const suffix = String(Date.now())
const app1Name = `app1-${suffix}`
const app2Name = `app2-${suffix}`
const app2Widgets = ['seed', 'steps']
// Create and save app1 with [seed, steps, cfg]
await createAndSaveApp(comfyPage, app1Name, WIDGETS)
await appMode.footer.exitBuilder()
// Create app2 in a new tab so both apps are open simultaneously
await comfyPage.menu.topbar.triggerTopbarCommand(['New'])
await createAndSaveApp(comfyPage, app2Name, app2Widgets)
await appMode.footer.exitBuilder()
// Switch to app1 tab and enter builder
await comfyPage.menu.topbar.getWorkflowTab(app1Name).click()
await appMode.enterBuilder()
await appMode.steps.goToInputs()
await expect(appMode.select.inputItemTitles).toHaveText(WIDGETS)
// Reorder app1 inputs: drag 'seed' from first to last
await appMode.select.dragInputItem(0, 2)
const app1Reordered = ['steps', 'cfg', 'seed']
await expect(appMode.select.inputItemTitles).toHaveText(app1Reordered)
// Switch to app2 tab and enter builder
await appMode.footer.exitBuilder()
await comfyPage.menu.topbar.getWorkflowTab(app2Name).click()
await appMode.enterBuilder()
await appMode.steps.goToInputs()
// Verify app2 inputs are not corrupted — still [seed, steps]
await expect(appMode.select.inputItemTitles).toHaveText(app2Widgets)
// Switch back to app1 and verify reorder persisted
await appMode.footer.exitBuilder()
await comfyPage.menu.topbar.getWorkflowTab(app1Name).click()
await appMode.enterBuilder()
await appMode.steps.goToInputs()
await expect(appMode.select.inputItemTitles).toHaveText(app1Reordered)
})
})