Compare commits

...

1 Commits

Author SHA1 Message Date
bymyself
1cc6f8c1ce refactor: replace inline getByRole('dialog') with page objects in E2E tests
- confirmDialogTextWrap: use comfyPage.confirmDialog.root
- resultGallery: add MediaLightbox page object to ComfyPage
- templates: add dialog accessor to ComfyTemplates helper
- appModeDropdownClipping: add imagePickerPopover to AppModeHelper
- ComfyNodeSearchBox: extract root locator on filter selection panel

Fixes #10723
2026-03-29 16:25:59 -07:00
8 changed files with 37 additions and 14 deletions

View File

@@ -121,6 +121,16 @@ type KeysOfType<T, Match> = {
[K in keyof T]: T[K] extends Match ? K : never
}[keyof T]
class MediaLightbox {
readonly root: Locator
readonly closeButton: Locator
constructor(public readonly page: Page) {
this.root = page.getByRole('dialog')
this.closeButton = this.root.getByLabel('Close')
}
}
class ConfirmDialog {
public readonly root: Locator
public readonly delete: Locator
@@ -182,6 +192,7 @@ export class ComfyPage {
public readonly templates: ComfyTemplates
public readonly settingDialog: SettingDialog
public readonly confirmDialog: ConfirmDialog
public readonly mediaLightbox: MediaLightbox
public readonly vueNodes: VueNodeHelpers
public readonly appMode: AppModeHelper
public readonly subgraph: SubgraphHelper
@@ -230,6 +241,7 @@ export class ComfyPage {
this.templates = new ComfyTemplates(page)
this.settingDialog = new SettingDialog(page, this)
this.confirmDialog = new ConfirmDialog(page)
this.mediaLightbox = new MediaLightbox(page)
this.vueNodes = new VueNodeHelpers(page)
this.appMode = new AppModeHelper(this)
this.subgraph = new SubgraphHelper(this)

View File

@@ -1,11 +1,14 @@
import type { Locator, Page } from '@playwright/test'
export class ComfyNodeSearchFilterSelectionPanel {
constructor(public readonly page: Page) {}
readonly root: Locator
constructor(public readonly page: Page) {
this.root = page.getByRole('dialog')
}
get header() {
return this.page
.getByRole('dialog')
return this.root
.locator('div')
.filter({ hasText: 'Add node filter condition' })
}

View File

@@ -83,6 +83,14 @@ export class AppModeHelper {
return this.page.locator('[data-testid="linear-widgets"]')
}
/** The PrimeVue Popover for the image picker (renders with role="dialog"). */
get imagePickerPopover(): Locator {
return this.page
.getByRole('dialog')
.filter({ has: this.page.getByRole('button', { name: 'All' }) })
.first()
}
/**
* Get the actions menu trigger for a widget in the app mode widget list.
* @param widgetName Text shown in the widget label (e.g. "seed").

View File

@@ -10,10 +10,12 @@ import { TestIds } from '../fixtures/selectors'
export class ComfyTemplates {
readonly content: Locator
readonly dialog: Locator
readonly allTemplateCards: Locator
constructor(readonly page: Page) {
this.content = page.getByTestId(TestIds.templates.content)
this.dialog = page.getByRole('dialog')
this.allTemplateCards = page.locator('[data-testid^="template-workflow-"]')
}

View File

@@ -145,10 +145,7 @@ test.describe('App mode dropdown clipping', { tag: '@ui' }, () => {
// The unstyled PrimeVue Popover renders with role="dialog".
// Locate the one containing the image grid (filter buttons like "All", "Inputs").
const popover = comfyPage.page
.getByRole('dialog')
.filter({ has: comfyPage.page.getByRole('button', { name: 'All' }) })
.first()
const popover = comfyPage.appMode.imagePickerPopover
await expect(popover).toBeVisible({ timeout: 5000 })
const isInViewport = await popover.evaluate((el) => {

View File

@@ -18,7 +18,7 @@ test.describe('Confirm dialog text wrapping', { tag: ['@mobile'] }, () => {
.catch(() => {})
}, longFilename)
const dialog = comfyPage.page.getByRole('dialog')
const dialog = comfyPage.confirmDialog.root
await expect(dialog).toBeVisible()
const confirmButton = dialog.getByRole('button', { name: 'Confirm' })

View File

@@ -41,7 +41,7 @@ test.describe('MediaLightbox', { tag: ['@slow'] }, () => {
await assetCard.hover()
await assetCard.getByLabel('Zoom in').click()
const gallery = comfyPage.page.getByRole('dialog')
const gallery = comfyPage.mediaLightbox.root
await expect(gallery).toBeVisible()
return { gallery }
@@ -58,13 +58,13 @@ test.describe('MediaLightbox', { tag: ['@slow'] }, () => {
await runAndOpenGallery(comfyPage)
await comfyPage.page.keyboard.press('Escape')
await expect(comfyPage.page.getByRole('dialog')).not.toBeVisible()
await expect(comfyPage.mediaLightbox.root).not.toBeVisible()
})
test('closes gallery when clicking close button', async ({ comfyPage }) => {
const { gallery } = await runAndOpenGallery(comfyPage)
await gallery.getByLabel('Close').click()
await expect(comfyPage.page.getByRole('dialog')).not.toBeVisible()
await expect(comfyPage.mediaLightbox.root).not.toBeVisible()
})
})

View File

@@ -116,7 +116,7 @@ test.describe('Templates', { tag: ['@slow', '@workflow'] }, () => {
await comfyPage.command.executeCommand('Comfy.BrowseTemplates')
const dialog = comfyPage.page.getByRole('dialog').filter({
const dialog = comfyPage.templates.dialog.filter({
has: comfyPage.page.getByRole('heading', { name: 'Modèles', exact: true })
})
await expect(dialog).toBeVisible()
@@ -220,8 +220,9 @@ test.describe('Templates', { tag: ['@slow', '@workflow'] }, () => {
await expect(comfyPage.templates.content).toBeVisible()
// Wait for filter bar select components to render
const dialog = comfyPage.page.getByRole('dialog')
const sortBySelect = dialog.getByRole('combobox', { name: /Sort/ })
const sortBySelect = comfyPage.templates.dialog.getByRole('combobox', {
name: /Sort/
})
await expect(sortBySelect).toBeVisible()
// Screenshot the filter bar containing MultiSelect and SingleSelect