mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 14:30:41 +00:00
Backport of #10245 to cloud/1.42. Fixes app mode widget renaming on subgraphs by allowing `renameWidget` to resolve promoted widget sources when the node is a subgraph, even without explicit parents. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10509-backport-cloud-1-42-fix-App-mode-renaming-widgets-on-subgraphs-10245-32e6d73d3650816aa780e765e8605acc) by [Unito](https://www.unito.io)
129 lines
4.1 KiB
TypeScript
129 lines
4.1 KiB
TypeScript
import type { Locator, Page } from '@playwright/test'
|
|
|
|
import type { ComfyPage } from '../ComfyPage'
|
|
import { TestIds } from '../selectors'
|
|
|
|
export class AppModeHelper {
|
|
constructor(private readonly comfyPage: ComfyPage) {}
|
|
|
|
private get page(): Page {
|
|
return this.comfyPage.page
|
|
}
|
|
|
|
private get builderToolbar(): Locator {
|
|
return this.page.getByRole('navigation', { name: 'App Builder' })
|
|
}
|
|
|
|
/** Enter builder mode via the "Workflow actions" dropdown → "Build app". */
|
|
async enterBuilder() {
|
|
await this.page
|
|
.getByRole('button', { name: 'Workflow actions' })
|
|
.first()
|
|
.click()
|
|
await this.page.getByRole('menuitem', { name: 'Build app' }).click()
|
|
await this.comfyPage.nextFrame()
|
|
}
|
|
|
|
/** Exit builder mode via the footer "Exit app builder" button. */
|
|
async exitBuilder() {
|
|
await this.page.getByRole('button', { name: 'Exit app builder' }).click()
|
|
await this.comfyPage.nextFrame()
|
|
}
|
|
|
|
/** Click the "Inputs" step in the builder toolbar. */
|
|
async goToInputs() {
|
|
await this.builderToolbar.getByRole('button', { name: 'Inputs' }).click()
|
|
await this.comfyPage.nextFrame()
|
|
}
|
|
|
|
/** Click the "Outputs" step in the builder toolbar. */
|
|
async goToOutputs() {
|
|
await this.builderToolbar.getByRole('button', { name: 'Outputs' }).click()
|
|
await this.comfyPage.nextFrame()
|
|
}
|
|
|
|
/** Click the "Preview" step in the builder toolbar. */
|
|
async goToPreview() {
|
|
await this.builderToolbar.getByRole('button', { name: 'Preview' }).click()
|
|
await this.comfyPage.nextFrame()
|
|
}
|
|
|
|
/** Click the "Next" button in the builder footer. */
|
|
async next() {
|
|
await this.page.getByRole('button', { name: 'Next' }).click()
|
|
await this.comfyPage.nextFrame()
|
|
}
|
|
|
|
/** Click the "Back" button in the builder footer. */
|
|
async back() {
|
|
await this.page.getByRole('button', { name: 'Back' }).click()
|
|
await this.comfyPage.nextFrame()
|
|
}
|
|
|
|
/** Toggle app mode (linear view) on/off. */
|
|
async toggleAppMode() {
|
|
await this.page.evaluate(() => {
|
|
window.app!.extensionManager.command.execute('Comfy.ToggleLinear')
|
|
})
|
|
await this.comfyPage.nextFrame()
|
|
}
|
|
|
|
/** The linear-mode widget list container (visible in app mode). */
|
|
get linearWidgets(): Locator {
|
|
return this.page.locator('[data-testid="linear-widgets"]')
|
|
}
|
|
|
|
/**
|
|
* 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").
|
|
*/
|
|
getAppModeWidgetMenu(widgetName: string): Locator {
|
|
return this.linearWidgets
|
|
.locator(`div:has(> div > span:text-is("${widgetName}"))`)
|
|
.getByTestId(TestIds.builder.widgetActionsMenu)
|
|
.first()
|
|
}
|
|
|
|
/**
|
|
* Get the actions menu trigger for a widget in the builder input-select
|
|
* sidebar (IoItem).
|
|
* @param title The widget title shown in the IoItem.
|
|
*/
|
|
getBuilderInputItemMenu(title: string): Locator {
|
|
return this.page
|
|
.getByTestId(TestIds.builder.ioItem)
|
|
.filter({ hasText: title })
|
|
.getByTestId(TestIds.builder.widgetActionsMenu)
|
|
}
|
|
|
|
/**
|
|
* Get the actions menu trigger for a widget in the builder preview/arrange
|
|
* sidebar (AppModeWidgetList with builderMode).
|
|
* @param ariaLabel The aria-label on the widget row, e.g. "seed — KSampler".
|
|
*/
|
|
getBuilderPreviewWidgetMenu(ariaLabel: string): Locator {
|
|
return this.page
|
|
.locator(`[aria-label="${ariaLabel}"]`)
|
|
.getByTestId(TestIds.builder.widgetActionsMenu)
|
|
}
|
|
|
|
/**
|
|
* Rename a widget by clicking its popover trigger, selecting "Rename",
|
|
* and filling in the dialog.
|
|
* @param popoverTrigger The button that opens the widget's actions popover.
|
|
* @param newName The new name to assign.
|
|
*/
|
|
async renameWidget(popoverTrigger: Locator, newName: string) {
|
|
await popoverTrigger.click()
|
|
await this.page.getByText('Rename', { exact: true }).click()
|
|
|
|
const dialogInput = this.page.locator(
|
|
'.p-dialog-content input[type="text"]'
|
|
)
|
|
await dialogInput.fill(newName)
|
|
await this.page.keyboard.press('Enter')
|
|
await dialogInput.waitFor({ state: 'hidden' })
|
|
await this.comfyPage.nextFrame()
|
|
}
|
|
}
|