mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-19 22:09:37 +00:00
## Summary Complete the @e2e/ path alias migration started in #10735 by converting all 354 remaining relative imports and adding a lint rule to prevent backsliding. ## Changes - **What**: Migrate all relative imports in browser_tests/ to use `@e2e/` (intra-directory) and `@/` (src/ imports) path aliases. Add `no-restricted-imports` ESLint rule banning `./` and `../` imports in `browser_tests/**/*.ts`. Suppress pre-existing oxlint `no-eval` and `no-console` warnings exposed by touching those files. ## Review Focus - ESLint flat-config merging: the `@playwright/test` ban and relative-import ban are in two separate blocks to avoid last-match-wins collision with the `useI18n`/`useVirtualList` blocks higher in the config. - The `['./**', '../**']` glob patterns (not `['./*', '../*']`) are needed to catch multi-level relative paths like `../../../src/foo`. Follows up on #10735 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10958-test-migrate-browser_tests-to-e2e-path-alias-and-add-lint-rule-33c6d73d365081649d1be771eac986fd) by [Unito](https://www.unito.io) Co-authored-by: Amp <amp@ampcode.com>
94 lines
2.8 KiB
TypeScript
94 lines
2.8 KiB
TypeScript
import type { Locator, Page } from '@playwright/test'
|
|
|
|
import type { ComfyPage } from '@e2e/fixtures/ComfyPage'
|
|
|
|
/**
|
|
* Helper for interacting with widgets rendered in app mode (linear view).
|
|
*
|
|
* Widgets are located by their key (format: "nodeId:widgetName") via the
|
|
* `data-widget-key` attribute on each widget item.
|
|
*/
|
|
export class AppModeWidgetHelper {
|
|
constructor(private readonly comfyPage: ComfyPage) {}
|
|
|
|
private get page(): Page {
|
|
return this.comfyPage.page
|
|
}
|
|
|
|
private get container(): Locator {
|
|
return this.comfyPage.appMode.linearWidgets
|
|
}
|
|
|
|
/** Get a widget item container by its key (e.g. "6:text", "3:seed"). */
|
|
getWidgetItem(key: string): Locator {
|
|
return this.container.locator(`[data-widget-key="${key}"]`)
|
|
}
|
|
|
|
/** Fill a textarea widget (e.g. CLIP Text Encode prompt). */
|
|
async fillTextarea(key: string, value: string) {
|
|
const widget = this.getWidgetItem(key)
|
|
await widget.locator('textarea').fill(value)
|
|
}
|
|
|
|
/**
|
|
* Set a number input widget value (INT or FLOAT).
|
|
* Targets the last input inside the widget — this works for both
|
|
* ScrubableNumberInput (single input) and slider+InputNumber combos
|
|
* (last input is the editable number field).
|
|
*/
|
|
async fillNumber(key: string, value: string) {
|
|
const widget = this.getWidgetItem(key)
|
|
const input = widget.locator('input').last()
|
|
await input.fill(value)
|
|
await input.press('Enter')
|
|
}
|
|
|
|
/** Fill a string text input widget (e.g. filename_prefix). */
|
|
async fillText(key: string, value: string) {
|
|
const widget = this.getWidgetItem(key)
|
|
await widget.locator('input').fill(value)
|
|
}
|
|
|
|
/** Select an option from a combo/select widget. */
|
|
async selectOption(key: string, optionName: string) {
|
|
const widget = this.getWidgetItem(key)
|
|
await widget.getByRole('combobox').click()
|
|
await this.page
|
|
.getByRole('option', { name: optionName, exact: true })
|
|
.click()
|
|
}
|
|
|
|
/**
|
|
* Intercept the /api/prompt POST, click Run, and return the prompt payload.
|
|
* Fulfills the route with a mock success response.
|
|
*/
|
|
async runAndCapturePrompt(): Promise<
|
|
Record<string, { inputs: Record<string, unknown> }>
|
|
> {
|
|
let promptBody: Record<string, { inputs: Record<string, unknown> }> | null =
|
|
null
|
|
await this.page.route(
|
|
'**/api/prompt',
|
|
async (route, req) => {
|
|
promptBody = req.postDataJSON().prompt
|
|
await route.fulfill({
|
|
status: 200,
|
|
body: JSON.stringify({
|
|
prompt_id: 'test-id',
|
|
number: 1,
|
|
node_errors: {}
|
|
})
|
|
})
|
|
},
|
|
{ times: 1 }
|
|
)
|
|
|
|
const responsePromise = this.page.waitForResponse('**/api/prompt')
|
|
await this.comfyPage.appMode.runButton.click()
|
|
await responsePromise
|
|
|
|
if (!promptBody) throw new Error('No prompt payload captured')
|
|
return promptBody
|
|
}
|
|
}
|