Manual backport of #11873 to `core/1.43`.
Cherry-picked squash merge commit
`04918360ebcf69adffdf5d8ff6603c24c7a2809a`.
## Why
#11873 moves missing asset detection to use exact BLAKE3 hash lookups
first when a workflow exposes a valid hash, then falls back to the
legacy asset-list matching path for non-hash, invalid, or transiently
unverifiable candidates.
For media inputs, the legacy fallback now reads from a separate
public-inclusive input asset cache in `assetService` instead of reusing
`assetsStore.inputAssets`. That keeps the UI/widget asset list user-only
while allowing missing input detection to account for public cloud
assets loaded by templates, avoiding false-positive missing media on
initial workflow load.
## Conflict resolution
- `src/platform/assets/services/assetService.test.ts`: `core/1.43` only
had the existing `shouldUseAssetBrowser` coverage, while #11873 adds
asset hash, upload validation, pagination, and public-inclusive input
cache tests. Kept the #11873 test expansion; the existing test coverage
is preserved in the incoming file.
- `src/stores/assetsStore.test.ts`: expanded the mocked `assetService`
surface and kept #11873's appended store tests for asset metadata/tag
updates, deletion state, input name mapping, and input cache
invalidation. The runtime `assetsStore.ts` changes auto-merged cleanly.
- All production files auto-merged cleanly.
## Validation
- `pnpm test:unit -- run
src/platform/assets/services/assetService.test.ts
src/stores/assetsStore.test.ts` ✅ (91/91 passing)
- `pnpm typecheck` ✅
- `pnpm exec oxfmt --check src/platform/assets/services/assetService.ts
src/platform/assets/services/assetService.test.ts
src/platform/missingMedia/missingMediaScan.ts
src/platform/missingMedia/missingMediaScan.test.ts
src/platform/missingModel/missingModelScan.ts
src/platform/missingModel/missingModelScan.test.ts
src/stores/assetsStore.ts src/stores/assetsStore.test.ts` ✅
- `git diff --check` ✅
- Commit hook also ran `oxfmt`, `oxlint`, `eslint`, and `pnpm typecheck`
on the changed files ✅
- Push hook ran `pnpm knip --cache` ✅
Original PR: #11873
Original commit: `04918360ebcf69adffdf5d8ff6603c24c7a2809a`
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11890-backport-core-1-43-fix-use-hash-lookup-for-missing-asset-detection-11873-3566d73d365081c9a76dfa3cd367122c)
by [Unito](https://www.unito.io)
*PR Created by the Glary-Bot Agent*
---
Manual backport of #11779 to `core/1.43` for inclusion in `v1.43.16`.
Cherry-picked from upstream merge commit `b8dfbfc0b`.
## Why
When inside a subgraph, the parent key handler intercepts the escape key
before `processKey` is called, causing a stale ghost node to be added to
the inner subgraph when the graph is changed to the parent. Moves escape
handler to document, prevents propagation, and adds a safety-net cancel
in `setGraph`.
## Conflict resolution
- `browser_tests/tests/nodeGhostPlacement.spec.ts`: PR adds 6 new test
cases inside the existing `describe` block. Conflict was
non-overlapping/additive — accepted all PR additions (existing tests
untouched). All referenced helpers (`comfyPage.subgraph`,
`Comfy.Graph.ConvertToSubgraph`, `Comfy.PublishSubgraph`,
`comfyPage.visibleToasts`) verified present on `core/1.43`.
- Test file rename `LGraphCanvas.ghostAutoPan.test.ts` →
`LGraphCanvas.ghost.test.ts` (intentional consolidation in PR) carried
through cleanly.
## Validation
- `pnpm typecheck` ✅
- `pnpm test:unit -- run
src/lib/litegraph/src/LGraphCanvas.ghost.test.ts` ✅ (11/11 passing)
- `pnpm exec eslint <changed files>` ✅ (0 errors)
- `pnpm exec oxfmt --check` ✅ (clean)
Source identical to upstream `b8dfbfc0b`, baking on `main` through
`v1.44.x`.
Original PR: #11779 / Original commit: `b8dfbfc0b`
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11860-backport-core-1-43-fix-ensure-escape-key-graph-navigation-cancels-ghost-node-placemen-3556d73d3650819baf2fd23c6fb260bf)
by [Unito](https://www.unito.io)
Co-authored-by: pythongosssss <125205205+pythongosssss@users.noreply.github.com>
*PR Created by the Glary-Bot Agent*
---
Manual backport of #11180 to `core/1.43` for inclusion in `v1.43.16`.
Cherry-picked from upstream merge commit `9599a4e00`.
Hardens 3 runtime crash paths reproducing on `cloud.comfy.org`:
- widget propagation crash when `this.widgets[0]` is missing
(CLOUD-FRONTEND-STAGING-429)
- ignored stale autogrow disconnect callbacks after group removal
- treats nullish executed outputs as empty during flatten/parsing
## Conflict resolution
- Dropped
`src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownMenuActions.test.ts`.
PR #11180 modified this test file but it was added on `main` by
unrelated PR #11443 which is **not** backported. Runtime fixes are in
source files; coverage exists in the targeted unit tests this PR adds.
## Validation
- `pnpm typecheck` ✅
- `pnpm test:unit` on changed test files ✅ (42/42 passing)
- `pnpm exec eslint <changed files>` ✅ (0 errors)
- `pnpm exec oxfmt --check` ✅ (clean)
Manual end-to-end verification not performed — these are crash-guard
fixes that require specific cloud-staging conditions to reproduce.
Source changes are byte-identical to upstream `9599a4e00` (baking on
`main` for ~3 weeks through `v1.44.x`).
Original PR: #11180 / Original commit: `9599a4e00`
Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
*PR Created by the Glary-Bot Agent*
---
Manual backport of #9935 to `core/1.43` for inclusion in `v1.43.16`.
Cherry-picked from upstream merge commit `2fea0aa53` cleanly.
## Why
VHS unbatch output slot color did not update when slot types changed via
`matchType` resolution in the Vue renderer. After `changeOutputType`
mutates `output.type` on objects inside a `shallowReactive` array,
spread-copies `this.outputs` to trigger the shallowReactive setter so
`SlotConnectionDot` re-evaluates the slot color.
## Conflict resolution
None — clean cherry-pick. 1 file, +4 lines.
## Validation
- `pnpm typecheck` ✅
- `pnpm exec eslint src/core/graph/widgets/dynamicWidgets.ts` ✅ (0
errors)
- `pnpm exec oxfmt --check` ✅ (clean)
Source identical to upstream `2fea0aa53`, baking on `main` for ~2 weeks
through `v1.44.x`.
Original PR: #9935 / Original commit: `2fea0aa53`
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11862-backport-core-1-43-fix-trigger-Vue-reactivity-on-output-slot-type-changes-in-matchTyp-3556d73d365081678f67c9949ccd4bb7)
by [Unito](https://www.unito.io)
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
*PR Created by the Glary-Bot Agent*
---
Manual backport of #11541 to `core/1.43` for inclusion in `v1.43.16`.
Cherry-picked from upstream merge commit `b23283144`.
## Why
`handleDrop` checked `handled === true` to gate `stopPropagation`, but
`onDragDrop` from `useNodeDragAndDrop` is async and always returns a
Promise — so the check never matched. The drop then bubbled to the
document handler in `app.ts` and spawned a new LoadImage node in
addition to the one that accepted the drop.
The fix moves the `preventDefault()`/`stopPropagation()` claim *into*
`onDragDrop` itself, gated by a new optional `claimEvent` flag.
## Conflict resolution
- **`src/composables/node/useNodeDragAndDrop.ts`** — `core/1.43` had the
older inline `node.onDragDrop = async function (e: DragEvent) { ... }`
form. Took #11541's full refactored version (named `installedDragDrop`
const + `onRemoved` cleanup via `useChainCallback`). `useChainCallback`
already exists on `core/1.43`. The new `(e, claimEvent = false)`
signature is backward-compatible with all existing callers.
- **`src/composables/node/useNodeDragAndDrop.test.ts`** — PR modified
this test file but the file was added on `main` by unrelated PR #11417
(`fix: reset file input value...`) which is **not** backported. Dropped
the test file from this backport. Runtime fix is intact; coverage exists
in `LGraphNode.test.ts` for the `claimEvent=true` call site.
- **`LGraphNode.{vue,test.ts}`, `litegraph-augmentation.d.ts`** —
auto-merged cleanly.
## Backport-only compatibility fix (added after code review)
The upstream PR removed `handleDrop`'s legacy `handled === true`
sync-return check in `LGraphNode.vue`. On `main` that's safe — all
in-repo `onDragDrop` handlers participate in the new `claimEvent` flag.
On `core/1.43` this is a public LiteGraph extension callback, and
custom-node packages may have synchronous `onDragDrop` implementations
that return `true` without honoring the new optional second argument.
Without the fallback, those drops would still bubble to the document
handler in `app.ts` and create duplicate nodes — the very bug this PR is
fixing.
Restored the legacy `handled === true` synchronous-claim path in
`handleDrop()` while keeping the new `claimEvent=true` call:
- async handlers from `useNodeDragAndDrop` claim the event themselves
- sync handlers returning `true` still get their event claimed
- handlers that return `false`/`undefined` still bubble (correct)
## Validation
- `pnpm typecheck` ✅
- `pnpm test:unit -- run
src/renderer/extensions/vueNodes/components/LGraphNode.test.ts` ✅ (15/15
passing)
- `pnpm exec eslint <changed files>` ✅ (0 errors)
- `pnpm exec oxfmt --check <changed files>` ✅ (clean)
Manual end-to-end verification (Playwright) was not performed because
the duplicate-node-creation bug requires a live ComfyUI backend with
model loading and real drag-drop interaction on an actual canvas — not
reproducible in the sandbox. The fix is byte-identical to upstream
`b23283144` (which has been baking on `main` for ~1 week through
`v1.44.x`) plus the backport-only sync-handler compatibility shim
documented above.
Original PR: #11541
Original commit: `b23283144`
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11856-backport-core-1-43-fix-stop-duplicate-node-creation-when-dropping-image-on-Vue-nodes--3556d73d36508165b811f2f4ab3ae749)
by [Unito](https://www.unito.io)
Co-authored-by: Terry Jia <terryjia88@gmail.com>
*PR Created by the Glary-Bot Agent*
---
Manual backport of #11063 to `core/1.43` for inclusion in `v1.43.16`.
Cherry-picked from upstream merge commit `4cf160d66`.
## Why
When a node with DOM widget overlays (e.g. CLIPTextEncode) is collapsed,
the overlay elements can intercept pointer events intended for the
canvas collapse toggler, making click-to-expand unreliable. Adds
`!widgetState.visible` to the `pointerEvents` condition in
`composeStyle()`, immediately setting `pointer-events: none` when the
widget becomes invisible — closing the timing gap before `v-show`
applies `display: none`. Fixes upstream issue #11006.
## Conflict resolution
- Skipped the change to `browser_tests/tests/interaction.spec.ts`. PR
#11063 removed a programmatic-collapse workaround introduced by
unrelated PR #10967 (which is **not** on `core/1.43`). On 1.43 the test
uses an older `delay(1000) + click` form that doesn't need adjustment —
the source fix in `DomWidget.vue` makes the second click reliable on its
own. Kept the source + unit-test changes.
## Validation
- `pnpm typecheck` ✅
- `pnpm test:unit -- run src/components/graph/widgets/DomWidget.test.ts`
✅ (2/2 passing)
- `pnpm exec eslint <changed files>` ✅ (0 errors)
- `pnpm exec oxfmt --check` ✅ (clean)
Manual end-to-end verification not performed — DOM widget pointer-event
timing requires live canvas+widget interaction, not feasible to
reproduce reliably in headless. Source identical to upstream
`4cf160d66`, baking on `main` for ~3 weeks through `v1.44.x`.
Original PR: #11063 / Original commit: `4cf160d66`
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11859-backport-core-1-43-fix-disable-pointer-events-on-non-visible-DOM-widget-overlays-11-3556d73d365081cab95ef32c17c0401e)
by [Unito](https://www.unito.io)
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Manual backport of #11778 to `core/1.43`.
Cherry-picked merge commit `46ba65e25cbfbd8214aec8b61951b77aa2db19e5`.
## Conflict resolution
- `browser_tests/tests/vueNodes/widgets/advancedWidgets.spec.ts`: kept
#11778's `SHOW_ADVANCED_INPUTS`/`HIDE_ADVANCED_INPUTS` constants and
collapsed-node regression test, resolving only the assertion text/style
drift from `core/1.43`.
- `src/renderer/extensions/vueNodes/components/LGraphNode.test.ts`: kept
the `core/1.43` `setActivePinia` setup, added #11778's `useSettingStore`
mock/i18n entries and collapsed advanced footer tests, and did not bring
the unrelated `app` import from later main drag/drop work.
- `src/renderer/extensions/vueNodes/components/LGraphNode.vue`: #11778's
runtime guard applied cleanly (`isCollapsed` hides the advanced footer
button).
## Validation
- `pnpm typecheck`
- `pnpm typecheck:browser`
- `pnpm test:unit -- run
src/renderer/extensions/vueNodes/components/LGraphNode.test.ts`
- `git diff --check`
- Commit/push hooks also ran lint-staged formatting/lint checks and
`pnpm knip`
┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11797-backport-core-1-43-fix-hide-advanced-footer-button-on-collapsed-Vue-nodes-3536d73d3650815db910f4772a29d008)
by [Unito](https://www.unito.io)
Manual backport of #10741 to `core/1.43`.
Cherry-picked merge commit `b157182a203671f4ea3bfa45ee8c30ae6b725676`.
## Conflict resolution
-
`browser_tests/tests/collapsedNodeLinks.spec.ts-snapshots/subgraph-entry-collapsed-node-links-chromium-linux.png`:
`core/1.43` did not have this screenshot expectation, while #10741 adds
the subgraph collapsed-node-link screenshot test. Kept the PR version.
## Validation
- `pnpm typecheck`
- `pnpm typecheck:browser`
- `pnpm test:unit -- run src/lib/litegraph/src/LGraphNode.test.ts
src/renderer/extensions/vueNodes/components/LGraphNode.test.ts
src/renderer/extensions/vueNodes/components/NodeFooter.test.ts
src/renderer/extensions/vueNodes/composables/useVueNodeResizeTracking.test.ts`
- `git diff --check`
- Commit/push hooks also ran lint-staged formatting/lint checks and
`pnpm knip`
┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11788-backport-core-1-43-refactor-inline-node-footer-layout-to-fix-selection-bounding-box-3536d73d36508184969bf3ad90647e83)
by [Unito](https://www.unito.io)
Backport of #11568 to `core/1.43`.
## Changes
Applies the e2e workflow filtering changes from #11568 to the
`core/1.43` release branch:
- **ci-tests-e2e.yaml**: Removed `paths-ignore` from `pull_request`
trigger, added `changes` job using `dorny/paths-filter` to detect
e2e-relevant file changes, added `needs: changes` and `should_run`
conditions to `setup`, `merge-reports`, `comment-on-pr-start`, and
`deploy-and-comment` jobs.
- **ci-tests-e2e-forks.yaml**: Switched `download-artifact` from
`actions/download-artifact@v7` to
`dawidd6/action-download-artifact@v12`, added `if_no_artifact_found:
warn`, added `hashFiles('reports/**') != ''` condition to `Handle Test
Completion`.
- **ci-tests-e2e-coverage.yaml**: Skipped — file does not exist on
`core/1.43`.
## Conflict Resolution
- Kept `core/1.43` branch's existing structure: container image
`0.0.16`, cloud build steps, `cloud` browser matrix entry, `Get PR
Number` step (not `resolve-pr-from-workflow-run`),
`pnpm/action-setup@v4.4.0`.
- Applied only the PR's intended behavioral changes on top.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11592-backport-core-1-43-ci-filter-e2e-workflow-on-PRs-to-skip-unrelated-changes-34c6d73d36508158ac90c13b298132fb)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
Manual backport of #10856 to `core/1.43`.
## Conflicts resolved
Two files had trivial conflicts from the same root cause — #10856
extracted the inline `cleanup_fake_model` block into a shared
`cleanupFakeModel` helper in
`browser_tests/tests/propertiesPanel/ErrorsTabHelper.ts`:
- `browser_tests/tests/errorOverlay.spec.ts`
- `browser_tests/tests/propertiesPanel/errorsTabMissingModels.spec.ts`
`core/1.43` still carries the original inline
`expect(cleanupOk).toBeTruthy()` form. main's version (post-#10967) uses
an inline `expect.poll()` instead. #10856 replaces both with `await
cleanupFakeModel(comfyPage)` calling the helper added by this same PR.
Resolution: accepted the PR version (helper call) on both conflict
sites. The helper itself is added as part of this backport, so no
runtime behavior is lost.
## Verification
- No residual conflict markers
- Cherry-picked commit carries the entire #10856 squash (45 files,
+3596/-209)
## Original PR summary
See #10856 for full behavioral description, test plan, and screenshots.
---
FixesComfy-Org/ComfyUI#13256 on core/1.43
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11217-backport-core-1-43-fix-exclude-muted-bypassed-nodes-from-missing-asset-detection-10-3426d73d365081f0becbcf7d909f0021)
by [Unito](https://www.unito.io)
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
## Summary
Removes hardcoded `version: 10` from `pnpm/action-setup` and instead
injects the `packageManager` field into `package.json` when absent
(legacy `core/*` branches).
## Why
PR #10952 re-added `version: 10` to fix old branches lacking
`packageManager`. But `main` now has **both** `version: 10` (workflow)
and `packageManager: pnpm@10.33.0` (`package.json`), causing
`pnpm/action-setup` to error with:
> Multiple versions of pnpm specified
Failed run:
https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/24158869559
This fix handles both cases:
- **`main`**: has `packageManager` → action reads it directly, no
conflict
- **`core/1.42` etc**: missing `packageManager` → step injects it before
the action runs
E2E test not applicable — this is a CI workflow configuration change
with no user-facing behavior.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10972-fix-ci-resolve-pnpm-version-conflict-in-version-bump-workflow-33c6d73d36508112802df75c0dd5ea50)
by [Unito](https://www.unito.io)
Closes#9226
## Summary
Image uploads had no timeout or abort mechanism, meaning a stalled
upload could hang indefinitely with no user feedback. This adds a
2-minute timeout using `AbortController` and shows a user-friendly toast
message when the upload times out.
## Changes
- `src/composables/node/useNodeImageUpload.ts`: Added `AbortController`
with a 120-second timeout to the `uploadFile` function. The abort signal
is passed to `fetchApi`. In the `handleUpload` error handler,
`AbortError` is now caught separately to display a localized timeout
message.
- `src/locales/en/main.json`: Added `uploadTimedOut` i18n translation
key.
---
Automated by coderabbit-fixer
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9491-fix-Add-timeout-and-abort-mechanism-for-image-upload-9226-31b6d73d365081d7a7d7f7016f3a71c6)
by [Unito](https://www.unito.io)
---------
Co-authored-by: CodeRabbit Fixer <coderabbit-fixer@automated.bot>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
## Summary
Adds Playwright E2E tests for the ShareWorkflow dialog component and its
various states.
## Tests added
- Dialog opens and shows unsaved state for new workflows (save prompt)
- Ready state shows create link button for saved but unpublished
workflows
- Shared state shows copy URL field with share link after publishing
- Stale state shows update link button when workflow modified after
publishing
- Close button dismisses dialog
- Create link transitions dialog from ready to shared state
- Tab switching between share link and publish to hub (when
comfyHubUploadEnabled)
- Tab aria-selected states update correctly on switch
## Approach
- Share dialog is gated behind `isCloud` (compile-time constant), so
tests invoke it directly via `page.evaluate()` importing
`useShareDialog`
- Share service API calls (`/api/userdata/*/publish`,
`/api/assets/from-workflow`) mocked via `page.route()` for deterministic
state testing
- Dialog state (loading → unsaved → ready → shared → stale) controlled
by mock responses
- Feature flags set via `serverFeatureFlags.value` for tab visibility
testing
## Notes
- All pre-existing TS2307 errors are `.vue` module resolution — no new
type errors
- Tests cover the 5 dialog states: loading, unsaved, ready, shared,
stale
## Task
Part of Test Coverage Q2 Overhaul (DLG-05).
## Conventions
- Uses Vue nodes with new menu enabled
- Tests read as user stories
- No full-page screenshots
- Proper waits, no sleeps
- All API calls mocked
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10588-test-add-ShareWorkflow-dialog-E2E-tests-DLG-05-3306d73d365081a0ab15f333707e493b)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
## Summary
Add design standards instructions so agents consult the canonical [Comfy
Design
Standards](https://www.figma.com/design/QreIv5htUaSICNuO2VBHw0/Comfy-Design-Standards)
Figma file before implementing user-facing features.
### Changes
- **`docs/guidance/design-standards.md`** — Auto-loaded guidance for
`src/components/**/*.vue` and `src/views/**/*.vue` with Figma MCP fetch
instructions, section node IDs, and component set references
- **`AGENTS.md`** — Added Design Standards section and Figma link in
External Resources
### Design
All content is fetched **live from Figma** via the Figma MCP tool —
designers can update the file and agents will always see the latest
version. No hardcoded design rules that can go stale.
Ref: COM-17639
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10696-feat-add-Comfy-Design-Standards-Figma-reference-for-agents-3326d73d36508181844fdcaa5c17cf00)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
## Summary
Add a "Testing with Cloud & Staging Environments" section to
CONTRIBUTING.md documenting how to test partner/API nodes that require
cloud backend authentication.
## Changes
- **What**: New section in CONTRIBUTING.md between "Dev Server" and
"Access dev server on touch devices" explaining two approaches for
staging/cloud development:
1. Frontend approach: `pnpm dev:cloud` or custom
`DEV_SERVER_COMFYUI_URL` in `.env`
2. Backend approach: `--comfy-api-base https://stagingapi.comfy.org`
flag
## Review Focus
- Accuracy of the `--comfy-api-base` backend flag documentation (sourced
from internal Slack discussion)
- Whether the section placement and level of detail is appropriate
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10775-docs-add-staging-environment-setup-instructions-to-CONTRIBUTING-md-3346d73d36508112bcd4df6ecb7f83c6)
by [Unito](https://www.unito.io)
## Summary
- Adds Playwright E2E tests for the Settings dialog covering behaviors
not tested elsewhere:
- About panel displays version badges (navigates to About, verifies
content)
- Boolean setting toggle through the UI persists the value (uses search
+ ToggleSwitch click, verifies via API)
- Dialog can be closed via the close button (complements existing
Escape-key test)
## Test plan
- [ ] `pnpm test:browser:local -- --grep "Settings dialog"` passes
- [ ] No overlap with existing tests in `dialog.spec.ts` or
`useSettingSearch.spec.ts`
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10797-test-add-E2E-tests-for-settings-dialog-3356d73d365081e4a3adcd3979048444)
by [Unito](https://www.unito.io)
## 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>
## Summary
Comprehensive Playwright E2E tests for the error systems: ErrorDialog,
ErrorOverlay, and the errors tab (missing nodes, models, media,
execution errors).
## Changes
- **What**:
- **ErrorDialog** (`errorDialog.spec.ts`, 7 tests): configure/prompt
error triggers, Show Report, Copy to Clipboard, Find Issues on GitHub,
Contact Support
- **ErrorOverlay** (`errorOverlay.spec.ts`, 12 tests): error count
labels, per-type button labels (missing nodes/models/media/multiple),
See Errors flow (open panel, dismiss, close), undo/redo persistence
- **Errors tab — common** (`errorsTab.spec.ts`, 3 tests): tab
visibility, search/filter execution errors
- **Errors tab — Missing nodes** (`errorsTabMissingNodes.spec.ts`, 5
tests): MissingNodeCard, packs group, expand/collapse, locate button
- **Errors tab — Missing models** (`errorsTabMissingModels.spec.ts`, 6
tests): group display, model name, expand/referencing nodes, clipboard
copy, OSS Copy URL/Download buttons
- **Errors tab — Missing media** (`errorsTabMissingMedia.spec.ts`, 7
tests): migrated from `missingMedia.spec.ts` with detection,
upload/library/cancel flows, locate
- **Errors tab — Execution** (`errorsTabExecution.spec.ts`, 2 tests):
Find on GitHub/Copy buttons, runtime error panel
- **Shared helpers**: `ErrorsTabHelper.ts` (openErrorsTabViaSeeErrors),
`clipboardSpy.ts` (interceptClipboardWrite/getClipboardText)
- **Component changes**: added `data-testid` to
`ErrorDialogContent.vue`, `FindIssueButton.vue`, `MissingModelRow.vue`,
`MissingModelCard.vue`
- **Selectors**: registered all new test IDs in `selectors.ts`
- **Test assets**: `missing_nodes_and_media.json` (compound errors),
`missing_models_with_nodes.json` (expand/locate)
- **Migrations**: error tests from `dialog.spec.ts` → dedicated files,
`errorOverlaySeeErrors.spec.ts` → `errorOverlay.spec.ts`,
`missingMedia.spec.ts` → `errorsTabMissingMedia.spec.ts`
## Review Focus
- OSS tests (`@oss` tag) verify Download/Copy URL buttons appear for
models with embedded URLs.
- The `missing_models.json` fixture must remain without nodes — adding
`CheckpointLoaderSimple` nodes causes directory mismatch in
`enrichWithEmbeddedMetadata` that prevents URL enrichment. A separate
`missing_models_with_nodes.json` fixture is used for expand/locate
tests.
## Cloud tests deferred
Missing model cloud environment tests (`@cloud` tag — hidden buttons,
import-unsupported notice) are deferred to a follow-up PR. The
`comfyPage` fixture cannot bypass the Firebase auth guard in cloud
builds, causing `window.app` initialization timeout. A separate infra PR
is needed to add cloud auth bypass to the fixture.
## Bug Discovery
During testing, a bug was found where the **Locate button for missing
nodes in subgraphs fails on initial workflow load**.
`collectMissingNodes` in `loadGraphData` captures execution IDs using
pre-`configure()` JSON node IDs, but `configure()` triggers subgraph
node ID deduplication (PR #8762, always-on since PR #9510) which remaps
colliding IDs. This will be addressed in a follow-up PR.
- Fixes#10847 (tracked, fix pending in separate PR)
## Testing
- 42 new/migrated E2E tests across 8 spec files
- All OSS tests pass locally and in CI
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10848-test-comprehensive-E2E-tests-for-error-dialog-overlay-and-errors-tab-3386d73d36508137a5e4cec8b12fa2fa)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>