647 Commits

Author SHA1 Message Date
Dante
e5c81488e4 fix: include focusMode in splitter refresh key to prevent panel resize (#11295)
## Summary

When the properties panel is open, toggling focus mode on then off
causes the panel to resize unexpectedly. The root cause is that
`splitterRefreshKey` in `LiteGraphCanvasSplitterOverlay.vue` does not
include `focusMode`, so the PrimeVue Splitter component instance is
reused across focus mode transitions and restores stale panel sizes from
localStorage.

Fix: add `focusMode` to `splitterRefreshKey` so the Splitter is
recreated when focus mode toggles.

## Red-Green Verification

| Commit | CI Status | Purpose |
|--------|-----------|---------|
| `test: add failing test for focus mode toggle resizing properties
panel` | 🔴 Red | Proves the test catches the bug |
| `fix: include focusMode in splitter refresh key to prevent panel
resize` | 🟢 Green | Proves the fix resolves the bug |

## demo

### AS IS


https://github.com/user-attachments/assets/95f6a9e3-e4c7-4aba-8e17-0eee11f70491


### TO BE


https://github.com/user-attachments/assets/595eafcd-6a80-443d-a6f3-bb7605ed0758



## Test Plan

- [ ] CI red on test-only commit
- [ ] CI green on fix commit
- [ ] E2E regression test added in
`browser_tests/tests/focusMode.spec.ts`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11295-fix-include-focusMode-in-splitter-refresh-key-to-prevent-panel-resize-3446d73d365081b7bc3ac65338e17a8f)
by [Unito](https://www.unito.io)
2026-04-16 13:43:02 +09:00
pythongosssss
ecb6fbe8fb test: Add waitForWorkflowIdle & remove redundant nextFrame (#11264)
## Summary

More cleanup and reliability

## Changes

- **What**: 
- Add wait for idle
- Remove redundant nextFrames

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11264-test-Add-waitForWorkflowIdle-remove-redundant-nextFrame-3436d73d3650812c837ac7503ce0947b)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-04-15 16:52:41 +00:00
Alexander Brown
52ccd9ed1a refactor: internalize nextFrame() into fixture/helper methods (#11166)
## Summary

Internalize `nextFrame()` calls into fixture/helper methods so spec
authors don't need to remember to call it after common operations.
`nextFrame()` waits for one `requestAnimationFrame` (~16ms) — an extra
call is always safe, making this a low-risk refactor.

## Changes

### Phase 1: `SettingsHelper.setSetting()`
`setSetting()` now calls `nextFrame()` internally. Removed 15 redundant
calls across 7 files.

### Phase 2: `CommandHelper.executeCommand()`
`executeCommand()` now calls `nextFrame()` internally. Removed 15
redundant calls across 7 files, including the now-redundant call in
`AppModeHelper.toggleAppMode()`.

### Phase 3: `WorkflowHelper.loadGraphData()`
New helper wraps `page.evaluate(loadGraphData)` + `nextFrame()`.
Migrated `SubgraphHelper.serializeAndReload()` and `groupNode.spec.ts`.

### Phase 4: `NodeReference` cleanup
Removed redundant `nextFrame()` from `copy()`, `convertToGroupNode()`,
`resizeNode()`, `dragTextEncodeNode2()`, and
`convertDefaultKSamplerToSubgraph()`. Removed 6 spec-level calls after
`node.click('title')`.

### Phase 5: `KeyboardHelper.press()` and `delete()`
New convenience methods that press a key and wait one frame. Converted
40 `canvas.press(key)` + `nextFrame()` pairs across 13 spec files.

### Phase 6: `ComfyPage.expectScreenshot()`
New helper combines `nextFrame()` + `toHaveScreenshot()`. Converted 45
pairs across 12 spec files.

## Total impact
- **~130 redundant `nextFrame()` calls eliminated** across ~35
spec/helper files
- **3 new helper methods** added (`loadGraphData`, `press`/`delete`,
`expectScreenshot`)
- **2 existing methods** enhanced (`setSetting`, `executeCommand`)

## What was NOT changed
- `performance.spec.ts` frame-counting loops (intentional)
- `ComfyMouse.ts` / `CanvasHelper.ts` (already internalized)
- `SubgraphHelper.packAllInteriorNodes()` (deliberate orchestration)
- Builder helpers (already internalized)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11166-refactor-internalize-nextFrame-into-fixture-helper-methods-33f6d73d3650817bb5f6fb46e396085e)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-04-15 15:25:47 +00:00
Kelly Yang
92ad6fc798 test: address review nits for image compare E2E (#11260)
## Summary
A follow-up PR of #11196.

| # | Nit | Action | Reason |
| :--- | :--- | :--- | :--- |
| 1 | Replace `page.on('pageerror')` with request-wait | **Left as-is**
| The `pageErrors` array is an accumulator checked at the end via
`expect(pageErrors).toHaveLength(0)` – the goal is to assert that broken
image URLs don't surface as uncaught JS exceptions during the test run.
A request-wait can't substitute for that behavioral assertion, so the
listener pattern is intentional here. |
| 2 | Move helpers to a `vueNodes.getImageCompareHelper()` subclass |
**Left as-is** | Helpers such as `setImageCompareValue` and
`moveToPercentage` are only used in this file, making local
encapsulation enough. Extracting them to a page object would increase
the file/interface surface area and violate YAGNI; additionally,
`AGENTS.md` clearly states to "minimize the exported values of each
module. |
| 3 | Use `TestIds` enum for test ID strings | **Fixed** – added
`imageCompare` section to `TestIds` in `selectors.ts`; replaced all 8
inline string IDs in `imageCompare.spec.ts` with
`TestIds.imageCompare.*` references | The project already has a
`TestIds` convention for centralizing test IDs. Inline strings create
drift risk between the Vue component and the test file. |
| 4 | Move `expect.poll` bounding box check to helper/page object |
**Left as-is** | This logic already lives inside `moveToPercentage`,
which is a local helper. Moving it further to a page object is the same
refactor as #2 above. |
| 5 | Remove `// ---` style section header comments | **Fixed** –
removed all 8 divider blocks from `imageCompare.spec.ts` | Consistent
with project guidelines and your explicit preference. Test names already
describe what each block does. |
| 6 | Name magic numbers `400` and `350` | **Fixed** – introduced
`minWidth = 400` and `minHeight = 350` constants in the test |
Descriptive names make the constraint self-documenting and easier to
update if the workflow asset changes. |

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: changes are limited to Playwright E2E test code and shared
selector constants, with no production logic impacted.
> 
> **Overview**
> **E2E Image Compare tests now use centralized selectors.** Adds an
`imageCompare` section to `TestIds` and updates `imageCompare.spec.ts`
to reference `TestIds.imageCompare.*` instead of inline `data-testid`
strings.
> 
> Cleans up the spec by removing divider comments and naming the minimum
size magic numbers (`minWidth`, `minHeight`) used in the node sizing
assertion.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ece25be5cc. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11260-test-address-review-nits-for-image-compare-E2E-3436d73d365081a69cacc1fff390035a)
by [Unito](https://www.unito.io)
2026-04-15 10:50:44 -04:00
pythongosssss
06686a1f50 test: App mode - additional app mode coverage (#11194)
## Summary

Adds additional test coverage for empty state/welcome screen/connect
outputs/vue nodes auto switch

## Changes

- **What**: 
- add tests

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11194-test-App-mode-additional-app-mode-coverage-3416d73d365081ca91d0ed61de19f840)
by [Unito](https://www.unito.io)
2026-04-15 11:42:22 +00:00
jaeone94
693b8383d6 fix: missing-asset correctness follow-ups from #10856 (#11233)
Follow-up to #10856. Four correctness issues and their regression tests.

## Bugs fixed

### 1. ErrorOverlay model count reflected node selection

`useErrorGroups` exposed `filteredMissingModelGroups` under the public
name `missingModelGroups`. `ErrorOverlay.vue` read that alias to compute
its model count label, so selecting a node shrank the overlay total. The
overlay must always show the whole workflow's errors.

Exposed both shapes explicitly: `missingModelGroups` /
`missingMediaGroups` (unfiltered totals) and
`filteredMissingModelGroups` / `filteredMissingMediaGroups`
(selection-scoped). `TabErrors.vue` destructures the filtered variant
with an alias.


Before 


https://github.com/user-attachments/assets/eb848c5f-d092-4a4f-b86f-d22bb4408003

After 


https://github.com/user-attachments/assets/75e67819-c9f2-45ec-9241-74023eca6120



### 2. Bypass → un-bypass dropped url/hash metadata

Realtime `scanNodeModelCandidates` only reads widget values, so
un-bypass produced a fresh candidate without the url that
`enrichWithEmbeddedMetadata` had previously attached from
`graphData.models`. `MissingModelRow`'s download/copy-url buttons
disappeared after a bypass/un-bypass cycle.

Added `enrichCandidateFromNodeProperties` that copies
`url`/`hash`/`directory` from the node's own `properties.models` — which
persists across mode toggles — into each scanned candidate. Applied to
every call site of the per-node scan. A later fix in the same branch
also enforces directory agreement to prevent a same-name /
different-directory collision from stamping the wrong metadata.

Before 


https://github.com/user-attachments/assets/39039d83-4d55-41a9-9d01-dec40843741b

After 


https://github.com/user-attachments/assets/047a603b-fb52-4320-886d-dfeed457d833



### 3. Initial full scan surfaced interior errors of a muted/bypassed
subgraph container

`scanAllModelCandidates`, `scanAllMediaCandidates`, and the JSON-based
missing-node scan only check each node's own mode. Interior nodes whose
parent container was bypassed passed the filter.

Added `isAncestorPathActive(rootGraph, executionId)` to
`graphTraversalUtil` and post-filter the three pipelines in `app.ts`
after the live rootGraph is configured. The filter uses the execution-ID
path (`"65:63"` → check node 65's mode) so it handles both
live-scan-produced and JSON-enrichment-produced candidates.

Before


https://github.com/user-attachments/assets/3032d46b-81cd-420e-ab8e-f58392267602

After 


https://github.com/user-attachments/assets/02a01931-951d-4a48-986c-06424044fbf8




### 4. Bypassed subgraph entry re-surfaced interior errors

`useGraphNodeManager` replays `graph.onNodeAdded` for each existing
interior node when the Vue node manager initializes on subgraph entry.
That chain reached `scanSingleNodeErrors` via
`installErrorClearingHooks`' `onNodeAdded` override. Each interior
node's own mode was active, so the caller guards passed and the scan
re-introduced the error that the initial pipeline had correctly
suppressed.

Added an ancestor-activity gate at the top of `scanSingleNodeErrors`,
the single entry point shared by paste, un-bypass, subgraph entry, and
subgraph container activation. A later commit also hardens this guard
against detached nodes (null execution ID → skip) and applies the same
ancestor check to `isCandidateStillActive` in the realtime verification
callback.

Before


https://github.com/user-attachments/assets/fe44862d-f1d6-41ed-982d-614a7e83d441

After


https://github.com/user-attachments/assets/497a76ce-3caa-479f-9024-4cd0f7bd20a4



## Tests

- 6 unit tests for `isAncestorPathActive` (root, active,
immediate-bypass, deep-nested mute, unresolvable ancestor, null
rootGraph)
- 4 unit tests for `enrichCandidateFromNodeProperties` (enrichment,
no-overwrite, name mismatch, directory mismatch)
- 1 unit test for `scanSingleNodeErrors` ancestor guard (subgraph entry
replaying onNodeAdded)
- 2 unit tests for `useErrorGroups` dual export + ErrorOverlay contract
- 4 E2E tests:
- ErrorOverlay model count stays constant when a node is selected (new
fixture `missing_models_distinct.json`)
- Bypass/un-bypass cycle preserves Copy URL button (uses
`missing_models_from_node_properties`)
- Loading a workflow with bypassed subgraph suppresses interior missing
model error (new fixture `missing_models_in_bypassed_subgraph.json`)
- Entering a bypassed subgraph does not resurface interior missing model
error (shares the above fixture)

`pnpm typecheck`, `pnpm lint`, 206 related unit tests passing.

## Follow-up

Several items raised by code review are deferred as pre-existing tech
debt or scope-avoided refactors. Tracked via comments on #11215 and
#11216.

---
Follows up on #10856.
2026-04-15 10:58:24 +00:00
Kelly Yang
66e8d570e7 test: expand Image Compare E2E and stabilize widget selectors (#11196)
## Summary

This PR extends **Image Compare** browser tests, adds **stable
`data-testid` hooks** on `WidgetImageCompare.vue`, and aligns slider
interactions with the **same viewport element** used by
`useMouseInElement`, with **layout polling** to reduce flakes.

## What this PR does

- [x] Adds **`data-testid="image-compare-viewport"`** on the compare
area root (the `containerRef` div) so E2E targets the real slider hit
region instead of a long Tailwind class chain or the `<img>` box alone.
- [x] Adds **`data-testid="image-compare-empty"`** on the no-images
branch so the empty state can be asserted **without hard-coded English**
UI text.
- [x] Adds a **smoke** test that the widget **shows both images and the
drag handle** after value injection, with **`waitForImagesLoaded`** (no
extra full-node screenshot to avoid duplicating the default-50 golden).
- [x] Extends slider coverage to **clamp at both edges** (**0%** and
**~100%**) using the viewport locator and **`expect.poll`** until
**`boundingBox()`** is valid before reading coordinates.
- [x] Updates **`moveToPercentage`** to **`expect.poll`** until the
target locator has a **non-empty layout box** before moving the mouse.
- [x] Routes **hover**, **preserve position**, and **25% / 75%
screenshot** mouse moves through **`image-compare-viewport`**
(consistent with `containerRef`).
- [x] Adds an E2E assertion that the **workflow ImageCompare node** size
is **at least 400×350** (matches the widget workflow asset).
- [x] Hardens the **broken image** case: **`page.on('pageerror')`** /
**`page.off`** in **`finally`**, **`http://127.0.0.1:1/...`** URLs for
fast failure, **`expect.soft`** on key UI invariants, and a hard
assertion that **no page errors** were recorded.
- [x] Extends the **large batch (20×20)** test to **page to the last
index** and assert **counters `20 / 20`**, **previous enabled**, and
**next disabled** on both sides.
- [x] Renames the clamp test title to use an **ASCII hyphen** (`0-100%`)
for easier grepping.

## Out of scope (unchanged in this PR)

- [ ] Replacing **`setImageCompareValue`**’s **`page.evaluate`** setup
with a full UI-driven path (would be a larger follow-up).

## Suggested title

`test: expand Image Compare E2E and stabilize widget selectors`

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Primarily test and selector-hook changes; low production risk, with
only minor DOM attribute additions that could affect external test
tooling if relied upon.
> 
> **Overview**
> Improves Image Compare Playwright coverage and reduces flakiness by
driving slider interactions through a new stable
`data-testid="image-compare-viewport"` hook and polling for a valid
layout box before mouse moves.
> 
> Updates assertions to avoid localized text (new
`data-testid="image-compare-empty"`), adds smoke coverage that
images/handle render after value injection, validates slider clamping at
both 0% and ~100%, and extends screenshot tests to use the same viewport
target.
> 
> Hardens edge-case tests by ensuring broken image loads don’t raise
uncaught `pageerror`s, adds a minimum node size assertion, and extends
large-batch navigation checks through the final index and
disabled/enabled nav states.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ce3f7fbf8c. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11196-test-expand-Image-Compare-E2E-and-stabilize-widget-selectors-3416d73d3650814d8d2bf207943d6205)
by [Unito](https://www.unito.io)
2026-04-14 21:53:13 -04:00
Dante
634d57809b test: add E2E tests for bottom panel core behaviors (#10814)
## Summary
- Add `browser_tests/tests/bottomPanel.spec.ts` with tests for behaviors
not covered by existing `bottomPanelLogs` and `bottomPanelShortcuts`
specs
- Tests cover: close button (X), tab persistence on re-open, resize
gutter visibility and drag, canvas interaction when panel is closed,
cross-panel switching (terminal <-> shortcuts), and registered tab
enumeration
- Extend `BottomPanel` fixture with `closeButton` and `resizeGutter`
locators

## Test plan
- [ ] `pnpm test:browser:local` passes all new tests in
`bottomPanel.spec.ts`
- [ ] Existing `bottomPanelLogs.spec.ts` and
`bottomPanelShortcuts.spec.ts` are unaffected
- [ ] `pnpm typecheck:browser` passes
- [ ] `pnpm lint` passes

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10814-test-add-E2E-tests-for-bottom-panel-core-behaviors-3366d73d365081ea9b90c643897845fa)
by [Unito](https://www.unito.io)

---------

Co-authored-by: dante <dante@danteui-MacStudio.local>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-04-14 23:33:11 +00:00
Dante
5807e03c74 test: expand E2E coverage for toolbox actions (#10968)
## Summary
- Adds `selectionToolboxMoreActions.spec.ts` with E2E coverage for
previously untested toolbox actions
- Covers: pin/unpin, minimize/expand, adjust size, copy, duplicate,
refresh button, align (top/left), distribute (horizontal/vertical),
alignment options hidden for single selection, multi-node bypass toggle
- Part of the FixIt Burndown test coverage initiative (toolbox actions)

## Test plan
- [ ] All new tests pass in CI
- [ ] No regressions in existing selectionToolbox tests

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10968-test-expand-E2E-coverage-for-toolbox-actions-33c6d73d3650811286cefdd0eb4f5242)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-04-14 23:20:45 +00:00
Dante
6847c7ba2d fix: store promoted widget values per SubgraphNode instance (#10849)
## Summary

- Multiple SubgraphNode instances of the same blueprint share inner
nodes, causing promoted widget values to collide — the last configured
instance overwrites all previous values
- Add per-instance value storage (`_instanceWidgetValues`) on
SubgraphNode so each instance preserves its own promoted widget values
independently
- Restore `widgets_values` from serialized data into this per-instance
map after promoted views are created during configure

- Fixes #10146

## Root Cause

When loading a workflow with multiple SubgraphNode instances of the same
blueprint:

1. `LGraph.configure()` creates ONE shared Subgraph per blueprint (line
2625)
2. Each SubgraphNode instance calls `configure(instanceData)`
sequentially
3. `PromotedWidgetView.value` setter writes to the **shared inner node's
widget** (`promotedWidgetView.ts:199`)
4. The last instance's `configure()` overwrites all previous instances'
values

**Regression**: Introduced by PR #8594 (WidgetValueStore, v1.41.3) which
centralized widget state without per-instance scoping for shared
blueprints.

## Fix

- **SubgraphNode**: Add `_instanceWidgetValues` Map and
`_pendingWidgetsValues` for configure-time restoration
- **PromotedWidgetView getter**: Check instance map first before falling
back to widget store / inner node
- **PromotedWidgetView setter**: Write to instance map to avoid shared
inner node mutation
- **_internalConfigureAfterSlots**: Apply serialized `widgets_values` to
per-instance map after promoted views are created

## Red-Green Verification

| Commit | CI Status | Purpose |
|--------|-----------|---------|
| `test: add failing tests for multi-instance subgraph widget value
collision` | 🔴 Red | Proves widget values collide across
instances |
| `fix: store promoted widget values per SubgraphNode instance` |
🟢 Green | Per-instance storage prevents collision |

## Test Plan

- [x] CI red on test-only commit
- [x] CI green on fix commit
- [x] Unit test: `preserves promoted widget values after configure with
different widgets_values`
- [x] All 253 existing subgraph tests pass
- [ ] Manual: load workflow from issue image → verify 3 subgraph
instances produce different results

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10849-fix-store-promoted-widget-values-per-SubgraphNode-instance-3386d73d3650815a8544f54adcc0d504)
by [Unito](https://www.unito.io)

---------

Co-authored-by: dante <dante@danteui-MacStudio.local>
2026-04-14 21:22:52 +00:00
AustinMroz
988a546721 Add missing dialog tests (#11133)
Leveraging the fancy coverage functionality of #10930, this PR aims to
add coverage to missing dialogue models.

This has proven quite constructive as many of the dialogues have since
been shown to be bugged.
- The APINodes sign in dialog that displays when attempting to run a
workflow containing Partner nodes while not logged in was intended to
display a list of nodes required to execute the workflow. The import for
this component was forgotten in the original commit (#3532) and the
backing component was later knipped
- Error dialogs resulting are intended to display the file responsible
for the error, but the prop was accidentally left out during the
refactoring of #3265
- ~~The node library migration (#8548) failed to include the 'Edit
Blueprint' button, and had incorrect sizing and color on the 'Delete
Blueprint' button.~~
- On request, the library button changes were spun out to a separate PR

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11133-Add-missing-dialog-tests-33e6d73d3650812cb142d610461adcd4)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-04-14 14:31:31 -07:00
pythongosssss
165984fe4c test: Improve speed of app mode input corruption test (#11236)
## Summary

Speeds up test that was timing out
https://9b579efd.comfyui-playwright-chromium.pages.dev/#?testId=b97e313f05078cede9be-5e6b75a76880fb6a5d96

## Changes

- **What**:
- load prebuilt workflows to reduce test time (17s -> 11s)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11236-test-Improve-speed-of-app-mode-input-corruption-test-3426d73d3650815b9475ec96dfbd7ad5)
by [Unito](https://www.unito.io)
2026-04-14 18:36:04 +00:00
pythongosssss
34a02a29c9 test: Remove unnecessary setup, UseNewMenu and waitForNodes calls (#11237)
## Summary

More simplification

## Changes

- **What**: 
- Remove more UseNewMenu settings calls
- Remove `await comfyPage.setup()`
- Remove `waitForNodes` in vue node tagged tests

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11237-test-Remove-unnecessary-setup-UseNewMenu-and-waitForNodes-calls-3426d73d36508198a100c218420d479c)
by [Unito](https://www.unito.io)
2026-04-14 17:40:23 +00:00
pythongosssss
a09bb81b98 test: Auto wait for nodes after loadWorkflow in vue-node tests (#11238)
## Summary

Updates tests to auto wait for vue-nodes when loading a workflow in a
test with the vue-nodes tag

## Changes

- **What**: 
- If tag includes vue-nodes, wait 
- Remove all load->wait calls

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11238-test-Auto-wait-for-nodes-after-loadWorkflow-in-vue-node-tests-3426d73d3650810e8760c5601186fde8)
by [Unito](https://www.unito.io)
2026-04-14 17:30:49 +00:00
Alexander Brown
72eed86cea test: remove redundant setup/settings now handled by @vue-nodes fixture (#11195)
## Summary

Follow-up cleanup for #11184 — removes redundant test setup calls that
the `@vue-nodes` fixture now handles.

## Changes

- **What**: Remove 40 lines of redundant `setSetting`, `setup()`, and
`waitForNodes()` calls across 11 test files
  - `UseNewMenu: 'Top'` calls (already fixture default)
- `setup()` + `waitForNodes()` on default workflow (fixture already does
this for `@vue-nodes`)
- Page reload in `subgraphZeroUuid` (fixture applies VueNodes.Enabled
server-side before navigation)

## Review Focus

Each removal was verified against the fixture's `setupSettings()`
defaults (ComfyPage.ts:420-442) and the `@vue-nodes` auto-setup (lines
454-456). Tests that call `setup()`/`waitForNodes()` after
`loadWorkflow()` or `page.evaluate()` were intentionally kept.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11195-test-remove-redundant-setup-settings-now-handled-by-vue-nodes-fixture-3416d73d36508154827df116a97e9130)
by [Unito](https://www.unito.io)

Co-authored-by: Amp <amp@ampcode.com>
2026-04-13 22:15:45 +00:00
pythongosssss
5899a9392e test: Simplify vue node/menu test setup (#11184)
## Summary
Simplifies test setup for common settings

## Changes

- **What**: 
- add vue-nodes tag to auto enable nodes 2.0
- remove UseNewMenu Top as this is default

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11184-test-Simplify-vue-node-menu-test-setup-3416d73d3650815487e0c357d28761fe)
by [Unito](https://www.unito.io)
2026-04-13 20:43:25 +00:00
pythongosssss
a373633ab2 refactor: fix lint errors in tests (#11182)
## Summary

Fix tests failing lint

## Changes

- **What**:
- Fix relative imports
- Fix test not using comfyPage

## Review Focus

<!-- Critical design decisions or edge cases that need attention -->

<!-- If this PR fixes an issue, uncomment and update the line below -->
<!-- Fixes #ISSUE_NUMBER -->

## Screenshots (if applicable)

<!-- Add screenshots or video recording to help explain your changes -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11182-refactor-fix-lint-errors-in-tests-3416d73d3650812fbf1bc88554c57de2)
by [Unito](https://www.unito.io)
2026-04-13 15:50:11 +00:00
jaeone94
521019d173 fix: exclude muted/bypassed nodes from missing asset detection (#10856)
## Summary

Muted and bypassed nodes are excluded from execution but were still
triggering missing model/media/node warnings. This PR makes the error
system mode-aware: muted/bypassed nodes no longer produce missing asset
errors, and all error lifecycle events (mode toggle, deletion, paste,
undo, tab switch) are handled consistently.

- Fixes Comfy-Org/ComfyUI#13256

## Behavioral notes

- **Tab switch overlay suppression (intentional)**: Switching back to a
workflow with missing assets no longer re-shows the error overlay. This
reverses the behavior introduced in #10190. The error state is still
restored silently in the errors tab — users can access it via the
properties panel without being interrupted by the overlay on every tab
switch.

## Changes

### 1. Scan filtering

- `scanAllModelCandidates`, `scanAllMediaCandidates`,
`scanMissingNodes`: skip nodes with `mode === NEVER || BYPASS`
- `collectMissingNodes` (serialized data): skip error reporting for
muted/bypassed nodes while still calling `sanitizeNodeName` for safe
`configure()`
- `collectEmbeddedModelsWithSource`: skip muted/bypassed nodes;
workflow-level `graphData.models` only create candidates when active
nodes exist
- `enrichWithEmbeddedMetadata`: filter unmatched workflow-level models
when all referencing nodes are inactive

### 2. Realtime mode change handling

- `useErrorClearingHooks.ts` chains `graph.onTrigger` to detect
`node:property:changed` (mode)
- Deactivation (active → muted/bypassed): remove missing
model/media/node errors for the node
- Activation (muted/bypassed → active): scan the node and add confirmed
errors, show overlay
- Subgraph container deactivation: remove all interior node errors
(execution ID prefix match)
- Subgraph container activation: scan all active interior nodes
recursively
- Subgraph interior mode change: resolve node via
`localGraph.getNodeById()` then compute execution ID from root graph

### 3. Node deletion

- `graph.onNodeRemoved`: remove missing model/media/node errors for the
deleted node
- Handle `node.graph === null` at callback time by using
`String(node.id)` for root-level nodes

### 4. Node paste/duplicate

- `graph.onNodeAdded`: scan via `queueMicrotask` (deferred until after
`node.configure()` restores widget values)
- Guard: skip during `ChangeTracker.isLoadingGraph` (undo/redo/tab
switch handled by pipeline)
- Guard: skip muted/bypassed nodes

### 5. Workflow tab switch optimization

- `skipAssetScans` option in `loadGraphData`: skip full pipeline on tab
switch
- Cache missing model/media/node state per workflow via
`PendingWarnings`
- `beforeLoadNewGraph`: save current store state to outgoing workflow's
`pendingWarnings`
- `showPendingWarnings`: restore cached errors silently (no overlay),
always sync missing nodes store (even when null)
- Preserve UI state (`fileSizes`, `urlInputs`) on tab switch by using
`setMissingModels([])` instead of `clearMissingModels()`
- `MissingModelRow.vue`: fetch file size on mount via
`fetchModelMetadata` memory cache

### 6. Undo/redo overlay suppression

- `silentAssetErrors` option propagated through pipeline →
`surfaceMissingModels`/`surfaceMissingMedia` `{ silent }` option
- `showPendingWarnings` `{ silent }` option for missing nodes overlay
- `changeTracker.ts`: pass `silentAssetErrors: true` on undo/redo

### 7. Error tab node filtering

- Selected node filters missing model/media card contents (not just
group visibility)
- `isAssetErrorInSelection`: resolve execution ID → graph node for
selection matching
- Missing nodes intentionally unfiltered (pack-level scope)
- `hasMissingMediaSelected` added to `RightSidePanel.vue` error tab
visibility
- Download All button: show only when 2+ downloadable models exist

### 8. New store functions

- `missingModelStore`: `addMissingModels`, `removeMissingModelsByNodeId`
- `missingMediaStore`: `addMissingMedia`, `removeMissingMediaByNodeId`
- `missingNodesErrorStore`: `removeMissingNodesByNodeId`
- `missingModelScan`: `scanNodeModelCandidates` (extracted single-node
scan)
- `missingMediaScan`: `scanNodeMediaCandidates` (extracted single-node
scan)

### 9. Test infrastructure improvements

- `data-testid` on `RightSidePanel.vue` tabs (`panel-tab-{value}`)
- Error-related TestIds moved from `dialogs` to `errorsTab` namespace in
`selectors.ts`
- Removed unused `TestIdValue` type
- Extracted `cleanupFakeModel` to shared `ErrorsTabHelper.ts`
- Renamed `openErrorsTabViaSeeErrors` → `loadWorkflowAndOpenErrorsTab`
- Added `aria-label` to pencil edit button and subgraph toggle button

## Test plan

### Unit tests (41 new)

- Store functions: `addMissing*`, `removeMissing*ByNodeId`
- `executionErrorStore`: `surfaceMissing*` silent option
- Scan functions: muted/bypassed filtering, `scanNodeModelCandidates`,
`scanNodeMediaCandidates`
- `workflowService`: `showPendingWarnings` silent, `beforeLoadNewGraph`
caching

### E2E tests (17 new in `errorsTabModeAware.spec.ts`)

**Missing nodes**
- [x] Deleting a missing node removes its error from the errors tab
- [x] Undo after bypass restores error without showing overlay

**Missing models**
- [x] Loading a workflow with all nodes bypassed shows no errors
- [x] Bypassing a node hides its error, un-bypassing restores it
- [x] Deleting a node with missing model removes its error
- [x] Undo after bypass restores error without showing overlay
- [x] Pasting a node with missing model increases referencing node count
- [x] Pasting a bypassed node does not add a new error
- [x] Selecting a node filters errors tab to only that node

**Missing media**
- [x] Loading a workflow with all nodes bypassed shows no errors
- [x] Bypassing a node hides its error, un-bypassing restores it
- [x] Pasting a bypassed node does not add a new error
- [x] Selecting a node filters errors tab to only that node

**Subgraph**
- [x] Bypassing a subgraph hides interior errors, un-bypassing restores
them
- [x] Bypassing a node inside a subgraph hides its error, un-bypassing
restores it

**Workflow switching**
- [x] Does not resurface error overlay when switching back to workflow
with missing nodes
- [x] Restores missing nodes in errors tab when switching back to
workflow

# Screenshots


https://github.com/user-attachments/assets/e0a5bcb8-69ba-4120-ab7f-5c83e4cfc3c5



## Follow-up work

- Extract error-detection computed properties from `RightSidePanel.vue`
into a composable (e.g. `useErrorsTabVisibility`)

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: GitHub Action <action@github.com>
2026-04-13 12:51:19 +00:00
Kelly Yang
bd82c855e0 test: add minimap E2E tests for graph content and click-to-navigate (#10738)
## Summary

Adds Playwright E2E tests verifying that 
1. the minimap canvas renders node content
2. clears when the graph is empty
3. correctly navigates the main canvas on click

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10738-test-add-minimap-E2E-tests-for-graph-content-and-click-to-navigate-3336d73d365081eb955ce711b3efc57f)
by [Unito](https://www.unito.io)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: changes are limited to adding `data-testid` attributes to
the minimap UI and expanding Playwright E2E assertions, with no
production behavior changes expected.
> 
> **Overview**
> Strengthens minimap E2E coverage by switching existing assertions from
CSS selectors to new `data-testid`-based selectors and adding helper
utilities for canvas/overlay interactions.
> 
> Adds new Playwright tests that verify the minimap canvas renders
content when nodes exist, clears when the graph is emptied, and that
clicking the minimap pans the main canvas (including a
post-`fitViewToSelectionAnimated` tolerance check).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
06e7542af1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Alexander Brown <DrJKL0424@gmail.com>
Co-authored-by: GitHub Action <action@github.com>
2026-04-13 04:28:04 +00:00
Kelly Yang
5b7ef3fe21 test: Painter Widget E2E Test Plan (#10846)
### Summary of Improvements

* **Custom Test Coverage Extension**: Enhanced the Painter widget E2E
test suite by refactoring logic for better maintainability and
robustness.
* **Stable Component Targeting**: Introduced
`data-testid="painter-dimension-text"` to `WidgetPainter.vue`, providing
a reliable, non-CSS-dependent locator for canvas size verification.
* **Improved Test Organization**: Reorganized existing test scenarios
into logical categories using `test.describe` blocks (Drawing, Brush
Settings, Canvas Size Controls, etc.).
* **Asynchronous Helper Integration**: Converted `hasCanvasContent` to
an asynchronous helper and unified its usage across multiple test cases
to eliminate redundant pixel-checking logic.
* **Locator Resilience**: Updated Reka UI slider interaction logic to
use more precise targeting (`:not([data-slot])`), preventing ambiguity
and improving test stability.
* **Scenario Refinement**: Updated the `pointerup` test logic to
accurately reflect pointer capture behavior when interactions occur
outside the canvas boundaries.
* **Enhanced Verification Feedback**: Added descriptive error messages
to `expect.poll` assertions to provide clearer context on potential
failure points.
* **Standardized Tagging**: Restored the original tagging strategy
(including `@smoke` and `@screenshot` tags) to ensure tests are
categorized correctly for CI environments.

### Red-Green Verification

| Commit | CI Status | Purpose |
| :--- | :--- | :--- |
| `test: refactor painter widget e2e tests and address review findings`
| 🟢 Green | Addresses all E2E test quality and stability issues from
review findings. |

### Test Plan

- [x] **Quality Checks**: `pnpm format`, `pnpm lint`, and `pnpm
typecheck` verified as passing.
- [x] **Component Integration**: `WidgetPainter.vue` `data-testid`
correctly applied and used in tests.
- [x] **Helper Reliability**: `hasCanvasContent` correctly identifies
colored pixels and returns a promise for `expect.poll`.
- [x] **Locator Robustness**: Verified Reka slider locators correctly
exclude internal thumb spans.
- [x] **Boundary Interaction**: Verified `pointerup` correctly ends
strokes when triggered outside the viewport.
- [x] **Tagging Consistency**: Verified `@smoke` and `@screenshot` tags
are present in the final test suite.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10846-test-Painter-Widget-E2E-Test-Plan-3386d73d365081deb70fe4afbd417efb)
by [Unito](https://www.unito.io)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Primarily adds/refactors Playwright E2E tests and stable `data-testid`
hooks, with no changes to Painter drawing logic. Risk is limited to
potential test brittleness or minor UI attribute changes.
> 
> **Overview**
> Expands the Painter widget Playwright suite with new grouped scenarios
covering drawing/erasing behavior, tool switching, brush inputs, canvas
resizing (including preserving drawings), clear behavior, and
serialization/upload flows (including failure toast).
> 
> Refactors the tests to use a shared `@e2e/helpers/painter` module
(`drawStroke`, `hasCanvasContent`, `triggerSerialization`), improves
stability via role/testid-based locators and clearer `expect.poll`
messaging, and adds `data-testid` attributes (e.g.,
`painter-clear-button`, `painter-*-row`, `painter-dimension-text`) to
`WidgetPainter.vue` to avoid CSS-dependent selectors.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
053a8e9ed2. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: GitHub Action <action@github.com>
2026-04-13 00:13:04 -04:00
Kelly Yang
85de833776 test: add E2E tests for ImageCompare widget (#10767)
## Summary
Add E2E tests for ImageCompare widget
Covers slider interaction, batch navigation, single-image modes, visual
regression screenshots, and edge cases for the ImageCompare Vue node
widget.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10767-test-add-E2E-tests-for-ImageCompare-widget-3346d73d365081c6bfc6fbd97fa04e4d)
by [Unito](https://www.unito.io)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Adds Playwright E2E coverage and screenshot assertions only; main risk
is increased CI runtime/flakiness due to additional image-loading and
hover/position polling.
> 
> **Overview**
> Adds a new Playwright E2E suite for the ImageCompare Vue widget
(tagged `@widget`) that programmatically sets widget values and asserts
rendering for empty, single-image, and dual-image states.
> 
> Expands coverage to **slider behavior** (default 50%, hover movement,
clamping, persistence) using polling on inline `clip-path`/handle
position, and adds **batch navigation** tests for multi-image
before/after sets.
> 
> Introduces **visual regression screenshots** at default and specific
slider positions, plus edge-case tests for broken URLs, rapid updates
resetting batch index, legacy string values, and custom alt text.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
2c65440384. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: GitHub Action <action@github.com>
2026-04-13 00:09:50 -04:00
Kelly Yang
cab46567c0 test: add E2E tests for ImageCropV2 widget (#10737)
## Summary
Adds Playwright E2E tests for the ImageCropV2 widget covering 
1. the empty state (no source image)
2. default control rendering
3. source image display with crop overlay
4. drag-to-reposition behavior.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10737-test-add-E2E-tests-for-ImageCropV2-widget-3336d73d365081b28ed9db63e5df383e)
by [Unito](https://www.unito.io)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: primarily adds Playwright E2E coverage and introduces
`data-testid` attributes for more stable selectors, with no changes to
core crop behavior.
> 
> **Overview**
> Adds new Playwright E2E coverage for the `ImageCropV2` Vue-node
widget, including workflows/fixtures for a disconnected input and a
`LoadImage -> ImageCropV2 -> PreviewImage` pipeline.
> 
> Tests validate the empty state and default controls, verify the crop
overlay renders after execution with screenshot assertions, and exercise
drag-to-reposition by dispatching pointer events and asserting the
widget’s crop value updates.
> 
> Updates `WidgetImageCrop.vue` to add `data-testid` hooks (empty
state/icon and crop overlay) to make the E2E selectors stable.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
9f29272742. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
2026-04-12 23:58:01 -04:00
Alexander Brown
6f579c5992 fix: enable playwright/no-force-option lint rule (#11164)
## Summary

Enable the previously disabled `playwright/no-force-option` lint rule at
error level and resolve all 29 violations across 10 files.

## Changes

### Lint rule
- `.oxlintrc.json`: `playwright/no-force-option` changed from `off` to
`error`

### Shared utility
- `CanvasHelper.ts`: Add `mouseClickAt()` and `mouseDblclickAt()`
methods that convert canvas-element-relative positions to absolute page
coordinates and use `page.mouse` APIs, avoiding Playwright's locator
actionability checks that fail when Vue DOM overlays sit above the
`<canvas>` element

### Force removal (20 violations)
- `selectionToolboxActions.spec.ts`: Remove `force: true` from 8 toolbox
button clicks (the `pointer-events: none` splitter overlay does not
intercept `elementFromPoint()`)
- `selectionToolboxSubmenus.spec.ts`: Remove `force: true` from 2
popover menu item clicks
- `BuilderSelectHelper.ts`: Remove `force: true` from 2 widget/node
clicks (builder mode does not disable pointer events)
- `linkInteraction.spec.ts`: Remove `force: true` from 3 slot `dragTo()`
calls (`::after` pseudo-elements do not intercept `elementFromPoint()`)
- `SidebarTab.ts`: Remove `force: true` from toast dismissal (`.catch()`
already handles failures)
- `nodeHelp.spec.ts`: Remove `force: true` from info button click
(preceding `toBeVisible()` assertion is sufficient)

### Rewrites (3 violations)
- `integerWidget.spec.ts`: Replace force-clicking disabled buttons with
`toBeDisabled()` assertions
- `Topbar.ts`: Replace force-click with `waitFor({ state: 'visible' })`
after hover

### Canvas coordinate clicks (9 violations)
- `litegraphUtils.ts`: Convert `NodeReference.click()` and
`navigateIntoSubgraph()` to use
`canvasOps.mouseClickAt()`/`mouseDblclickAt()`
- `subgraphPromotion.spec.ts`: Convert 3 right-click canvas calls to
`canvasOps.mouseClickAt()`
- `selectionToolboxSubmenus.spec.ts`: Convert 1 canvas dismiss-click to
`canvasOps.mouseClickAt()`

## Rationale

The original `force: true` usages were added defensively based on
incorrect assumptions about the `z-999 pointer-events: none` splitter
overlay intercepting Playwright's actionability checks. In reality,
`elementFromPoint()` skips elements with `pointer-events: none`, so the
overlay is transparent to Playwright's hit-test.

For canvas coordinate clicks, `force: true` on a locator does not tunnel
through DOM overlays — it only skips Playwright's preflight checks.
`page.mouse.click()` is the correct API for coordinate-based canvas
interactions.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11164-fix-enable-playwright-no-force-option-lint-rule-33f6d73d365081e78601c6114121d272)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-04-11 19:59:34 +00:00
Alexander Brown
8c9328c1b2 feat: add eslint-plugin-playwright via oxlint JS plugins (#11136)
## Summary

Add eslint-plugin-playwright as an oxlint JS plugin scoped to
browser_tests/, enforcing Playwright best practices at lint time.

## Changes

- **What**: Configure eslint-plugin-playwright@2.10.1 via oxlint's alpha
`jsPlugins` field (`.oxlintrc.json` override scoped to
`browser_tests/**/*.ts`). 18 recommended rules +
`prefer-native-locators` + `require-to-pass-timeout` at error severity.
All 173 initial violations resolved (config, auto-fix, manual fixes).
`no-force-option` set to off — 28 violations need triage (canvas overlay
workarounds vs unnecessary force) in a dedicated PR.
- **Dependencies**: `eslint-plugin-playwright@^2.10.1` (devDependency,
required by oxlint jsPlugins at runtime)

## Review Focus

- `.oxlintrc.json` override structure — this is the first use of
oxlint's JS plugins alpha feature in this repo
- Manual fixes in spec files: `waitForSelector` → `locator.waitFor`,
deprecated page methods → locator equivalents, `toPass()` timeout
additions
- Compound CSS selectors replaced with `.and()` (Playwright native
locator composition) to avoid `prefer-native-locators` suppressions
- Lint script changes in `package.json` to include `browser_tests/` in
oxlint targets

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
2026-04-11 01:25:14 +00:00
Johnpaul Chiwetelu
f0ae91de43 test: add e2e coverage for alt+drag duplicate and meta multi-select drag (#10994)
## Summary

Add Playwright coverage for two previously-untested canvas gestures:
Alt+drag to duplicate a regular node, and holding Meta across
click-click-click-drag to move multiple selected Vue nodes together.

## Changes

- **What**:
- `browser_tests/tests/interaction.spec.ts` — new `Node Duplication`
sub-describe with `Can duplicate a regular node via Alt+drag`. Asserts
CLIPTextEncode count goes 2 → 3 via poll, original node still exists.
Exercises the legacy canvas path at
`src/lib/litegraph/src/LGraphCanvas.ts:2434-2458`, which was only tested
for subgraph nodes before.
- `browser_tests/tests/vueNodes/interactions/node/move.spec.ts` — new
`should move all selected nodes together when dragging one with Meta
held`. Holds Meta for the entire sequence (3× `click({ modifiers:
['Meta'] })` + drag), asserts selection stays at 3 and all three nodes
move by the same delta. Exercises
`src/renderer/extensions/vueNodes/layout/useNodeDrag.ts:54-191`.
- Small refactor: `getLoadCheckpointHeaderPos` now delegates to a
reusable `getHeaderPos(comfyPage, title)` helper. Added `deltaBetween`
and `expectSameDelta` utilities (stricter than `expectPosChanged`, which
only checks `> 0`).


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10994-test-add-e2e-coverage-for-alt-drag-duplicate-and-meta-multi-select-drag-33d6d73d3650812dbf15c7053f44f0fd)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-04-11 00:18:16 +00:00
pythongosssss
82fb8ce658 test: App mode - Execution tests (#10801)
## Summary

Adds tests that simulate the execution flow and output feed

## Changes

- **What**: 
- Add ExecutionHelper for mocking network activity
- Refactor ws fixture to use Playwright websocket helper instead of
patching window
- 

## Review Focus

<!-- Critical design decisions or edge cases that need attention -->

<!-- If this PR fixes an issue, uncomment and update the line below -->
<!-- Fixes #ISSUE_NUMBER -->

## Screenshots (if applicable)

<!-- Add screenshots or video recording to help explain your changes -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10801-test-App-mode-Execution-tests-3356d73d365081e4acf0c34378600031)
by [Unito](https://www.unito.io)
2026-04-10 23:31:56 +00:00
Alexander Brown
f1bb756929 fix: remove redundant and counterproductive e2e timeout overrides (#11110)
## Summary

Alright, alright, alright. These e2e tests have been runnin' around like
they're late for somethin', settin' tight little timeouts like the
world's gonna end in 250 milliseconds. Man, you gotta *breathe*. Let the
framework do its thing. Go slow to go fast, that's what I always say.

## Changes

- **What**: Removed ~120 redundant timeout overrides from auto-retrying
Playwright assertions (`toBeVisible`, `toBeHidden`, `toHaveCount`,
`toBeEnabled`, `toHaveAttribute`, `toContainText`, `expect.poll`) where
5000ms is already the default. Also removed sub-5s timeouts (1s, 2s, 3s)
that were just *begging* for flaky failures — like wearin' a belt and
suspenders and also holdin' your pants up with both hands. Raised the
absurdly short timeouts in `customMatchers.ts` (250ms `toPass` → 5000ms,
256ms poll → default). Kept `timeout: 5000` on `.toPass()` calls
(defaults to 0), `.waitFor()`, `waitForRequest`, `waitForFunction`,
intentionally-short timeouts inside retry loops, and conditional
`.isVisible()/.catch()` checks — those fellas actually need the help.

## Review Focus

Every remaining timeout in the diff is there for a *reason*. The ones on
`.toPass()` stay because that API defaults to zero — it won't retry at
all without one. The ones on `.waitFor()` and `waitForRequest` stay
because those are locator actions, not auto-retrying assertions. The
intentionally-short ones inside `toPass` retry loops
(`interaction.spec.ts`) and the negative assertions (`actionbar.spec.ts`
confirming no response arrives) — those are *supposed* to be tight.

The short timeouts on regular assertions were actively *encouragin'*
flaky failures. That's like settin' your alarm for 4 AM and then gettin'
mad you're tired. Just... don't do that, man. Let things take the time
they need.

38 files, net -115 lines. Less code, more chill. That's livin'.

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-04-10 19:47:20 +00:00
pythongosssss
e38dd1efae test: App mode - Add test for cross-workflow input corruption (#10944)
## Summary

Adds test for the issue where inputs from one workflow would overwrite
those on another after sorting

## Changes

- **What**: 
- add test

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10944-test-App-mode-Add-test-for-cross-workflow-input-corruption-33b6d73d365081deab26d8f23d2318ae)
by [Unito](https://www.unito.io)
2026-04-10 17:55:33 +00:00
Christian Byrne
4cf160d66e fix: disable pointer events on non-visible DOM widget overlays (#11063)
## Problem

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.

## Root Cause

`updateWidgets()` runs during `onDrawForeground` (canvas render cycle)
and sets `widgetState.visible = false` for collapsed nodes. `v-show`
then hides the element with `display: none`. However, there is a timing
gap between the canvas state change and Vue's DOM update — during this
gap the widget overlay still intercepts pointer events.

## Fix

Add `!widgetState.visible` to the `pointerEvents` condition in
`composeStyle()`. This immediately sets `pointer-events: none` when the
widget becomes invisible, preventing event interception before `v-show`
applies `display: none`.

Also restores click-to-expand in the E2E test, removing the programmatic
`node.collapse()` workaround from PR #10967.

- Fixes #11006

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11063-fix-disable-pointer-events-on-non-visible-DOM-widget-overlays-33e6d73d36508179a83cd47121cf933f)
by [Unito](https://www.unito.io)
2026-04-10 14:28:25 +00:00
Alexander Brown
0132c77c7d test: harden 82 Playwright specs for deterministic CI runs (#10967)
## Summary

Harden 98 E2E spec files and 8 fixtures/helpers for deterministic CI
runs by replacing race-prone patterns with retry-safe alternatives.

No source code changes -- only `browser_tests/` is touched.

## Changes

- **E2E spec hardening** (98 spec files, 6 fixtures, 2 helpers):

  | Fix class | Sites | Examples |
  |-----------|-------|---------:|
| `expect(await ...)` -> `expect.poll()` | ~153 | interaction,
defaultKeybindings, workflows, featureFlags |
| `const x = await loc.count(); expect(x)` -> `toHaveCount()` | ~19 |
menu, linkInteraction, assets, bottomPanelShortcuts |
| `nextFrame()` -> `waitForHidden()` after menu clicks | ~22 |
contextMenu, rightClickMenu, subgraphHelper |
| Redundant `nextFrame()` removed | many | defaultKeybindings, minimap,
builderSaveFlow |
| `expect(async () => { ... }).toPass()` retry blocks | 5 | interaction
(graphdialog dismiss guard) |
| `force:true` removed from `BaseDialog.close()` | 1 | BaseDialog
fixture |
| ContextMenu `waitForHidden` simplified (check-then-act race removed) |
1 | ContextMenu fixture |
| Non-deterministic node order -> proximity-based selection | 1 |
interaction (toggle dom widget) |
  | Tight poll timeout (250ms) -> >=2000ms | 2 | templates |

- **Helper improvements**: Exposed locator getters on
`ComfyPage.domWidgets`, `ToastHelper.toastErrors`, and
`WorkflowsSidebarTab.activeWorkflowLabel` so callers can use retrying
assertions (`toHaveCount()`, `toHaveText()`) directly.

- **Flake pattern catalog**: Added section 7 table to
`browser_tests/FLAKE_PREVENTION_RULES.md` documenting 8 pattern classes
for reviewers and future authors.

- **Docs**: Fixed bad examples in `browser_tests/README.md` to use
`expect.poll()`.

- **Breaking**: None
- **Dependencies**: None

## Review Focus

- All fixes follow the rules in
`browser_tests/FLAKE_PREVENTION_RULES.md`
- No behavioral changes to tests -- only timing/retry strategy is
updated
- The `ContextMenu.waitForHidden` simplification removes a
swallowed-error anti-pattern; both locators now use direct `waitFor({
state: 'hidden' })`

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-04-09 20:50:56 -07:00
Terry Jia
277ee5c32e test: add E2E tests for Load3D model upload and drag-drop and basic e2e for 3d viewer (#10957)
## Summary
Add tests verifying real model loading:
- Upload cube.obj via file chooser button
- Drag-and-drop cube.obj onto the 3D canvas
- Add data-testid to LoadingOverlay for stable test selectors.
Add tests verifying 3d viewer openning:
- Open viewer from Load3D node via expand button, verify canvas and
controls sidebar
- Cancel button closes the viewer dialog

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10957-test-add-E2E-tests-for-Load3D-model-upload-and-drag-drop-and-basic-e2e-for-3d-viewer-33c6d73d3650810c8ff8ed656a5164a6)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-04-09 21:36:07 -04:00
Dante
e8787dee9d fix: prevent node context menu from overflowing viewport on desktop (#10854)
## Summary

The node "More Options" (⋮) context menu had `md:max-h-none
md:overflow-y-visible` responsive overrides that removed the height
constraint and scrollability on desktop (768px+). When the menu had many
items (e.g., KSampler), items below the viewport fold were inaccessible
with no scrollbar.

Removed the desktop overrides so `max-h-[80vh] overflow-y-auto` applies
at all screen sizes.

- Fixes #10824

## Red-Green Verification

| Commit | CI Status | Purpose |
|--------|-----------|---------|
| `test: add failing test for node context menu viewport overflow` |
🔴 Red | Proves the test catches the bug |
| `fix: prevent node context menu from overflowing viewport on desktop`
| 🟢 Green | Proves the fix resolves the bug |

## Test Plan

- [ ] CI red on test-only commit
- [ ] CI green on fix commit
- [ ] Manual verification: zoom out to 50%, open node More Options menu,
verify last item ("Remove") is scrollable

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10854-fix-prevent-node-context-menu-from-overflowing-viewport-on-desktop-3396d73d365081989403c981847aeda6)
by [Unito](https://www.unito.io)
2026-04-10 10:31:04 +09:00
Dante
ba0bab3e50 test: add E2E tests for ManagerDialog (#10970)
## Summary
- Add Playwright E2E tests for the ManagerDialog component which had
zero test coverage
- Covers dialog opening, pack browsing, search filtering, tab
navigation, sort controls, search mode switching, error states, install
action, info panel, and close behavior
- All API calls (Algolia search, Manager installed packs, queue) are
mocked with typed responses

Part of the FixIt Burndown test coverage initiative.

## Test plan
- [ ] CI browser tests pass
- [ ] Tests validate core ManagerDialog user flows with mocked APIs
- [ ] No regressions in existing tests

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10970-test-add-E2E-tests-for-ManagerDialog-33c6d73d365081468a4ad8fc1894f05b)
by [Unito](https://www.unito.io)
2026-04-10 10:26:35 +09:00
Kelly Yang
bbb07053c4 test: add E2E tests for CanvasModeSelector toolbar component (#10934)
Adds `browser_tests/tests/canvasModeSelector.spec.ts`, covering the
canvas toolbar mode-selector component that was introduced with no E2E
coverage.
  Covers:
- Trigger button: toolbar visibility, `aria-expanded` state, icon
reflects active mode
- Popover lifecycle: open on click, close on re-click / item selection /
Escape
- Mode switching: clicking Hand/Select drives `canvas.state.readOnly`;
clicking the active item is a no-op
- ARIA state: `aria-checked` and roving `tabindex` track active mode,
including state driven by external commands
- Keyboard navigation: ArrowDown/Up with wraparound, Escape restores
focus to trigger — all using `toBeFocused()` retrying assertions
- Focus management: popover auto-focuses the checked item on open
- Keybinding integration: `H` / `V` keys update both
`canvas.state.readOnly` and the trigger icon
- Shortcut hint display: both menu items render non-empty key-sequence
hints
  22 tests across 7 `describe` groups. All selectors are ARIA-driven.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10934-test-add-E2E-tests-for-CanvasModeSelector-toolbar-component-33b6d73d3650819cb2cfdca22bf0b9a5)
by [Unito](https://www.unito.io)
2026-04-09 20:44:30 -04:00
jaeone94
809da9c11c fix: use cloud assets for asset widget default value (#10983)
## Summary

In cloud mode, asset-supported nodes (e.g. CheckpointLoaderSimple) used
the server's `object_info` combo options as their default widget value.
These options list local files on the backend which may not exist in the
user's cloud asset library. When the missing-model pipeline runs (on
undo, reload, or tab switch), it checks widget values against cloud
assets and correctly flags these local-only files as missing — producing
errors that appear to be false positives but are actually valid
detections of unusable defaults.

This PR changes the default value source from server combo options to
the cloud assets store.

## Default Value Behavior (Before → After)

### Cloud + asset-supported widgets (changed)

| Condition | Before | After |
|-----------|--------|-------|
| Assets cached, `inputSpec.default` in assets | `inputSpec.default` |
`inputSpec.default` |
| Assets cached, `inputSpec.default` not in assets | `inputSpec.default`
| `assets[0]` |
| Assets cached, no `inputSpec.default`, `options` exist | `options[0]`
| `assets[0]` |
| Assets not cached, `inputSpec.default` exists | `inputSpec.default` |
`undefined` → "Select model" |
| Assets not cached, no `inputSpec.default`, `options` exist |
`options[0]` | `undefined` → "Select model" |
| Assets not cached, no `inputSpec.default`, no `options` | `undefined`
→ "Select model" | `undefined` → "Select model" |

### Cloud + non-asset widgets (unchanged)

| Condition | Behavior |
|-----------|----------|
| `inputSpec.default` exists | `inputSpec.default` |
| `options` exist | `options[0]` |
| `remote` input | `"Loading..."` |
| None | `undefined` |

### OSS (unchanged)

| Condition | Behavior |
|-----------|----------|
| `inputSpec.default` exists | `inputSpec.default` |
| `options` exist | `options[0]` |
| `remote` input | `"Loading..."` |
| None | `undefined` |

## Root Cause

1. `addComboWidget` called `getDefaultValue(inputSpec)` which returns
`inputSpec.options[0]` — a local file from `object_info`
2. In cloud mode, `shouldUseAssetBrowser()` creates an asset widget with
this local filename as default
3. The model (e.g.
`dynamicrafter/controlnet/dc-sketch_encoder_fp16.safetensors`) exists on
the server but not in the user's cloud asset library
4. On undo/reload, `verifyAssetSupportedCandidates()` checks the widget
value against cloud assets → not found → marked as missing

## Changes

### Production (`useComboWidget.ts`)
- New `resolveCloudDefault(nodeType, specDefault)` function encapsulates
cloud default resolution
- Default priority: `inputSpec.default` (if found in cloud assets) →
first cloud asset → `undefined` (shows "Select model" placeholder)
- Edge case guards: `!= null` check for falsy defaults, `|| undefined`
for empty `getAssetFilename` return
- Server combo options (`object_info`) are no longer used as defaults
for asset widgets

### Unit Tests (`useComboWidget.test.ts`)
- 6 scenarios covering all default value paths:
  - Cloud assets loaded, no `inputSpec.default` → `assets[0]`
  - Cloud assets loaded, `inputSpec.default` in assets → uses default
  - Cloud assets loaded, `inputSpec.default` not in assets → `assets[0]`
  - No cloud assets, with `inputSpec.default` → placeholder
  - No cloud assets, with server options → placeholder
  - Asset widget creation verification
- Test helper refactored: assertions moved from helper to each test for
clarity

### E2E Test (`cloud-asset-default.spec.ts`)
- New `@cloud` tagged test verifying CheckpointLoaderSimple uses first
cloud asset, not server default
- Fixture extension stubs `/api/assets` before app loads (local backend
returns 503 for this endpoint)
- Uses typed mock data from existing `assetFixtures.ts`

## Scope

- **Cloud only**: All changes gated behind `isCloud` +
`shouldUseAssetBrowser()`
- **OSS impact**: None — code path is not entered in non-cloud builds
- **Breaking changes**: None — `useComboWidget` export signature
unchanged

## Review Focus
- Should the `/api/assets` stub in the E2E fixture extension be moved
into `ComfyPage` for all `@cloud` tests?

## Record
Before 


https://github.com/user-attachments/assets/994162a0-b56a-4e84-9b1c-d0f0068196d5



After


https://github.com/user-attachments/assets/ba299990-9bd3-4565-bd09-bffac3db60a9
2026-04-09 15:44:04 +09:00
Alexander Brown
25d1ac7456 test: reorganize subgraph test suite into composable domain specs (#10759)
## Summary

Reorganize the subgraph test suite so browser tests are thin
representative user journeys while lower-level Vitest suites own
combinatorics, migration edge cases, and data-shape semantics.

## Changes

- **What**: Migrate 17 flat subgraph browser specs into 10
domain-organized specs under `browser_tests/tests/subgraph/`, move
redundant semantic coverage down to 8 Vitest owner suites, delete all
legacy flat files
- **Browser specs** (54 tests): `subgraphSlots`, `subgraphPromotion`,
`subgraphPromotionDom`, `subgraphSerialization`, `subgraphNavigation`,
`subgraphNested`, `subgraphLifecycle`, `subgraphCrud`, `subgraphSearch`,
`subgraphOperations`
- **Vitest owners** (230 tests): `SubgraphNode.test.ts` (rename/label
propagation), `subgraphNodePromotion.test.ts`,
`promotedWidgetView.test.ts`, `SubgraphSerialization.test.ts`
(duplicate-ID remap), `SubgraphWidgetPromotion.test.ts` (legacy
hydration), `subgraphNavigationStore*.test.ts` (viewport cache,
workflow-switch), `subgraphStore.test.ts` (search aliases, description)
- **Net effect**: browser suite shrinks from ~96 scattered tests to 54
focused journeys

## Review Focus

- Coverage ownership split: each browser test has a unique UI-only
failure mode; semantic coverage lives in Vitest
- `subgraphPromotionDom.spec.ts` forces LiteGraph mode and uses
`canvas.openSubgraph()` instead of `navigateIntoSubgraph()` to avoid a
wrapper-specific DOM overlay duplication issue — entry-affordance
coverage lives in `subgraphNavigation.spec.ts`
- No product code changes — test-only migration

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10759-test-reorganize-subgraph-test-suite-into-composable-domain-specs-3336d73d365081b0a56bcbf809b1f584)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-04-08 15:04:33 -07:00
Christian Byrne
9b769656ac test: add ShareWorkflow dialog E2E tests (DLG-05) (#10588)
## 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>
2026-04-08 14:14:47 -07:00
Dante
537e4bc4f2 test: add E2E tests for settings dialog (#10797)
## 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)
2026-04-09 05:29:53 +09:00
pythongosssss
4b0b8e7240 test: App mode - Welcome screen state (#10747)
## Summary

Adds tests for validating welcome screen state

## Changes

- **What**: 
- add clear graph util function

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10747-test-App-mode-Welcome-screen-state-3336d73d365081f0ba27d567c3c81505)
by [Unito](https://www.unito.io)
2026-04-08 12:33:51 -07:00
Alexander Brown
3b78dfbe1c test: migrate browser_tests/ to @e2e/ path alias and add lint rule (#10958)
## 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>
2026-04-08 11:28:59 -07:00
pythongosssss
036be1c7e9 test: App mode - Pruning tests (#10805)
## Summary

Adds tests that deleted nodes automatically remove selections from app
mode

## Changes

- **What**: 
- always prune when entering app builder (fix)
- add tests (delete output node, delete input node, change dynamic
widget value)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10805-test-App-mode-Pruning-tests-3356d73d365081bcb12fc226af31a724)
by [Unito](https://www.unito.io)
2026-04-08 10:42:47 -07:00
jaeone94
3f375bea9c test: comprehensive E2E tests for error dialog, overlay, and errors tab (#10848)
## 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>
2026-04-08 14:45:17 +09:00
Alexander Brown
4cb83353cb test: stabilize flaky Playwright tests (#10817)
Stabilize flaky Playwright tests by improving test reliability.

This PR aims to identify and fix flaky e2e tests.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10817-test-stabilize-flaky-Playwright-tests-3366d73d365081ada40de73ce11af625)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-04-07 19:47:27 -07:00
Terry Jia
d73c4406ed test: add basic E2E tests for Load3D node (#10731)
## Summary
Add Playwright tests covering widget rendering, controls menu
interaction, background color change, and recording controls visibility.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10731-test-add-basic-E2E-tests-for-Load3D-node-3336d73d36508194bff9eb2a7c9356b9)
by [Unito](https://www.unito.io)
2026-04-07 22:41:12 -04:00
Dante
ccdde8697c test: add E2E regression tests for workflow tab save bug (#10815)
## Summary

- Adds E2E regression tests for the bug fixed in PR #10745 where closing
an inactive workflow tab would save the active workflow's content into
the closing tab's file
- Three test scenarios covering the full range of the bug surface:
  1. Closing an unmodified inactive tab preserves both workflows
2. Closing a modified inactive tab with "Save" preserves its own content
(not the active tab's)
3. Closing an unsaved inactive tab with "Save As" preserves its own
content

## Linked Issues

- Regression coverage for #10745 / Comfy-Org/ComfyUI#13230

## Test plan

- [ ] `pnpm exec playwright test
browser_tests/tests/topbar/workflowTabSave.spec.ts` passes against the
current main (with the fix)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10815-test-add-E2E-regression-tests-for-workflow-tab-save-bug-3366d73d365081eab409ed303620a959)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-04-08 10:40:12 +09:00
Johnpaul Chiwetelu
4078f8be8f test: add E2E test for subgraph duplicate independent widget values (#10949)
## Summary
- Add E2E test verifying duplicated subgraphs maintain independent
widget values (convert CLIP node to subgraph, duplicate, set different
text in each, assert no bleed)
- Extract `clickMenuItemExact` and `openForVueNode` into `ContextMenu`
fixture for reuse across Vue node tests
- Refactor `contextMenu.spec.ts` to delegate to the new fixture methods

## Test plan
- [x] `pnpm typecheck:browser` passes
- [x] `pnpm lint` passes
- [x] New test passes locally (`pnpm test:browser:local --
browser_tests/tests/subgraph/subgraphDuplicateIndependentValues.spec.ts`)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10949-test-add-E2E-test-for-subgraph-duplicate-independent-widget-values-33b6d73d3650818191c1f78ef8db4455)
by [Unito](https://www.unito.io)
2026-04-08 00:20:23 +01:00
Christian Byrne
83f4e7060a test(infra): AssetHelper with builder pattern + deterministic fixtures (#10545)
## What

Adds `AssetHelper` — a builder-pattern helper for mocking asset-related
API endpoints in Playwright E2E tests, plus deterministic fixture data.

## Why

12+ asset-related API endpoints need mocking for asset browser tests
(PNL-02), cloud dialog testing (DLG-08), and other asset-dependent E2E
scenarios. Random mock data from existing `createMockAssets()` is
unsuitable for deterministic E2E assertions.

## What's included

### `AssetHelper.ts` (307 LOC)
- Fluent builder API: `assetHelper.withModels(3).withImages(5).mock()`
- Stateful mock store (Map) for upload→verify→delete flows
- Endpoint coverage: GET/POST/PUT/DELETE `/assets`, download progress
- `mockError()` for error state testing
- `clearMocks()` cleanup matching QueueHelper/FeatureFlagHelper pattern

### `assetFixtures.ts` (304 LOC)
- 11 stable named constants (checkpoints, loras, VAE, embedding, inputs,
outputs)
- Factory functions: `generateModels()`, `generateInputFiles()`,
`generateOutputAssets()`
- Fixed IDs/dates/sizes — no randomness, safe for screenshot comparisons

### ComfyPage integration
- Available as `comfyPage.assets` in all tests

## Testing
- TypeScript compiles clean
- Follows existing QueueHelper/FeatureFlagHelper conventions

## Unblocks
- PNL-02: Asset browser tests (@Jaewon Yoon)
- DLG-08: Assets modal / cloud dialog testing

Part of: Test Coverage Q2 Overhaul

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10545-test-infra-AssetHelper-with-builder-pattern-deterministic-fixtures-32f6d73d365081d3985ef079ff3dbede)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-04-07 14:23:36 -07:00
AustinMroz
31c789c242 Support svg outputs in assets panel (#10470)
A trivial fix to support svg outputs in the assets panel

| Before | After |
| ------ | ----- |
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/2fca84f7-40f1-4966-b3dd-96facb8a4067"
/> | <img width="360" alt="after"
src="https://github.com/user-attachments/assets/cad1a9fc-f511-43bc-8895-80d931baad1c"
/>|

Note: SVG do not display on cloud in node, or the assets panel because
they are being served with the incorrect content-type of `text/plain`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10470-Support-svg-outputs-in-assets-panel-32d6d73d3650815fbba1fe788297e715)
by [Unito](https://www.unito.io)
2026-04-07 13:53:37 -07:00
pythongosssss
1b05927ff4 test: App mode - setting widget value test (#10746)
## Summary

Adds a test for setting various types of widgets in app mode, then
validating the /prompt API is called with the expected values

## Changes

- **What**: 
- extract duplicated enableLinearMode
- add AppModeWidgetHelper for setting values

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10746-test-App-mode-setting-widget-value-test-3336d73d365081739598fb5280d0127e)
by [Unito](https://www.unito.io)
2026-04-07 13:53:01 -07:00
pythongosssss
6f8e58bfa5 test: App Mode - widget reordering (#10685)
## Summary

Adds tests that simulate the user sorting the inputs and ensures they
are persisted and visible in app mode

## Changes

- **What**: 
- rework input/output selection helpers to accept widget/node names
- extract additional shared helpers

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10685-test-App-Mode-widget-reordering-3316d73d3650813b8348da5f29fd01f8)
by [Unito](https://www.unito.io)
2026-04-07 11:56:43 -07:00