mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-04 21:22:07 +00:00
test: App Mode - widget reordering (#10685)
## Summary Adds tests that simulate the user sorting the inputs and ensures they are persisted and visible in app mode ## Changes - **What**: - rework input/output selection helpers to accept widget/node names - extract additional shared helpers ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10685-test-App-Mode-widget-reordering-3316d73d3650813b8348da5f29fd01f8) by [Unito](https://www.unito.io)
This commit is contained in:
163
browser_tests/tests/builderReorder.spec.ts
Normal file
163
browser_tests/tests/builderReorder.spec.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
import {
|
||||
comfyPageFixture as test,
|
||||
comfyExpect as expect
|
||||
} from '../fixtures/ComfyPage'
|
||||
import type { ComfyPage } from '../fixtures/ComfyPage'
|
||||
import type { AppModeHelper } from '../fixtures/helpers/AppModeHelper'
|
||||
import {
|
||||
builderSaveAs,
|
||||
openWorkflowFromSidebar,
|
||||
setupBuilder
|
||||
} from '../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 comfyPage.nextFrame()
|
||||
|
||||
await appMode.footer.exitBuilder()
|
||||
await openWorkflowFromSidebar(comfyPage, workflowName)
|
||||
await appMode.toggleAppMode()
|
||||
}
|
||||
|
||||
test.describe('Builder input reordering', { tag: '@ui' }, () => {
|
||||
test.beforeEach(async ({ comfyPage }) => {
|
||||
await comfyPage.page.evaluate(() => {
|
||||
window.app!.api.serverFeatureFlags.value = {
|
||||
...window.app!.api.serverFeatureFlags.value,
|
||||
linear_toggle_enabled: true
|
||||
}
|
||||
})
|
||||
await comfyPage.settings.setSetting('Comfy.UseNewMenu', 'Top')
|
||||
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({ timeout: 5000 })
|
||||
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({ timeout: 5000 })
|
||||
await expect(appMode.select.previewWidgetLabels).toHaveText([
|
||||
'steps',
|
||||
'cfg',
|
||||
'seed'
|
||||
])
|
||||
})
|
||||
})
|
||||
@@ -2,45 +2,14 @@ import {
|
||||
comfyPageFixture as test,
|
||||
comfyExpect as expect
|
||||
} from '../fixtures/ComfyPage'
|
||||
import type { ComfyPage } from '../fixtures/ComfyPage'
|
||||
import type { AppModeHelper } from '../fixtures/helpers/AppModeHelper'
|
||||
import { setupBuilder } from '../helpers/builderTestUtils'
|
||||
import {
|
||||
builderSaveAs,
|
||||
openWorkflowFromSidebar,
|
||||
setupBuilder
|
||||
} from '../helpers/builderTestUtils'
|
||||
import { fitToViewInstant } from '../helpers/fitToView'
|
||||
|
||||
/**
|
||||
* Open the save-as dialog, fill name + view type, click save,
|
||||
* and wait for the success dialog.
|
||||
*/
|
||||
async function builderSaveAs(
|
||||
appMode: AppModeHelper,
|
||||
workflowName: string,
|
||||
viewType: 'App' | 'Node graph'
|
||||
) {
|
||||
await appMode.footer.saveAsButton.click()
|
||||
await expect(appMode.saveAs.nameInput).toBeVisible({ timeout: 5000 })
|
||||
await appMode.saveAs.fillAndSave(workflowName, viewType)
|
||||
await expect(appMode.saveAs.successMessage).toBeVisible({ timeout: 5000 })
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a different workflow, then reopen the named one from the sidebar.
|
||||
* Caller must ensure the page is in graph mode (not builder or app mode)
|
||||
* before calling.
|
||||
*/
|
||||
async function openWorkflowFromSidebar(comfyPage: ComfyPage, name: string) {
|
||||
await comfyPage.workflow.loadWorkflow('default')
|
||||
await comfyPage.nextFrame()
|
||||
const { workflowsTab } = comfyPage.menu
|
||||
await workflowsTab.open()
|
||||
await workflowsTab.getPersistedItem(name).dblclick()
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
await expect(async () => {
|
||||
const path = await comfyPage.workflow.getActiveWorkflowPath()
|
||||
expect(path).toContain(name)
|
||||
}).toPass({ timeout: 5000 })
|
||||
}
|
||||
|
||||
/**
|
||||
* After a first save, open save-as again from the chevron,
|
||||
* fill name + view type, and save.
|
||||
@@ -203,10 +172,9 @@ test.describe('Builder save flow', { tag: ['@ui'] }, () => {
|
||||
|
||||
// Select I/O to enable the button
|
||||
await appMode.steps.goToInputs()
|
||||
const ksampler = await comfyPage.nodeOps.getNodeRefById('3')
|
||||
await appMode.select.selectInputWidget(ksampler)
|
||||
await appMode.select.selectInputWidget('KSampler', 'seed')
|
||||
await appMode.steps.goToOutputs()
|
||||
await appMode.select.selectOutputNode()
|
||||
await appMode.select.selectOutputNode('Save Image')
|
||||
|
||||
// State 2: Enabled "Save as" (unsaved, has outputs)
|
||||
const enabledBox = await appMode.footer.saveAsButton.boundingBox()
|
||||
|
||||
Reference in New Issue
Block a user