Files
ComfyUI_frontend/browser_tests/tests/propertiesPanel/errorsTabMissingModels.spec.ts
Christian Byrne 963a7bf178 refactor: consolidate browser_tests/helpers/ into fixtures/ (#11411)
*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>
2026-04-28 02:18:31 +00:00

157 lines
5.0 KiB
TypeScript

import { expect } from '@playwright/test'
import { comfyPageFixture as test } from '@e2e/fixtures/ComfyPage'
import { TestIds } from '@e2e/fixtures/selectors'
import {
interceptClipboardWrite,
getClipboardText
} from '@e2e/fixtures/utils/clipboardSpy'
import {
cleanupFakeModel,
loadWorkflowAndOpenErrorsTab
} from '@e2e/tests/propertiesPanel/ErrorsTabHelper'
test.describe('Errors tab - Missing models', { tag: '@ui' }, () => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.settings.setSetting(
'Comfy.RightSidePanel.ShowErrorsTab',
true
)
await cleanupFakeModel(comfyPage)
})
test('Should show missing models group in errors tab', async ({
comfyPage
}) => {
await loadWorkflowAndOpenErrorsTab(comfyPage, 'missing/missing_models')
await expect(
comfyPage.page.getByTestId(TestIds.dialogs.missingModelsGroup)
).toBeVisible()
})
test('Should display model name with referencing node count', async ({
comfyPage
}) => {
await loadWorkflowAndOpenErrorsTab(comfyPage, 'missing/missing_models')
const modelsGroup = comfyPage.page.getByTestId(
TestIds.dialogs.missingModelsGroup
)
await expect(modelsGroup).toContainText(/fake_model\.safetensors\s*\(\d+\)/)
})
test('Should expand model row to show referencing nodes', async ({
comfyPage
}) => {
await loadWorkflowAndOpenErrorsTab(
comfyPage,
'missing/missing_models_with_nodes'
)
const locateButton = comfyPage.page.getByTestId(
TestIds.dialogs.missingModelLocate
)
await expect(locateButton.first()).toBeHidden()
const expandButton = comfyPage.page.getByTestId(
TestIds.dialogs.missingModelExpand
)
await expect(expandButton.first()).toBeVisible()
await expandButton.first().click()
await expect(locateButton.first()).toBeVisible()
})
test('Should copy model name to clipboard', async ({ comfyPage }) => {
await loadWorkflowAndOpenErrorsTab(comfyPage, 'missing/missing_models')
await interceptClipboardWrite(comfyPage.page)
const copyButton = comfyPage.page.getByTestId(
TestIds.dialogs.missingModelCopyName
)
await expect(copyButton.first()).toBeVisible()
await copyButton.first().dispatchEvent('click')
const copiedText = await getClipboardText(comfyPage.page)
expect(copiedText).toContain('fake_model.safetensors')
})
test.describe('OSS-specific', { tag: '@oss' }, () => {
test('Should show Copy URL button for non-asset models', async ({
comfyPage
}) => {
await loadWorkflowAndOpenErrorsTab(comfyPage, 'missing/missing_models')
const copyUrlButton = comfyPage.page.getByTestId(
TestIds.dialogs.missingModelCopyUrl
)
await expect(copyUrlButton.first()).toBeVisible()
})
test('Should show Download button for downloadable models', async ({
comfyPage
}) => {
await loadWorkflowAndOpenErrorsTab(comfyPage, 'missing/missing_models')
const downloadButton = comfyPage.page.getByTestId(
TestIds.dialogs.missingModelDownload
)
await expect(downloadButton.first()).toBeVisible()
})
test('Should render Download all and Refresh actions for one downloadable model', async ({
comfyPage
}) => {
await loadWorkflowAndOpenErrorsTab(comfyPage, 'missing/missing_models')
await expect(
comfyPage.page.getByTestId(TestIds.dialogs.missingModelActions)
).toBeVisible()
await expect(
comfyPage.page.getByTestId(TestIds.dialogs.missingModelDownloadAll)
).toBeVisible()
await expect(
comfyPage.page.getByTestId(TestIds.dialogs.missingModelRefresh)
).toBeVisible()
})
test('Should clear resolved missing model when Refresh is clicked', async ({
comfyPage
}) => {
await loadWorkflowAndOpenErrorsTab(comfyPage, 'missing/missing_models')
await comfyPage.page.route(/\/object_info$/, async (route) => {
const response = await route.fetch()
const objectInfo = await response.json()
const ckptName =
objectInfo.CheckpointLoaderSimple.input.required.ckpt_name
ckptName[0] = [...ckptName[0], 'fake_model.safetensors']
await route.fulfill({ response, json: objectInfo })
})
const objectInfoResponse = comfyPage.page.waitForResponse((response) => {
const url = new URL(response.url())
return url.pathname.endsWith('/object_info') && response.ok()
})
const modelFoldersResponse = comfyPage.page.waitForResponse(
(response) => {
const url = new URL(response.url())
return url.pathname.endsWith('/experiment/models') && response.ok()
}
)
const refreshButton = comfyPage.page.getByTestId(
TestIds.dialogs.missingModelRefresh
)
await Promise.all([
objectInfoResponse,
modelFoldersResponse,
refreshButton.click()
])
await expect(
comfyPage.page.getByTestId(TestIds.dialogs.missingModelsGroup)
).toBeHidden()
})
})
})