mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-04 05:02:17 +00:00
test: add E2E regression tests for workflow tab save bug (#10815)
## Summary - Adds E2E regression tests for the bug fixed in PR #10745 where closing an inactive workflow tab would save the active workflow's content into the closing tab's file - Three test scenarios covering the full range of the bug surface: 1. Closing an unmodified inactive tab preserves both workflows 2. Closing a modified inactive tab with "Save" preserves its own content (not the active tab's) 3. Closing an unsaved inactive tab with "Save As" preserves its own content ## Linked Issues - Regression coverage for #10745 / Comfy-Org/ComfyUI#13230 ## Test plan - [ ] `pnpm exec playwright test browser_tests/tests/topbar/workflowTabSave.spec.ts` passes against the current main (with the fix) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10815-test-add-E2E-regression-tests-for-workflow-tab-save-bug-3366d73d365081eab409ed303620a959) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
@@ -33,35 +33,45 @@ test.describe('Change Tracker', { tag: '@workflow' }, () => {
|
||||
// Save, confirm no errors & workflow modified flag removed
|
||||
await comfyPage.menu.topbar.saveWorkflow('undo-redo-test')
|
||||
expect(await comfyPage.toast.getToastErrorCount()).toBe(0)
|
||||
expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(false)
|
||||
expect(await comfyPage.workflow.getUndoQueueSize()).toBe(0)
|
||||
expect(await comfyPage.workflow.getRedoQueueSize()).toBe(0)
|
||||
await expect
|
||||
.poll(() => comfyPage.workflow.isCurrentWorkflowModified())
|
||||
.toBe(false)
|
||||
await expect.poll(() => comfyPage.workflow.getUndoQueueSize()).toBe(0)
|
||||
await expect.poll(() => comfyPage.workflow.getRedoQueueSize()).toBe(0)
|
||||
|
||||
const node = (await comfyPage.nodeOps.getFirstNodeRef())!
|
||||
await node.click('title')
|
||||
await node.click('collapse')
|
||||
await expect(node).toBeCollapsed()
|
||||
expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(true)
|
||||
expect(await comfyPage.workflow.getUndoQueueSize()).toBe(1)
|
||||
expect(await comfyPage.workflow.getRedoQueueSize()).toBe(0)
|
||||
await expect
|
||||
.poll(() => comfyPage.workflow.isCurrentWorkflowModified())
|
||||
.toBe(true)
|
||||
await expect.poll(() => comfyPage.workflow.getUndoQueueSize()).toBe(1)
|
||||
await expect.poll(() => comfyPage.workflow.getRedoQueueSize()).toBe(0)
|
||||
|
||||
await comfyPage.keyboard.bypass()
|
||||
await expect(node).toBeBypassed()
|
||||
expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(true)
|
||||
expect(await comfyPage.workflow.getUndoQueueSize()).toBe(2)
|
||||
expect(await comfyPage.workflow.getRedoQueueSize()).toBe(0)
|
||||
await expect
|
||||
.poll(() => comfyPage.workflow.isCurrentWorkflowModified())
|
||||
.toBe(true)
|
||||
await expect.poll(() => comfyPage.workflow.getUndoQueueSize()).toBe(2)
|
||||
await expect.poll(() => comfyPage.workflow.getRedoQueueSize()).toBe(0)
|
||||
|
||||
await comfyPage.keyboard.undo()
|
||||
await expect(node).not.toBeBypassed()
|
||||
expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(true)
|
||||
expect(await comfyPage.workflow.getUndoQueueSize()).toBe(1)
|
||||
expect(await comfyPage.workflow.getRedoQueueSize()).toBe(1)
|
||||
await expect
|
||||
.poll(() => comfyPage.workflow.isCurrentWorkflowModified())
|
||||
.toBe(true)
|
||||
await expect.poll(() => comfyPage.workflow.getUndoQueueSize()).toBe(1)
|
||||
await expect.poll(() => comfyPage.workflow.getRedoQueueSize()).toBe(1)
|
||||
|
||||
await comfyPage.keyboard.undo()
|
||||
await expect(node).not.toBeCollapsed()
|
||||
expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(false)
|
||||
expect(await comfyPage.workflow.getUndoQueueSize()).toBe(0)
|
||||
expect(await comfyPage.workflow.getRedoQueueSize()).toBe(2)
|
||||
await expect
|
||||
.poll(() => comfyPage.workflow.isCurrentWorkflowModified())
|
||||
.toBe(false)
|
||||
await expect.poll(() => comfyPage.workflow.getUndoQueueSize()).toBe(0)
|
||||
await expect.poll(() => comfyPage.workflow.getRedoQueueSize()).toBe(2)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -323,6 +323,71 @@ test.describe('Workflow Persistence', () => {
|
||||
expect(linkCountAfter).toBe(linkCountBefore)
|
||||
})
|
||||
|
||||
test('Closing an unmodified inactive tab preserves both workflows', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
test.info().annotations.push({
|
||||
type: 'regression',
|
||||
description:
|
||||
'PR #10745 — closing inactive tab could corrupt the persisted file'
|
||||
})
|
||||
|
||||
await comfyPage.settings.setSetting(
|
||||
'Comfy.Workflow.WorkflowTabsPosition',
|
||||
'Topbar'
|
||||
)
|
||||
|
||||
const suffix = Date.now().toString(36)
|
||||
const nameA = `test-A-${suffix}`
|
||||
const nameB = `test-B-${suffix}`
|
||||
|
||||
// Save the default workflow as A
|
||||
await comfyPage.menu.topbar.saveWorkflow(nameA)
|
||||
const nodeCountA = await comfyPage.nodeOps.getNodeCount()
|
||||
|
||||
// Create B: duplicate, add a node, then save (unmodified after save)
|
||||
await comfyPage.command.executeCommand('Comfy.DuplicateWorkflow')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
await comfyPage.page.evaluate(() => {
|
||||
window.app!.graph.add(window.LiteGraph!.createNode('Note', undefined, {}))
|
||||
})
|
||||
await comfyPage.nextFrame()
|
||||
await comfyPage.menu.topbar.saveWorkflow(nameB)
|
||||
|
||||
const nodeCountB = await comfyPage.nodeOps.getNodeCount()
|
||||
expect(nodeCountB).toBe(nodeCountA + 1)
|
||||
|
||||
// Switch to A (making B inactive and unmodified)
|
||||
await comfyPage.menu.topbar.getWorkflowTab(nameA).click()
|
||||
await comfyPage.workflow.waitForWorkflowIdle()
|
||||
await expect
|
||||
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 3000 })
|
||||
.toBe(nodeCountA)
|
||||
|
||||
// Close inactive B via middle-click — no save dialog expected
|
||||
await comfyPage.menu.topbar.getWorkflowTab(nameB).click({
|
||||
button: 'middle'
|
||||
})
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// A should still have its own content
|
||||
await expect
|
||||
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 3000 })
|
||||
.toBe(nodeCountA)
|
||||
|
||||
// Reopen B from saved list
|
||||
const workflowsTab = comfyPage.menu.workflowsTab
|
||||
await workflowsTab.open()
|
||||
await workflowsTab.getPersistedItem(nameB).dblclick()
|
||||
await comfyPage.workflow.waitForWorkflowIdle()
|
||||
|
||||
// B should have its original content, not A's
|
||||
await expect
|
||||
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 5000 })
|
||||
.toBe(nodeCountB)
|
||||
})
|
||||
|
||||
test('Closing an inactive tab with save preserves its own content', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
|
||||
Reference in New Issue
Block a user