refactor playwright tests based on platform/workbench/renderer

This commit is contained in:
bymyself
2025-10-04 20:46:01 -07:00
parent 37fab21daf
commit 05da3ea928
272 changed files with 89 additions and 86 deletions

View File

@@ -0,0 +1,320 @@
import {
comfyExpect as expect,
comfyPageFixture as test
} from '../../fixtures/ComfyPage'
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Disabled')
})
test.describe('Node search box', () => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.LinkRelease.Action', 'search box')
await comfyPage.setSetting('Comfy.LinkRelease.ActionShift', 'search box')
await comfyPage.setSetting('Comfy.NodeSearchBoxImpl', 'default')
})
test(`Can trigger on empty canvas double click`, async ({ comfyPage }) => {
await comfyPage.doubleClickCanvas()
await expect(comfyPage.searchBox.input).toHaveCount(1)
})
test(`Can trigger on group body double click`, async ({ comfyPage }) => {
await comfyPage.loadWorkflow('groups/single_group_only')
await comfyPage.page.mouse.dblclick(50, 50, { delay: 5 })
await comfyPage.nextFrame()
await expect(comfyPage.searchBox.input).toHaveCount(1)
})
test('Can trigger on link release', async ({ comfyPage }) => {
await comfyPage.disconnectEdge()
await expect(comfyPage.searchBox.input).toHaveCount(1)
})
test('New user (1.24.1+) gets search box by default on link release', async ({
comfyPage
}) => {
// Start fresh to test new user behavior
await comfyPage.setup({ clearStorage: true })
// Simulate new user with 1.24.1+ installed version
await comfyPage.setSetting('Comfy.InstalledVersion', '1.24.1')
await comfyPage.setSetting('Comfy.NodeSearchBoxImpl', 'default')
// Don't set LinkRelease settings explicitly to test versioned defaults
await comfyPage.disconnectEdge()
await expect(comfyPage.searchBox.input).toHaveCount(1)
await expect(comfyPage.searchBox.input).toBeVisible()
})
test('Can add node', 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 }) => {
await comfyPage.disconnectEdge()
// Select the second item as the first item is always reroute
await comfyPage.searchBox.fillAndSelectFirstNode('CLIPTextEncode', {
suggestionIndex: 0
})
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')
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'
)
})
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'
await comfyPage.doubleClickCanvas()
await comfyPage.searchBox.input.waitFor({ state: 'visible' })
await comfyPage.searchBox.input.fill(node)
await comfyPage.searchBox.dropdown.waitFor({ state: 'visible' })
// Wait for some time for the auto complete list to update.
// The auto complete list is debounced and may take some time to update.
await comfyPage.page.waitForTimeout(500)
const firstResult = comfyPage.searchBox.dropdown.locator('li').first()
await expect(firstResult).toHaveAttribute('aria-label', node)
})
test('@mobile Can trigger on empty canvas tap', async ({ comfyPage }) => {
await comfyPage.closeMenu()
await comfyPage.loadWorkflow('nodes/single_ksampler')
const screenCenter = {
x: 200,
y: 400
}
await comfyPage.canvas.tap({
position: screenCenter
})
await comfyPage.canvas.tap({
position: screenCenter
})
await comfyPage.page.waitForTimeout(256)
await expect(comfyPage.searchBox.input).not.toHaveCount(0)
})
test.describe('Filtering', () => {
const expectFilterChips = async (comfyPage, expectedTexts: string[]) => {
const chips = comfyPage.searchBox.filterChips
// Check that the number of chips matches the expected count
await expect(chips).toHaveCount(expectedTexts.length)
// Verify the text and visibility of each filter chip
await Promise.all(
expectedTexts.map(async (text, index) => {
const chip = chips.nth(index)
await expect(chip).toContainText(text)
await expect(chip).toBeVisible()
})
)
}
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.doubleClickCanvas()
})
test('Can add filter', async ({ comfyPage }) => {
await comfyPage.searchBox.addFilter('MODEL', 'Input Type')
await expectFilterChips(comfyPage, ['MODEL'])
})
// Flaky test.
// Sample test failure:
// https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/12696912248/job/35391990861?pr=2210
/*
1) [chromium-2x] nodeSearchBox.spec.ts:135:5 Node search box Filtering Outer click dismisses filter panel but keeps search box visible
Error: expect(locator).not.toBeVisible()
Locator: getByRole('dialog').locator('div').filter({ hasText: 'Add node filter condition' })
Expected: not visible
Received: visible
Call log:
- expect.not.toBeVisible with timeout 5000ms
- waiting for getByRole('dialog').locator('div').filter({ hasText: 'Add node filter condition' })
143 |
144 | // Verify the filter selection panel is hidden
> 145 | expect(panel.header).not.toBeVisible()
| ^
146 |
147 | // Verify the node search dialog is still visible
148 | expect(comfyPage.searchBox.input).toBeVisible()
at /home/runner/work/ComfyUI_frontend/ComfyUI_frontend/ComfyUI_frontend/browser_tests/nodeSearchBox.spec.ts:145:32
*/
test.skip('Outer click dismisses filter panel but keeps search box visible', async ({
comfyPage
}) => {
await comfyPage.searchBox.filterButton.click()
const panel = comfyPage.searchBox.filterSelectionPanel
await panel.header.waitFor({ state: 'visible' })
const panelBounds = await panel.header.boundingBox()
await comfyPage.page.mouse.click(panelBounds!.x - 10, panelBounds!.y - 10)
// Verify the filter selection panel is hidden
await expect(panel.header).not.toBeVisible()
// Verify the node search dialog is still visible
await expect(comfyPage.searchBox.input).toBeVisible()
})
test('Can add multiple filters', async ({ comfyPage }) => {
await comfyPage.searchBox.addFilter('MODEL', 'Input Type')
await comfyPage.searchBox.addFilter('CLIP', 'Output Type')
await expectFilterChips(comfyPage, ['MODEL', 'CLIP'])
})
test('Can remove filter', async ({ comfyPage }) => {
await comfyPage.searchBox.addFilter('MODEL', 'Input Type')
await comfyPage.searchBox.removeFilter(0)
await expectFilterChips(comfyPage, [])
})
test.describe('Removing from multiple filters', () => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.searchBox.addFilter('MODEL', 'Input Type')
await comfyPage.searchBox.addFilter('CLIP', 'Output Type')
await comfyPage.searchBox.addFilter('utils', 'Category')
})
test('Can remove first filter', async ({ comfyPage }) => {
await comfyPage.searchBox.removeFilter(0)
await expectFilterChips(comfyPage, ['CLIP', 'utils'])
await comfyPage.searchBox.removeFilter(0)
await expectFilterChips(comfyPage, ['utils'])
await comfyPage.searchBox.removeFilter(0)
await expectFilterChips(comfyPage, [])
})
test('Can remove middle filter', async ({ comfyPage }) => {
await comfyPage.searchBox.removeFilter(1)
await expectFilterChips(comfyPage, ['MODEL', 'utils'])
})
test('Can remove last filter', async ({ comfyPage }) => {
await comfyPage.searchBox.removeFilter(2)
await expectFilterChips(comfyPage, ['MODEL', 'CLIP'])
})
})
})
test.describe('Input focus behavior', () => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.doubleClickCanvas()
})
test('focuses input after adding a filter', async ({ comfyPage }) => {
await comfyPage.searchBox.addFilter('MODEL', 'Input Type')
await expect(comfyPage.searchBox.input).toHaveFocus()
})
test('focuses input after removing a filter', async ({ comfyPage }) => {
await comfyPage.searchBox.addFilter('MODEL', 'Input Type')
await comfyPage.searchBox.removeFilter(0)
await expect(comfyPage.searchBox.input).toHaveFocus()
})
})
})
test.describe('Release context menu', () => {
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()
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('Existing user (pre-1.24.1) gets context menu by default on link release', async ({
comfyPage
}) => {
// Start fresh to test existing user behavior
await comfyPage.setup({ clearStorage: true })
// Simulate existing user with pre-1.24.1 version
await comfyPage.setSetting('Comfy.InstalledVersion', '1.23.0')
await comfyPage.setSetting('Comfy.NodeSearchBoxImpl', 'default')
// Don't set LinkRelease settings explicitly to test versioned defaults
await comfyPage.disconnectEdge()
// Context menu should appear, search box should not
await expect(comfyPage.searchBox.input).toHaveCount(0)
const contextMenu = comfyPage.page.locator('.litecontextmenu')
await expect(contextMenu).toBeVisible()
})
test('Explicit setting overrides versioned defaults', async ({
comfyPage
}) => {
// Start fresh and simulate new user who should get search box by default
await comfyPage.setup({ clearStorage: true })
await comfyPage.setSetting('Comfy.InstalledVersion', '1.24.1')
// But explicitly set to context menu (overriding versioned default)
await comfyPage.setSetting('Comfy.LinkRelease.Action', 'context menu')
await comfyPage.setSetting('Comfy.NodeSearchBoxImpl', 'default')
await comfyPage.disconnectEdge()
// Context menu should appear due to explicit setting, not search box
await expect(comfyPage.searchBox.input).toHaveCount(0)
const contextMenu = comfyPage.page.locator('.litecontextmenu')
await expect(contextMenu).toBeVisible()
})
})