diff --git a/browser_tests/tests/actionbar.spec.ts b/browser_tests/tests/actionbar.spec.ts index bd086b4610..1a18577d72 100644 --- a/browser_tests/tests/actionbar.spec.ts +++ b/browser_tests/tests/actionbar.spec.ts @@ -7,7 +7,7 @@ import { webSocketFixture } from '../fixtures/ws.ts' const test = mergeTests(comfyPageFixture, webSocketFixture) -test.describe('Actionbar', () => { +test.describe('Actionbar', { tag: '@ui' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') }) diff --git a/browser_tests/tests/bottomPanelShortcuts.spec.ts b/browser_tests/tests/bottomPanelShortcuts.spec.ts index 67a3670c53..354f0fb519 100644 --- a/browser_tests/tests/bottomPanelShortcuts.spec.ts +++ b/browser_tests/tests/bottomPanelShortcuts.spec.ts @@ -2,7 +2,7 @@ import { expect } from '@playwright/test' import { comfyPageFixture as test } from '../fixtures/ComfyPage' -test.describe('Bottom Panel Shortcuts', () => { +test.describe('Bottom Panel Shortcuts', { tag: '@ui' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') }) diff --git a/browser_tests/tests/browserTabTitle.spec.ts b/browser_tests/tests/browserTabTitle.spec.ts index fd855ea4af..f3ad9515e0 100644 --- a/browser_tests/tests/browserTabTitle.spec.ts +++ b/browser_tests/tests/browserTabTitle.spec.ts @@ -2,7 +2,7 @@ import { expect } from '@playwright/test' import { comfyPageFixture as test } from '../fixtures/ComfyPage' -test.describe('Browser tab title', () => { +test.describe('Browser tab title', { tag: '@smoke' }, () => { test.describe('Beta Menu', () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') diff --git a/browser_tests/tests/changeTracker.spec.ts b/browser_tests/tests/changeTracker.spec.ts index 8e39154f15..e115192c98 100644 --- a/browser_tests/tests/changeTracker.spec.ts +++ b/browser_tests/tests/changeTracker.spec.ts @@ -19,7 +19,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Change Tracker', () => { +test.describe('Change Tracker', { tag: '@workflow' }, () => { test.describe('Undo/Redo', () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') diff --git a/browser_tests/tests/colorPalette.spec.ts b/browser_tests/tests/colorPalette.spec.ts index 3bc1b9167b..0118955fb7 100644 --- a/browser_tests/tests/colorPalette.spec.ts +++ b/browser_tests/tests/colorPalette.spec.ts @@ -151,7 +151,7 @@ const customColorPalettes: Record = { } } -test.describe('Color Palette', () => { +test.describe('Color Palette', { tag: ['@screenshot', '@settings'] }, () => { test('Can show custom color palette', async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.CustomColorPalettes', customColorPalettes) // Reload to apply the new setting. Setting Comfy.CustomColorPalettes directly @@ -194,104 +194,110 @@ test.describe('Color Palette', () => { }) }) -test.describe('Node Color Adjustments', () => { - test.beforeEach(async ({ comfyPage }) => { - await comfyPage.loadWorkflow('nodes/every_node_color') - }) - - test('should adjust opacity via node opacity setting', async ({ - comfyPage - }) => { - await comfyPage.setSetting('Comfy.Node.Opacity', 0.5) - - // Drag mouse to force canvas to redraw - await comfyPage.page.mouse.move(0, 0) - - await expect(comfyPage.canvas).toHaveScreenshot('node-opacity-0.5.png') - - await comfyPage.setSetting('Comfy.Node.Opacity', 1.0) - - await comfyPage.page.mouse.move(8, 8) - await expect(comfyPage.canvas).toHaveScreenshot('node-opacity-1.png') - }) - - test('should persist color adjustments when changing themes', async ({ - comfyPage - }) => { - await comfyPage.setSetting('Comfy.Node.Opacity', 0.2) - await comfyPage.setSetting('Comfy.ColorPalette', 'arc') - await comfyPage.nextFrame() - await comfyPage.page.mouse.move(0, 0) - await expect(comfyPage.canvas).toHaveScreenshot( - 'node-opacity-0.2-arc-theme.png' - ) - }) - - test('should not serialize color adjustments in workflow', async ({ - comfyPage - }) => { - await comfyPage.setSetting('Comfy.Node.Opacity', 0.5) - await comfyPage.setSetting('Comfy.ColorPalette', 'light') - await comfyPage.nextFrame() - const parsed = await ( - await comfyPage.page.waitForFunction( - () => { - const workflow = localStorage.getItem('workflow') - if (!workflow) return null - try { - const data = JSON.parse(workflow) - return Array.isArray(data?.nodes) ? data : null - } catch { - return null - } - }, - { timeout: 3000 } - ) - ).jsonValue() - expect(parsed.nodes).toBeDefined() - expect(Array.isArray(parsed.nodes)).toBe(true) - for (const node of parsed.nodes) { - if (node.bgcolor) expect(node.bgcolor).not.toMatch(/hsla/) - if (node.color) expect(node.color).not.toMatch(/hsla/) - } - }) - - test('should lighten node colors when switching to light theme', async ({ - comfyPage - }) => { - await comfyPage.setSetting('Comfy.ColorPalette', 'light') - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot('node-lightened-colors.png') - }) - - test.describe('Context menu color adjustments', () => { +test.describe( + 'Node Color Adjustments', + { tag: ['@screenshot', '@settings'] }, + () => { test.beforeEach(async ({ comfyPage }) => { + await comfyPage.loadWorkflow('nodes/every_node_color') + }) + + test('should adjust opacity via node opacity setting', async ({ + comfyPage + }) => { + await comfyPage.setSetting('Comfy.Node.Opacity', 0.5) + + // Drag mouse to force canvas to redraw + await comfyPage.page.mouse.move(0, 0) + + await expect(comfyPage.canvas).toHaveScreenshot('node-opacity-0.5.png') + + await comfyPage.setSetting('Comfy.Node.Opacity', 1.0) + + await comfyPage.page.mouse.move(8, 8) + await expect(comfyPage.canvas).toHaveScreenshot('node-opacity-1.png') + }) + + test('should persist color adjustments when changing themes', async ({ + comfyPage + }) => { + await comfyPage.setSetting('Comfy.Node.Opacity', 0.2) + await comfyPage.setSetting('Comfy.ColorPalette', 'arc') + await comfyPage.nextFrame() + await comfyPage.page.mouse.move(0, 0) + await expect(comfyPage.canvas).toHaveScreenshot( + 'node-opacity-0.2-arc-theme.png' + ) + }) + + test('should not serialize color adjustments in workflow', async ({ + comfyPage + }) => { + await comfyPage.setSetting('Comfy.Node.Opacity', 0.5) await comfyPage.setSetting('Comfy.ColorPalette', 'light') - await comfyPage.setSetting('Comfy.Node.Opacity', 0.3) - const node = await comfyPage.getFirstNodeRef() - await node?.clickContextMenuOption('Colors') + await comfyPage.nextFrame() + const parsed = await ( + await comfyPage.page.waitForFunction( + () => { + const workflow = localStorage.getItem('workflow') + if (!workflow) return null + try { + const data = JSON.parse(workflow) + return Array.isArray(data?.nodes) ? data : null + } catch { + return null + } + }, + { timeout: 3000 } + ) + ).jsonValue() + expect(parsed.nodes).toBeDefined() + expect(Array.isArray(parsed.nodes)).toBe(true) + for (const node of parsed.nodes) { + if (node.bgcolor) expect(node.bgcolor).not.toMatch(/hsla/) + if (node.color) expect(node.color).not.toMatch(/hsla/) + } }) - test('should persist color adjustments when changing custom node colors', async ({ + test('should lighten node colors when switching to light theme', async ({ comfyPage }) => { - await comfyPage.page - .locator('.litemenu-entry.submenu span:has-text("red")') - .click() + await comfyPage.setSetting('Comfy.ColorPalette', 'light') + await comfyPage.nextFrame() await expect(comfyPage.canvas).toHaveScreenshot( - 'node-opacity-0.3-color-changed.png' + 'node-lightened-colors.png' ) }) - test('should persist color adjustments when removing custom node color', async ({ - comfyPage - }) => { - await comfyPage.page - .locator('.litemenu-entry.submenu span:has-text("No color")') - .click() - await expect(comfyPage.canvas).toHaveScreenshot( - 'node-opacity-0.3-color-removed.png' - ) + test.describe('Context menu color adjustments', () => { + test.beforeEach(async ({ comfyPage }) => { + await comfyPage.setSetting('Comfy.ColorPalette', 'light') + await comfyPage.setSetting('Comfy.Node.Opacity', 0.3) + const node = await comfyPage.getFirstNodeRef() + await node?.clickContextMenuOption('Colors') + }) + + test('should persist color adjustments when changing custom node colors', async ({ + comfyPage + }) => { + await comfyPage.page + .locator('.litemenu-entry.submenu span:has-text("red")') + .click() + await expect(comfyPage.canvas).toHaveScreenshot( + 'node-opacity-0.3-color-changed.png' + ) + }) + + test('should persist color adjustments when removing custom node color', async ({ + comfyPage + }) => { + await comfyPage.page + .locator('.litemenu-entry.submenu span:has-text("No color")') + .click() + await expect(comfyPage.canvas).toHaveScreenshot( + 'node-opacity-0.3-color-removed.png' + ) + }) }) - }) -}) + } +) diff --git a/browser_tests/tests/commands.spec.ts b/browser_tests/tests/commands.spec.ts index e271f2e15c..acf99d1772 100644 --- a/browser_tests/tests/commands.spec.ts +++ b/browser_tests/tests/commands.spec.ts @@ -6,7 +6,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Keybindings', () => { +test.describe('Keybindings', { tag: '@keyboard' }, () => { test('Should execute command', async ({ comfyPage }) => { await comfyPage.registerCommand('TestCommand', () => { window['foo'] = true diff --git a/browser_tests/tests/copyPaste.spec.ts b/browser_tests/tests/copyPaste.spec.ts index cabb849e80..a04cc191b5 100644 --- a/browser_tests/tests/copyPaste.spec.ts +++ b/browser_tests/tests/copyPaste.spec.ts @@ -6,7 +6,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Copy Paste', () => { +test.describe('Copy Paste', { tag: ['@screenshot', '@workflow'] }, () => { test('Can copy and paste node', async ({ comfyPage }) => { await comfyPage.clickEmptyLatentNode() await comfyPage.page.mouse.move(10, 10) diff --git a/browser_tests/tests/customIcons.spec.ts b/browser_tests/tests/customIcons.spec.ts index da640fd895..eb4eccfd54 100644 --- a/browser_tests/tests/customIcons.spec.ts +++ b/browser_tests/tests/customIcons.spec.ts @@ -22,7 +22,7 @@ async function verifyCustomIconSvg(iconElement: Locator) { expect(decodedSvg).toContain(" { +test.describe('Custom Icons', { tag: '@settings' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') }) diff --git a/browser_tests/tests/dialog.spec.ts b/browser_tests/tests/dialog.spec.ts index 081f472753..dd190f2a5e 100644 --- a/browser_tests/tests/dialog.spec.ts +++ b/browser_tests/tests/dialog.spec.ts @@ -8,7 +8,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Load workflow warning', () => { +test.describe('Load workflow warning', { tag: '@ui' }, () => { test('Should display a warning when loading a workflow with missing nodes', async ({ comfyPage }) => { diff --git a/browser_tests/tests/domWidget.spec.ts b/browser_tests/tests/domWidget.spec.ts index 02392f51d5..d0468210e8 100644 --- a/browser_tests/tests/domWidget.spec.ts +++ b/browser_tests/tests/domWidget.spec.ts @@ -6,7 +6,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('DOM Widget', () => { +test.describe('DOM Widget', { tag: '@widget' }, () => { test('Collapsed multiline textarea is not visible', async ({ comfyPage }) => { await comfyPage.loadWorkflow('widgets/collapsed_multiline') const textareaWidget = comfyPage.page.locator('.comfy-multiline-input') @@ -29,12 +29,16 @@ test.describe('DOM Widget', () => { await expect(lastMultiline).not.toBeVisible() }) - test('Position update when entering focus mode', async ({ comfyPage }) => { - await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') - await comfyPage.executeCommand('Workspace.ToggleFocusMode') - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot('focus-mode-on.png') - }) + test( + 'Position update when entering focus mode', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') + await comfyPage.executeCommand('Workspace.ToggleFocusMode') + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot('focus-mode-on.png') + } + ) // No DOM widget should be created by creation of interim LGraphNode objects. test('Copy node with DOM widget by dragging + alt', async ({ comfyPage }) => { diff --git a/browser_tests/tests/execution.spec.ts b/browser_tests/tests/execution.spec.ts index ba22b38e96..2173c86234 100644 --- a/browser_tests/tests/execution.spec.ts +++ b/browser_tests/tests/execution.spec.ts @@ -6,40 +6,48 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Execution', () => { - test('Report error on unconnected slot', async ({ comfyPage }) => { - await comfyPage.disconnectEdge() - await comfyPage.clickEmptySpace() +test.describe('Execution', { tag: ['@smoke', '@workflow'] }, () => { + test( + 'Report error on unconnected slot', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.disconnectEdge() + await comfyPage.clickEmptySpace() - await comfyPage.executeCommand('Comfy.QueuePrompt') - await expect(comfyPage.page.locator('.comfy-error-report')).toBeVisible() - await comfyPage.page.locator('.p-dialog-close-button').click() - await comfyPage.page.locator('.comfy-error-report').waitFor({ - state: 'hidden' - }) - await expect(comfyPage.canvas).toHaveScreenshot( - 'execution-error-unconnected-slot.png' - ) - }) + await comfyPage.executeCommand('Comfy.QueuePrompt') + await expect(comfyPage.page.locator('.comfy-error-report')).toBeVisible() + await comfyPage.page.locator('.p-dialog-close-button').click() + await comfyPage.page.locator('.comfy-error-report').waitFor({ + state: 'hidden' + }) + await expect(comfyPage.canvas).toHaveScreenshot( + 'execution-error-unconnected-slot.png' + ) + } + ) }) -test.describe('Execute to selected output nodes', () => { - test('Execute to selected output nodes', async ({ comfyPage }) => { - await comfyPage.loadWorkflow('execution/partial_execution') - const input = await comfyPage.getNodeRefById(3) - const output1 = await comfyPage.getNodeRefById(1) - const output2 = await comfyPage.getNodeRefById(4) - expect(await (await input.getWidget(0)).getValue()).toBe('foo') - expect(await (await output1.getWidget(0)).getValue()).toBe('') - expect(await (await output2.getWidget(0)).getValue()).toBe('') - - await output1.click('title') - - await comfyPage.executeCommand('Comfy.QueueSelectedOutputNodes') - await expect(async () => { +test.describe( + 'Execute to selected output nodes', + { tag: ['@smoke', '@workflow'] }, + () => { + test('Execute to selected output nodes', async ({ comfyPage }) => { + await comfyPage.loadWorkflow('execution/partial_execution') + const input = await comfyPage.getNodeRefById(3) + const output1 = await comfyPage.getNodeRefById(1) + const output2 = await comfyPage.getNodeRefById(4) expect(await (await input.getWidget(0)).getValue()).toBe('foo') - expect(await (await output1.getWidget(0)).getValue()).toBe('foo') + expect(await (await output1.getWidget(0)).getValue()).toBe('') expect(await (await output2.getWidget(0)).getValue()).toBe('') - }).toPass({ timeout: 2_000 }) - }) -}) + + await output1.click('title') + + await comfyPage.executeCommand('Comfy.QueueSelectedOutputNodes') + await expect(async () => { + expect(await (await input.getWidget(0)).getValue()).toBe('foo') + expect(await (await output1.getWidget(0)).getValue()).toBe('foo') + expect(await (await output2.getWidget(0)).getValue()).toBe('') + }).toPass({ timeout: 2_000 }) + }) + } +) diff --git a/browser_tests/tests/featureFlags.spec.ts b/browser_tests/tests/featureFlags.spec.ts index 9155ae9108..73f1cd2f57 100644 --- a/browser_tests/tests/featureFlags.spec.ts +++ b/browser_tests/tests/featureFlags.spec.ts @@ -6,7 +6,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Feature Flags', () => { +test.describe('Feature Flags', { tag: ['@slow', '@settings'] }, () => { test('Client and server exchange feature flags on connection', async ({ comfyPage }) => { diff --git a/browser_tests/tests/graph.spec.ts b/browser_tests/tests/graph.spec.ts index 0c021b5f2b..340b5b6977 100644 --- a/browser_tests/tests/graph.spec.ts +++ b/browser_tests/tests/graph.spec.ts @@ -6,7 +6,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Graph', () => { +test.describe('Graph', { tag: ['@smoke', '@canvas'] }, () => { // Should be able to fix link input slot index after swap the input order // Ref: https://github.com/Comfy-Org/ComfyUI_frontend/issues/3348 test('Fix link input slots', async ({ comfyPage }) => { diff --git a/browser_tests/tests/graphCanvasMenu.spec.ts b/browser_tests/tests/graphCanvasMenu.spec.ts index fc8385e497..4e6d1b2fb3 100644 --- a/browser_tests/tests/graphCanvasMenu.spec.ts +++ b/browser_tests/tests/graphCanvasMenu.spec.ts @@ -6,7 +6,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Graph Canvas Menu', () => { +test.describe('Graph Canvas Menu', { tag: ['@screenshot', '@canvas'] }, () => { test.beforeEach(async ({ comfyPage }) => { // Set link render mode to spline to make sure it's not affected by other tests' // side effects. @@ -15,29 +15,33 @@ test.describe('Graph Canvas Menu', () => { await comfyPage.setSetting('Comfy.Graph.CanvasMenu', true) }) - test('Can toggle link visibility', async ({ comfyPage }) => { - const button = comfyPage.page.getByTestId('toggle-link-visibility-button') - await button.click() - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot( - 'canvas-with-hidden-links.png' - ) - const hiddenLinkRenderMode = await comfyPage.page.evaluate(() => { - return window['LiteGraph'].HIDDEN_LINK - }) - expect(await comfyPage.getSetting('Comfy.LinkRenderMode')).toBe( - hiddenLinkRenderMode - ) + test( + 'Can toggle link visibility', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + const button = comfyPage.page.getByTestId('toggle-link-visibility-button') + await button.click() + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot( + 'canvas-with-hidden-links.png' + ) + const hiddenLinkRenderMode = await comfyPage.page.evaluate(() => { + return window['LiteGraph'].HIDDEN_LINK + }) + expect(await comfyPage.getSetting('Comfy.LinkRenderMode')).toBe( + hiddenLinkRenderMode + ) - await button.click() - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot( - 'canvas-with-visible-links.png' - ) - expect(await comfyPage.getSetting('Comfy.LinkRenderMode')).not.toBe( - hiddenLinkRenderMode - ) - }) + await button.click() + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot( + 'canvas-with-visible-links.png' + ) + expect(await comfyPage.getSetting('Comfy.LinkRenderMode')).not.toBe( + hiddenLinkRenderMode + ) + } + ) test('Toggle minimap button is clickable and has correct test id', async ({ comfyPage diff --git a/browser_tests/tests/groupNode.spec.ts b/browser_tests/tests/groupNode.spec.ts index 9d67a0951a..9dbbe58f83 100644 --- a/browser_tests/tests/groupNode.spec.ts +++ b/browser_tests/tests/groupNode.spec.ts @@ -8,7 +8,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Group Node', () => { +test.describe('Group Node', { tag: '@node' }, () => { test.describe('Node library sidebar', () => { const groupNodeName = 'DefautWorkflowGroupNode' const groupNodeCategory = 'group nodes>workflow' @@ -89,16 +89,20 @@ test.describe('Group Node', () => { // does not have a v-model on the query, so we cannot observe the raw // query update, and thus cannot set the spinning state between the raw query // update and the debounced search update. - test.skip('Can be added to canvas using search', async ({ comfyPage }) => { - const groupNodeName = 'DefautWorkflowGroupNode' - await comfyPage.convertAllNodesToGroupNode(groupNodeName) - await comfyPage.doubleClickCanvas() - await comfyPage.nextFrame() - await comfyPage.searchBox.fillAndSelectFirstNode(groupNodeName) - await expect(comfyPage.canvas).toHaveScreenshot( - 'group-node-copy-added-from-search.png' - ) - }) + test.skip( + 'Can be added to canvas using search', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + const groupNodeName = 'DefautWorkflowGroupNode' + await comfyPage.convertAllNodesToGroupNode(groupNodeName) + await comfyPage.doubleClickCanvas() + await comfyPage.nextFrame() + await comfyPage.searchBox.fillAndSelectFirstNode(groupNodeName) + await expect(comfyPage.canvas).toHaveScreenshot( + 'group-node-copy-added-from-search.png' + ) + } + ) test('Displays tooltip on title hover', async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.EnableTooltips', true) diff --git a/browser_tests/tests/interaction.spec.ts b/browser_tests/tests/interaction.spec.ts index 451cbffa3d..a7bcc651d5 100644 --- a/browser_tests/tests/interaction.spec.ts +++ b/browser_tests/tests/interaction.spec.ts @@ -13,7 +13,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Item Interaction', () => { +test.describe('Item Interaction', { tag: ['@screenshot', '@node'] }, () => { test('Can select/delete all items', async ({ comfyPage }) => { await comfyPage.loadWorkflow('groups/mixed_graph_items') await comfyPage.canvas.press('Control+a') @@ -60,13 +60,17 @@ test.describe('Node Interaction', () => { }) }) - test('@2x Can highlight selected', async ({ comfyPage }) => { - await expect(comfyPage.canvas).toHaveScreenshot('default.png') - await comfyPage.clickTextEncodeNode1() - await expect(comfyPage.canvas).toHaveScreenshot('selected-node1.png') - await comfyPage.clickTextEncodeNode2() - await expect(comfyPage.canvas).toHaveScreenshot('selected-node2.png') - }) + test( + '@2x Can highlight selected', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await expect(comfyPage.canvas).toHaveScreenshot('default.png') + await comfyPage.clickTextEncodeNode1() + await expect(comfyPage.canvas).toHaveScreenshot('selected-node1.png') + await comfyPage.clickTextEncodeNode2() + await expect(comfyPage.canvas).toHaveScreenshot('selected-node2.png') + } + ) const dragSelectNodes = async ( comfyPage: ComfyPage, @@ -150,12 +154,12 @@ test.describe('Node Interaction', () => { }) }) - test('Can drag node', async ({ comfyPage }) => { + test('Can drag node', { tag: '@screenshot' }, async ({ comfyPage }) => { await comfyPage.dragNode2() await expect(comfyPage.canvas).toHaveScreenshot('dragged-node1.png') }) - test.describe('Edge Interaction', () => { + test.describe('Edge Interaction', { tag: '@screenshot' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.LinkRelease.Action', 'no action') await comfyPage.setSetting('Comfy.LinkRelease.ActionShift', 'no action') @@ -222,12 +226,18 @@ test.describe('Node Interaction', () => { }) }) - test('Can adjust widget value', async ({ comfyPage }) => { - await comfyPage.adjustWidgetValue() - await expect(comfyPage.canvas).toHaveScreenshot('adjusted-widget-value.png') - }) + test( + 'Can adjust widget value', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.adjustWidgetValue() + await expect(comfyPage.canvas).toHaveScreenshot( + 'adjusted-widget-value.png' + ) + } + ) - test('Link snap to slot', async ({ comfyPage }) => { + test('Link snap to slot', { tag: '@screenshot' }, async ({ comfyPage }) => { await comfyPage.loadWorkflow('links/snap_to_slot') await expect(comfyPage.canvas).toHaveScreenshot('snap_to_slot.png') @@ -244,57 +254,67 @@ test.describe('Node Interaction', () => { await expect(comfyPage.canvas).toHaveScreenshot('snap_to_slot_linked.png') }) - test('Can batch move links by drag with shift', async ({ comfyPage }) => { - await comfyPage.loadWorkflow('links/batch_move_links') - await expect(comfyPage.canvas).toHaveScreenshot('batch_move_links.png') + test( + 'Can batch move links by drag with shift', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.loadWorkflow('links/batch_move_links') + await expect(comfyPage.canvas).toHaveScreenshot('batch_move_links.png') - const outputSlot1Pos = { - x: 304, - y: 127 + const outputSlot1Pos = { + x: 304, + y: 127 + } + const outputSlot2Pos = { + x: 307, + y: 310 + } + + await comfyPage.page.keyboard.down('Shift') + await comfyPage.dragAndDrop(outputSlot1Pos, outputSlot2Pos) + await comfyPage.page.keyboard.up('Shift') + + await expect(comfyPage.canvas).toHaveScreenshot( + 'batch_move_links_moved.png' + ) } - const outputSlot2Pos = { - x: 307, - y: 310 + ) + + test( + 'Can batch disconnect links with ctrl+alt+click', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + const loadCheckpointClipSlotPos = { + x: 332, + y: 508 + } + await comfyPage.canvas.click({ + modifiers: ['Control', 'Alt'], + position: loadCheckpointClipSlotPos + }) + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot( + 'batch-disconnect-links-disconnected.png' + ) } + ) - await comfyPage.page.keyboard.down('Shift') - await comfyPage.dragAndDrop(outputSlot1Pos, outputSlot2Pos) - await comfyPage.page.keyboard.up('Shift') - - await expect(comfyPage.canvas).toHaveScreenshot( - 'batch_move_links_moved.png' - ) - }) - - test('Can batch disconnect links with ctrl+alt+click', async ({ - comfyPage - }) => { - const loadCheckpointClipSlotPos = { - x: 332, - y: 508 + test( + 'Can toggle dom widget node open/closed', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await expect(comfyPage.canvas).toHaveScreenshot('default.png') + await comfyPage.clickTextEncodeNodeToggler() + await expect(comfyPage.canvas).toHaveScreenshot( + 'text-encode-toggled-off.png' + ) + await comfyPage.delay(1000) + await comfyPage.clickTextEncodeNodeToggler() + await expect(comfyPage.canvas).toHaveScreenshot( + 'text-encode-toggled-back-open.png' + ) } - await comfyPage.canvas.click({ - modifiers: ['Control', 'Alt'], - position: loadCheckpointClipSlotPos - }) - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot( - 'batch-disconnect-links-disconnected.png' - ) - }) - - test('Can toggle dom widget node open/closed', async ({ comfyPage }) => { - await expect(comfyPage.canvas).toHaveScreenshot('default.png') - await comfyPage.clickTextEncodeNodeToggler() - await expect(comfyPage.canvas).toHaveScreenshot( - 'text-encode-toggled-off.png' - ) - await comfyPage.delay(1000) - await comfyPage.clickTextEncodeNodeToggler() - await expect(comfyPage.canvas).toHaveScreenshot( - 'text-encode-toggled-back-open.png' - ) - }) + ) test('Can close prompt dialog with canvas click (number widget)', async ({ comfyPage @@ -341,19 +361,23 @@ test.describe('Node Interaction', () => { await expect(legacyPrompt).toBeHidden() }) - test('Can double click node title to edit', async ({ comfyPage }) => { - await comfyPage.loadWorkflow('nodes/single_ksampler') - await comfyPage.canvas.dblclick({ - position: { - x: 50, - y: 10 - }, - delay: 5 - }) - await comfyPage.page.keyboard.type('Hello World') - await comfyPage.page.keyboard.press('Enter') - await expect(comfyPage.canvas).toHaveScreenshot('node-title-edited.png') - }) + test( + 'Can double click node title to edit', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.loadWorkflow('nodes/single_ksampler') + await comfyPage.canvas.dblclick({ + position: { + x: 50, + y: 10 + }, + delay: 5 + }) + await comfyPage.page.keyboard.type('Hello World') + await comfyPage.page.keyboard.press('Enter') + await expect(comfyPage.canvas).toHaveScreenshot('node-title-edited.png') + } + ) test('Double click node body does not trigger edit', async ({ comfyPage @@ -369,29 +393,41 @@ test.describe('Node Interaction', () => { expect(await comfyPage.page.locator('.node-title-editor').count()).toBe(0) }) - test('Can group selected nodes', async ({ comfyPage }) => { - await comfyPage.setSetting('Comfy.GroupSelectedNodes.Padding', 10) - await comfyPage.select2Nodes() - await comfyPage.page.keyboard.down('Control') - await comfyPage.page.keyboard.press('KeyG') - await comfyPage.page.keyboard.up('Control') - await comfyPage.nextFrame() - // Confirm group title - await comfyPage.page.keyboard.press('Enter') - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot('group-selected-nodes.png') - }) + test( + 'Can group selected nodes', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.setSetting('Comfy.GroupSelectedNodes.Padding', 10) + await comfyPage.select2Nodes() + await comfyPage.page.keyboard.down('Control') + await comfyPage.page.keyboard.press('KeyG') + await comfyPage.page.keyboard.up('Control') + await comfyPage.nextFrame() + // Confirm group title + await comfyPage.page.keyboard.press('Enter') + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot( + 'group-selected-nodes.png' + ) + } + ) - test('Can fit group to contents', async ({ comfyPage }) => { - await comfyPage.loadWorkflow('groups/oversized_group') - await comfyPage.ctrlA() - await comfyPage.nextFrame() - await comfyPage.executeCommand('Comfy.Graph.FitGroupToContents') - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot('group-fit-to-contents.png') - }) + test( + 'Can fit group to contents', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.loadWorkflow('groups/oversized_group') + await comfyPage.ctrlA() + await comfyPage.nextFrame() + await comfyPage.executeCommand('Comfy.Graph.FitGroupToContents') + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot( + 'group-fit-to-contents.png' + ) + } + ) - test('Can pin/unpin nodes', async ({ comfyPage }) => { + test('Can pin/unpin nodes', { tag: '@screenshot' }, async ({ comfyPage }) => { await comfyPage.select2Nodes() await comfyPage.executeCommand('Comfy.Canvas.ToggleSelectedNodes.Pin') await comfyPage.nextFrame() @@ -401,20 +437,22 @@ test.describe('Node Interaction', () => { await expect(comfyPage.canvas).toHaveScreenshot('nodes-unpinned.png') }) - test('Can bypass/unbypass nodes with keyboard shortcut', async ({ - comfyPage - }) => { - await comfyPage.select2Nodes() - await comfyPage.canvas.press('Control+b') - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot('nodes-bypassed.png') - await comfyPage.canvas.press('Control+b') - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot('nodes-unbypassed.png') - }) + test( + 'Can bypass/unbypass nodes with keyboard shortcut', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.select2Nodes() + await comfyPage.canvas.press('Control+b') + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot('nodes-bypassed.png') + await comfyPage.canvas.press('Control+b') + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot('nodes-unbypassed.png') + } + ) }) -test.describe('Group Interaction', () => { +test.describe('Group Interaction', { tag: '@screenshot' }, () => { test('Can double click group title to edit', async ({ comfyPage }) => { await comfyPage.loadWorkflow('groups/single_group') await comfyPage.canvas.dblclick({ @@ -430,7 +468,7 @@ test.describe('Group Interaction', () => { }) }) -test.describe('Canvas Interaction', () => { +test.describe('Canvas Interaction', { tag: '@screenshot' }, () => { test('Can zoom in/out', async ({ comfyPage }) => { await comfyPage.zoom(-100) await expect(comfyPage.canvas).toHaveScreenshot('zoomed-in.png') @@ -632,7 +670,7 @@ test.describe('Widget Interaction', () => { }) }) -test.describe('Load workflow', () => { +test.describe('Load workflow', { tag: '@screenshot' }, () => { test('Can load workflow with string node id', async ({ comfyPage }) => { await comfyPage.loadWorkflow('nodes/string_node_id') await expect(comfyPage.canvas).toHaveScreenshot('string_node_id.png') @@ -824,7 +862,7 @@ test.describe('Viewport settings', () => { }) }) -test.describe('Canvas Navigation', () => { +test.describe('Canvas Navigation', { tag: '@screenshot' }, () => { test.describe('Legacy Mode', () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.Canvas.NavigationMode', 'legacy') diff --git a/browser_tests/tests/keybindings.spec.ts b/browser_tests/tests/keybindings.spec.ts index f4244ae669..feb3b0f5d4 100644 --- a/browser_tests/tests/keybindings.spec.ts +++ b/browser_tests/tests/keybindings.spec.ts @@ -6,7 +6,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Keybindings', () => { +test.describe('Keybindings', { tag: '@keyboard' }, () => { test('Should not trigger non-modifier keybinding when typing in input fields', async ({ comfyPage }) => { diff --git a/browser_tests/tests/litegraphEvent.spec.ts b/browser_tests/tests/litegraphEvent.spec.ts index 184943fe05..12d6ec9c4c 100644 --- a/browser_tests/tests/litegraphEvent.spec.ts +++ b/browser_tests/tests/litegraphEvent.spec.ts @@ -14,7 +14,7 @@ function listenForEvent(): Promise { }) } -test.describe('Canvas Event', () => { +test.describe('Canvas Event', { tag: '@canvas' }, () => { test('Emit litegraph:canvas empty-release', async ({ comfyPage }) => { const eventPromise = comfyPage.page.evaluate(listenForEvent) const disconnectPromise = comfyPage.disconnectEdge() diff --git a/browser_tests/tests/loadWorkflowInMedia.spec.ts b/browser_tests/tests/loadWorkflowInMedia.spec.ts index 3a7f7a71a6..754f373a7b 100644 --- a/browser_tests/tests/loadWorkflowInMedia.spec.ts +++ b/browser_tests/tests/loadWorkflowInMedia.spec.ts @@ -6,46 +6,50 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Load Workflow in Media', () => { - const fileNames = [ - 'workflow.webp', - 'edited_workflow.webp', - 'no_workflow.webp', - 'large_workflow.webp', - 'workflow_prompt_parameters.png', - 'workflow.webm', - // Skipped due to 3d widget unstable visual result. - // 3d widget shows grid after fully loaded. - // 'workflow.glb', - 'workflow.mp4', - 'workflow.mov', - 'workflow.m4v', - 'workflow.svg' - // TODO: Re-enable after fixing test asset to use core nodes only - // Currently opens missing nodes dialog which is outside scope of AVIF loading functionality - // 'workflow.avif' - ] - fileNames.forEach(async (fileName) => { - test(`Load workflow in ${fileName} (drop from filesystem)`, async ({ - comfyPage - }) => { - await comfyPage.dragAndDropFile(`workflowInMedia/${fileName}`) - await expect(comfyPage.canvas).toHaveScreenshot(`${fileName}.png`) +test.describe( + 'Load Workflow in Media', + { tag: ['@screenshot', '@workflow'] }, + () => { + const fileNames = [ + 'workflow.webp', + 'edited_workflow.webp', + 'no_workflow.webp', + 'large_workflow.webp', + 'workflow_prompt_parameters.png', + 'workflow.webm', + // Skipped due to 3d widget unstable visual result. + // 3d widget shows grid after fully loaded. + // 'workflow.glb', + 'workflow.mp4', + 'workflow.mov', + 'workflow.m4v', + 'workflow.svg' + // TODO: Re-enable after fixing test asset to use core nodes only + // Currently opens missing nodes dialog which is outside scope of AVIF loading functionality + // 'workflow.avif' + ] + fileNames.forEach(async (fileName) => { + test(`Load workflow in ${fileName} (drop from filesystem)`, async ({ + comfyPage + }) => { + await comfyPage.dragAndDropFile(`workflowInMedia/${fileName}`) + await expect(comfyPage.canvas).toHaveScreenshot(`${fileName}.png`) + }) }) - }) - const urls = [ - 'https://comfyanonymous.github.io/ComfyUI_examples/hidream/hidream_dev_example.png' - ] - urls.forEach(async (url) => { - test(`Load workflow from URL ${url} (drop from different browser tabs)`, async ({ - comfyPage - }) => { - await comfyPage.dragAndDropURL(url) - const readableName = url.split('/').pop() - await expect(comfyPage.canvas).toHaveScreenshot( - `dropped_workflow_url_${readableName}.png` - ) + const urls = [ + 'https://comfyanonymous.github.io/ComfyUI_examples/hidream/hidream_dev_example.png' + ] + urls.forEach(async (url) => { + test(`Load workflow from URL ${url} (drop from different browser tabs)`, async ({ + comfyPage + }) => { + await comfyPage.dragAndDropURL(url) + const readableName = url.split('/').pop() + await expect(comfyPage.canvas).toHaveScreenshot( + `dropped_workflow_url_${readableName}.png` + ) + }) }) - }) -}) + } +) diff --git a/browser_tests/tests/lodThreshold.spec.ts b/browser_tests/tests/lodThreshold.spec.ts index 154ac3c16f..e1098cd280 100644 --- a/browser_tests/tests/lodThreshold.spec.ts +++ b/browser_tests/tests/lodThreshold.spec.ts @@ -6,7 +6,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('LOD Threshold', () => { +test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => { test('Should switch to low quality mode at correct zoom threshold', async ({ comfyPage }) => { @@ -149,53 +149,55 @@ test.describe('LOD Threshold', () => { expect(state.scale).toBeLessThan(0.2) // Very zoomed out }) - test('Should show visual difference between LOD on and off', async ({ - comfyPage - }) => { - // Load a workflow with text-heavy nodes for clear visual difference - await comfyPage.loadWorkflow('default') + test( + 'Should show visual difference between LOD on and off', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + // Load a workflow with text-heavy nodes for clear visual difference + await comfyPage.loadWorkflow('default') - // Set zoom level clearly below the threshold to ensure LOD activates - const targetZoom = 0.4 // Well below default threshold of ~0.571 + // Set zoom level clearly below the threshold to ensure LOD activates + const targetZoom = 0.4 // Well below default threshold of ~0.571 - // Zoom to target level - await comfyPage.page.evaluate((zoom) => { - window['app'].canvas.ds.scale = zoom - window['app'].canvas.setDirty(true, true) - }, targetZoom) - await comfyPage.nextFrame() + // Zoom to target level + await comfyPage.page.evaluate((zoom) => { + window['app'].canvas.ds.scale = zoom + window['app'].canvas.setDirty(true, true) + }, targetZoom) + await comfyPage.nextFrame() - // Take snapshot with LOD active (default 8px setting) - await expect(comfyPage.canvas).toHaveScreenshot( - 'lod-comparison-low-quality.png' - ) + // Take snapshot with LOD active (default 8px setting) + await expect(comfyPage.canvas).toHaveScreenshot( + 'lod-comparison-low-quality.png' + ) - const lowQualityState = await comfyPage.page.evaluate(() => { - const canvas = window['app'].canvas - return { - lowQuality: canvas.low_quality, - scale: canvas.ds.scale - } - }) - expect(lowQualityState.lowQuality).toBe(true) + const lowQualityState = await comfyPage.page.evaluate(() => { + const canvas = window['app'].canvas + return { + lowQuality: canvas.low_quality, + scale: canvas.ds.scale + } + }) + expect(lowQualityState.lowQuality).toBe(true) - // Disable LOD to see high quality at same zoom - await comfyPage.setSetting('LiteGraph.Canvas.MinFontSizeForLOD', 0) - await comfyPage.nextFrame() + // Disable LOD to see high quality at same zoom + await comfyPage.setSetting('LiteGraph.Canvas.MinFontSizeForLOD', 0) + await comfyPage.nextFrame() - // Take snapshot with LOD disabled (full quality at same zoom) - await expect(comfyPage.canvas).toHaveScreenshot( - 'lod-comparison-high-quality.png' - ) + // Take snapshot with LOD disabled (full quality at same zoom) + await expect(comfyPage.canvas).toHaveScreenshot( + 'lod-comparison-high-quality.png' + ) - const highQualityState = await comfyPage.page.evaluate(() => { - const canvas = window['app'].canvas - return { - lowQuality: canvas.low_quality, - scale: canvas.ds.scale - } - }) - expect(highQualityState.lowQuality).toBe(false) - expect(highQualityState.scale).toBeCloseTo(targetZoom, 2) - }) + const highQualityState = await comfyPage.page.evaluate(() => { + const canvas = window['app'].canvas + return { + lowQuality: canvas.low_quality, + scale: canvas.ds.scale + } + }) + expect(highQualityState.lowQuality).toBe(false) + expect(highQualityState.scale).toBeCloseTo(targetZoom, 2) + } + ) }) diff --git a/browser_tests/tests/menu.spec.ts b/browser_tests/tests/menu.spec.ts index 1ba1e55240..06ab9a9a88 100644 --- a/browser_tests/tests/menu.spec.ts +++ b/browser_tests/tests/menu.spec.ts @@ -2,7 +2,7 @@ import { expect } from '@playwright/test' import { comfyPageFixture as test } from '../fixtures/ComfyPage' -test.describe('Menu', () => { +test.describe('Menu', { tag: '@ui' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') }) diff --git a/browser_tests/tests/minimap.spec.ts b/browser_tests/tests/minimap.spec.ts index cea5fe9a80..b30adb933a 100644 --- a/browser_tests/tests/minimap.spec.ts +++ b/browser_tests/tests/minimap.spec.ts @@ -2,7 +2,7 @@ import { expect } from '@playwright/test' import { comfyPageFixture as test } from '../fixtures/ComfyPage' -test.describe('Minimap', () => { +test.describe('Minimap', { tag: '@canvas' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') await comfyPage.setSetting('Comfy.Minimap.Visible', true) diff --git a/browser_tests/tests/mobileBaseline.spec.ts b/browser_tests/tests/mobileBaseline.spec.ts index ff766a4347..9e9ddec943 100644 --- a/browser_tests/tests/mobileBaseline.spec.ts +++ b/browser_tests/tests/mobileBaseline.spec.ts @@ -1,35 +1,39 @@ import { comfyPageFixture as test } from '../fixtures/ComfyPage' import { expect } from '@playwright/test' -test.describe('Mobile Baseline Snapshots', () => { - test('@mobile empty canvas', async ({ comfyPage }) => { - await comfyPage.setSetting('Comfy.ConfirmClear', false) - await comfyPage.executeCommand('Comfy.ClearWorkflow') - await expect(async () => { - expect(await comfyPage.getGraphNodesCount()).toBe(0) - }).toPass({ timeout: 256 }) - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot('mobile-empty-canvas.png') - }) +test.describe( + 'Mobile Baseline Snapshots', + { tag: ['@mobile', '@screenshot'] }, + () => { + test('@mobile empty canvas', async ({ comfyPage }) => { + await comfyPage.setSetting('Comfy.ConfirmClear', false) + await comfyPage.executeCommand('Comfy.ClearWorkflow') + await expect(async () => { + expect(await comfyPage.getGraphNodesCount()).toBe(0) + }).toPass({ timeout: 256 }) + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot('mobile-empty-canvas.png') + }) - test('@mobile default workflow', async ({ comfyPage }) => { - await comfyPage.loadWorkflow('default') - await expect(comfyPage.canvas).toHaveScreenshot( - 'mobile-default-workflow.png' - ) - }) + test('@mobile default workflow', async ({ comfyPage }) => { + await comfyPage.loadWorkflow('default') + await expect(comfyPage.canvas).toHaveScreenshot( + 'mobile-default-workflow.png' + ) + }) - test('@mobile settings dialog', async ({ comfyPage }) => { - await comfyPage.settingDialog.open() - await comfyPage.nextFrame() + test('@mobile settings dialog', async ({ comfyPage }) => { + await comfyPage.settingDialog.open() + await comfyPage.nextFrame() - await expect(comfyPage.settingDialog.root).toHaveScreenshot( - 'mobile-settings-dialog.png', - { - mask: [ - comfyPage.settingDialog.root.getByTestId('current-user-indicator') - ] - } - ) - }) -}) + await expect(comfyPage.settingDialog.root).toHaveScreenshot( + 'mobile-settings-dialog.png', + { + mask: [ + comfyPage.settingDialog.root.getByTestId('current-user-indicator') + ] + } + ) + }) + } +) diff --git a/browser_tests/tests/nodeBadge.spec.ts b/browser_tests/tests/nodeBadge.spec.ts index 111efe29cf..f4cf493a99 100644 --- a/browser_tests/tests/nodeBadge.spec.ts +++ b/browser_tests/tests/nodeBadge.spec.ts @@ -8,7 +8,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Node Badge', () => { +test.describe('Node Badge', { tag: ['@screenshot', '@smoke', '@node'] }, () => { test('Can add badge', async ({ comfyPage }) => { await comfyPage.page.evaluate(() => { const LGraphBadge = window['LGraphBadge'] @@ -66,50 +66,60 @@ test.describe('Node Badge', () => { }) }) -test.describe('Node source badge', () => { - Object.values(NodeBadgeMode).forEach(async (mode) => { - test(`Shows node badges (${mode})`, async ({ comfyPage }) => { - // Execution error workflow has both custom node and core node. - await comfyPage.loadWorkflow('nodes/execution_error') - await comfyPage.setSetting('Comfy.NodeBadge.NodeSourceBadgeMode', mode) - await comfyPage.setSetting('Comfy.NodeBadge.NodeIdBadgeMode', mode) - await comfyPage.nextFrame() - await comfyPage.resetView() - await expect(comfyPage.canvas).toHaveScreenshot(`node-badge-${mode}.png`) +test.describe( + 'Node source badge', + { tag: ['@screenshot', '@smoke', '@node'] }, + () => { + Object.values(NodeBadgeMode).forEach(async (mode) => { + test(`Shows node badges (${mode})`, async ({ comfyPage }) => { + // Execution error workflow has both custom node and core node. + await comfyPage.loadWorkflow('nodes/execution_error') + await comfyPage.setSetting('Comfy.NodeBadge.NodeSourceBadgeMode', mode) + await comfyPage.setSetting('Comfy.NodeBadge.NodeIdBadgeMode', mode) + await comfyPage.nextFrame() + await comfyPage.resetView() + await expect(comfyPage.canvas).toHaveScreenshot( + `node-badge-${mode}.png` + ) + }) }) - }) -}) + } +) -test.describe('Node badge color', () => { - test('Can show node badge with unknown color palette', async ({ - comfyPage - }) => { - await comfyPage.setSetting( - 'Comfy.NodeBadge.NodeIdBadgeMode', - NodeBadgeMode.ShowAll - ) - await comfyPage.setSetting('Comfy.ColorPalette', 'unknown') - await comfyPage.nextFrame() - // Click empty space to trigger canvas re-render. - await comfyPage.clickEmptySpace() - await expect(comfyPage.canvas).toHaveScreenshot( - 'node-badge-unknown-color-palette.png' - ) - }) +test.describe( + 'Node badge color', + { tag: ['@screenshot', '@smoke', '@node'] }, + () => { + test('Can show node badge with unknown color palette', async ({ + comfyPage + }) => { + await comfyPage.setSetting( + 'Comfy.NodeBadge.NodeIdBadgeMode', + NodeBadgeMode.ShowAll + ) + await comfyPage.setSetting('Comfy.ColorPalette', 'unknown') + await comfyPage.nextFrame() + // Click empty space to trigger canvas re-render. + await comfyPage.clickEmptySpace() + await expect(comfyPage.canvas).toHaveScreenshot( + 'node-badge-unknown-color-palette.png' + ) + }) - test('Can show node badge with light color palette', async ({ - comfyPage - }) => { - await comfyPage.setSetting( - 'Comfy.NodeBadge.NodeIdBadgeMode', - NodeBadgeMode.ShowAll - ) - await comfyPage.setSetting('Comfy.ColorPalette', 'light') - await comfyPage.nextFrame() - // Click empty space to trigger canvas re-render. - await comfyPage.clickEmptySpace() - await expect(comfyPage.canvas).toHaveScreenshot( - 'node-badge-light-color-palette.png' - ) - }) -}) + test('Can show node badge with light color palette', async ({ + comfyPage + }) => { + await comfyPage.setSetting( + 'Comfy.NodeBadge.NodeIdBadgeMode', + NodeBadgeMode.ShowAll + ) + await comfyPage.setSetting('Comfy.ColorPalette', 'light') + await comfyPage.nextFrame() + // Click empty space to trigger canvas re-render. + await comfyPage.clickEmptySpace() + await expect(comfyPage.canvas).toHaveScreenshot( + 'node-badge-light-color-palette.png' + ) + }) + } +) diff --git a/browser_tests/tests/nodeDisplay.spec.ts b/browser_tests/tests/nodeDisplay.spec.ts index fdaae14bcb..541ddaf0f9 100644 --- a/browser_tests/tests/nodeDisplay.spec.ts +++ b/browser_tests/tests/nodeDisplay.spec.ts @@ -8,7 +8,7 @@ test.beforeEach(async ({ comfyPage }) => { // If an input is optional by node definition, it should be shown as // a hollow circle no matter what shape it was defined in the workflow JSON. -test.describe('Optional input', () => { +test.describe('Optional input', { tag: ['@screenshot', '@node'] }, () => { test('No shape specified', async ({ comfyPage }) => { await comfyPage.loadWorkflow('inputs/optional_input_no_shape') await expect(comfyPage.canvas).toHaveScreenshot('optional_input.png') diff --git a/browser_tests/tests/nodeHelp.spec.ts b/browser_tests/tests/nodeHelp.spec.ts index 709c19a4b8..095cb37ec1 100644 --- a/browser_tests/tests/nodeHelp.spec.ts +++ b/browser_tests/tests/nodeHelp.spec.ts @@ -23,7 +23,7 @@ async function selectNodeWithPan(comfyPage: ComfyPage, nodeRef: NodeReference) { await nodeRef.click('title') } -test.describe('Node Help', () => { +test.describe('Node Help', { tag: ['@slow', '@ui'] }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setup() await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') diff --git a/browser_tests/tests/nodeSearchBox.spec.ts b/browser_tests/tests/nodeSearchBox.spec.ts index 2eea223290..f227b2932a 100644 --- a/browser_tests/tests/nodeSearchBox.spec.ts +++ b/browser_tests/tests/nodeSearchBox.spec.ts @@ -7,7 +7,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Node search box', () => { +test.describe('Node search box', { tag: '@node' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.LinkRelease.Action', 'search box') await comfyPage.setSetting('Comfy.LinkRelease.ActionShift', 'search box') @@ -46,14 +46,14 @@ test.describe('Node search box', () => { await expect(comfyPage.searchBox.input).toBeVisible() }) - test('Can add node', async ({ comfyPage }) => { + test('Can add node', { tag: '@screenshot' }, async ({ comfyPage }) => { await comfyPage.doubleClickCanvas() await expect(comfyPage.searchBox.input).toHaveCount(1) await comfyPage.searchBox.fillAndSelectFirstNode('KSampler') await expect(comfyPage.canvas).toHaveScreenshot('added-node.png') }) - test('Can auto link node', async ({ comfyPage }) => { + test('Can auto link node', { tag: '@screenshot' }, async ({ comfyPage }) => { await comfyPage.disconnectEdge() // Select the second item as the first item is always reroute await comfyPage.searchBox.fillAndSelectFirstNode('CLIPTextEncode', { @@ -62,41 +62,47 @@ test.describe('Node search box', () => { await expect(comfyPage.canvas).toHaveScreenshot('auto-linked-node.png') }) - test('Can auto link batch moved node', async ({ comfyPage }) => { - await comfyPage.loadWorkflow('links/batch_move_links') + test( + 'Can auto link batch moved node', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.loadWorkflow('links/batch_move_links') - const outputSlot1Pos = { - x: 304, - y: 127 + const outputSlot1Pos = { + x: 304, + y: 127 + } + const emptySpacePos = { + x: 5, + y: 5 + } + await comfyPage.page.keyboard.down('Shift') + await comfyPage.dragAndDrop(outputSlot1Pos, emptySpacePos) + await comfyPage.page.keyboard.up('Shift') + + // Select the second item as the first item is always reroute + await comfyPage.searchBox.fillAndSelectFirstNode('Load Checkpoint', { + suggestionIndex: 0 + }) + await expect(comfyPage.canvas).toHaveScreenshot( + 'auto-linked-node-batch.png' + ) } - const emptySpacePos = { - x: 5, - y: 5 + ) + + test( + 'Link release connecting to node with no slots', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.disconnectEdge() + await expect(comfyPage.searchBox.input).toHaveCount(1) + await comfyPage.page.locator('.p-chip-remove-icon').click() + await comfyPage.searchBox.fillAndSelectFirstNode('KSampler') + await expect(comfyPage.canvas).toHaveScreenshot( + 'added-node-no-connection.png' + ) } - await comfyPage.page.keyboard.down('Shift') - await comfyPage.dragAndDrop(outputSlot1Pos, emptySpacePos) - await comfyPage.page.keyboard.up('Shift') - - // Select the second item as the first item is always reroute - await comfyPage.searchBox.fillAndSelectFirstNode('Load Checkpoint', { - suggestionIndex: 0 - }) - await expect(comfyPage.canvas).toHaveScreenshot( - 'auto-linked-node-batch.png' - ) - }) - - test('Link release connecting to node with no slots', async ({ - comfyPage - }) => { - await comfyPage.disconnectEdge() - await expect(comfyPage.searchBox.input).toHaveCount(1) - await comfyPage.page.locator('.p-chip-remove-icon').click() - await comfyPage.searchBox.fillAndSelectFirstNode('KSampler') - await expect(comfyPage.canvas).toHaveScreenshot( - 'added-node-no-connection.png' - ) - }) + ) test('Has correct aria-labels on search results', async ({ comfyPage }) => { const node = 'Load Checkpoint' @@ -251,40 +257,45 @@ test.describe('Node search box', () => { }) }) -test.describe('Release context menu', () => { +test.describe('Release context menu', { tag: '@node' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.LinkRelease.Action', 'context menu') await comfyPage.setSetting('Comfy.LinkRelease.ActionShift', 'search box') await comfyPage.setSetting('Comfy.NodeSearchBoxImpl', 'default') }) - test('Can trigger on link release', async ({ comfyPage }) => { - await comfyPage.disconnectEdge() - const contextMenu = comfyPage.page.locator('.litecontextmenu') - // Wait for context menu with correct title (slot name | slot type) - // The title shows the output slot name and type from the disconnected link - await expect(contextMenu.locator('.litemenu-title')).toContainText( - 'CLIP | CLIP' - ) - await comfyPage.page.mouse.move(10, 10) - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot( - 'link-release-context-menu.png' - ) - }) + test( + 'Can trigger on link release', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.disconnectEdge() + const contextMenu = comfyPage.page.locator('.litecontextmenu') + // Wait for context menu with correct title (slot name | slot type) + // The title shows the output slot name and type from the disconnected link + await expect(contextMenu.locator('.litemenu-title')).toContainText( + 'CLIP | CLIP' + ) + await comfyPage.page.mouse.move(10, 10) + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot( + 'link-release-context-menu.png' + ) + } + ) - test('Can search and add node from context menu', async ({ - comfyPage, - comfyMouse - }) => { - await comfyPage.disconnectEdge() - await comfyMouse.move({ x: 10, y: 10 }) - await comfyPage.clickContextMenuItem('Search') - await comfyPage.searchBox.fillAndSelectFirstNode('CLIP Prompt') - await expect(comfyPage.canvas).toHaveScreenshot( - 'link-context-menu-search.png' - ) - }) + test( + 'Can search and add node from context menu', + { tag: '@screenshot' }, + async ({ comfyPage, comfyMouse }) => { + await comfyPage.disconnectEdge() + await comfyMouse.move({ x: 10, y: 10 }) + await comfyPage.clickContextMenuItem('Search') + await comfyPage.searchBox.fillAndSelectFirstNode('CLIP Prompt') + await expect(comfyPage.canvas).toHaveScreenshot( + 'link-context-menu-search.png' + ) + } + ) test('Existing user (pre-1.24.1) gets context menu by default on link release', async ({ comfyPage diff --git a/browser_tests/tests/noteNode.spec.ts b/browser_tests/tests/noteNode.spec.ts index 52dc575423..4bb5519625 100644 --- a/browser_tests/tests/noteNode.spec.ts +++ b/browser_tests/tests/noteNode.spec.ts @@ -6,8 +6,8 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Note Node', () => { - test('Can load node nodes', async ({ comfyPage }) => { +test.describe('Note Node', { tag: '@node' }, () => { + test('Can load node nodes', { tag: '@screenshot' }, async ({ comfyPage }) => { await comfyPage.loadWorkflow('nodes/note_nodes') await expect(comfyPage.canvas).toHaveScreenshot('note_nodes.png') }) diff --git a/browser_tests/tests/primitiveNode.spec.ts b/browser_tests/tests/primitiveNode.spec.ts index 0584a3bec2..2e2e11ae54 100644 --- a/browser_tests/tests/primitiveNode.spec.ts +++ b/browser_tests/tests/primitiveNode.spec.ts @@ -7,7 +7,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Primitive Node', () => { +test.describe('Primitive Node', { tag: ['@screenshot', '@node'] }, () => { test('Can load with correct size', async ({ comfyPage }) => { await comfyPage.loadWorkflow('primitive/primitive_node') await expect(comfyPage.canvas).toHaveScreenshot('primitive_node.png') diff --git a/browser_tests/tests/recordAudio.spec.ts b/browser_tests/tests/recordAudio.spec.ts index cc0ac3684f..d343990c1c 100644 --- a/browser_tests/tests/recordAudio.spec.ts +++ b/browser_tests/tests/recordAudio.spec.ts @@ -6,7 +6,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Record Audio Node', () => { +test.describe('Record Audio Node', { tag: '@screenshot' }, () => { test('should add a record audio node and take a screenshot', async ({ comfyPage }) => { diff --git a/browser_tests/tests/remoteWidgets.spec.ts b/browser_tests/tests/remoteWidgets.spec.ts index 18cc77f445..cc7cad64f2 100644 --- a/browser_tests/tests/remoteWidgets.spec.ts +++ b/browser_tests/tests/remoteWidgets.spec.ts @@ -3,7 +3,7 @@ import { expect } from '@playwright/test' import type { ComfyPage } from '../fixtures/ComfyPage' import { comfyPageFixture as test } from '../fixtures/ComfyPage' -test.describe('Remote COMBO Widget', () => { +test.describe('Remote COMBO Widget', { tag: '@widget' }, () => { const mockOptions = ['d', 'c', 'b', 'a'] const addRemoteWidgetNode = async ( diff --git a/browser_tests/tests/rerouteNode.spec.ts b/browser_tests/tests/rerouteNode.spec.ts index 0b2b1e0f62..48f155419f 100644 --- a/browser_tests/tests/rerouteNode.spec.ts +++ b/browser_tests/tests/rerouteNode.spec.ts @@ -3,7 +3,7 @@ import { expect } from '@playwright/test' import { comfyPageFixture as test } from '../fixtures/ComfyPage' import { getMiddlePoint } from '../fixtures/utils/litegraphUtils' -test.describe('Reroute Node', () => { +test.describe('Reroute Node', { tag: ['@screenshot', '@node'] }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') }) @@ -38,92 +38,96 @@ test.describe('Reroute Node', () => { }) }) -test.describe('LiteGraph Native Reroute Node', () => { - test.beforeEach(async ({ comfyPage }) => { - await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') - await comfyPage.setSetting('LiteGraph.Reroute.SplineOffset', 80) - }) +test.describe( + 'LiteGraph Native Reroute Node', + { tag: ['@screenshot', '@node'] }, + () => { + test.beforeEach(async ({ comfyPage }) => { + await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') + await comfyPage.setSetting('LiteGraph.Reroute.SplineOffset', 80) + }) - test('loads from workflow', async ({ comfyPage }) => { - await comfyPage.loadWorkflow('reroute/native_reroute') - await expect(comfyPage.canvas).toHaveScreenshot('native_reroute.png') - }) + test('loads from workflow', async ({ comfyPage }) => { + await comfyPage.loadWorkflow('reroute/native_reroute') + await expect(comfyPage.canvas).toHaveScreenshot('native_reroute.png') + }) - test('@2x @0.5x Can add reroute by alt clicking on link', async ({ - comfyPage - }) => { - const loadCheckpointNode = ( - await comfyPage.getNodeRefsByTitle('Load Checkpoint') - )[0] - const clipEncodeNode = ( - await comfyPage.getNodeRefsByTitle('CLIP Text Encode (Prompt)') - )[0] + test('@2x @0.5x Can add reroute by alt clicking on link', async ({ + comfyPage + }) => { + const loadCheckpointNode = ( + await comfyPage.getNodeRefsByTitle('Load Checkpoint') + )[0] + const clipEncodeNode = ( + await comfyPage.getNodeRefsByTitle('CLIP Text Encode (Prompt)') + )[0] - const slot1 = await loadCheckpointNode.getOutput(1) - const slot2 = await clipEncodeNode.getInput(0) - const middlePoint = getMiddlePoint( - await slot1.getPosition(), - await slot2.getPosition() - ) + const slot1 = await loadCheckpointNode.getOutput(1) + const slot2 = await clipEncodeNode.getInput(0) + const middlePoint = getMiddlePoint( + await slot1.getPosition(), + await slot2.getPosition() + ) - await comfyPage.page.keyboard.down('Alt') - await comfyPage.page.mouse.click(middlePoint.x, middlePoint.y) - await comfyPage.page.keyboard.up('Alt') + await comfyPage.page.keyboard.down('Alt') + await comfyPage.page.mouse.click(middlePoint.x, middlePoint.y) + await comfyPage.page.keyboard.up('Alt') - await expect(comfyPage.canvas).toHaveScreenshot( - 'native_reroute_alt_click.png' - ) - }) + await expect(comfyPage.canvas).toHaveScreenshot( + 'native_reroute_alt_click.png' + ) + }) - test('Can add reroute by clicking middle of link context menu', async ({ - comfyPage - }) => { - const loadCheckpointNode = ( - await comfyPage.getNodeRefsByTitle('Load Checkpoint') - )[0] - const clipEncodeNode = ( - await comfyPage.getNodeRefsByTitle('CLIP Text Encode (Prompt)') - )[0] + test('Can add reroute by clicking middle of link context menu', async ({ + comfyPage + }) => { + const loadCheckpointNode = ( + await comfyPage.getNodeRefsByTitle('Load Checkpoint') + )[0] + const clipEncodeNode = ( + await comfyPage.getNodeRefsByTitle('CLIP Text Encode (Prompt)') + )[0] - const slot1 = await loadCheckpointNode.getOutput(1) - const slot2 = await clipEncodeNode.getInput(0) - const middlePoint = getMiddlePoint( - await slot1.getPosition(), - await slot2.getPosition() - ) + const slot1 = await loadCheckpointNode.getOutput(1) + const slot2 = await clipEncodeNode.getInput(0) + const middlePoint = getMiddlePoint( + await slot1.getPosition(), + await slot2.getPosition() + ) - await comfyPage.page.mouse.click(middlePoint.x, middlePoint.y) - await comfyPage.page - .locator('.litecontextmenu .litemenu-entry', { hasText: 'Add Reroute' }) - .click() + await comfyPage.page.mouse.click(middlePoint.x, middlePoint.y) + await comfyPage.page + .locator('.litecontextmenu .litemenu-entry', { hasText: 'Add Reroute' }) + .click() - await expect(comfyPage.canvas).toHaveScreenshot( - 'native_reroute_context_menu.png' - ) - }) + await expect(comfyPage.canvas).toHaveScreenshot( + 'native_reroute_context_menu.png' + ) + }) - test('Can delete link that is connected to two reroutes', async ({ - comfyPage - }) => { - // https://github.com/Comfy-Org/ComfyUI_frontend/issues/4695 - await comfyPage.loadWorkflow( - 'reroute/single-native-reroute-default-workflow' - ) + test('Can delete link that is connected to two reroutes', async ({ + comfyPage + }) => { + // https://github.com/Comfy-Org/ComfyUI_frontend/issues/4695 + await comfyPage.loadWorkflow( + 'reroute/single-native-reroute-default-workflow' + ) - // To find the clickable midpoint button, we use the hardcoded value from the browser logs - // since the link is a bezier curve and not a straight line. - const middlePoint = { x: 359.4188232421875, y: 468.7716979980469 } + // To find the clickable midpoint button, we use the hardcoded value from the browser logs + // since the link is a bezier curve and not a straight line. + const middlePoint = { x: 359.4188232421875, y: 468.7716979980469 } - // Click the middle point of the link to open the context menu. - await comfyPage.page.mouse.click(middlePoint.x, middlePoint.y) + // Click the middle point of the link to open the context menu. + await comfyPage.page.mouse.click(middlePoint.x, middlePoint.y) - // Click the "Delete" context menu option. - await comfyPage.page - .locator('.litecontextmenu .litemenu-entry', { hasText: 'Delete' }) - .click() + // Click the "Delete" context menu option. + await comfyPage.page + .locator('.litecontextmenu .litemenu-entry', { hasText: 'Delete' }) + .click() - await expect(comfyPage.canvas).toHaveScreenshot( - 'native_reroute_delete_from_midpoint_context_menu.png' - ) - }) -}) + await expect(comfyPage.canvas).toHaveScreenshot( + 'native_reroute_delete_from_midpoint_context_menu.png' + ) + }) + } +) diff --git a/browser_tests/tests/rightClickMenu.spec.ts b/browser_tests/tests/rightClickMenu.spec.ts index d2c17b43db..3114a94560 100644 --- a/browser_tests/tests/rightClickMenu.spec.ts +++ b/browser_tests/tests/rightClickMenu.spec.ts @@ -7,43 +7,49 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Canvas Right Click Menu', () => { - test('Can add node', async ({ comfyPage }) => { - await comfyPage.rightClickCanvas() - await expect(comfyPage.canvas).toHaveScreenshot('right-click-menu.png') - await comfyPage.page.getByText('Add Node').click() - await comfyPage.nextFrame() - await comfyPage.page.getByText('loaders').click() - await comfyPage.nextFrame() - await comfyPage.page.getByText('Load VAE').click() - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot('add-node-node-added.png') - }) +test.describe( + 'Canvas Right Click Menu', + { tag: ['@screenshot', '@ui'] }, + () => { + test('Can add node', async ({ comfyPage }) => { + await comfyPage.rightClickCanvas() + await expect(comfyPage.canvas).toHaveScreenshot('right-click-menu.png') + await comfyPage.page.getByText('Add Node').click() + await comfyPage.nextFrame() + await comfyPage.page.getByText('loaders').click() + await comfyPage.nextFrame() + await comfyPage.page.getByText('Load VAE').click() + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot('add-node-node-added.png') + }) - test('Can add group', async ({ comfyPage }) => { - await comfyPage.rightClickCanvas() - await expect(comfyPage.canvas).toHaveScreenshot('right-click-menu.png') - await comfyPage.page.getByText('Add Group', { exact: true }).click() - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot('add-group-group-added.png') - }) + test('Can add group', async ({ comfyPage }) => { + await comfyPage.rightClickCanvas() + await expect(comfyPage.canvas).toHaveScreenshot('right-click-menu.png') + await comfyPage.page.getByText('Add Group', { exact: true }).click() + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot( + 'add-group-group-added.png' + ) + }) - test('Can convert to group node', async ({ comfyPage }) => { - await comfyPage.select2Nodes() - await expect(comfyPage.canvas).toHaveScreenshot('selected-2-nodes.png') - await comfyPage.rightClickCanvas() - await comfyPage.clickContextMenuItem('Convert to Group Node (Deprecated)') - await comfyPage.promptDialogInput.fill('GroupNode2CLIP') - await comfyPage.page.keyboard.press('Enter') - await comfyPage.promptDialogInput.waitFor({ state: 'hidden' }) - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot( - 'right-click-node-group-node.png' - ) - }) -}) + test('Can convert to group node', async ({ comfyPage }) => { + await comfyPage.select2Nodes() + await expect(comfyPage.canvas).toHaveScreenshot('selected-2-nodes.png') + await comfyPage.rightClickCanvas() + await comfyPage.clickContextMenuItem('Convert to Group Node (Deprecated)') + await comfyPage.promptDialogInput.fill('GroupNode2CLIP') + await comfyPage.page.keyboard.press('Enter') + await comfyPage.promptDialogInput.waitFor({ state: 'hidden' }) + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot( + 'right-click-node-group-node.png' + ) + }) + } +) -test.describe('Node Right Click Menu', () => { +test.describe('Node Right Click Menu', { tag: ['@screenshot', '@ui'] }, () => { test('Can open properties panel', async ({ comfyPage }) => { await comfyPage.rightClickEmptyLatentNode() await expect(comfyPage.canvas).toHaveScreenshot('right-click-node.png') diff --git a/browser_tests/tests/selectionToolbox.spec.ts b/browser_tests/tests/selectionToolbox.spec.ts index 6b85769826..fd74a4aa70 100644 --- a/browser_tests/tests/selectionToolbox.spec.ts +++ b/browser_tests/tests/selectionToolbox.spec.ts @@ -10,7 +10,7 @@ test.beforeEach(async ({ comfyPage }) => { const BLUE_COLOR = 'rgb(51, 51, 85)' const RED_COLOR = 'rgb(85, 51, 51)' -test.describe('Selection Toolbox', () => { +test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.Canvas.SelectionToolbox', true) }) diff --git a/browser_tests/tests/selectionToolboxSubmenus.spec.ts b/browser_tests/tests/selectionToolboxSubmenus.spec.ts index fd4c55faf2..c5d74c1678 100644 --- a/browser_tests/tests/selectionToolboxSubmenus.spec.ts +++ b/browser_tests/tests/selectionToolboxSubmenus.spec.ts @@ -7,178 +7,190 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Selection Toolbox - More Options Submenus', () => { - test.beforeEach(async ({ comfyPage }) => { - await comfyPage.setSetting('Comfy.Canvas.SelectionToolbox', true) - await comfyPage.loadWorkflow('nodes/single_ksampler') - await comfyPage.nextFrame() - await comfyPage.selectNodes(['KSampler']) - await comfyPage.nextFrame() - }) - - const openMoreOptions = async (comfyPage: ComfyPage) => { - const ksamplerNodes = await comfyPage.getNodeRefsByTitle('KSampler') - if (ksamplerNodes.length === 0) { - throw new Error('No KSampler nodes found') - } - - // Drag the KSampler to the center of the screen - const nodePos = await ksamplerNodes[0].getPosition() - const viewportSize = comfyPage.page.viewportSize() - const centerX = viewportSize.width / 3 - const centerY = viewportSize.height / 2 - await comfyPage.dragAndDrop( - { x: nodePos.x, y: nodePos.y }, - { x: centerX, y: centerY } - ) - await comfyPage.nextFrame() - - await ksamplerNodes[0].click('title') - await comfyPage.nextFrame() - - await expect(comfyPage.page.locator('.selection-toolbox')).toBeVisible({ - timeout: 5000 - }) - - const moreOptionsBtn = comfyPage.page.locator( - '[data-testid="more-options-button"]' - ) - await expect(moreOptionsBtn).toBeVisible({ timeout: 3000 }) - - await comfyPage.page.click('[data-testid="more-options-button"]') - - await comfyPage.nextFrame() - - const menuOptionsVisible = await comfyPage.page - .getByText('Rename') - .isVisible({ timeout: 2000 }) - .catch(() => false) - if (menuOptionsVisible) { - return - } - - await moreOptionsBtn.click({ force: true }) - await comfyPage.nextFrame() - - const menuOptionsVisibleAfterClick = await comfyPage.page - .getByText('Rename') - .isVisible({ timeout: 2000 }) - .catch(() => false) - if (menuOptionsVisibleAfterClick) { - return - } - - throw new Error('Could not open More Options menu - popover not showing') - } - - test('opens Node Info from More Options menu', async ({ comfyPage }) => { - await openMoreOptions(comfyPage) - const nodeInfoButton = comfyPage.page.getByText('Node Info', { - exact: true - }) - await expect(nodeInfoButton).toBeVisible() - await nodeInfoButton.click() - await comfyPage.nextFrame() - }) - - test('changes node shape via Shape submenu', async ({ comfyPage }) => { - const nodeRef = (await comfyPage.getNodeRefsByTitle('KSampler'))[0] - const initialShape = await nodeRef.getProperty('shape') - - await openMoreOptions(comfyPage) - await comfyPage.page.getByText('Shape', { exact: true }).hover() - await expect(comfyPage.page.getByText('Box', { exact: true })).toBeVisible({ - timeout: 5000 - }) - await comfyPage.page.getByText('Box', { exact: true }).click() - await comfyPage.nextFrame() - - const newShape = await nodeRef.getProperty('shape') - expect(newShape).not.toBe(initialShape) - expect(newShape).toBe(1) - }) - - test('changes node color via Color submenu swatch', async ({ comfyPage }) => { - const nodeRef = (await comfyPage.getNodeRefsByTitle('KSampler'))[0] - const initialColor = await nodeRef.getProperty('color') - - await openMoreOptions(comfyPage) - await comfyPage.page.getByText('Color', { exact: true }).click() - const blueSwatch = comfyPage.page.locator('[title="Blue"]') - await expect(blueSwatch.first()).toBeVisible({ timeout: 5000 }) - await blueSwatch.first().click() - await comfyPage.nextFrame() - - const newColor = await nodeRef.getProperty('color') - expect(newColor).toBe('#223') - if (initialColor) { - expect(newColor).not.toBe(initialColor) - } - }) - - test('renames a node using Rename action', async ({ comfyPage }) => { - const nodeRef = (await comfyPage.getNodeRefsByTitle('KSampler'))[0] - await openMoreOptions(comfyPage) - await comfyPage.page - .getByText('Rename', { exact: true }) - .click({ force: true }) - const input = comfyPage.page.locator( - '.group-title-editor.node-title-editor .editable-text input' - ) - await expect(input).toBeVisible() - await input.fill('RenamedNode') - await input.press('Enter') - await comfyPage.nextFrame() - const newTitle = await nodeRef.getProperty('title') - expect(newTitle).toBe('RenamedNode') - }) - - test('closes More Options menu when clicking outside', async ({ - comfyPage - }) => { - await openMoreOptions(comfyPage) - const renameItem = comfyPage.page.getByText('Rename', { exact: true }) - await expect(renameItem).toBeVisible({ timeout: 5000 }) - - // Wait for multiple frames to allow PrimeVue's outside click handler to initialize - for (let i = 0; i < 30; i++) { +test.describe( + 'Selection Toolbox - More Options Submenus', + { tag: '@ui' }, + () => { + test.beforeEach(async ({ comfyPage }) => { + await comfyPage.setSetting('Comfy.Canvas.SelectionToolbox', true) + await comfyPage.loadWorkflow('nodes/single_ksampler') await comfyPage.nextFrame() + await comfyPage.selectNodes(['KSampler']) + await comfyPage.nextFrame() + }) + + const openMoreOptions = async (comfyPage: ComfyPage) => { + const ksamplerNodes = await comfyPage.getNodeRefsByTitle('KSampler') + if (ksamplerNodes.length === 0) { + throw new Error('No KSampler nodes found') + } + + // Drag the KSampler to the center of the screen + const nodePos = await ksamplerNodes[0].getPosition() + const viewportSize = comfyPage.page.viewportSize() + const centerX = viewportSize.width / 3 + const centerY = viewportSize.height / 2 + await comfyPage.dragAndDrop( + { x: nodePos.x, y: nodePos.y }, + { x: centerX, y: centerY } + ) + await comfyPage.nextFrame() + + await ksamplerNodes[0].click('title') + await comfyPage.nextFrame() + + await expect(comfyPage.page.locator('.selection-toolbox')).toBeVisible({ + timeout: 5000 + }) + + const moreOptionsBtn = comfyPage.page.locator( + '[data-testid="more-options-button"]' + ) + await expect(moreOptionsBtn).toBeVisible({ timeout: 3000 }) + + await comfyPage.page.click('[data-testid="more-options-button"]') + + await comfyPage.nextFrame() + + const menuOptionsVisible = await comfyPage.page + .getByText('Rename') + .isVisible({ timeout: 2000 }) + .catch(() => false) + if (menuOptionsVisible) { + return + } + + await moreOptionsBtn.click({ force: true }) + await comfyPage.nextFrame() + + const menuOptionsVisibleAfterClick = await comfyPage.page + .getByText('Rename') + .isVisible({ timeout: 2000 }) + .catch(() => false) + if (menuOptionsVisibleAfterClick) { + return + } + + throw new Error('Could not open More Options menu - popover not showing') } - await comfyPage.page - .locator('#graph-canvas') - .click({ position: { x: 0, y: 50 }, force: true }) + test('opens Node Info from More Options menu', async ({ comfyPage }) => { + await openMoreOptions(comfyPage) + const nodeInfoButton = comfyPage.page.getByText('Node Info', { + exact: true + }) + await expect(nodeInfoButton).toBeVisible() + await nodeInfoButton.click() + await comfyPage.nextFrame() + }) - await comfyPage.nextFrame() - await expect( - comfyPage.page.getByText('Rename', { exact: true }) - ).not.toBeVisible() - }) + test('changes node shape via Shape submenu', async ({ comfyPage }) => { + const nodeRef = (await comfyPage.getNodeRefsByTitle('KSampler'))[0] + const initialShape = await nodeRef.getProperty('shape') - test('closes More Options menu when clicking the button again (toggle)', async ({ - comfyPage - }) => { - await openMoreOptions(comfyPage) - await expect( - comfyPage.page.getByText('Rename', { exact: true }) - ).toBeVisible({ timeout: 5000 }) + await openMoreOptions(comfyPage) + await comfyPage.page.getByText('Shape', { exact: true }).hover() + await expect( + comfyPage.page.getByText('Box', { exact: true }) + ).toBeVisible({ + timeout: 5000 + }) + await comfyPage.page.getByText('Box', { exact: true }).click() + await comfyPage.nextFrame() - await comfyPage.page.evaluate(() => { - const btn = document.querySelector('[data-testid="more-options-button"]') - if (btn) { - const event = new MouseEvent('click', { - bubbles: true, - cancelable: true, - view: window, - detail: 1 - }) - btn.dispatchEvent(event) + const newShape = await nodeRef.getProperty('shape') + expect(newShape).not.toBe(initialShape) + expect(newShape).toBe(1) + }) + + test('changes node color via Color submenu swatch', async ({ + comfyPage + }) => { + const nodeRef = (await comfyPage.getNodeRefsByTitle('KSampler'))[0] + const initialColor = await nodeRef.getProperty( + 'color' + ) + + await openMoreOptions(comfyPage) + await comfyPage.page.getByText('Color', { exact: true }).click() + const blueSwatch = comfyPage.page.locator('[title="Blue"]') + await expect(blueSwatch.first()).toBeVisible({ timeout: 5000 }) + await blueSwatch.first().click() + await comfyPage.nextFrame() + + const newColor = await nodeRef.getProperty('color') + expect(newColor).toBe('#223') + if (initialColor) { + expect(newColor).not.toBe(initialColor) } }) - await comfyPage.nextFrame() - await expect( - comfyPage.page.getByText('Rename', { exact: true }) - ).not.toBeVisible() - }) -}) + test('renames a node using Rename action', async ({ comfyPage }) => { + const nodeRef = (await comfyPage.getNodeRefsByTitle('KSampler'))[0] + await openMoreOptions(comfyPage) + await comfyPage.page + .getByText('Rename', { exact: true }) + .click({ force: true }) + const input = comfyPage.page.locator( + '.group-title-editor.node-title-editor .editable-text input' + ) + await expect(input).toBeVisible() + await input.fill('RenamedNode') + await input.press('Enter') + await comfyPage.nextFrame() + const newTitle = await nodeRef.getProperty('title') + expect(newTitle).toBe('RenamedNode') + }) + + test('closes More Options menu when clicking outside', async ({ + comfyPage + }) => { + await openMoreOptions(comfyPage) + const renameItem = comfyPage.page.getByText('Rename', { exact: true }) + await expect(renameItem).toBeVisible({ timeout: 5000 }) + + // Wait for multiple frames to allow PrimeVue's outside click handler to initialize + for (let i = 0; i < 30; i++) { + await comfyPage.nextFrame() + } + + await comfyPage.page + .locator('#graph-canvas') + .click({ position: { x: 0, y: 50 }, force: true }) + + await comfyPage.nextFrame() + await expect( + comfyPage.page.getByText('Rename', { exact: true }) + ).not.toBeVisible() + }) + + test('closes More Options menu when clicking the button again (toggle)', async ({ + comfyPage + }) => { + await openMoreOptions(comfyPage) + await expect( + comfyPage.page.getByText('Rename', { exact: true }) + ).toBeVisible({ timeout: 5000 }) + + await comfyPage.page.evaluate(() => { + const btn = document.querySelector( + '[data-testid="more-options-button"]' + ) + if (btn) { + const event = new MouseEvent('click', { + bubbles: true, + cancelable: true, + view: window, + detail: 1 + }) + btn.dispatchEvent(event) + } + }) + await comfyPage.nextFrame() + + await expect( + comfyPage.page.getByText('Rename', { exact: true }) + ).not.toBeVisible() + }) + } +) diff --git a/browser_tests/tests/subgraph-rename-dialog.spec.ts b/browser_tests/tests/subgraph-rename-dialog.spec.ts index 0bdb9766df..f917bdb9b9 100644 --- a/browser_tests/tests/subgraph-rename-dialog.spec.ts +++ b/browser_tests/tests/subgraph-rename-dialog.spec.ts @@ -12,7 +12,7 @@ const SELECTORS = { promptDialog: '.graphdialog input' } as const -test.describe('Subgraph Slot Rename Dialog', () => { +test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) diff --git a/browser_tests/tests/subgraph.spec.ts b/browser_tests/tests/subgraph.spec.ts index 6359156211..1719ba0596 100644 --- a/browser_tests/tests/subgraph.spec.ts +++ b/browser_tests/tests/subgraph.spec.ts @@ -16,7 +16,7 @@ const SELECTORS = { domWidget: '.comfy-multiline-input' } as const -test.describe('Subgraph Operations', () => { +test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) diff --git a/browser_tests/tests/templates.spec.ts b/browser_tests/tests/templates.spec.ts index 4921165f7c..334c761af0 100644 --- a/browser_tests/tests/templates.spec.ts +++ b/browser_tests/tests/templates.spec.ts @@ -13,7 +13,7 @@ async function checkTemplateFileExists( return response.ok() } -test.describe('Templates', () => { +test.describe('Templates', { tag: ['@slow', '@workflow'] }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') await comfyPage.setSetting('Comfy.Workflow.ShowMissingModelsWarning', false) @@ -207,109 +207,114 @@ test.describe('Templates', () => { await expect(nav).toBeVisible() // Nav should be visible at tablet size }) - test('template cards descriptions adjust height dynamically', async ({ - comfyPage - }) => { - // Setup test by intercepting templates response to inject cards with varying description lengths - await comfyPage.page.route('**/templates/index.json', async (route, _) => { - const response = [ - { - moduleName: 'default', - title: 'Test Templates', - type: 'image', - templates: [ + test( + 'template cards descriptions adjust height dynamically', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + // Setup test by intercepting templates response to inject cards with varying description lengths + await comfyPage.page.route( + '**/templates/index.json', + async (route, _) => { + const response = [ { - name: 'short-description', - title: 'Short Description', - mediaType: 'image', - mediaSubtype: 'webp', - description: 'This is a short description.' - }, - { - name: 'medium-description', - title: 'Medium Description', - mediaType: 'image', - mediaSubtype: 'webp', - description: - 'This is a medium length description that should take up two lines on most displays.' - }, - { - name: 'long-description', - title: 'Long Description', - mediaType: 'image', - mediaSubtype: 'webp', - description: - 'This is a much longer description that should definitely wrap to multiple lines. It contains enough text to demonstrate how the cards handle varying amounts of content while maintaining a consistent layout grid.' + moduleName: 'default', + title: 'Test Templates', + type: 'image', + templates: [ + { + name: 'short-description', + title: 'Short Description', + mediaType: 'image', + mediaSubtype: 'webp', + description: 'This is a short description.' + }, + { + name: 'medium-description', + title: 'Medium Description', + mediaType: 'image', + mediaSubtype: 'webp', + description: + 'This is a medium length description that should take up two lines on most displays.' + }, + { + name: 'long-description', + title: 'Long Description', + mediaType: 'image', + mediaSubtype: 'webp', + description: + 'This is a much longer description that should definitely wrap to multiple lines. It contains enough text to demonstrate how the cards handle varying amounts of content while maintaining a consistent layout grid.' + } + ] } ] + await route.fulfill({ + status: 200, + body: JSON.stringify(response), + headers: { + 'Content-Type': 'application/json', + 'Cache-Control': 'no-store' + } + }) } - ] - await route.fulfill({ - status: 200, - body: JSON.stringify(response), - headers: { - 'Content-Type': 'application/json', + ) + + // Mock the thumbnail images to avoid 404s + await comfyPage.page.route('**/templates/**.webp', async (route) => { + const headers = { + 'Content-Type': 'image/webp', 'Cache-Control': 'no-store' } + await route.fulfill({ + status: 200, + path: 'browser_tests/assets/example.webp', + headers + }) }) - }) - // Mock the thumbnail images to avoid 404s - await comfyPage.page.route('**/templates/**.webp', async (route) => { - const headers = { - 'Content-Type': 'image/webp', - 'Cache-Control': 'no-store' - } - await route.fulfill({ - status: 200, - path: 'browser_tests/assets/example.webp', - headers - }) - }) + // Open templates dialog + await comfyPage.executeCommand('Comfy.BrowseTemplates') + await expect(comfyPage.templates.content).toBeVisible() - // Open templates dialog - await comfyPage.executeCommand('Comfy.BrowseTemplates') - await expect(comfyPage.templates.content).toBeVisible() + // Wait for cards to load + await expect( + comfyPage.page.locator( + '[data-testid="template-workflow-short-description"]' + ) + ).toBeVisible({ timeout: 5000 }) - // Wait for cards to load - await expect( - comfyPage.page.locator( + // Verify all three cards with different descriptions are visible + const shortDescCard = comfyPage.page.locator( '[data-testid="template-workflow-short-description"]' ) - ).toBeVisible({ timeout: 5000 }) + const mediumDescCard = comfyPage.page.locator( + '[data-testid="template-workflow-medium-description"]' + ) + const longDescCard = comfyPage.page.locator( + '[data-testid="template-workflow-long-description"]' + ) - // Verify all three cards with different descriptions are visible - const shortDescCard = comfyPage.page.locator( - '[data-testid="template-workflow-short-description"]' - ) - const mediumDescCard = comfyPage.page.locator( - '[data-testid="template-workflow-medium-description"]' - ) - const longDescCard = comfyPage.page.locator( - '[data-testid="template-workflow-long-description"]' - ) + await expect(shortDescCard).toBeVisible() + await expect(mediumDescCard).toBeVisible() + await expect(longDescCard).toBeVisible() - await expect(shortDescCard).toBeVisible() - await expect(mediumDescCard).toBeVisible() - await expect(longDescCard).toBeVisible() + // Verify descriptions are visible and have line-clamp class + // The description is in a p tag with text-muted class + const shortDesc = shortDescCard.locator('p.text-muted.line-clamp-2') + const mediumDesc = mediumDescCard.locator('p.text-muted.line-clamp-2') + const longDesc = longDescCard.locator('p.text-muted.line-clamp-2') - // Verify descriptions are visible and have line-clamp class - // The description is in a p tag with text-muted class - const shortDesc = shortDescCard.locator('p.text-muted.line-clamp-2') - const mediumDesc = mediumDescCard.locator('p.text-muted.line-clamp-2') - const longDesc = longDescCard.locator('p.text-muted.line-clamp-2') + await expect(shortDesc).toContainText('short description') + await expect(mediumDesc).toContainText('medium length description') + await expect(longDesc).toContainText('much longer description') - await expect(shortDesc).toContainText('short description') - await expect(mediumDesc).toContainText('medium length description') - await expect(longDesc).toContainText('much longer description') - - // Verify grid layout maintains consistency - const templateGrid = comfyPage.page.locator( - '[data-testid="template-workflows-content"]' - ) - await expect(templateGrid).toBeVisible() - await expect(templateGrid).toHaveScreenshot( - 'template-grid-varying-content.png' - ) - }) + // Verify grid layout maintains consistency + const templateGrid = comfyPage.page.locator( + '[data-testid="template-workflows-content"]' + ) + await expect(templateGrid).toBeVisible() + await expect(templateGrid).toHaveScreenshot( + 'template-grid-varying-content.png' + ) + } + ) }) diff --git a/browser_tests/tests/useSettingSearch.spec.ts b/browser_tests/tests/useSettingSearch.spec.ts index f022bb4bd2..aa34814081 100644 --- a/browser_tests/tests/useSettingSearch.spec.ts +++ b/browser_tests/tests/useSettingSearch.spec.ts @@ -6,7 +6,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Settings Search functionality', () => { +test.describe('Settings Search functionality', { tag: '@settings' }, () => { test.beforeEach(async ({ comfyPage }) => { // Register test settings to verify hidden/deprecated filtering await comfyPage.page.evaluate(() => { diff --git a/browser_tests/tests/userSelectView.spec.ts b/browser_tests/tests/userSelectView.spec.ts index 38b1a2317b..45eccb0c19 100644 --- a/browser_tests/tests/userSelectView.spec.ts +++ b/browser_tests/tests/userSelectView.spec.ts @@ -5,7 +5,7 @@ import { userSelectPageFixture as test } from '../fixtures/UserSelectPage' /** * Expects ComfyUI backend to be launched with `--multi-user` flag. */ -test.describe('User Select View', () => { +test.describe('User Select View', { tag: '@settings' }, () => { test.beforeEach(async ({ userSelectPage, page }) => { await page.goto(userSelectPage.url) await page.evaluate(() => { diff --git a/browser_tests/tests/versionMismatchWarnings.spec.ts b/browser_tests/tests/versionMismatchWarnings.spec.ts index 223770b122..15c55873f2 100644 --- a/browser_tests/tests/versionMismatchWarnings.spec.ts +++ b/browser_tests/tests/versionMismatchWarnings.spec.ts @@ -3,7 +3,7 @@ import { expect } from '@playwright/test' import type { SystemStats } from '../../src/schemas/apiSchema' import { comfyPageFixture as test } from '../fixtures/ComfyPage' -test.describe('Version Mismatch Warnings', () => { +test.describe('Version Mismatch Warnings', { tag: '@slow' }, () => { const ALWAYS_AHEAD_OF_INSTALLED_VERSION = '100.100.100' const ALWAYS_BEHIND_INSTALLED_VERSION = '0.0.0' diff --git a/browser_tests/tests/viewport.spec.ts b/browser_tests/tests/viewport.spec.ts index 7bc686a1cf..c0d65ca38c 100644 --- a/browser_tests/tests/viewport.spec.ts +++ b/browser_tests/tests/viewport.spec.ts @@ -2,7 +2,7 @@ import { expect } from '@playwright/test' import { comfyPageFixture as test } from '../fixtures/ComfyPage' -test.describe('Viewport', () => { +test.describe('Viewport', { tag: ['@screenshot', '@smoke', '@canvas'] }, () => { test('Fits view to nodes when saved viewport position is offscreen', async ({ comfyPage }) => { diff --git a/browser_tests/tests/vueNodes/groups/groups.spec.ts b/browser_tests/tests/vueNodes/groups/groups.spec.ts index c12c1772b9..19404f7d4b 100644 --- a/browser_tests/tests/vueNodes/groups/groups.spec.ts +++ b/browser_tests/tests/vueNodes/groups/groups.spec.ts @@ -5,7 +5,7 @@ import { const CREATE_GROUP_HOTKEY = 'Control+g' -test.describe('Vue Node Groups', () => { +test.describe('Vue Node Groups', { tag: '@screenshot' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.VueNodes.Enabled', true) await comfyPage.setSetting('Comfy.Minimap.ShowGroups', true) diff --git a/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts b/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts index a91a9b928c..ed18ab3678 100644 --- a/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts +++ b/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts @@ -9,10 +9,14 @@ test.describe('Vue Nodes Canvas Pan', () => { await comfyPage.vueNodes.waitForNodes() }) - test('@mobile Can pan with touch', async ({ comfyPage }) => { - await comfyPage.panWithTouch({ x: 64, y: 64 }, { x: 256, y: 256 }) - await expect(comfyPage.canvas).toHaveScreenshot( - 'vue-nodes-paned-with-touch.png' - ) - }) + test( + '@mobile Can pan with touch', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.panWithTouch({ x: 64, y: 64 }, { x: 256, y: 256 }) + await expect(comfyPage.canvas).toHaveScreenshot( + 'vue-nodes-paned-with-touch.png' + ) + } + ) }) diff --git a/browser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts b/browser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts index 2166233376..0b064dd81b 100644 --- a/browser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts +++ b/browser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts @@ -10,25 +10,30 @@ test.describe('Vue Nodes Zoom', () => { await comfyPage.vueNodes.waitForNodes() }) - test('should not capture drag while zooming with ctrl+shift+drag', async ({ - comfyPage - }) => { - const checkpointNode = comfyPage.vueNodes.getNodeByTitle('Load Checkpoint') - const nodeBoundingBox = await checkpointNode.boundingBox() - if (!nodeBoundingBox) throw new Error('Node bounding box not available') + test( + 'should not capture drag while zooming with ctrl+shift+drag', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + const checkpointNode = + comfyPage.vueNodes.getNodeByTitle('Load Checkpoint') + const nodeBoundingBox = await checkpointNode.boundingBox() + if (!nodeBoundingBox) throw new Error('Node bounding box not available') - const nodeMidpointX = nodeBoundingBox.x + nodeBoundingBox.width / 2 - const nodeMidpointY = nodeBoundingBox.y + nodeBoundingBox.height / 2 + const nodeMidpointX = nodeBoundingBox.x + nodeBoundingBox.width / 2 + const nodeMidpointY = nodeBoundingBox.y + nodeBoundingBox.height / 2 - // Start the Ctrl+Shift drag-to-zoom on the canvas and continue dragging over - // the node. The node should not capture the drag while drag-zooming. - await comfyPage.page.keyboard.down('Control') - await comfyPage.page.keyboard.down('Shift') - await comfyPage.dragAndDrop( - { x: 200, y: 300 }, - { x: nodeMidpointX, y: nodeMidpointY } - ) + // Start the Ctrl+Shift drag-to-zoom on the canvas and continue dragging over + // the node. The node should not capture the drag while drag-zooming. + await comfyPage.page.keyboard.down('Control') + await comfyPage.page.keyboard.down('Shift') + await comfyPage.dragAndDrop( + { x: 200, y: 300 }, + { x: nodeMidpointX, y: nodeMidpointY } + ) - await expect(comfyPage.canvas).toHaveScreenshot('zoomed-in-ctrl-shift.png') - }) + await expect(comfyPage.canvas).toHaveScreenshot( + 'zoomed-in-ctrl-shift.png' + ) + } + ) }) diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts index 9b007afb2b..b22baf5b11 100644 --- a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts +++ b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts @@ -98,7 +98,7 @@ async function connectSlots( await nextFrame() } -test.describe('Vue Node Link Interaction', () => { +test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') await comfyPage.setSetting('Comfy.VueNodes.Enabled', true) diff --git a/browser_tests/tests/vueNodes/interactions/node/bringToFront.spec.ts b/browser_tests/tests/vueNodes/interactions/node/bringToFront.spec.ts index 6e20f9e367..07b23e0883 100644 --- a/browser_tests/tests/vueNodes/interactions/node/bringToFront.spec.ts +++ b/browser_tests/tests/vueNodes/interactions/node/bringToFront.spec.ts @@ -5,7 +5,7 @@ import { import type { ComfyPage } from '../../../../fixtures/ComfyPage' import { fitToViewInstant } from '../../../../helpers/fitToView' -test.describe('Vue Node Bring to Front', () => { +test.describe('Vue Node Bring to Front', { tag: '@screenshot' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') await comfyPage.setSetting('Comfy.VueNodes.Enabled', true) diff --git a/browser_tests/tests/vueNodes/interactions/node/move.spec.ts b/browser_tests/tests/vueNodes/interactions/node/move.spec.ts index ac4759934e..fd74872e52 100644 --- a/browser_tests/tests/vueNodes/interactions/node/move.spec.ts +++ b/browser_tests/tests/vueNodes/interactions/node/move.spec.ts @@ -1,8 +1,8 @@ import { - type ComfyPage, comfyExpect as expect, comfyPageFixture as test } from '../../../../fixtures/ComfyPage' +import type { ComfyPage } from '../../../../fixtures/ComfyPage' import type { Position } from '../../../../fixtures/types' test.describe('Vue Node Moving', () => { @@ -29,39 +29,47 @@ test.describe('Vue Node Moving', () => { expect(diffY).toBeGreaterThan(0) } - test('should allow moving nodes by dragging', async ({ comfyPage }) => { - const loadCheckpointHeaderPos = await getLoadCheckpointHeaderPos(comfyPage) - await comfyPage.dragAndDrop(loadCheckpointHeaderPos, { - x: 256, - y: 256 - }) + test( + 'should allow moving nodes by dragging', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + const loadCheckpointHeaderPos = + await getLoadCheckpointHeaderPos(comfyPage) + await comfyPage.dragAndDrop(loadCheckpointHeaderPos, { + x: 256, + y: 256 + }) - const newHeaderPos = await getLoadCheckpointHeaderPos(comfyPage) - await expectPosChanged(loadCheckpointHeaderPos, newHeaderPos) + const newHeaderPos = await getLoadCheckpointHeaderPos(comfyPage) + await expectPosChanged(loadCheckpointHeaderPos, newHeaderPos) - await expect(comfyPage.canvas).toHaveScreenshot('vue-node-moved-node.png') - }) + await expect(comfyPage.canvas).toHaveScreenshot('vue-node-moved-node.png') + } + ) - test('@mobile should allow moving nodes by dragging on touch devices', async ({ - comfyPage - }) => { - // Disable minimap (gets in way of the node on small screens) - await comfyPage.setSetting('Comfy.Minimap.Visible', false) + test( + '@mobile should allow moving nodes by dragging on touch devices', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + // Disable minimap (gets in way of the node on small screens) + await comfyPage.setSetting('Comfy.Minimap.Visible', false) - const loadCheckpointHeaderPos = await getLoadCheckpointHeaderPos(comfyPage) - await comfyPage.panWithTouch( - { - x: 64, - y: 64 - }, - loadCheckpointHeaderPos - ) + const loadCheckpointHeaderPos = + await getLoadCheckpointHeaderPos(comfyPage) + await comfyPage.panWithTouch( + { + x: 64, + y: 64 + }, + loadCheckpointHeaderPos + ) - const newHeaderPos = await getLoadCheckpointHeaderPos(comfyPage) - await expectPosChanged(loadCheckpointHeaderPos, newHeaderPos) + const newHeaderPos = await getLoadCheckpointHeaderPos(comfyPage) + await expectPosChanged(loadCheckpointHeaderPos, newHeaderPos) - await expect(comfyPage.canvas).toHaveScreenshot( - 'vue-node-moved-node-touch.png' - ) - }) + await expect(comfyPage.canvas).toHaveScreenshot( + 'vue-node-moved-node-touch.png' + ) + } + ) }) diff --git a/browser_tests/tests/vueNodes/nodeStates/bypass.spec.ts b/browser_tests/tests/vueNodes/nodeStates/bypass.spec.ts index 7074bbc2d7..fb9ff28725 100644 --- a/browser_tests/tests/vueNodes/nodeStates/bypass.spec.ts +++ b/browser_tests/tests/vueNodes/nodeStates/bypass.spec.ts @@ -15,22 +15,25 @@ test.describe('Vue Node Bypass', () => { await comfyPage.vueNodes.waitForNodes() }) - test('should allow toggling bypass on a selected node with hotkey', async ({ - comfyPage - }) => { - await comfyPage.page.getByText('Load Checkpoint').click() - await comfyPage.page.keyboard.press(BYPASS_HOTKEY) + test( + 'should allow toggling bypass on a selected node with hotkey', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.page.getByText('Load Checkpoint').click() + await comfyPage.page.keyboard.press(BYPASS_HOTKEY) - const checkpointNode = comfyPage.vueNodes.getNodeByTitle('Load Checkpoint') - await expect(checkpointNode).toHaveClass(BYPASS_CLASS) - await comfyPage.nextFrame() - await expect(comfyPage.canvas).toHaveScreenshot( - 'vue-node-bypassed-state.png' - ) + const checkpointNode = + comfyPage.vueNodes.getNodeByTitle('Load Checkpoint') + await expect(checkpointNode).toHaveClass(BYPASS_CLASS) + await comfyPage.nextFrame() + await expect(comfyPage.canvas).toHaveScreenshot( + 'vue-node-bypassed-state.png' + ) - await comfyPage.page.keyboard.press(BYPASS_HOTKEY) - await expect(checkpointNode).not.toHaveClass(BYPASS_CLASS) - }) + await comfyPage.page.keyboard.press(BYPASS_HOTKEY) + await expect(checkpointNode).not.toHaveClass(BYPASS_CLASS) + } + ) test('should allow toggling bypass on multiple selected nodes with hotkey', async ({ comfyPage diff --git a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts index e61e3ca013..369c7e195d 100644 --- a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts +++ b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts @@ -3,7 +3,7 @@ import { comfyPageFixture as test } from '../../../fixtures/ComfyPage' -test.describe('Vue Node Custom Colors', () => { +test.describe('Vue Node Custom Colors', { tag: '@screenshot' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') await comfyPage.setSetting('Comfy.Canvas.SelectionToolbox', true) diff --git a/browser_tests/tests/vueNodes/nodeStates/mute.spec.ts b/browser_tests/tests/vueNodes/nodeStates/mute.spec.ts index 3fe656ebc9..e59d79cfd7 100644 --- a/browser_tests/tests/vueNodes/nodeStates/mute.spec.ts +++ b/browser_tests/tests/vueNodes/nodeStates/mute.spec.ts @@ -12,19 +12,24 @@ test.describe('Vue Node Mute', () => { await comfyPage.vueNodes.waitForNodes() }) - test('should allow toggling mute on a selected node with hotkey', async ({ - comfyPage - }) => { - await comfyPage.page.getByText('Load Checkpoint').click() - await comfyPage.page.keyboard.press(MUTE_HOTKEY) + test( + 'should allow toggling mute on a selected node with hotkey', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.page.getByText('Load Checkpoint').click() + await comfyPage.page.keyboard.press(MUTE_HOTKEY) - const checkpointNode = comfyPage.vueNodes.getNodeByTitle('Load Checkpoint') - await expect(checkpointNode).toHaveCSS('opacity', MUTE_OPACITY) - await expect(comfyPage.canvas).toHaveScreenshot('vue-node-muted-state.png') + const checkpointNode = + comfyPage.vueNodes.getNodeByTitle('Load Checkpoint') + await expect(checkpointNode).toHaveCSS('opacity', MUTE_OPACITY) + await expect(comfyPage.canvas).toHaveScreenshot( + 'vue-node-muted-state.png' + ) - await comfyPage.page.keyboard.press(MUTE_HOTKEY) - await expect(checkpointNode).not.toHaveCSS('opacity', MUTE_OPACITY) - }) + await comfyPage.page.keyboard.press(MUTE_HOTKEY) + await expect(checkpointNode).not.toHaveCSS('opacity', MUTE_OPACITY) + } + ) test('should allow toggling mute on multiple selected nodes with hotkey', async ({ comfyPage diff --git a/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts b/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts index 8fcc3360df..2ae178d221 100644 --- a/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts +++ b/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts @@ -9,13 +9,17 @@ test.describe('Vue Upload Widgets', () => { await comfyPage.vueNodes.waitForNodes() }) - test('should hide canvas-only upload buttons', async ({ comfyPage }) => { - await comfyPage.setup() - await comfyPage.loadWorkflow('widgets/all_load_widgets') - await comfyPage.vueNodes.waitForNodes() + test( + 'should hide canvas-only upload buttons', + { tag: '@screenshot' }, + async ({ comfyPage }) => { + await comfyPage.setup() + await comfyPage.loadWorkflow('widgets/all_load_widgets') + await comfyPage.vueNodes.waitForNodes() - await expect(comfyPage.canvas).toHaveScreenshot( - 'vue-nodes-upload-widgets.png' - ) - }) + await expect(comfyPage.canvas).toHaveScreenshot( + 'vue-nodes-upload-widgets.png' + ) + } + ) }) diff --git a/browser_tests/tests/widget.spec.ts b/browser_tests/tests/widget.spec.ts index 075854860b..a0dfb0a6ea 100644 --- a/browser_tests/tests/widget.spec.ts +++ b/browser_tests/tests/widget.spec.ts @@ -6,7 +6,7 @@ test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled') }) -test.describe('Combo text widget', () => { +test.describe('Combo text widget', { tag: ['@screenshot', '@widget'] }, () => { test('Truncates text when resized', async ({ comfyPage }) => { await comfyPage.resizeLoadCheckpointNode(0.2, 1) await expect(comfyPage.canvas).toHaveScreenshot( @@ -79,7 +79,7 @@ test.describe('Combo text widget', () => { }) }) -test.describe('Boolean widget', () => { +test.describe('Boolean widget', { tag: ['@screenshot', '@widget'] }, () => { test('Can toggle', async ({ comfyPage }) => { await comfyPage.loadWorkflow('widgets/boolean_widget') await expect(comfyPage.canvas).toHaveScreenshot('boolean_widget.png') @@ -92,7 +92,7 @@ test.describe('Boolean widget', () => { }) }) -test.describe('Slider widget', () => { +test.describe('Slider widget', { tag: ['@screenshot', '@widget'] }, () => { test('Can drag adjust value', async ({ comfyPage }) => { await comfyPage.loadWorkflow('inputs/simple_slider') const node = (await comfyPage.getFirstNodeRef())! @@ -113,7 +113,7 @@ test.describe('Slider widget', () => { }) }) -test.describe('Number widget', () => { +test.describe('Number widget', { tag: ['@screenshot', '@widget'] }, () => { test('Can drag adjust value', async ({ comfyPage }) => { await comfyPage.loadWorkflow('widgets/seed_widget') @@ -134,22 +134,28 @@ test.describe('Number widget', () => { }) }) -test.describe('Dynamic widget manipulation', () => { - test('Auto expand node when widget is added dynamically', async ({ - comfyPage - }) => { - await comfyPage.loadWorkflow('nodes/single_ksampler') +test.describe( + 'Dynamic widget manipulation', + { tag: ['@screenshot', '@widget'] }, + () => { + test('Auto expand node when widget is added dynamically', async ({ + comfyPage + }) => { + await comfyPage.loadWorkflow('nodes/single_ksampler') - await comfyPage.page.evaluate(() => { - window['graph'].nodes[0].addWidget('number', 'new_widget', 10) - window['graph'].setDirtyCanvas(true, true) + await comfyPage.page.evaluate(() => { + window['graph'].nodes[0].addWidget('number', 'new_widget', 10) + window['graph'].setDirtyCanvas(true, true) + }) + + await expect(comfyPage.canvas).toHaveScreenshot( + 'ksampler_widget_added.png' + ) }) + } +) - await expect(comfyPage.canvas).toHaveScreenshot('ksampler_widget_added.png') - }) -}) - -test.describe('Image widget', () => { +test.describe('Image widget', { tag: ['@screenshot', '@widget'] }, () => { test('Can load image', async ({ comfyPage }) => { await comfyPage.loadWorkflow('widgets/load_image_widget') await expect(comfyPage.canvas).toHaveScreenshot('load_image_widget.png') @@ -236,99 +242,103 @@ test.describe('Image widget', () => { }) }) -test.describe('Animated image widget', () => { - // https://github.com/Comfy-Org/ComfyUI_frontend/issues/3718 - test.skip('Shows preview of uploaded animated image', async ({ - comfyPage - }) => { - await comfyPage.loadWorkflow('widgets/load_animated_webp') +test.describe( + 'Animated image widget', + { tag: ['@screenshot', '@widget'] }, + () => { + // https://github.com/Comfy-Org/ComfyUI_frontend/issues/3718 + test.skip('Shows preview of uploaded animated image', async ({ + comfyPage + }) => { + await comfyPage.loadWorkflow('widgets/load_animated_webp') - // Get position of the load animated webp node - const nodes = await comfyPage.getNodeRefsByType( - 'DevToolsLoadAnimatedImageTest' - ) - const loadAnimatedWebpNode = nodes[0] - const { x, y } = await loadAnimatedWebpNode.getPosition() + // Get position of the load animated webp node + const nodes = await comfyPage.getNodeRefsByType( + 'DevToolsLoadAnimatedImageTest' + ) + const loadAnimatedWebpNode = nodes[0] + const { x, y } = await loadAnimatedWebpNode.getPosition() - // Drag and drop image file onto the load animated webp node - await comfyPage.dragAndDropFile('animated_webp.webp', { - dropPosition: { x, y } + // Drag and drop image file onto the load animated webp node + await comfyPage.dragAndDropFile('animated_webp.webp', { + dropPosition: { x, y } + }) + + // Expect the image preview to change automatically + await expect(comfyPage.canvas).toHaveScreenshot( + 'animated_image_preview_drag_and_dropped.png' + ) + + // Move mouse and click on canvas to trigger render + await comfyPage.page.mouse.click(64, 64) + + // Expect the image preview to change to the next frame of the animation + await expect(comfyPage.canvas).toHaveScreenshot( + 'animated_image_preview_drag_and_dropped_next_frame.png' + ) }) - // Expect the image preview to change automatically - await expect(comfyPage.canvas).toHaveScreenshot( - 'animated_image_preview_drag_and_dropped.png' - ) + test('Can drag-and-drop animated webp image', async ({ comfyPage }) => { + await comfyPage.loadWorkflow('widgets/load_animated_webp') - // Move mouse and click on canvas to trigger render - await comfyPage.page.mouse.click(64, 64) + // Get position of the load animated webp node + const nodes = await comfyPage.getNodeRefsByType( + 'DevToolsLoadAnimatedImageTest' + ) + const loadAnimatedWebpNode = nodes[0] + const { x, y } = await loadAnimatedWebpNode.getPosition() - // Expect the image preview to change to the next frame of the animation - await expect(comfyPage.canvas).toHaveScreenshot( - 'animated_image_preview_drag_and_dropped_next_frame.png' - ) - }) + // Drag and drop image file onto the load animated webp node + await comfyPage.dragAndDropFile('animated_webp.webp', { + dropPosition: { x, y }, + waitForUpload: true + }) - test('Can drag-and-drop animated webp image', async ({ comfyPage }) => { - await comfyPage.loadWorkflow('widgets/load_animated_webp') - - // Get position of the load animated webp node - const nodes = await comfyPage.getNodeRefsByType( - 'DevToolsLoadAnimatedImageTest' - ) - const loadAnimatedWebpNode = nodes[0] - const { x, y } = await loadAnimatedWebpNode.getPosition() - - // Drag and drop image file onto the load animated webp node - await comfyPage.dragAndDropFile('animated_webp.webp', { - dropPosition: { x, y }, - waitForUpload: true + // Expect the filename combo value to be updated + const fileComboWidget = await loadAnimatedWebpNode.getWidget(0) + const filename = await fileComboWidget.getValue() + expect(filename).toContain('animated_webp.webp') }) - // Expect the filename combo value to be updated - const fileComboWidget = await loadAnimatedWebpNode.getWidget(0) - const filename = await fileComboWidget.getValue() - expect(filename).toContain('animated_webp.webp') - }) + test('Can preview saved animated webp image', async ({ comfyPage }) => { + await comfyPage.loadWorkflow('widgets/save_animated_webp') - test('Can preview saved animated webp image', async ({ comfyPage }) => { - await comfyPage.loadWorkflow('widgets/save_animated_webp') + // Get position of the load animated webp node + const loadNodes = await comfyPage.getNodeRefsByType( + 'DevToolsLoadAnimatedImageTest' + ) + const loadAnimatedWebpNode = loadNodes[0] + const { x, y } = await loadAnimatedWebpNode.getPosition() - // Get position of the load animated webp node - const loadNodes = await comfyPage.getNodeRefsByType( - 'DevToolsLoadAnimatedImageTest' - ) - const loadAnimatedWebpNode = loadNodes[0] - const { x, y } = await loadAnimatedWebpNode.getPosition() + // Drag and drop image file onto the load animated webp node + await comfyPage.dragAndDropFile('animated_webp.webp', { + dropPosition: { x, y } + }) + await comfyPage.nextFrame() - // Drag and drop image file onto the load animated webp node - await comfyPage.dragAndDropFile('animated_webp.webp', { - dropPosition: { x, y } + // Get the SaveAnimatedWEBP node + const saveNodes = await comfyPage.getNodeRefsByType('SaveAnimatedWEBP') + const saveAnimatedWebpNode = saveNodes[0] + if (!saveAnimatedWebpNode) + throw new Error('SaveAnimatedWEBP node not found') + + // Simulate the graph executing + await comfyPage.page.evaluate( + ([loadId, saveId]) => { + // Set the output of the SaveAnimatedWEBP node to equal the loader node's image + window['app'].nodeOutputs[saveId] = window['app'].nodeOutputs[loadId] + app.canvas.setDirty(true) + }, + [loadAnimatedWebpNode.id, saveAnimatedWebpNode.id] + ) + await expect( + comfyPage.page.locator('.dom-widget').locator('img') + ).toHaveCount(2) }) - await comfyPage.nextFrame() + } +) - // Get the SaveAnimatedWEBP node - const saveNodes = await comfyPage.getNodeRefsByType('SaveAnimatedWEBP') - const saveAnimatedWebpNode = saveNodes[0] - if (!saveAnimatedWebpNode) - throw new Error('SaveAnimatedWEBP node not found') - - // Simulate the graph executing - await comfyPage.page.evaluate( - ([loadId, saveId]) => { - // Set the output of the SaveAnimatedWEBP node to equal the loader node's image - window['app'].nodeOutputs[saveId] = window['app'].nodeOutputs[loadId] - app.canvas.setDirty(true) - }, - [loadAnimatedWebpNode.id, saveAnimatedWebpNode.id] - ) - await expect( - comfyPage.page.locator('.dom-widget').locator('img') - ).toHaveCount(2) - }) -}) - -test.describe('Load audio widget', () => { +test.describe('Load audio widget', { tag: ['@screenshot', '@widget'] }, () => { test('Can load audio', async ({ comfyPage }) => { await comfyPage.loadWorkflow('widgets/load_audio_widget') // Wait for the audio widget to be rendered in the DOM @@ -338,7 +348,7 @@ test.describe('Load audio widget', () => { }) }) -test.describe('Unserialized widgets', () => { +test.describe('Unserialized widgets', { tag: '@widget' }, () => { test('Unserialized widgets values do not mark graph as modified', async ({ comfyPage }) => { diff --git a/browser_tests/tests/workflowTabThumbnail.spec.ts b/browser_tests/tests/workflowTabThumbnail.spec.ts index 31b15067f6..1f4d9464d6 100644 --- a/browser_tests/tests/workflowTabThumbnail.spec.ts +++ b/browser_tests/tests/workflowTabThumbnail.spec.ts @@ -1,8 +1,9 @@ import { expect } from '@playwright/test' -import { type ComfyPage, comfyPageFixture as test } from '../fixtures/ComfyPage' +import { comfyPageFixture as test } from '../fixtures/ComfyPage' +import type { ComfyPage } from '../fixtures/ComfyPage' -test.describe('Workflow Tab Thumbnails', () => { +test.describe('Workflow Tab Thumbnails', { tag: '@workflow' }, () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') await comfyPage.setSetting('Comfy.Workflow.WorkflowTabsPosition', 'Topbar') diff --git a/package.json b/package.json index 0106043d1c..86db51eb8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@comfyorg/comfyui-frontend", - "version": "1.39.1", + "version": "1.39.2", "private": true, "description": "Official front-end implementation of ComfyUI", "homepage": "https://comfy.org", diff --git a/src/components/dialog/content/setting/KeybindingPanel.vue b/src/components/dialog/content/setting/KeybindingPanel.vue index 03ca3df47c..4ef7c3e953 100644 --- a/src/components/dialog/content/setting/KeybindingPanel.vue +++ b/src/components/dialog/content/setting/KeybindingPanel.vue @@ -265,18 +265,15 @@ function cancelEdit() { } async function saveKeybinding() { - if (currentEditingCommand.value && newBindingKeyCombo.value) { - const updated = keybindingStore.updateKeybindingOnCommand( - new KeybindingImpl({ - commandId: currentEditingCommand.value.id, - combo: newBindingKeyCombo.value - }) - ) - if (updated) { - await keybindingService.persistUserKeybindings() - } - } + const commandId = currentEditingCommand.value?.id + const combo = newBindingKeyCombo.value cancelEdit() + if (!combo || commandId == undefined) return + + const updated = keybindingStore.updateKeybindingOnCommand( + new KeybindingImpl({ commandId, combo }) + ) + if (updated) await keybindingService.persistUserKeybindings() } async function resetKeybinding(commandData: ICommandData) { diff --git a/src/components/helpcenter/HelpCenterPopups.vue b/src/components/helpcenter/HelpCenterPopups.vue index d4f059fd22..516ecb976a 100644 --- a/src/components/helpcenter/HelpCenterPopups.vue +++ b/src/components/helpcenter/HelpCenterPopups.vue @@ -1,6 +1,6 @@
@@ -65,6 +65,7 @@ import MediaAssetCard from '@/platform/assets/components/MediaAssetCard.vue' import type { AssetItem } from '@/platform/assets/schemas/assetSchema' import { isActiveJobState } from '@/utils/queueUtil' import { cn } from '@/utils/tailwindUtil' +import { useSettingStore } from '@/platform/settings/settingStore' const { assets, @@ -90,6 +91,11 @@ const emit = defineEmits<{ const { t } = useI18n() const { jobItems } = useJobList() +const settingStore = useSettingStore() + +const isQueuePanelV2Enabled = computed(() => + settingStore.get('Comfy.Queue.QPOV2') +) type AssetGridItem = { key: string; asset: AssetItem } diff --git a/src/components/sidebar/tabs/AssetsSidebarListView.vue b/src/components/sidebar/tabs/AssetsSidebarListView.vue index f7fc73c3c8..209a744f2c 100644 --- a/src/components/sidebar/tabs/AssetsSidebarListView.vue +++ b/src/components/sidebar/tabs/AssetsSidebarListView.vue @@ -1,7 +1,7 @@