mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-27 09:45:13 +00:00
main
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
4d57c41fdb |
test: subgraph integration contracts and expanded Playwright coverage (#10123)
## Summary Add integration contract tests (unit) and expanded Playwright coverage for subgraph promotion, hydration, navigation, and lifecycle edge behaviors. ## Changes - **What**: 22 unit/integration tests across 9 files covering promotion store sync, widget view lifecycle, input link resolution, pseudo-widget cache, navigation viewport restore, and subgraph operations. 13 Playwright E2E tests covering proxyWidgets hydration stability, promoted source removal cleanup, pseudo-preview unpack/remove, multi-link representative round-trip, nested promotion retarget, and navigation state on workflow switch. - **Helpers**: Added `isPseudoPreviewEntry`, `getPseudoPreviewWidgets`, `getNonPreviewPromotedWidgets` to promotedWidgets helper. Added `SubgraphHelper.getNodeCount()`. ## Review Focus - Test-only PR — no production code changes - Validates existing subgraph behaviors are covered by regression tests before further feature work - Phase 4 (unit/integration contracts) and Phase 5 (Playwright expansion) of the subgraph test coverage plan ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10123-test-subgraph-integration-contracts-and-expanded-Playwright-coverage-3256d73d365081258023e3a763859e00) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: GitHub Action <action@github.com> |
||
|
|
34a77e5016 |
test: harden subgraph test coverage and remove low-value tests (#9967)
## Summary Harden subgraph test coverage: remove low-value change-detector tests, consolidate fixtures, add behavioral coverage, and fix test infrastructure issues. Includes minor production code corrections discovered during test hardening. ## Changes - **What**: Comprehensive subgraph test suite overhaul across 6 phases - Removed change-detector tests and redundant assertions - Consolidated fixture helpers into `subgraphHelpers.ts` / `subgraphFixtures.ts` - Added Pinia initialization and fixture reset to all test files - Fixed barrel import violations (circular dependency prevention) - Added behavioral coverage for slot connections, events, edge cases - Added E2E helper and smoke test for subgraph promotion - Exported `SubgraphSlotBase` from litegraph barrel for test access - **Production code changes** (minor correctness fixes found during testing): - `resolveSubgraphInputLink.ts`: iterate forward (first-connected-wins) to match `_resolveLinkedPromotionBySubgraphInput` - `promotionSchema.ts`: return `[]` instead of throwing on invalid `proxyWidgets`; console.warn always (not DEV-only) - `LGraph.ts`: disconnect-after-veto ordering fix - `litegraph.ts`: barrel export swap for `SubgraphSlotBase` - **Stats**: 349 tests passing, 0 skipped across 26 test files ## Review Focus - Tests that merely asserted default property values were deleted (change detectors) - Fixture state is now reset via `resetSubgraphFixtureState()` in `beforeEach` - All imports use `@/lib/litegraph/src/litegraph` barrel to avoid circular deps - Production changes are small and directly motivated by test findings --------- Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: bymyself <cbyrne@comfy.org> |
||
|
|
c25f9a0e93 |
feat: synthetic widgets getter for SubgraphNode (proxy-widget-v2) (#8856)
## Summary Replace the Proxy-based proxy widget system with a store-driven architecture where `promotionStore` and `widgetValueStore` are the single sources of truth for subgraph widget promotion and widget values, and `SubgraphNode.widgets` is a synthetic getter composing lightweight `PromotedWidgetView` objects from store state. ## Motivation The subgraph widget promotion system previously scattered state across multiple unsynchronized layers: - **Persistence**: `node.properties.proxyWidgets` (tuples on the LiteGraph node) - **Runtime**: Proxy-based `proxyWidget.ts` with `Overlay` objects, `DisconnectedWidget` singleton, and `isProxyWidget` type guards - **UI**: Each Vue component independently calling `parseProxyWidgets()` via `customRef` hacks - **Mutation flags**: Imperative `widget.promoted = true/false` set on `subgraph-opened` events This led to 4+ independent parsings of the same data, complex cache invalidation, and no reactive contract between the promotion state and the rendering layer. Widget values were similarly owned by LiteGraph with no Vue-reactive backing. The core principle driving these changes: **Vue owns truth**. Pinia stores are the canonical source; LiteGraph objects delegate to stores via getters/setters; Vue components react to store state directly. ## Changes ### New stores (single sources of truth) - **`promotionStore`** — Reactive `Map<NodeId, PromotionEntry[]>` tracking which interior widgets are promoted on which SubgraphNode instances. Graph-scoped by root graph ID to prevent cross-workflow state collision. Replaces `properties.proxyWidgets` parsing, `customRef` hacks, `widget.promoted` mutation, and the `subgraph-opened` event listener. - **`widgetValueStore`** — Graph-scoped `Map<WidgetKey, WidgetState>` that is the canonical owner of widget values. `BaseWidget.value` delegates to this store via getter/setter when a node ID is assigned. Eliminates the need for Proxy-based value forwarding. ### Synthetic widgets getter (SubgraphNode) `SubgraphNode.widgets` is now a getter that reads `promotionStore.getPromotions(rootGraphId, nodeId)` and returns cached `PromotedWidgetView` objects. No stubs, no Proxies, no fake widgets persisted in the array. The setter is a no-op — mutations go through `promotionStore`. ### PromotedWidgetView A class behind a `createPromotedWidgetView` factory, implementing the `PromotedWidgetView` interface. Delegates value/type/options/drawing to the resolved interior widget and stores. Owns positional state (`y`, `computedHeight`) for canvas layout. Cached by `PromotedWidgetViewManager` for object-identity stability across frames. ### DOM widget promotion Promoted DOM widgets (textarea, image upload, etc.) render on the SubgraphNode surface via `positionOverride` in `domWidgetStore`. `DomWidgets.vue` checks for overrides and uses the SubgraphNode's coordinates instead of the interior node's. ### Promoted previews New `usePromotedPreviews` composable resolves image/audio/video preview widgets from promoted entries, enabling SubgraphNodes to display previews of interior preview nodes. ### Deleted - `proxyWidget.ts` (257 lines) — Proxy handler, `Overlay`, `newProxyWidget`, `isProxyWidget` - `DisconnectedWidget.ts` (39 lines) — Singleton Proxy target - `useValueTransform.ts` (32 lines) — Replaced by store delegation ### Key architectural changes - `BaseWidget.value` getter/setter delegates to `widgetValueStore` when node ID is set - `LGraph.add()` reordered: `node.graph` assigned before widget `setNodeId` (enables store registration) - `LGraph.clear()` cleans up graph-scoped stores to prevent stale entries across workflow switches - `promotionStore` and `widgetValueStore` state nested under root graph UUID for multi-workflow isolation - `SubgraphNode.serialize()` writes promotions back to `properties.proxyWidgets` for persistence compatibility - Legacy `-1` promotion entries resolved and migrated on first load with dev warning ## Test coverage - **3,700+ lines of new/updated tests** across 36 test files - **Unit**: `promotionStore.test.ts`, `widgetValueStore.test.ts`, `promotedWidgetView.test.ts` (921 lines), `subgraphNodePromotion.test.ts`, `proxyWidgetUtils.test.ts`, `DomWidgets.test.ts`, `PromotedWidgetViewManager.test.ts`, `usePromotedPreviews.test.ts`, `resolvePromotedWidget.test.ts`, `subgraphPseudoWidgetCache.test.ts` - **E2E**: `subgraphPromotion.spec.ts` (622 lines) — promote/demote, manual/auto promotion, paste preservation, seed control augmentation, image preview promotion; `imagePreview.spec.ts` extended with multi-promoted-preview coverage - **Fixtures**: 2 new subgraph workflow fixtures for preview promotion scenarios ## Review focus - Graph-scoped store keying (`rootGraphId`) — verify isolation across workflows/tabs and cleanup on `LGraph.clear()` - `PromotedWidgetView` positional stability — `_arrangeWidgets` writes to `y`/`computedHeight` on cached objects; getter returns fresh array but stable object references - DOM widget position override lifecycle — overrides set on promote, cleared on demote/removal/subgraph navigation - Legacy `-1` entry migration — resolved and written back on first load; unresolvable entries dropped with dev warning - Serialization round-trip — `promotionStore` state → `properties.proxyWidgets` on serialize, hydrated back on configure ## Diff breakdown (excluding lockfile) - 153 files changed, ~7,500 insertions, ~1,900 deletions (excluding pnpm-lock.yaml churn) - ~3,700 lines are tests - ~300 lines deleted (proxyWidget.ts, DisconnectedWidget.ts, useValueTransform.ts) <!-- Fixes #ISSUE_NUMBER --> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8856-feat-synthetic-widgets-getter-for-SubgraphNode-proxy-widget-v2-3076d73d365081c7b517f5ec7cb514f3) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: GitHub Action <action@github.com> |