## Summary
Add `windowsHide: true` to the `execSync('git rev-parse HEAD')` call in
`vite.config.mts` to prevent a console window from flashing on Windows
during builds.
## Changes
- **What**: Pass `windowsHide: true` option to `execSync` when fetching
the git commit hash at build time. This suppresses the transient cmd.exe
popup that appears on Windows.
## Review Focus
Minimal, single-option change. `windowsHide` is a Node.js built-in
option for `child_process` methods — no-op on non-Windows platforms.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11144-fix-vite-hide-git-rev-parse-window-on-Windows-33e6d73d365081ed9a14da5f47ccac4d)
by [Unito](https://www.unito.io)
Co-authored-by: Amp <amp@ampcode.com>
## 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)
## Summary
Fix undersized delete and edit icons on user blueprint items in the node
library sidebar.
## Changes
- **What**: Changed blueprint action icons (trash, edit) from `size-3.5`
(14px) to `size-4` (16px), matching the standard icon size used across
the codebase.
## Review Focus
Trivial sizing fix — `size-4` is the codebase-wide convention for
iconify icons in buttons, and what the button base styles default SVGs
to.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10992-fix-use-standard-size-4-for-blueprint-action-icons-33d6d73d365081be8c65f9e2a7b1d6ec)
by [Unito](https://www.unito.io)
## 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>
## 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)
## Summary
Three issues caused GLSL preview to diverge from backend results:
1. Uniform source resolution always read widgets[0] instead of using
link.origin_slot to select the correct widget. Added directValue
fallback for widgets not registered in widgetValueStore.
2. Hex color strings (e.g. "#45edf5") were coerced to 0 by Number().
Added hexToInt to colorUtil and used it in toNumber coercion.
3. Custom size_mode was ignored — preview always used upstream image
dimensions. Now checks size_mode widget first and respects "custom".
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11010-fix-resolve-incorrect-GLSL-live-preview-for-non-primitive-widget-types-33e6d73d36508101a76bfe8383c0c6ab)
by [Unito](https://www.unito.io)
## 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)
## 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)
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)
## Description
Fixes the WebcamCapture image upload path construction that was still
broken on cloud environments after #10220.
### Root cause
The cloud `/upload/image` endpoint returns:
```json
{ "name": "hash.png", "subfolder": "", "type": "input" }
```
The previous fix used `??` (nullish coalescing), which doesn't catch
empty strings:
- `subfolder: ""` → `"" ?? "webcam"` = `""` → path becomes `/hash.png`
(wrong)
- `type` was hardcoded as `[temp]` but cloud stores as `input` → file
not found
### Fix
- `??` → `||` so empty strings fall back to defaults
- Use `data.type` from server response instead of hardcoding `[temp]`
### QA evidence
Prod (cloud/1.42): `ImageDownloadError: the input file
'webcam/1775685296883.png [temp]' doesn't exist`
Staging (cloud/1.42): `ImageDownloadError: Failed to validate images`
### Related
- Fixes the remaining issue from #10220
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11000-fix-use-instead-of-and-server-type-in-WebcamCapture-upload-path-33d6d73d36508156b93cfce0aae8e017)
by [Unito](https://www.unito.io)
## Automated Ingest API Type Update
This PR updates the Ingest API TypeScript types and Zod schemas from the
latest cloud OpenAPI specification.
- Cloud commit: 48d94b7
- Generated using @hey-api/openapi-ts with Zod plugin
These types cover cloud-only endpoints (workspaces, billing, secrets,
assets, tasks, etc.).
Overlapping endpoints shared with the local ComfyUI Python backend are
excluded.
---------
Co-authored-by: MillerMedia <7741082+MillerMedia@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
## Summary
Replace Zendesk feedback URLs with Typeform survey (`q7azbWPi`) in the
action bar feedback button and Help Center menu for Cloud/Nightly
distributions.
## Changes
- **What**:
- `cloudFeedbackTopbarButton.ts`: Replace `buildFeedbackUrl()` (Zendesk)
with direct Typeform survey URL. Remove unused Zendesk import.
- `HelpCenterMenuContent.vue`: Feedback menu item now opens Typeform URL
for Cloud/Nightly builds; falls back to `Comfy.ContactSupport` (Zendesk)
for other distributions. Added external link icon for Cloud/Nightly.
- Help menu item and `Comfy.ContactSupport` command unchanged — support
flows still route to Zendesk.
## Review Focus
- Gating logic: `isCloud || isNightly` correctly limits Typeform
redirect to intended distributions
- Help item intentionally unchanged (support ≠ feedback)
Ticket: COM-17992
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10890-feat-integrate-Typeform-survey-into-feedback-button-33a6d73d36508185abbfe57e7a36b5f7)
by [Unito](https://www.unito.io)
## 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
## Summary
- Fix `CustomCombo` copy/paste so the combo keeps its option list and
selected value
- Scope the fix to `src/extensions/core/customWidgets.ts` instead of
changing LiteGraph core deserialization
- Replace the previous round-trip test with a regression test that
exercises the actual clone/paste lifecycle
- Fixes#9927
## Root Cause
`CustomCombo` option widgets override `value` to read from
`widgetValueStore`.
During `node.clone()` and clipboard paste, `configure()` restores widget
values before the new node is added to the graph and before those
widgets are registered in the store.
That meant the option widgets read back as empty while `updateCombo()`
was rebuilding the combo state, so `comboWidget.options.values` became
blank on the pasted node.
## Fix
Keep a local fallback value for each generated `option*` widget in
`customWidgets.ts`.
The getter now returns the store-backed value when available and falls
back to the locally restored value before store registration.
This preserves the option list during `clone().serialize()` and paste
without hard-coding `CustomCombo` behavior into
`LGraphNode.configure()`.
## Why No E2E Test
This regression happens in the internal LiteGraph clipboard lifecycle:
`clone() -> serialize() -> createNode() -> configure() -> graph.add()`.
The failing state is the transient pre-add relationship between
`CustomCombo`'s store-backed option widgets and
`comboWidget.options.values`, which is not directly exposed through a
stable DOM assertion in the current Playwright suite.
A focused unit regression test is the most direct way to cover that
lifecycle without depending on brittle canvas interaction timing.
## Test Plan
- [x] Regression test covers `clone().serialize() -> createNode() ->
configure() -> graph.add()` for `CustomCombo`
- [ ] CI on the latest two commits (`81ac6d2ce`, `94147caf1`)
- [ ] Manual: create `CustomCombo` -> add `alpha`, `beta`, `gamma` ->
select `beta` -> copy/paste -> verify the pasted combo still shows all
three options and keeps `beta` selected
## Summary
<!-- One sentence describing what changed and why. -->
## Changes
- **What**: <!-- Core functionality added/modified -->
- **Breaking**: <!-- Any breaking changes (if none, remove this line)
-->
- **Dependencies**: <!-- New dependencies (if none, remove this line)
-->
## 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-10157-feat-website-add-zh-CN-translations-for-homepage-and-secondary-pages-3266d73d3650811f918cc35eca62a4bc)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
## Summary
Consolidate the `SubscriptionTier` type from 3 independent definitions
into a single source of truth in `tierPricing.ts`.
## Changes
- **What**: Exported `SubscriptionTier` from `tierPricing.ts`. Removed
hand-written unions from `workspaceApi.ts` (lines 80-88),
`PricingTable.vue`, and `PricingTableWorkspace.vue`. All now import from
the canonical location.
- **Files**: 4 files changed (type-only, ~5 net lines)
## Review Focus
- This is a type-only change — `pnpm typecheck` is the primary
validation
- If the OpenAPI schema ever adds tiers, there is now one place to
update
## Stack
PR 5/5: #10483 → #10484 → #10485 → #10486 → **→ This PR**
## Summary
Decompose the 562-line `MembersPanelContent.vue` into focused
single-responsibility components.
## Changes
- **What**: Extracted `RoleBadge.vue`, `MemberListItem.vue`,
`PendingInvitesList.vue`, and `MemberUpsellBanner.vue` from
`MembersPanelContent.vue`. Added `RoleBadge.test.ts`. The parent
component is slimmed from 562 → ~120 lines.
- **Files**: 6 files changed (4 new components + 1 new test + 1
refactored)
## Review Focus
- Component boundaries — each extracted component has a clear single
responsibility
- `MembersPanelContent.vue` still orchestrates all behavior; extracted
components are presentational
- Visual QA needed: workspace settings panel should look and behave
identically
## Stack
PR 4/5: #10483 → #10484 → #10485 → **→ This PR** → #10487
---------
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
## 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>
## Summary
- Upload Model dialog stays stuck in "Processing" after async download
completes because the wizard never watches for task completion
- `useUploadModelWizard.ts` sets `uploadStatus = 'processing'` but has
no watcher linking it to `assetDownloadStore.lastCompletedDownload`
- Added a `watch` on `lastCompletedDownload` that transitions
`uploadStatus` to `'success'` when the tracked task finishes
- Fixes#10609
## Root Cause
`uploadModel()` (line 249) sets `uploadStatus = 'processing'` when the
async task starts, but control flow ends there. The `assetDownloadStore`
receives WebSocket completion events and updates
`lastCompletedDownload`, but the wizard never watches this reactive
state.
## Fix
Added a `watch` inside the async branch that monitors
`assetDownloadStore.lastCompletedDownload`. When the completed task ID
matches the upload's task ID, it transitions `uploadStatus` from
`'processing'` to `'success'` and refreshes model caches. The watcher
auto-disposes after firing.
## Red-Green Verification
| Commit | CI Status | Purpose |
|--------|-----------|---------|
| `test: add failing test for upload dialog stuck in processing state` |
🔴 Red | Proves the test catches the bug |
| `fix: update upload dialog status when async download completes` |
🟢 Green | Proves the fix resolves the bug |
## Test Plan
- [x] CI red on test-only commit
- [x] CI green on fix commit
- [x] Unit test: `updates uploadStatus to success when async download
completes`
- [ ] Manual: Import model via URL → verify dialog transitions from
Processing to Success (requires `--enable-assets`)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10838-fix-update-upload-dialog-status-when-async-download-completes-3376d73d365081b6a5b1d2be3804ce4b)
by [Unito](https://www.unito.io)
## 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>