mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-11 16:30:57 +00:00
*PR Created by the Glary-Bot Agent* --- ## Summary - Eliminates the confusing dual-helpers structure where `browser_tests/helpers/` and `browser_tests/fixtures/helpers/` coexisted one tier apart with overlapping purposes - Routes each file to its natural home based on what it actually *is*: page objects → `components/`, standalone utils → `utils/`, domain helper classes stay in `helpers/` - Adds an ESLint guard (`no-restricted-imports`) to prevent re-creating `browser_tests/helpers/` ## File Moves | File | From | To | Reason | |---|---|---|---| | `actionbar.ts` | `helpers/` | `fixtures/components/Actionbar.ts` | Page object class imported by ComfyPage | | `templates.ts` | `helpers/` | `fixtures/components/Templates.ts` | Page object class imported by ComfyPage | | `boundsUtils.ts` | `fixtures/helpers/` | `fixtures/utils/` | Pure function, not a helper class | | `mimeTypeUtil.ts` | `fixtures/helpers/` | `fixtures/utils/` | Pure function, not a helper class | | `builderTestUtils.ts` | `helpers/` | `fixtures/utils/` | Shared test setup functions | | `clipboardSpy.ts` | `helpers/` | `fixtures/utils/` | Page injection utility | | `fitToView.ts` | `helpers/` | `fixtures/utils/` | Canvas utility function | | `manageGroupNode.ts` | `helpers/` | `fixtures/utils/` | Litegraph interaction helper | | `painter.ts` | `helpers/` | `fixtures/utils/` | Test helper functions | | `perfReporter.ts` | `helpers/` | `fixtures/utils/` | Test infrastructure | | `promotedWidgets.ts` | `helpers/` | `fixtures/utils/` | Query helpers for specs | ## What Changed Beyond File Moves - **28 import statements** updated across test specs, fixtures, and infra files - **AGENTS.md** — directory tree diagram and architectural separation descriptions updated - **README.md** — "Leverage Existing Fixtures and Helpers" section updated - **`.claude/skills/perf-fix-with-proof/SKILL.md`** — perfReporter path reference updated - **`eslint.config.ts`** — added `@e2e/helpers/*` restricted import pattern to both spec and non-spec browser_tests rules ## Verification - `pnpm typecheck` — clean - `pnpm typecheck:browser` — clean - `pnpm lint` — 0 errors, 0 warnings - `pnpm format:check` — all files formatted - `pnpm knip` — clean - Pre-commit hooks passed full pipeline (oxfmt, oxlint, eslint, typecheck, typecheck:browser) ## Config Audit No changes needed to: `tsconfig.json` (`@e2e/*` alias covers all subdirs), `playwright.config.ts`, `vite.config.mts`, `knip.config.ts`, `.oxlintrc.json`, `nx.json` ## Manual Verification Note This is a pure structural refactoring (file moves + import updates) with zero behavioral or visual changes. The typecheck and lint passes confirm all imports resolve correctly. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11411-refactor-consolidate-browser_tests-helpers-into-fixtures-3476d73d3650816cb671ef7fa8433f66) by [Unito](https://www.unito.io) --------- Co-authored-by: glary-bot <glary-bot@comfy.org> Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> Co-authored-by: DrJKL <DrJKL0424@gmail.com> Co-authored-by: Amp <amp@ampcode.com>
196 lines
6.1 KiB
TypeScript
196 lines
6.1 KiB
TypeScript
import type { Page } from '@playwright/test'
|
|
|
|
import { expect } from '@playwright/test'
|
|
|
|
import type { ComfyPage } from '@e2e/fixtures/ComfyPage'
|
|
import { comfyPageFixture as test } from '@e2e/fixtures/ComfyPage'
|
|
import { TestIds } from '@e2e/fixtures/selectors'
|
|
import {
|
|
interceptClipboardWrite,
|
|
getClipboardText
|
|
} from '@e2e/fixtures/utils/clipboardSpy'
|
|
|
|
async function triggerConfigureError(
|
|
comfyPage: ComfyPage,
|
|
message = 'Error on configure!'
|
|
) {
|
|
await comfyPage.page.evaluate((msg: string) => {
|
|
const graph = window.graph!
|
|
;(graph as { configure: () => void }).configure = () => {
|
|
throw new Error(msg)
|
|
}
|
|
}, message)
|
|
|
|
await comfyPage.workflow.loadWorkflow('default')
|
|
|
|
return comfyPage.page.getByTestId(TestIds.dialogs.errorDialog)
|
|
}
|
|
|
|
async function waitForPopupNavigation(page: Page, action: () => Promise<void>) {
|
|
const popupPromise = page.waitForEvent('popup')
|
|
await action()
|
|
const popup = await popupPromise
|
|
await popup.waitForLoadState()
|
|
return popup
|
|
}
|
|
|
|
test.describe('Error dialog', () => {
|
|
test.beforeEach(async ({ comfyPage }) => {
|
|
await comfyPage.settings.setSetting('Comfy.UseNewMenu', 'Disabled')
|
|
})
|
|
|
|
test('Should display an error dialog when graph configure fails', async ({
|
|
comfyPage
|
|
}) => {
|
|
const errorDialog = await triggerConfigureError(comfyPage)
|
|
await expect(errorDialog).toBeVisible()
|
|
})
|
|
|
|
test('Should display an error dialog when prompt execution fails', async ({
|
|
comfyPage
|
|
}) => {
|
|
await comfyPage.page.evaluate(async () => {
|
|
const app = window.app!
|
|
app.api.queuePrompt = () => {
|
|
throw new Error('Error on queuePrompt!')
|
|
}
|
|
await app.queuePrompt(0)
|
|
})
|
|
const errorDialog = comfyPage.page.getByTestId(TestIds.dialogs.errorDialog)
|
|
await expect(errorDialog).toBeVisible()
|
|
})
|
|
|
|
test('Should display error message body', async ({ comfyPage }) => {
|
|
const errorDialog = await triggerConfigureError(
|
|
comfyPage,
|
|
'Test error message body'
|
|
)
|
|
await expect(errorDialog).toBeVisible()
|
|
await expect(errorDialog).toContainText('Test error message body')
|
|
})
|
|
|
|
test('Should show report section when "Show Report" is clicked', async ({
|
|
comfyPage
|
|
}) => {
|
|
const errorDialog = await triggerConfigureError(comfyPage)
|
|
await expect(errorDialog).toBeVisible()
|
|
await expect(errorDialog.locator('pre')).toBeHidden()
|
|
|
|
await errorDialog.getByTestId(TestIds.dialogs.errorDialogShowReport).click()
|
|
|
|
const reportPre = errorDialog.locator('pre')
|
|
await expect(reportPre).toBeVisible()
|
|
await expect(reportPre).toHaveText(/\S/)
|
|
await expect(
|
|
errorDialog.getByTestId(TestIds.dialogs.errorDialogShowReport)
|
|
).toBeHidden()
|
|
})
|
|
|
|
test('Should copy report to clipboard when "Copy to Clipboard" is clicked', async ({
|
|
comfyPage
|
|
}) => {
|
|
const errorDialog = await triggerConfigureError(comfyPage)
|
|
await expect(errorDialog).toBeVisible()
|
|
|
|
await errorDialog.getByTestId(TestIds.dialogs.errorDialogShowReport).click()
|
|
await expect(errorDialog.locator('pre')).toBeVisible()
|
|
|
|
await interceptClipboardWrite(comfyPage.page)
|
|
|
|
await errorDialog.getByTestId(TestIds.dialogs.errorDialogCopyReport).click()
|
|
|
|
const reportText = await errorDialog.locator('pre').textContent()
|
|
await expect
|
|
.poll(async () => await getClipboardText(comfyPage.page))
|
|
.toBe(reportText)
|
|
})
|
|
|
|
test('Should open GitHub issues search when "Find Issues" is clicked', async ({
|
|
comfyPage
|
|
}) => {
|
|
const errorDialog = await triggerConfigureError(comfyPage)
|
|
await expect(errorDialog).toBeVisible()
|
|
|
|
const popup = await waitForPopupNavigation(comfyPage.page, () =>
|
|
errorDialog.getByTestId(TestIds.dialogs.errorDialogFindIssues).click()
|
|
)
|
|
|
|
const url = new URL(popup.url())
|
|
expect(url.hostname).toBe('github.com')
|
|
expect(url.pathname).toContain('/issues')
|
|
|
|
await popup.close()
|
|
})
|
|
|
|
test('Should open contact support when "Help Fix This" is clicked', async ({
|
|
comfyPage
|
|
}) => {
|
|
const errorDialog = await triggerConfigureError(comfyPage)
|
|
await expect(errorDialog).toBeVisible()
|
|
|
|
const popup = await waitForPopupNavigation(comfyPage.page, () =>
|
|
errorDialog.getByTestId(TestIds.dialogs.errorDialogContactSupport).click()
|
|
)
|
|
|
|
const url = new URL(popup.url())
|
|
expect(url.hostname).toBe('support.comfy.org')
|
|
|
|
await popup.close()
|
|
})
|
|
|
|
test('Should display extension file hint when available', async ({
|
|
comfyPage
|
|
}) => {
|
|
await comfyPage.page.evaluate(() => {
|
|
const error = new Error('Extension error!')
|
|
;(error as Error & { fileName: string }).fileName =
|
|
'/extensions/my-custom-extension/main.js'
|
|
|
|
window.app!.extensionManager.dialog.showErrorDialog(error)
|
|
})
|
|
|
|
const errorDialog = comfyPage.page.getByTestId(TestIds.dialogs.errorDialog)
|
|
await expect(errorDialog).toBeVisible()
|
|
|
|
await expect(
|
|
errorDialog.getByText('/extensions/my-custom-extension/main.js')
|
|
).toBeVisible()
|
|
await expect(
|
|
errorDialog.getByText('This may be due to the following script')
|
|
).toBeVisible()
|
|
})
|
|
|
|
test('Should display string error messages', async ({ comfyPage }) => {
|
|
await comfyPage.page.evaluate(() => {
|
|
window.app!.extensionManager.dialog.showErrorDialog(
|
|
'Something went wrong',
|
|
{
|
|
title: 'Custom Error Title'
|
|
}
|
|
)
|
|
})
|
|
|
|
const errorDialog = comfyPage.page.getByTestId(TestIds.dialogs.errorDialog)
|
|
await expect(errorDialog).toBeVisible()
|
|
|
|
await expect(errorDialog.getByText('Custom Error Title')).toBeVisible()
|
|
await expect(errorDialog.getByText('Something went wrong')).toBeVisible()
|
|
})
|
|
|
|
test('Should display default title when no title provided', async ({
|
|
comfyPage
|
|
}) => {
|
|
await comfyPage.page.evaluate(() => {
|
|
window.app!.extensionManager.dialog.showErrorDialog(
|
|
'A simple string error'
|
|
)
|
|
})
|
|
|
|
const errorDialog = comfyPage.page.getByTestId(TestIds.dialogs.errorDialog)
|
|
await expect(errorDialog).toBeVisible()
|
|
|
|
await expect(errorDialog.getByText('Unknown Error')).toBeVisible()
|
|
await expect(errorDialog.getByText('A simple string error')).toBeVisible()
|
|
})
|
|
})
|