fix(browser_tests): replace .nth() with semantic selectors

- Remove unused saveButton selector from ComfyMenu
- Replace widgetTextBox .nth(1) with node-scoped selector
- Replace .nth(3) toast selector with .p-toast-message filter
- Replace .nth(1) category selector with getByTestId
- Replace .nth(1) node selector with getNodeInFolder() helper
- Add nodeSelector(), folderSelector(), getNodeInFolder() methods
- Add saveButton and nodeLibrary TestIds to selectors.ts

Amp-Thread-ID: https://ampcode.com/threads/T-019c155c-92e1-76f3-b6ce-7fc3ffa11582
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Alexander Brown
2026-01-31 10:52:41 -08:00
parent 22ff808d59
commit 7f2454efec
6 changed files with 37 additions and 24 deletions

View File

@@ -56,15 +56,11 @@ class ComfyMenu {
public readonly sideToolbar: Locator public readonly sideToolbar: Locator
public readonly propertiesPanel: ComfyPropertiesPanel public readonly propertiesPanel: ComfyPropertiesPanel
public readonly themeToggleButton: Locator public readonly themeToggleButton: Locator
public readonly saveButton: Locator
constructor(public readonly page: Page) { constructor(public readonly page: Page) {
this.sideToolbar = page.getByTestId(TestIds.sidebar.toolbar) this.sideToolbar = page.getByTestId(TestIds.sidebar.toolbar)
this.themeToggleButton = page.getByTestId(TestIds.sidebar.themeToggle) this.themeToggleButton = page.getByTestId(TestIds.sidebar.themeToggle)
this.propertiesPanel = new ComfyPropertiesPanel(page) this.propertiesPanel = new ComfyPropertiesPanel(page)
this.saveButton = page
.locator('button[title="Save the current workflow"]')
.nth(0)
} }
get buttons() { get buttons() {
@@ -202,7 +198,10 @@ export class ComfyPage {
this.url = process.env.PLAYWRIGHT_TEST_URL || 'http://localhost:8188' this.url = process.env.PLAYWRIGHT_TEST_URL || 'http://localhost:8188'
this.canvas = page.locator('#graph-canvas') this.canvas = page.locator('#graph-canvas')
this.selectionToolbox = page.locator('.selection-toolbox') this.selectionToolbox = page.locator('.selection-toolbox')
this.widgetTextBox = page.getByPlaceholder('text').nth(1) this.widgetTextBox = page
.locator('[data-node-id]')
.first()
.getByPlaceholder('text')
this.resetViewButton = page.getByRole('button', { name: 'Reset View' }) this.resetViewButton = page.getByRole('button', { name: 'Reset View' })
this.queueButton = page.getByRole('button', { name: 'Queue Prompt' }) this.queueButton = page.getByRole('button', { name: 'Queue Prompt' })
this.runButton = page this.runButton = page

View File

@@ -84,6 +84,20 @@ export class NodeLibrarySidebarTab extends SidebarTab {
`[data-testid="node-tree-leaf"][data-node-name="${nodeName}"]` `[data-testid="node-tree-leaf"][data-node-name="${nodeName}"]`
) )
} }
nodeSelector(nodeName: string): string {
return `[data-testid="node-tree-leaf"][data-node-name="${nodeName}"]`
}
folderSelector(folderName: string): string {
return `[data-testid="node-tree-folder"][data-folder-name="${folderName}"]`
}
getNodeInFolder(nodeName: string, folderName: string) {
return this.getFolder(folderName)
.locator('xpath=ancestor::li')
.locator(`[data-testid="node-tree-leaf"][data-node-name="${nodeName}"]`)
}
} }
export class WorkflowsSidebarTab extends SidebarTab { export class WorkflowsSidebarTab extends SidebarTab {

View File

@@ -27,7 +27,11 @@ export const TestIds = {
about: 'about-panel' about: 'about-panel'
}, },
topbar: { topbar: {
queueButton: 'queue-button' queueButton: 'queue-button',
saveButton: 'save-workflow-button'
},
nodeLibrary: {
bookmarksSection: 'node-library-bookmarks-section'
} }
} as const } as const
@@ -40,3 +44,4 @@ export type TestIdValue =
| (typeof TestIds.canvas)[keyof typeof TestIds.canvas] | (typeof TestIds.canvas)[keyof typeof TestIds.canvas]
| (typeof TestIds.dialogs)[keyof typeof TestIds.dialogs] | (typeof TestIds.dialogs)[keyof typeof TestIds.dialogs]
| (typeof TestIds.topbar)[keyof typeof TestIds.topbar] | (typeof TestIds.topbar)[keyof typeof TestIds.topbar]
| (typeof TestIds.nodeLibrary)[keyof typeof TestIds.nodeLibrary]

View File

@@ -183,9 +183,8 @@ test.describe('Node library sidebar', () => {
]) ])
const tab = comfyPage.menu.nodeLibraryTab const tab = comfyPage.menu.nodeLibraryTab
await tab.getFolder('sampling').click() await tab.getFolder('sampling').click()
await comfyPage.page await tab
.locator(tab.nodeSelector('KSampler (Advanced)')) .getNodeInFolder('KSampler (Advanced)', 'sampling')
.nth(1)
.locator('.bookmark-button') .locator('.bookmark-button')
.click() .click()
expect( expect(

View File

@@ -109,19 +109,16 @@ test.describe('Settings Search functionality', { tag: '@settings' }, () => {
const settingsDialog = comfyPage.page.locator('.settings-container') const settingsDialog = comfyPage.page.locator('.settings-container')
await expect(settingsDialog).toBeVisible() await expect(settingsDialog).toBeVisible()
// Get categories and click on different ones // Click on a specific category (Appearance) to verify category switching
const categories = comfyPage.page.locator( const appearanceCategory = comfyPage.page.getByTestId(
'.settings-sidebar .p-listbox-option' 'settings-tab-Appearance'
) )
const categoryCount = await categories.count() await appearanceCategory.click()
if (categoryCount > 1) { // Verify the category is selected by checking if its parent option has the selected class
// Click on the second category await expect(appearanceCategory.locator('xpath=ancestor::li')).toHaveClass(
await categories.nth(1).click() /p-listbox-option-selected/
)
// Verify the category is selected
await expect(categories.nth(1)).toHaveClass(/p-listbox-option-selected/)
}
}) })
test('settings content area is visible', async ({ comfyPage }) => { test('settings content area is visible', async ({ comfyPage }) => {

View File

@@ -103,10 +103,9 @@ test.describe('Version Mismatch Warnings', { tag: '@slow' }, () => {
await comfyPage.setup() await comfyPage.setup()
// Locate the warning toast and dismiss it // Locate the warning toast and dismiss it
const warningToast = comfyPage.page const warningToast = comfyPage.page.locator('.p-toast-message').filter({
.locator('div') hasText: 'Version Compatibility'
.filter({ hasText: 'Version Compatibility' }) })
.nth(3)
await warningToast.waitFor({ state: 'visible' }) await warningToast.waitFor({ state: 'visible' })
const dismissButton = warningToast.getByRole('button', { name: 'Close' }) const dismissButton = warningToast.getByRole('button', { name: 'Close' })
await dismissButton.click() await dismissButton.click()