Skip to content

Conversation

@Myestery
Copy link
Contributor

@Myestery Myestery commented Jan 23, 2026

Summary

Reduced unsafe as unknown as type assertions from ~107 to 6 (94% reduction) across 18 test files in graph components and composables.

Changes

  • Created centralized mock utilities in src/utils/__tests__/litegraphTestUtils.ts
    • createMockLGraphNode(), createMockPositionable(), createMockLGraphGroup(), createMockSubgraphNode()
  • Updated 8 test files to use centralized utilities
  • Replaced spread operator with Object.assign to avoid constructor property conflicts
  • Used union types Partial<T> | Record<string, unknown> for flexible mock creation

Remaining Assertions

6 as unknown as assertions remain for incomplete Pinia store mocks where providing complete $state properties is impractical.

Results

  • ✅ 0 typecheck errors (down from 14)
  • ✅ 0 lint errors
  • ✅ 118/118 tests passing in modified files

Files Modified (15)

  • src/components/graph/SelectionToolbox.test.ts
  • src/components/graph/selectionToolbox/{BypassButton,ColorPickerButton,ExecuteButton}.test.ts
  • src/components/sidebar/tabs/queue/ResultGallery.test.ts
  • src/composables/canvas/useSelectedLiteGraphItems.test.ts
  • src/composables/graph/{useGraphHierarchy,useSelectionState}.test.ts
  • src/composables/maskeditor/{useCanvasHistory,useCanvasManager,useCanvasTransform}.test.ts
  • src/composables/node/{useNodePricing,useWatchWidget}.test.ts
  • src/composables/useCoreCommands.test.ts
  • src/utils/__tests__/litegraphTestUtils.ts (new)

┆Issue is synchronized with this Notion page by Unito

Reduced 'as unknown as' instances from ~107 to 6 (94% reduction) across 18 test files in graph components and composables.

Created centralized mock utilities:
- src/utils/__tests__/litegraphTestUtils.ts with 7 factory functions
- createMockLGraphNode(), createMockPositionable(), createMockLGraphGroup()
- createMockSubgraphNode(), createMockCanvas(), createMockLGraphCanvas()
- createPiniaStoreProps() for consistent store mocking

Type safety improvements:
- Object.assign pattern to avoid constructor conflicts
- Union types (Partial<T> | Record<string, unknown>) for flexible mocking
- 8 test files now use centralized utilities

Remaining 6 'as unknown as' assertions are required for incomplete Pinia store mocks where providing complete $state properties is impractical.

Results:
- ✅ 0 typecheck errors (down from 14)
- ✅ 0 lint errors
- ✅ 118/118 tests passing

Files modified:
- src/components/graph/SelectionToolbox.test.ts
- src/components/graph/selectionToolbox/BypassButton.test.ts
- src/components/graph/selectionToolbox/ColorPickerButton.test.ts
- src/components/graph/selectionToolbox/ExecuteButton.test.ts
- src/components/sidebar/tabs/queue/ResultGallery.test.ts
- src/composables/canvas/useSelectedLiteGraphItems.test.ts
- src/composables/graph/useGraphHierarchy.test.ts
- src/composables/graph/useSelectionState.test.ts
- src/composables/maskeditor/useCanvasHistory.test.ts
- src/composables/maskeditor/useCanvasManager.test.ts
- src/composables/maskeditor/useCanvasTransform.test.ts
- src/composables/node/useNodePricing.test.ts
- src/composables/node/useWatchWidget.test.ts
- src/composables/useCoreCommands.test.ts

New file:
- src/utils/__tests__/litegraphTestUtils.ts
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Jan 23, 2026
@github-actions
Copy link

github-actions bot commented Jan 23, 2026

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 01/23/2026, 02:47:50 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Jan 23, 2026

🎭 Playwright Tests: ⚠️ Passed with flaky tests

Results: 505 passed, 0 failed, 1 flaky, 8 skipped (Total: 514)

❌ Failed Tests

📊 Browser Reports
  • chromium: View Report (✅ 495 / ❌ 0 / ⚠️ 0 / ⏭️ 8)
  • chromium-2x: View Report (✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • chromium-0.5x: View Report (✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • mobile-chrome: View Report (✅ 7 / ❌ 0 / ⚠️ 1 / ⏭️ 0)

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

Refactors tests and adds centralized litegraph test utilities; tightens and standardizes mock typings across many test suites; updates several test-only mocks to concrete signatures; refactors useChainCallback generic typing and adjusts widgetInputs typings/signature usage.

Changes

Cohort / File(s) Summary
LiteGraph test utilities
src/utils/__tests__/litegraphTestUtils.ts
Added factory helpers: createMockLGraphNode, createMockPositionable, createMockLGraphGroup, createMockSubgraphNode.
Selection toolbox tests
src/components/graph/SelectionToolbox.test.ts, src/components/graph/selectionToolbox/BypassButton.test.ts, src/components/graph/selectionToolbox/ColorPickerButton.test.ts, src/components/graph/selectionToolbox/ExecuteButton.test.ts
Replaced inline node/positionable mocks with factory helpers; introduced stronger typed mocks (MockCanvas, MockCanvasStore, MockCommandStore) and expanded mocked store shapes.
Gallery / thumbnail tests
src/components/sidebar/tabs/queue/ResultGallery.test.ts, src/components/templates/thumbnails/BaseThumbnail.test.ts
Tightened component instance typings and prop/pt casts to avoid any usage.
Canvas & selection composables tests
src/composables/canvas/useSelectedLiteGraphItems.test.ts, src/composables/graph/useGraphHierarchy.test.ts, src/composables/graph/useSelectionState.test.ts
Replaced ad-hoc nodes/groups with factory helpers and Rectangle-based boundingRects; returned mocked stores cast to proper ReturnType<...>.
Mask editor tests
src/composables/maskeditor/* (useCanvasHistory.test.ts, useCanvasManager.test.ts, useCanvasTools.test.ts, useCanvasTransform.test.ts, useImageLoader.test.ts)
Replaced permissive casts with direct global types and Partial-based typed stubs for canvases/contexts; tightened test mock shapes.
Node / widget tests
src/composables/node/useNodePricing.test.ts, src/composables/node/useWatchWidget.test.ts
Replaced inline mock node shapes with createMockLGraphNode/createMockNode helpers; tightened widget callback typings and guards.
Queue & utilities tests
src/composables/queue/useJobMenu.test.ts, src/composables/useCachedRequest.test.ts, src/composables/useBrowserTabTitle.test.ts
Reworked external mocks to explicit signatures (downloadFile, copyToClipboard, mapTaskOutputToAssetItem, interrupt, deleteItem, downloadBlob, getJobWorkflow, createAnnotatedPath); tightened mock store typings.
Core commands tests
src/composables/useCoreCommands.test.ts
Added createMockNode and createMockSubgraph test helpers; expanded mocked store shapes and replaced inline subgraph literals.
Composable refactor
src/composables/functional/useChainCallback.ts
Removed exported CallbackParams alias; generalized useChainCallback generics and improved runtime checks/casts for chained callbacks.
Extension typing update
src/extensions/core/widgetInputs.ts
Removed CallbackParams usage; changed PrimitiveNode.controlValues type to TWidgetValue[]; updated onInputDblClick override parameter typing.

Possibly related PRs

Suggested reviewers

  • DrJKL
  • shinshin86
  • KarryCharon
  • christian-byrne
  • comfyui-wiki
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

Bundle Size Report

Summary

  • Raw size: 21.8 MB baseline 21.8 MB — 🟢 -156 B
  • Gzip: 4.53 MB baseline 4.53 MB — 🟢 -24 B
  • Brotli: 3.36 MB baseline 3.36 MB — 🔴 +283 B
  • Bundles: 166 current • 166 baseline • 76 added / 76 removed

Category Glance
Other 🟢 -192 B (6.36 MB) · Data & Services 🔴 +44 B (3.17 MB) · Panels & Settings 🟢 -8 B (440 kB) · Vendor & Third-Party ⚪ 0 B (10.7 MB) · Graph Workspace ⚪ 0 B (949 kB) · Views & Navigation ⚪ 0 B (80.7 kB) · + 5 more

Per-category breakdown
App Entry Points — 22.7 kB (baseline 22.7 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-BJ66WPRR.js (removed) 22.7 kB 🟢 -22.7 kB 🟢 -6.83 kB 🟢 -6.01 kB
assets/index-mKa1rAdC.js (new) 22.7 kB 🔴 +22.7 kB 🔴 +6.82 kB 🔴 +6 kB

Status: 1 added / 1 removed

Graph Workspace — 949 kB (baseline 949 kB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-CBwKGRFm.js (removed) 949 kB 🟢 -949 kB 🟢 -191 kB 🟢 -145 kB
assets/GraphView-COzcNQBL.js (new) 949 kB 🔴 +949 kB 🔴 +191 kB 🔴 +145 kB

Status: 1 added / 1 removed

Views & Navigation — 80.7 kB (baseline 80.7 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-BcmybtYu.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -3.61 kB 🟢 -3.05 kB
assets/CloudSurveyView-P2Eo5Iem.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +3.6 kB 🔴 +3.05 kB
assets/CloudLoginView--Fiqbcvf.js (removed) 11.8 kB 🟢 -11.8 kB 🟢 -3.09 kB 🟢 -2.72 kB
assets/CloudLoginView-BWBK1diZ.js (new) 11.8 kB 🔴 +11.8 kB 🔴 +3.09 kB 🔴 +2.72 kB
assets/UserCheckView-CJUJn8sC.js (new) 10.5 kB 🔴 +10.5 kB 🔴 +2.45 kB 🔴 +2.13 kB
assets/UserCheckView-vcFc4OPn.js (removed) 10.5 kB 🟢 -10.5 kB 🟢 -2.45 kB 🟢 -2.13 kB
assets/CloudLayoutView-BWTZC3a2.js (new) 8.54 kB 🔴 +8.54 kB 🔴 +2.25 kB 🔴 +1.96 kB
assets/CloudLayoutView-CLHVF8XM.js (removed) 8.54 kB 🟢 -8.54 kB 🟢 -2.25 kB 🟢 -1.96 kB
assets/CloudSignupView-B3SM114w.js (new) 8.18 kB 🔴 +8.18 kB 🔴 +2.33 kB 🔴 +2.02 kB
assets/CloudSignupView-DGblAAIG.js (removed) 8.18 kB 🟢 -8.18 kB 🟢 -2.33 kB 🟢 -2.03 kB
assets/CloudForgotPasswordView-D68i92UJ.js (new) 6.26 kB 🔴 +6.26 kB 🔴 +1.92 kB 🔴 +1.69 kB
assets/CloudForgotPasswordView-lVQlmApt.js (removed) 6.26 kB 🟢 -6.26 kB 🟢 -1.92 kB 🟢 -1.69 kB
assets/UserSelectView-BcksWDGY.js (removed) 5.28 kB 🟢 -5.28 kB 🟢 -1.76 kB 🟢 -1.58 kB
assets/UserSelectView-m-19EOY7.js (new) 5.28 kB 🔴 +5.28 kB 🔴 +1.76 kB 🔴 +1.57 kB
assets/CloudSubscriptionRedirectView-D3T87fyS.js (new) 5.27 kB 🔴 +5.27 kB 🔴 +1.73 kB 🔴 +1.55 kB
assets/CloudSubscriptionRedirectView-DS3onApH.js (removed) 5.27 kB 🟢 -5.27 kB 🟢 -1.73 kB 🟢 -1.55 kB
assets/CloudAuthTimeoutView-BPnv_Y5P.js (removed) 5.24 kB 🟢 -5.24 kB 🟢 -1.7 kB 🟢 -1.48 kB
assets/CloudAuthTimeoutView-DLGJsh4F.js (new) 5.24 kB 🔴 +5.24 kB 🔴 +1.7 kB 🔴 +1.48 kB
assets/CloudSorryContactSupportView-CIWojqyX.js 1.97 kB 1.97 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/layout-DQZzOBYR.js 500 B 500 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 9 added / 9 removed

Panels & Settings — 440 kB (baseline 440 kB) • 🟢 -8 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/LegacyCreditsPanel-Dq-ZXOAc.js (new) 23.8 kB 🔴 +23.8 kB 🔴 +5.94 kB 🔴 +5.23 kB
assets/LegacyCreditsPanel-TMcA8dP5.js (removed) 23.8 kB 🟢 -23.8 kB 🟢 -5.94 kB 🟢 -5.23 kB
assets/SubscriptionPanel-B51TZeu4.js (new) 20.9 kB 🔴 +20.9 kB 🔴 +5.01 kB 🔴 +4.42 kB
assets/SubscriptionPanel-BuGjYH57.js (removed) 20.9 kB 🟢 -20.9 kB 🟢 -5 kB 🟢 -4.41 kB
assets/KeybindingPanel-Cj8vBE00.js (removed) 14.2 kB 🟢 -14.2 kB 🟢 -3.73 kB 🟢 -3.31 kB
assets/KeybindingPanel-DD8QnlRq.js (new) 14.2 kB 🔴 +14.2 kB 🔴 +3.73 kB 🔴 +3.31 kB
assets/AboutPanel-Beov6Lma.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.68 kB 🟢 -2.44 kB
assets/AboutPanel-juh1sXRF.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.68 kB 🔴 +2.44 kB
assets/ExtensionPanel-BhqJpwQ9.js (removed) 10.2 kB 🟢 -10.2 kB 🟢 -2.71 kB 🟢 -2.4 kB
assets/ExtensionPanel-mJ2Gaqt2.js (new) 10.2 kB 🔴 +10.2 kB 🔴 +2.71 kB 🔴 +2.4 kB
assets/WorkspacePanel-aJ3MUYw1.js (removed) 8.17 kB 🟢 -8.17 kB 🟢 -2.3 kB 🟢 -2.08 kB
assets/WorkspacePanel-XOw9SuvE.js (new) 8.17 kB 🔴 +8.17 kB 🔴 +2.31 kB 🔴 +2.08 kB
assets/ServerConfigPanel-C_YEhJTQ.js (removed) 7.23 kB 🟢 -7.23 kB 🟢 -2.16 kB 🟢 -1.94 kB
assets/ServerConfigPanel-CQFhzsiT.js (new) 7.23 kB 🔴 +7.23 kB 🔴 +2.17 kB 🔴 +1.94 kB
assets/UserPanel-0XP-BkyN.js (removed) 6.58 kB 🟢 -6.58 kB 🟢 -1.9 kB 🟢 -1.68 kB
assets/UserPanel-BmKjx2Xg.js (new) 6.58 kB 🔴 +6.58 kB 🔴 +1.9 kB 🔴 +1.67 kB
assets/cloudRemoteConfig-BIboSwEU.js (new) 1.82 kB 🔴 +1.82 kB 🔴 +771 B 🔴 +657 B
assets/cloudRemoteConfig-Djj-iJ6A.js (removed) 1.82 kB 🟢 -1.82 kB 🟢 -770 B 🟢 -658 B
assets/config-DLvQ8pCd.js (removed) 1.16 kB 🟢 -1.16 kB 🟢 -611 B 🟢 -535 B
assets/config-C5Ry9-s1.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +604 B 🔴 +525 B
assets/remoteConfig-CZVd5eda.js 188 B 188 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/remoteConfig-maWXk_kA.js 1.07 kB 1.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-_w0F8Os2.js 30.4 kB 30.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BcyB3JCe.js 28.9 kB 28.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BhNjTsTR.js 29.6 kB 29.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Bv3zi5bR.js 34.3 kB 34.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BXVr0R9W.js 38.3 kB 38.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Ca_EqdTH.js 31.2 kB 31.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Ccc7OH1N.js 28.6 kB 28.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CheSGCN4.js 32.1 kB 32.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CY-0EA4m.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Dkz0uATE.js 29.5 kB 29.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DNMBWO2D.js 25.9 kB 25.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 10 added / 10 removed

User & Accounts — 3.94 kB (baseline 3.94 kB) • ⚪ 0 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-BD0w3FUx.js (removed) 3.54 kB 🟢 -3.54 kB 🟢 -1.24 kB 🟢 -1.06 kB
assets/auth-BHHjvPf2.js (new) 3.54 kB 🔴 +3.54 kB 🔴 +1.24 kB 🔴 +1.06 kB
assets/firebaseAuthStore-de4MDfcG.js (removed) 217 B 🟢 -217 B 🟢 -136 B 🟢 -115 B
assets/firebaseAuthStore-gav0c1_r.js (new) 217 B 🔴 +217 B 🔴 +136 B 🔴 +119 B
assets/auth-CMEVDbrz.js (new) 178 B 🔴 +178 B 🔴 +142 B 🔴 +137 B
assets/auth-VCPDhIZw.js (removed) 178 B 🟢 -178 B 🟢 -142 B 🟢 -143 B

Status: 3 added / 3 removed

Editors & Dialogs — 2.83 kB (baseline 2.83 kB) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useSubscriptionDialog-BY1eMF2b.js (removed) 2.65 kB 🟢 -2.65 kB 🟢 -1.25 kB 🟢 -1.1 kB
assets/useSubscriptionDialog-CmZHqnOR.js (new) 2.65 kB 🔴 +2.65 kB 🔴 +1.25 kB 🔴 +1.1 kB
assets/useSubscriptionDialog-BuB_1UF8.js (removed) 179 B 🟢 -179 B 🟢 -110 B 🟢 -102 B
assets/useSubscriptionDialog-DUzrxjk8.js (new) 179 B 🔴 +179 B 🔴 +110 B 🔴 +108 B

Status: 2 added / 2 removed

UI Components — 33.7 kB (baseline 33.7 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-BNw9cXhR.js (new) 9.52 kB 🔴 +9.52 kB 🔴 +2.69 kB 🔴 +2.41 kB
assets/ComfyQueueButton-C2kz1ke2.js (removed) 9.52 kB 🟢 -9.52 kB 🟢 -2.68 kB 🟢 -2.41 kB
assets/SubscribeButton-BAi7uZjq.js (removed) 4.63 kB 🟢 -4.63 kB 🟢 -1.57 kB 🟢 -1.39 kB
assets/SubscribeButton-Bs0WAjSW.js (new) 4.63 kB 🔴 +4.63 kB 🔴 +1.57 kB 🔴 +1.39 kB
assets/CloudBadge-9J6jsiXi.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +724 B 🔴 +641 B
assets/CloudBadge-B2I_t3N8.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -724 B 🟢 -645 B
assets/cloudFeedbackTopbarButton-CiJ0qFDK.js (removed) 1.24 kB 🟢 -1.24 kB 🟢 -677 B 🟢 -577 B
assets/cloudFeedbackTopbarButton-Dl3RtxKy.js (new) 1.24 kB 🔴 +1.24 kB 🔴 +676 B 🔴 +577 B
assets/ComfyQueueButton-Bagux8Vi.js (removed) 181 B 🟢 -181 B 🟢 -118 B 🟢 -105 B
assets/ComfyQueueButton-DuIaIUId.js (new) 181 B 🔴 +181 B 🔴 +118 B 🔴 +123 B
assets/Button-CBiuMrWI.js 3.77 kB 3.77 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/TopbarBadge-CIuqyTWW.js 8.36 kB 8.36 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserAvatar-BvUzYvJd.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-DzXs11SA.js 2.41 kB 2.41 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 5 added / 5 removed

Data & Services — 3.17 MB (baseline 3.17 MB) • 🔴 +44 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-Bguhebbe.js (new) 1.99 MB 🔴 +1.99 MB 🔴 +420 kB 🔴 +321 kB
assets/dialogService-C1iTs-r8.js (removed) 1.99 MB 🟢 -1.99 MB 🟢 -420 kB 🟢 -320 kB
assets/api-DSYJAFuR.js (new) 1.16 MB 🔴 +1.16 MB 🔴 +241 kB 🔴 +187 kB
assets/api-B3CMyGDN.js (removed) 1.16 MB 🟢 -1.16 MB 🟢 -241 kB 🟢 -187 kB
assets/releaseStore-CMtlAR7_.js (new) 8.91 kB 🔴 +8.91 kB 🔴 +2.4 kB 🔴 +2.12 kB
assets/releaseStore-D7aLZ4ic.js (removed) 8.91 kB 🟢 -8.91 kB 🟢 -2.4 kB 🟢 -2.12 kB
assets/keybindingService-BT-MlxSy.js (removed) 6.78 kB 🟢 -6.78 kB 🟢 -1.74 kB 🟢 -1.52 kB
assets/keybindingService-DPc4vF2c.js (new) 6.78 kB 🔴 +6.78 kB 🔴 +1.74 kB 🔴 +1.51 kB
assets/userStore-B1AcpVzO.js (removed) 2.16 kB 🟢 -2.16 kB 🟢 -814 B 🟢 -725 B
assets/userStore-g7g6DrpL.js (new) 2.16 kB 🔴 +2.16 kB 🔴 +813 B 🔴 +726 B
assets/audioService-kWjm5Zma.js (removed) 2.03 kB 🟢 -2.03 kB 🟢 -933 B 🟢 -820 B
assets/audioService-S7D1r-GZ.js (new) 2.03 kB 🔴 +2.03 kB 🔴 +933 B 🔴 +821 B
assets/teamWorkspaceStore-BZW_7xdm.js (removed) 165 B 🟢 -165 B 🟢 -123 B 🟢 -111 B
assets/teamWorkspaceStore-CW99vaLS.js (new) 165 B 🔴 +165 B 🔴 +123 B 🔴 +109 B
assets/releaseStore-Duz28Whq.js (new) 140 B 🔴 +140 B 🔴 +106 B 🔴 +103 B
assets/releaseStore-qz4rU9q5.js (removed) 140 B 🟢 -140 B 🟢 -106 B 🟢 -108 B
assets/serverConfigStore-D6BZBqR8.js 2.64 kB 2.64 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 8 added / 8 removed

Utilities & Hooks — 24 kB (baseline 24 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useErrorHandling-bP9VxRSG.js (removed) 5.08 kB 🟢 -5.08 kB 🟢 -1.5 kB 🟢 -1.31 kB
assets/useErrorHandling-nj5vbo2X.js (new) 5.08 kB 🔴 +5.08 kB 🔴 +1.5 kB 🔴 +1.31 kB
assets/useWorkspaceUI-B4R9p_pb.js (removed) 2.25 kB 🟢 -2.25 kB 🟢 -756 B 🟢 -666 B
assets/useWorkspaceUI-BnbtxJ1r.js (new) 2.25 kB 🔴 +2.25 kB 🔴 +756 B 🔴 +663 B
assets/useSubscriptionActions-8Radu3Ud.js (removed) 2.22 kB 🟢 -2.22 kB 🟢 -867 B 🟢 -759 B
assets/useSubscriptionActions-DlSXTDYz.js (new) 2.22 kB 🔴 +2.22 kB 🔴 +866 B 🔴 +766 B
assets/subscriptionCheckoutUtil-DvbF2kc-.js (removed) 1.98 kB 🟢 -1.98 kB 🟢 -860 B 🟢 -745 B
assets/subscriptionCheckoutUtil-VEO3CoJM.js (new) 1.98 kB 🔴 +1.98 kB 🔴 +862 B 🔴 +746 B
assets/useSubscriptionCredits-BgcHwXj-.js (removed) 1.39 kB 🟢 -1.39 kB 🟢 -596 B 🟢 -526 B
assets/useSubscriptionCredits-CE4g2Ff0.js (new) 1.39 kB 🔴 +1.39 kB 🔴 +596 B 🔴 +526 B
assets/audioUtils-B6jRp0uc.js (removed) 970 B 🟢 -970 B 🟢 -543 B 🟢 -455 B
assets/audioUtils-CYRd--ns.js (new) 970 B 🔴 +970 B 🔴 +545 B 🔴 +456 B
assets/useCurrentUser-BIjt4gWE.js (new) 145 B 🔴 +145 B 🔴 +114 B 🔴 +102 B
assets/useCurrentUser-BQAozLuE.js (removed) 145 B 🟢 -145 B 🟢 -114 B 🟢 -105 B
assets/_plugin-vue_export-helper-Dt9-hEHc.js 467 B 467 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/colorUtil-CWN_VD-w.js 7.2 kB 7.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/markdownRendererUtil-BH-xeUTY.js 1.78 kB 1.78 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/tailwindUtil-CuQ_kVBG.js 488 B 488 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 7 added / 7 removed

Vendor & Third-Party — 10.7 MB (baseline 10.7 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-chart-CzCG8jcG.js 408 kB 408 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-CCO1nq9Q.js 4.1 MB 4.1 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-D9jS_6ky.js 3.04 MB 3.04 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-reka-ui-C7fVHAth.js 256 kB 256 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-BKj_AHFn.js 1.83 MB 1.83 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-CLU9nzy5.js 650 kB 650 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-DhS5MB4h.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-AIoMGdmt.js 398 kB 398 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 6.36 MB (baseline 6.36 MB) • 🟢 -192 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-0wIUO4a0.js (removed) 178 kB 🟢 -178 kB 🟢 -43 kB 🟢 -35.9 kB
assets/core-DGwgZVTY.js (new) 178 kB 🔴 +178 kB 🔴 +42.9 kB 🔴 +35.9 kB
assets/Load3D-C3eZEtp5.js (new) 55.7 kB 🔴 +55.7 kB 🔴 +9.18 kB 🔴 +7.93 kB
assets/Load3D-DOlgF6u6.js (removed) 55.7 kB 🟢 -55.7 kB 🟢 -9.18 kB 🟢 -7.92 kB
assets/WidgetSelect-DadMjkTO.js (new) 50.5 kB 🔴 +50.5 kB 🔴 +11.1 kB 🔴 +9.72 kB
assets/WidgetSelect-DO5MYzzw.js (removed) 50.5 kB 🟢 -50.5 kB 🟢 -11.1 kB 🟢 -9.7 kB
assets/SubscriptionRequiredDialogContent-CAkStVaJ.js (new) 28.7 kB 🔴 +28.7 kB 🔴 +6.78 kB 🔴 +5.9 kB
assets/SubscriptionRequiredDialogContent-pljKLoF2.js (removed) 28.7 kB 🟢 -28.7 kB 🟢 -6.78 kB 🟢 -5.91 kB
assets/CurrentUserPopoverWorkspace-B_3uMYpT.js (new) 21.6 kB 🔴 +21.6 kB 🔴 +4.84 kB 🔴 +4.3 kB
assets/CurrentUserPopoverWorkspace-BK41WyG2.js (removed) 21.6 kB 🟢 -21.6 kB 🟢 -4.84 kB 🟢 -4.3 kB
assets/WidgetInputNumber-COhkl_uQ.js (new) 18.3 kB 🔴 +18.3 kB 🔴 +4.51 kB 🔴 +4.01 kB
assets/WidgetInputNumber-DQbwxQnC.js (removed) 18.3 kB 🟢 -18.3 kB 🟢 -4.51 kB 🟢 -4.01 kB
assets/WidgetRecordAudio-CXCUNEd8.js (removed) 18.2 kB 🟢 -18.2 kB 🟢 -4.96 kB 🟢 -4.44 kB
assets/WidgetRecordAudio-DEE1yORu.js (new) 18.2 kB 🔴 +18.2 kB 🔴 +4.96 kB 🔴 +4.43 kB
assets/SubscriptionPanelContentWorkspace-CfQFnXza.js (removed) 17.7 kB 🟢 -17.7 kB 🟢 -4.34 kB 🟢 -3.78 kB
assets/SubscriptionPanelContentWorkspace-CFS7Y6hR.js (new) 17.7 kB 🔴 +17.7 kB 🔴 +4.34 kB 🔴 +3.78 kB
assets/WidgetImageCrop-DOkX1AQk.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +4.14 kB 🔴 +3.62 kB
assets/WidgetImageCrop-DYy2Ls4B.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -4.14 kB 🟢 -3.63 kB
assets/PanelTemplate-BcbEAJAA.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -5.45 kB 🟢 -4.79 kB
assets/PanelTemplate-CfM-FkLT.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +5.45 kB 🔴 +4.79 kB
assets/AudioPreviewPlayer-Dc8ftrkg.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.97 kB 🟢 -2.65 kB
assets/AudioPreviewPlayer-YOKBBRN0.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.97 kB 🔴 +2.65 kB
assets/WidgetWithControl-Bm7YpihG.js (removed) 8.02 kB 🟢 -8.02 kB 🟢 -2.65 kB 🟢 -2.38 kB
assets/WidgetWithControl-Dc2mgjug.js (new) 8.02 kB 🔴 +8.02 kB 🔴 +2.65 kB 🔴 +2.38 kB
assets/CreateWorkspaceDialogContent-DItX9OPr.js (new) 5.92 kB 🔴 +5.92 kB 🔴 +1.92 kB 🔴 +1.67 kB
assets/CreateWorkspaceDialogContent-xd5PtuRu.js (removed) 5.92 kB 🟢 -5.92 kB 🟢 -1.92 kB 🟢 -1.67 kB
assets/EditWorkspaceDialogContent-ajWe7DHx.js (removed) 5.69 kB 🟢 -5.69 kB 🟢 -1.87 kB 🟢 -1.63 kB
assets/EditWorkspaceDialogContent-BNkbGHU5.js (new) 5.69 kB 🔴 +5.69 kB 🔴 +1.87 kB 🔴 +1.64 kB
assets/ValueControlPopover-bxxYq-BA.js (removed) 4.86 kB 🟢 -4.86 kB 🟢 -1.54 kB 🟢 -1.38 kB
assets/ValueControlPopover-CfJUXIom.js (new) 4.86 kB 🔴 +4.86 kB 🔴 +1.54 kB 🔴 +1.37 kB
assets/DeleteWorkspaceDialogContent-BsuIg26y.js (new) 4.59 kB 🔴 +4.59 kB 🔴 +1.56 kB 🔴 +1.35 kB
assets/DeleteWorkspaceDialogContent-CQTAq8uJ.js (removed) 4.59 kB 🟢 -4.59 kB 🟢 -1.56 kB 🟢 -1.35 kB
assets/LeaveWorkspaceDialogContent-D6TIFTNP.js (removed) 4.41 kB 🟢 -4.41 kB 🟢 -1.5 kB 🟢 -1.3 kB
assets/LeaveWorkspaceDialogContent-r6cndUam.js (new) 4.41 kB 🔴 +4.41 kB 🔴 +1.5 kB 🔴 +1.31 kB
assets/GlobalToast-B8Bt6O_J.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.1 kB 🔴 +941 B
assets/GlobalToast-CNCe8Odb.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.1 kB 🟢 -942 B
assets/SubscribeToRun-Ck1GyVix.js (removed) 2.96 kB 🟢 -2.96 kB 🟢 -1.15 kB 🟢 -1.01 kB
assets/SubscribeToRun-DvqgzcLe.js (new) 2.96 kB 🔴 +2.96 kB 🔴 +1.15 kB 🔴 +1.01 kB
assets/cloudSessionCookie-Fh9Coo6j.js (removed) 2.94 kB 🟢 -2.94 kB 🟢 -934 B 🟢 -800 B
assets/cloudSessionCookie-IEnX3uat.js (new) 2.94 kB 🔴 +2.94 kB 🔴 +933 B 🔴 +803 B
assets/BaseViewTemplate-CBLR9Rin.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.04 kB 🟢 -945 B
assets/BaseViewTemplate-DR6OkPpZ.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.05 kB 🔴 +943 B
assets/CloudRunButtonWrapper-dQ5MxDGL.js (removed) 1.79 kB 🟢 -1.79 kB 🟢 -641 B 🟢 -561 B
assets/CloudRunButtonWrapper-DVHx2fF5.js (new) 1.79 kB 🔴 +1.79 kB 🔴 +641 B 🔴 +560 B
assets/cloudBadges-DdJngFNF.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -538 B 🟢 -480 B
assets/cloudBadges-DK7Z0LxK.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +538 B 🔴 +478 B
assets/graphHasMissingNodes-DeNnczmy.js (new) 1.06 kB 🔴 +1.06 kB 🔴 +460 B 🔴 +428 B
assets/graphHasMissingNodes-DtMf8pAy.js (removed) 1.06 kB 🟢 -1.06 kB 🟢 -460 B 🟢 -429 B
assets/cloudSubscription-BKT3cAnU.js (removed) 976 B 🟢 -976 B 🟢 -461 B 🟢 -401 B
assets/cloudSubscription-Dgzrs4aX.js (new) 976 B 🔴 +976 B 🔴 +459 B 🔴 +401 B
assets/nightlyBadges-ChiQ042D.js (new) 594 B 🔴 +594 B 🔴 +357 B 🔴 +312 B
assets/nightlyBadges-CL8xLQWh.js (removed) 594 B 🟢 -594 B 🟢 -356 B 🟢 -311 B
assets/SubscriptionPanelContentWorkspace-C46lVwVP.js (new) 266 B 🔴 +266 B 🔴 +136 B 🔴 +127 B
assets/SubscriptionPanelContentWorkspace-COm-rB1d.js (removed) 266 B 🟢 -266 B 🟢 -136 B 🟢 -112 B
assets/WidgetInputNumber-lNMwvwR8.js (removed) 186 B 🟢 -186 B 🟢 -119 B 🟢 -122 B
assets/WidgetInputNumber-TJuRcpib.js (new) 186 B 🔴 +186 B 🔴 +119 B 🔴 +120 B
assets/WidgetLegacy-DBsCLyaX.js (removed) 164 B 🟢 -164 B 🟢 -125 B 🟢 -111 B
assets/WidgetLegacy-ODX5faPk.js (new) 164 B 🔴 +164 B 🔴 +125 B 🔴 +111 B
assets/Load3D-Bzb8UX4v.js (new) 131 B 🔴 +131 B 🔴 +107 B 🔴 +122 B
assets/Load3D-CFnST8Kk.js (removed) 131 B 🟢 -131 B 🟢 -107 B 🟢 -108 B
assets/auto-C-D16_U1.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-4PR1bHpF.js 18.5 kB 18.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-B2EAJ50e.js 17.2 kB 17.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-B2K4kJ7I.js 17.9 kB 17.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-B8DPxzq3.js 19.3 kB 19.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BeMMi6hO.js 18 kB 18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BFBrL4wa.js 17 kB 17 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CDiUUOet.js 19.3 kB 19.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CVY7Ty6w.js 18.8 kB 18.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DFPZ6_-M.js 20.6 kB 20.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Ds2wjN52.js 17.8 kB 17.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Ep6sQmXs.js 18 kB 18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/LazyImage-D6PpiUVK.js 14.1 kB 14.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BhEFmLQr.js 143 kB 143 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BJmSXHk5.js 136 kB 136 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BwdWUSzx.js 119 kB 119 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-C1TIlcBD.js 126 kB 126 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-C8G9GjDN.js 123 kB 123 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cmx0L4BY.js 147 kB 147 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CNZb5sh8.js 107 kB 107 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cp7Xi9AK.js 106 kB 106 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-jf-B109s.js 121 kB 121 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-mcBLF1lP.js 119 kB 119 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-utjp9h7e.js 164 kB 164 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Media3DTop-CSW_ENx8.js 2.38 kB 2.38 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-DvEvCs7d.js 2 kB 2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-BqI9AZuA.js 2.34 kB 2.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-gfxHG4G4.js 2.84 kB 2.84 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/mixpanel.module-DKpe8oFs.js 143 B 143 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-_yIUj67D.js 374 kB 374 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BF6TtCbU.js 365 kB 365 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BlOB_fqn.js 355 kB 355 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BQZ8zPIN.js 358 kB 358 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BrvlAvf6.js 437 kB 437 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CbhW6UrA.js 332 kB 332 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CK5btlaD.js 361 kB 361 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-D8jcNSNH.js 334 kB 334 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DdZJ1mp4.js 403 kB 403 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DZm7fb-y.js 361 kB 361 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-y33GjNKL.js 403 kB 403 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/preservedQueryNamespaces-zCg1CMIu.js 3.23 kB 3.23 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/previousFullPath-DhQpJZe1.js 838 B 838 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/rolldown-runtime-cVp-94Rc.js 1.96 kB 1.96 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Slider-BoORvfqb.js 4.21 kB 4.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widget-C_FImE7Q.js 518 B 518 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-DacGBD5y.js 4.71 kB 4.71 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-XFIqgKWC.js 186 B 186 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-JRS-Yy_C.js 2.79 kB 2.79 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetColorPicker-BaHD90N-.js 3.71 kB 3.71 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetGalleria-CroZXP26.js 4.57 kB 4.57 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-BWtVkybW.js 3.79 kB 3.79 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetInputText-BEqVMoBy.js 2.58 kB 2.58 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLayoutField-B82nEQwY.js 2.61 kB 2.61 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetMarkdown-B3dZxgK8.js 3.22 kB 3.22 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BmJCg-u2.js 1.31 kB 1.31 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetTextarea-DZBuNrhg.js 3.52 kB 3.52 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetToggleSwitch-CJnK-DG-.js 3.08 kB 3.08 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 30 added / 30 removed

@github-actions
Copy link

🔧 Auto-fixes Applied

This PR has been automatically updated to fix linting and formatting issues.

⚠️ Important: Your local branch is now behind. Run git pull before making additional changes to avoid conflicts.

Changes made:

  • ESLint auto-fixes
  • Oxfmt formatting

@Myestery
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 23, 2026

✅ Actions performed

Full review triggered.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/composables/graph/useSelectionState.test.ts (1)

91-160: Replace as unknown as with explicit Partial<T> as T casts in store mocks.

All four store mocks in this block use as unknown as ReturnType<...> which obscures their partial nature. Use Partial<ReturnType<...>> as ReturnType<...> instead to make the incomplete implementation explicit while maintaining type safety.

♻️ Suggested update (pattern)
-    } as unknown as ReturnType<typeof useCanvasStore>)
+    } as Partial<ReturnType<typeof useCanvasStore>> as ReturnType<
+      typeof useCanvasStore
+    >)

Apply the same change to the useNodeDefStore, useSidebarTabStore, and useNodeHelpStore mocks on lines 123, 139, and 160.

src/composables/queue/useJobMenu.test.ts (1)

146-162: Use Partial<TaskItemImpl> for MockTaskRef to make incomplete mock implementation explicit.

Record<string, unknown> obscures the actual type contract. Since TaskItemImpl is imported and available, using Partial<TaskItemImpl> with the double-cast pattern (as Partial<TaskItemImpl> as TaskItemImpl | undefined) explicitly acknowledges the mock's incomplete implementation while maintaining type safety, consistent with test-file typing guidance.

♻️ Suggested refactor
-type MockTaskRef = Record<string, unknown>
+type MockTaskRef = Partial<TaskItemImpl>
@@
-  taskRef: overrides.taskRef as TaskItemImpl | undefined,
+  taskRef: overrides.taskRef as Partial<TaskItemImpl> as TaskItemImpl | undefined,
🤖 Fix all issues with AI agents
In `@src/components/graph/SelectionToolbox.test.ts`:
- Around line 14-21: The test helper createMockCanvas currently casts to the
invalid type useCanvasStore.prototype.canvas (pinia composables have no
prototype); fix by removing that incorrect prototype reference and cast to a
real type or no type: either omit the annotation entirely, or import/use the
proper type like ReturnType<typeof useCanvasStore>['canvas'] (or the explicit
Canvas type if exported) and cast the returned object to that type; update
createMockCanvas to use the correct type reference (or no annotation) so the
mock's type is valid.
- Around line 23-31: The mock in createMockExtensionService implements only part
of the useExtensionService return shape; change its cast to make that explicit
by casting the object as Partial<ReturnType<typeof useExtensionService>> and
then as ReturnType<typeof useExtensionService> (i.e., use "as
Partial<ReturnType<typeof useExtensionService>> as ReturnType<typeof
useExtensionService>") so the incomplete mock is explicit while preserving the
original expected type; update the return statement in
createMockExtensionService accordingly.

In `@src/components/graph/selectionToolbox/BypassButton.test.ts`:
- Line 15: The test defines mockLGraphNode at module scope using
createMockLGraphNode which can leak state between tests; change to generate a
fresh mock per test by either moving the call into a beforeEach or introduce a
factory function (e.g., getMockLGraphNode) and call getMockLGraphNode() inside
each test that needs it so tests don't share/mutate the same mockLGraphNode
instance.

In `@src/components/graph/selectionToolbox/ColorPickerButton.test.ts`:
- Around line 16-25: The mock returned by createMockWorkflow only supplies
changeTracker but not other required fields of LoadedComfyWorkflow; update the
return value to use an explicit two-step cast so the incomplete object is first
typed as Partial<LoadedComfyWorkflow> and then cast to LoadedComfyWorkflow
(i.e., construct the object with changeTracker and overrides, cast it as
Partial<LoadedComfyWorkflow>, then cast that result to LoadedComfyWorkflow) so
the test intent is explicit while keeping the function signature
createMockWorkflow and the changeTracker mock unchanged.

In `@src/components/graph/selectionToolbox/ExecuteButton.test.ts`:
- Around line 47-49: The MockCommandStore type falsely promises a full store by
intersecting ReturnType<typeof useCommandStore> with { execute: Mock } while the
mock only implements execute; replace it by typing the mock as
Partial<ReturnType<typeof useCommandStore>> (e.g. const mock = { execute:
jest.fn() } as Partial<ReturnType<typeof useCommandStore>> as ReturnType<typeof
useCommandStore>) so missing properties are explicit, update usages of
MockCommandStore to use that pattern, and remove the MockCommandStore alias if
it’s no longer needed; ensure execute remains a Mock and all tests compile.

In `@src/components/sidebar/tabs/queue/ResultGallery.test.ts`:
- Line 95: The test currently casts mockGalleryItems directly to
ResultItemImpl[]; change this to the explicit double-cast pattern to indicate
the items are partials by casting mockGalleryItems as Partial<ResultItemImpl>[]
as ResultItemImpl[] and update the assignment at allGalleryItems to use that
double-cast so the incomplete implementation is explicit (reference:
allGalleryItems and ResultItemImpl in ResultGallery.test.ts).

In `@src/composables/functional/useChainCallback.ts`:
- Around line 8-13: The exported const useChainCallback likely should be a
function declaration per guidelines; verify whether the arrow was deliberately
chosen for its lexical this behavior for the chaining pattern—if not, change the
exported const useChainCallback to a named function declaration preserving the
same generic signature and parameters (originalCallback and callbacks) and
update any imports/usages accordingly; if the arrow is intentional, add a short
code comment above useChainCallback stating that the arrow function is required
for lexical this semantics to avoid automated refactors.
- Around line 17-24: The declared return type Ret is misleading because the
returned wrapper never returns the originalCallback's result; update the wrapper
to reflect side-effect-only behavior by changing its return type to void (remove
or stop using the Ret generic) so the function signature and the cast at the end
become (this: O, ...args: Args) => void; ensure you update any type parameters
or uses in useChainCallback that reference Ret and keep the implementation
calling originalCallback and callbacks as-is (referencing originalCallback and
callbacks in the returned function).

In `@src/composables/graph/useGraphHierarchy.test.ts`:
- Around line 37-56: The mock currently uses an "unknown" escape hatch; instead
declare mockCanvasStore with an explicit Partial type and avoid the double
cast—e.g. const mockCanvasStore: Partial<ReturnType<typeof useCanvasStore>> = {
canvas: { graph: { groups: mockGroups } }, $id: 'canvas', $state: {}, $patch:
vi.fn(), $reset: vi.fn(), $subscribe: vi.fn(), $onAction: vi.fn(), $dispose:
vi.fn(), _customProperties: new Set(), _p: {} }; then pass it into the mocked
factory with a single, deliberate cast when needed:
vi.mocked(useCanvasStore).mockReturnValue(mockCanvasStore as ReturnType<typeof
useCanvasStore>); this preserves type intent for mockCanvasStore and removes the
"unknown" escape hatch while keeping useCanvasStore mockable.

In `@src/composables/maskeditor/useImageLoader.test.ts`:
- Around line 117-133: The tests use verbose inline casts for mockStore members;
define a proper mock type/interface for your test (e.g., MockStore with
maskCanvas: {width:number;height:number}, rgbCanvas, imgCtx: {clearRect:
jest.Mock}, maskCtx: {clearRect: jest.Mock}, etc.) or cast mockStore once to
that type near the top of the test, then simplify assertions in the
useImageLoader/loadImages test to use direct property access like
mockStore.maskCanvas!.width and mockStore.imgCtx!.clearRect
toHaveBeenCalledWith(0,0,0,0) instead of repeated inline casts.
- Around line 10-30: Replace the ad-hoc unknown-typed mocks with explicit mock
interfaces/types: declare a MockStore type (with imgCanvas: HTMLCanvasElement |
null, maskCanvas, rgbCanvas, imgCtx: CanvasRenderingContext2D | null, maskCtx,
image: HTMLImageElement | null) and a MockDataStore type (with inputData typed
to the real input shape or any|null), then change mockStore and mockDataStore to
use Partial<MockStore>/Partial<MockDataStore> or those concrete types; update
the test setup in beforeEach that assigns canvases/contexts/images to match the
new types and remove the inline casts in the assertions that reference mockStore
and mockDataStore (the symbols to change: mockStore, mockDataStore, and the test
setup in beforeEach).

In `@src/composables/queue/useJobMenu.test.ts`:
- Around line 104-106: Replace the ad-hoc mock typing for nodeDefStoreMock with
the real ComfyNodeDefImpl to keep types aligned: import ComfyNodeDefImpl from
the store module and change nodeDefStoreMock.nodeDefsByName's type to
Record<string, Partial<ComfyNodeDefImpl>> so the mock can be partial while
preserving the actual shape; update any places creating entries to match
Partial<ComfyNodeDefImpl> fields used in tests.

In `@src/composables/useBrowserTabTitle.test.ts`:
- Around line 42-44: The test's reactive mock `settingStore` includes a
redundant type assertion "'Enabled' as string"; remove the unnecessary "as
string" so the `get` mock returns the string literal directly (keep the vi.fn
signature unchanged) — update the `settingStore` definition in
useBrowserTabTitle.test.ts where `get: vi.fn((_key: string) => 'Enabled' as
string)` appears to `get: vi.fn((_key: string) => 'Enabled')`.
♻️ Duplicate comments (1)
src/composables/maskeditor/useImageLoader.test.ts (1)

205-208: Same verbose cast pattern as above.

These casts follow the same pattern and would benefit from the mock interface refactoring suggested earlier.

Comment on lines +14 to +21
function createMockCanvas(): typeof useCanvasStore.prototype.canvas {
return {
setDirty: vi.fn(),
state: {
selectionChanged: false
}
} as typeof useCanvasStore.prototype.canvas
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Incorrect type reference: useCanvasStore.prototype.canvas is invalid.

useCanvasStore is a Pinia store composable function, not a class, so it doesn't have a prototype property. This cast is misleading and may not provide the intended type safety.

🛠️ Suggested fix
-function createMockCanvas(): typeof useCanvasStore.prototype.canvas {
-  return {
-    setDirty: vi.fn(),
-    state: {
-      selectionChanged: false
-    }
-  } as typeof useCanvasStore.prototype.canvas
-}
+function createMockCanvas() {
+  return {
+    setDirty: vi.fn(),
+    state: {
+      selectionChanged: false
+    }
+  } as Partial<ReturnType<typeof useCanvasStore>['canvas']> as ReturnType<typeof useCanvasStore>['canvas']
+}

Or simply return the object without a type annotation since it's only used within this test file.

🤖 Prompt for AI Agents
In `@src/components/graph/SelectionToolbox.test.ts` around lines 14 - 21, The test
helper createMockCanvas currently casts to the invalid type
useCanvasStore.prototype.canvas (pinia composables have no prototype); fix by
removing that incorrect prototype reference and cast to a real type or no type:
either omit the annotation entirely, or import/use the proper type like
ReturnType<typeof useCanvasStore>['canvas'] (or the explicit Canvas type if
exported) and cast the returned object to that type; update createMockCanvas to
use the correct type reference (or no annotation) so the mock's type is valid.

Comment on lines +23 to +31
function createMockExtensionService(): ReturnType<typeof useExtensionService> {
return {
extensionCommands: { value: new Map() },
loadExtensions: vi.fn(),
registerExtension: vi.fn(),
invokeExtensions: vi.fn(() => []),
invokeExtensionsAsync: vi.fn()
} as ReturnType<typeof useExtensionService>
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider using explicit Partial cast for incomplete mock.

The mock only implements a subset of useExtensionService return type. Based on learnings, prefer as Partial<ReturnType<typeof useExtensionService>> as ReturnType<typeof useExtensionService> to make the incomplete implementation explicit.

♻️ Suggested pattern
 function createMockExtensionService(): ReturnType<typeof useExtensionService> {
   return {
     extensionCommands: { value: new Map() },
     loadExtensions: vi.fn(),
     registerExtension: vi.fn(),
     invokeExtensions: vi.fn(() => []),
     invokeExtensionsAsync: vi.fn()
-  } as ReturnType<typeof useExtensionService>
+  } as Partial<ReturnType<typeof useExtensionService>> as ReturnType<typeof useExtensionService>
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function createMockExtensionService(): ReturnType<typeof useExtensionService> {
return {
extensionCommands: { value: new Map() },
loadExtensions: vi.fn(),
registerExtension: vi.fn(),
invokeExtensions: vi.fn(() => []),
invokeExtensionsAsync: vi.fn()
} as ReturnType<typeof useExtensionService>
}
function createMockExtensionService(): ReturnType<typeof useExtensionService> {
return {
extensionCommands: { value: new Map() },
loadExtensions: vi.fn(),
registerExtension: vi.fn(),
invokeExtensions: vi.fn(() => []),
invokeExtensionsAsync: vi.fn()
} as Partial<ReturnType<typeof useExtensionService>> as ReturnType<typeof useExtensionService>
}
🤖 Prompt for AI Agents
In `@src/components/graph/SelectionToolbox.test.ts` around lines 23 - 31, The mock
in createMockExtensionService implements only part of the useExtensionService
return shape; change its cast to make that explicit by casting the object as
Partial<ReturnType<typeof useExtensionService>> and then as ReturnType<typeof
useExtensionService> (i.e., use "as Partial<ReturnType<typeof
useExtensionService>> as ReturnType<typeof useExtensionService>") so the
incomplete mock is explicit while preserving the original expected type; update
the return statement in createMockExtensionService accordingly.

title: 'Test Node',
mode: LGraphEventMode.ALWAYS
}
const mockLGraphNode = createMockLGraphNode({ type: 'TestNode' })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Module-level mock may affect test isolation.

mockLGraphNode is created once at module scope (line 15) and reused across all tests. If any test mutates this object, it could affect subsequent tests. Consider creating the mock in beforeEach or using a factory function call within each test.

♻️ Suggested improvement
-const mockLGraphNode = createMockLGraphNode({ type: 'TestNode' })
+function getMockLGraphNode() {
+  return createMockLGraphNode({ type: 'TestNode' })
+}

Then call getMockLGraphNode() in each test that needs it.

🤖 Prompt for AI Agents
In `@src/components/graph/selectionToolbox/BypassButton.test.ts` at line 15, The
test defines mockLGraphNode at module scope using createMockLGraphNode which can
leak state between tests; change to generate a fresh mock per test by either
moving the call into a beforeEach or introduce a factory function (e.g.,
getMockLGraphNode) and call getMockLGraphNode() inside each test that needs it
so tests don't share/mutate the same mockLGraphNode instance.

Comment on lines +16 to +25
function createMockWorkflow(
overrides: Partial<LoadedComfyWorkflow> = {}
): LoadedComfyWorkflow {
return {
changeTracker: {
checkState: vi.fn() as Mock
},
...overrides
} as LoadedComfyWorkflow
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Apply explicit Partial cast for incomplete workflow mock.

The mock only provides changeTracker but LoadedComfyWorkflow has additional required fields like isLoaded, originalContent, content, initialState, and activeState. Based on learnings, use the two-step cast to make the incomplete implementation explicit.

♻️ Suggested fix
 function createMockWorkflow(
   overrides: Partial<LoadedComfyWorkflow> = {}
 ): LoadedComfyWorkflow {
   return {
     changeTracker: {
       checkState: vi.fn() as Mock
     },
     ...overrides
-  } as LoadedComfyWorkflow
+  } as Partial<LoadedComfyWorkflow> as LoadedComfyWorkflow
 }
🤖 Prompt for AI Agents
In `@src/components/graph/selectionToolbox/ColorPickerButton.test.ts` around lines
16 - 25, The mock returned by createMockWorkflow only supplies changeTracker but
not other required fields of LoadedComfyWorkflow; update the return value to use
an explicit two-step cast so the incomplete object is first typed as
Partial<LoadedComfyWorkflow> and then cast to LoadedComfyWorkflow (i.e.,
construct the object with changeTracker and overrides, cast it as
Partial<LoadedComfyWorkflow>, then cast that result to LoadedComfyWorkflow) so
the test intent is explicit while keeping the function signature
createMockWorkflow and the changeTracker mock unchanged.

Comment on lines +47 to +49
type MockCommandStore = ReturnType<typeof useCommandStore> & {
execute: Mock
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider aligning MockCommandStore with the full store type.

MockCommandStore intersects ReturnType<typeof useCommandStore> with { execute: Mock }, but the mock object at line 97-99 only provides execute. This works because TypeScript allows the cast, but it may cause issues if tests later access other useCommandStore properties.

Based on learnings, prefer as Partial<ReturnType<typeof useCommandStore>> as ReturnType<typeof useCommandStore> pattern to make the incomplete implementation explicit.

♻️ Suggested pattern
-    mockCommandStore = {
-      execute: vi.fn()
-    } as MockCommandStore
+    mockCommandStore = {
+      execute: vi.fn()
+    } as Partial<ReturnType<typeof useCommandStore>> as ReturnType<typeof useCommandStore>

Then remove the MockCommandStore type alias if no longer needed.

🤖 Prompt for AI Agents
In `@src/components/graph/selectionToolbox/ExecuteButton.test.ts` around lines 47
- 49, The MockCommandStore type falsely promises a full store by intersecting
ReturnType<typeof useCommandStore> with { execute: Mock } while the mock only
implements execute; replace it by typing the mock as Partial<ReturnType<typeof
useCommandStore>> (e.g. const mock = { execute: jest.fn() } as
Partial<ReturnType<typeof useCommandStore>> as ReturnType<typeof
useCommandStore>) so missing properties are explicit, update usages of
MockCommandStore to use that pattern, and remove the MockCommandStore alias if
it’s no longer needed; ensure execute remains a Mock and all tests compile.

Comment on lines +10 to 30
const mockStore: {
imgCanvas: unknown
maskCanvas: unknown
rgbCanvas: unknown
imgCtx: unknown
maskCtx: unknown
image: unknown
} = {
imgCanvas: null,
maskCanvas: null,
rgbCanvas: null,
imgCtx: null,
maskCtx: null,
image: null
}

const mockDataStore = {
inputData: null as any
const mockDataStore: {
inputData: unknown
} = {
inputData: null
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider defining explicit mock interfaces to reduce inline casts.

Using unknown for all properties is type-safe but requires verbose inline casts at every assertion site. Define the mock shape explicitly to match what's assigned in beforeEach:

♻️ Suggested refactor
-const mockStore: {
-  imgCanvas: unknown
-  maskCanvas: unknown
-  rgbCanvas: unknown
-  imgCtx: unknown
-  maskCtx: unknown
-  image: unknown
-} = {
+interface MockCanvas {
+  width: number
+  height: number
+}
+
+interface MockContext {
+  clearRect: ReturnType<typeof vi.fn>
+}
+
+const mockStore: {
+  imgCanvas: MockCanvas | null
+  maskCanvas: MockCanvas | null
+  rgbCanvas: MockCanvas | null
+  imgCtx: MockContext | null
+  maskCtx: MockContext | null
+  image: HTMLImageElement | null
+} = {
   imgCanvas: null,
   maskCanvas: null,
   rgbCanvas: null,
   imgCtx: null,
   maskCtx: null,
   image: null
 }
 
-const mockDataStore: {
-  inputData: unknown
-} = {
+const mockDataStore: {
+  inputData: {
+    baseLayer: { image: HTMLImageElement } | null
+    maskLayer: { image: HTMLImageElement } | null
+    paintLayer: { image: HTMLImageElement } | null
+  } | null
+} = {
   inputData: null
 }

This eliminates the need for inline casts in assertions (lines 117-120, 128-133, 205-208) and makes the mock structure self-documenting. Based on learnings, explicit partial types are preferred over unknown with inline casts.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const mockStore: {
imgCanvas: unknown
maskCanvas: unknown
rgbCanvas: unknown
imgCtx: unknown
maskCtx: unknown
image: unknown
} = {
imgCanvas: null,
maskCanvas: null,
rgbCanvas: null,
imgCtx: null,
maskCtx: null,
image: null
}
const mockDataStore = {
inputData: null as any
const mockDataStore: {
inputData: unknown
} = {
inputData: null
}
interface MockCanvas {
width: number
height: number
}
interface MockContext {
clearRect: ReturnType<typeof vi.fn>
}
const mockStore: {
imgCanvas: MockCanvas | null
maskCanvas: MockCanvas | null
rgbCanvas: MockCanvas | null
imgCtx: MockContext | null
maskCtx: MockContext | null
image: HTMLImageElement | null
} = {
imgCanvas: null,
maskCanvas: null,
rgbCanvas: null,
imgCtx: null,
maskCtx: null,
image: null
}
const mockDataStore: {
inputData: {
baseLayer: { image: HTMLImageElement } | null
maskLayer: { image: HTMLImageElement } | null
paintLayer: { image: HTMLImageElement } | null
} | null
} = {
inputData: null
}
🤖 Prompt for AI Agents
In `@src/composables/maskeditor/useImageLoader.test.ts` around lines 10 - 30,
Replace the ad-hoc unknown-typed mocks with explicit mock interfaces/types:
declare a MockStore type (with imgCanvas: HTMLCanvasElement | null, maskCanvas,
rgbCanvas, imgCtx: CanvasRenderingContext2D | null, maskCtx, image:
HTMLImageElement | null) and a MockDataStore type (with inputData typed to the
real input shape or any|null), then change mockStore and mockDataStore to use
Partial<MockStore>/Partial<MockDataStore> or those concrete types; update the
test setup in beforeEach that assigns canvases/contexts/images to match the new
types and remove the inline casts in the assertions that reference mockStore and
mockDataStore (the symbols to change: mockStore, mockDataStore, and the test
setup in beforeEach).

Comment on lines +117 to +133
expect((mockStore.maskCanvas as { width: number }).width).toBe(512)
expect((mockStore.maskCanvas as { height: number }).height).toBe(512)
expect((mockStore.rgbCanvas as { width: number }).width).toBe(512)
expect((mockStore.rgbCanvas as { height: number }).height).toBe(512)
})

it('should clear canvas contexts', async () => {
const loader = useImageLoader()

await loader.loadImages()

expect(mockStore.imgCtx.clearRect).toHaveBeenCalledWith(0, 0, 0, 0)
expect(mockStore.maskCtx.clearRect).toHaveBeenCalledWith(0, 0, 0, 0)
expect(
(mockStore.imgCtx as { clearRect: ReturnType<typeof vi.fn> }).clearRect
).toHaveBeenCalledWith(0, 0, 0, 0)
expect(
(mockStore.maskCtx as { clearRect: ReturnType<typeof vi.fn> }).clearRect
).toHaveBeenCalledWith(0, 0, 0, 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Verbose inline casts could be eliminated with proper mock types.

The repeated inline casts like (mockStore.maskCanvas as { width: number }).width and (mockStore.imgCtx as { clearRect: ReturnType<typeof vi.fn> }).clearRect are functional but verbose. If the mock interfaces are properly defined as suggested above, these assertions simplify to:

expect(mockStore.maskCanvas!.width).toBe(512)
expect(mockStore.imgCtx!.clearRect).toHaveBeenCalledWith(0, 0, 0, 0)
🤖 Prompt for AI Agents
In `@src/composables/maskeditor/useImageLoader.test.ts` around lines 117 - 133,
The tests use verbose inline casts for mockStore members; define a proper mock
type/interface for your test (e.g., MockStore with maskCanvas:
{width:number;height:number}, rgbCanvas, imgCtx: {clearRect: jest.Mock},
maskCtx: {clearRect: jest.Mock}, etc.) or cast mockStore once to that type near
the top of the test, then simplify assertions in the useImageLoader/loadImages
test to use direct property access like mockStore.maskCanvas!.width and
mockStore.imgCtx!.clearRect toHaveBeenCalledWith(0,0,0,0) instead of repeated
inline casts.

Comment on lines 104 to 106
const nodeDefStoreMock = {
nodeDefsByName: {} as Record<string, any>
nodeDefsByName: {} as Record<string, { id: string }>
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find and inspect the nodeDefStore to understand the real type of nodeDefsByName
find src/stores -name "*nodeDefStore*" -type f

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 128


🏁 Script executed:

#!/bin/bash
# Also check the test file to understand the context
cat -n src/composables/queue/useJobMenu.test.ts | sed -n '95,120p'

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 832


🏁 Script executed:

#!/bin/bash
# Search for nodeDefsByName usage patterns in the codebase
rg -n "nodeDefsByName" src -A 2 -B 2 --max-count=20

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 22588


🏁 Script executed:

#!/bin/bash
# Inspect the nodeDefStore to see ComfyNodeDefImpl and the return type
cat -n src/stores/nodeDefStore.ts | head -100

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 4068


🏁 Script executed:

#!/bin/bash
# Check the full return type definition of useNodeDefStore
cat -n src/stores/nodeDefStore.ts | sed -n '440,460p'

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 596


🏁 Script executed:

#!/bin/bash
# Search for ComfyNodeDefImpl definition
rg -n "class ComfyNodeDefImpl|export.*ComfyNodeDefImpl" src/stores -A 5

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 872


🏁 Script executed:

#!/bin/bash
# Verify the type derivation approach would work
cat -n src/stores/nodeDefStore.ts | sed -n '300,305p'

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 389


🏁 Script executed:

#!/bin/bash
# Check how nodeDefsByName is used in the useJobMenu.ts to understand what properties are actually needed
cat -n src/composables/queue/useJobMenu.ts | sed -n '135,145p'

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 440


🏁 Script executed:

#!/bin/bash
# Check if ComfyNodeDefImpl is already imported anywhere in test files
rg -n "import.*ComfyNodeDefImpl" src/composables/queue/

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

#!/bin/bash
# Check what the ref property actually resolves to in the returned store type
cat -n src/stores/nodeDefStore.ts | sed -n '301,303p'

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 293


🏁 Script executed:

#!/bin/bash
# Verify how other similar mocks in the codebase handle the type
cat -n src/stores/modelToNodeStore.test.ts | sed -n '70,85p'

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 686


🏁 Script executed:

#!/bin/bash
# Check if there's a type export of nodeDefsByName or similar pattern
rg -n "type NodeDefsByName|export.*Record.*ComfyNodeDefImpl" src/stores

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

#!/bin/bash
# Check if NodeDefStoreType is defined and how it's used
rg -n "NodeDefStoreType" src/stores

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 266


🏁 Script executed:

#!/bin/bash
# Let's understand the full return type by looking at the end of useNodeDefStore
cat -n src/stores/nodeDefStore.ts | sed -n '440,475p'

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 1129


🏁 Script executed:

#!/bin/bash
# Verify how nodeDefsByName is actually accessed in the test and in production code
cat -n src/composables/queue/useJobMenu.test.ts | sed -n '200,210p'

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 500


🏁 Script executed:

#!/antml/bash
# Check if there's any Vue ref unwrapping or storeToRefs being used
rg -n "storeToRefs|\.value" src/composables/queue/useJobMenu.ts | head -20

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 460


Replace ad-hoc type with real ComfyNodeDefImpl.

The { id: string } shape is incomplete and risks drift from the actual store definition. Import ComfyNodeDefImpl from the store and use Record<string, Partial<ComfyNodeDefImpl>> to acknowledge the incomplete mock while maintaining type safety.

♻️ Suggested refactor
+import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
+
 const nodeDefStoreMock = {
-  nodeDefsByName: {} as Record<string, { id: string }>
+  nodeDefsByName: {} as Record<string, Partial<ComfyNodeDefImpl>>
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const nodeDefStoreMock = {
nodeDefsByName: {} as Record<string, any>
nodeDefsByName: {} as Record<string, { id: string }>
}
import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
const nodeDefStoreMock = {
nodeDefsByName: {} as Record<string, Partial<ComfyNodeDefImpl>>
}
🤖 Prompt for AI Agents
In `@src/composables/queue/useJobMenu.test.ts` around lines 104 - 106, Replace the
ad-hoc mock typing for nodeDefStoreMock with the real ComfyNodeDefImpl to keep
types aligned: import ComfyNodeDefImpl from the store module and change
nodeDefStoreMock.nodeDefsByName's type to Record<string,
Partial<ComfyNodeDefImpl>> so the mock can be partial while preserving the
actual shape; update any places creating entries to match
Partial<ComfyNodeDefImpl> fields used in tests.

Comment on lines 42 to 44
const settingStore = reactive({
get: vi.fn(() => 'Enabled')
get: vi.fn((_key: string) => 'Enabled' as string)
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Redundant type assertion on string literal.

The as string cast on 'Enabled' is unnecessary since string literals are already typed as string by default in this context.

♻️ Minor cleanup
 const settingStore = reactive({
-  get: vi.fn((_key: string) => 'Enabled' as string)
+  get: vi.fn((_key: string) => 'Enabled')
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const settingStore = reactive({
get: vi.fn(() => 'Enabled')
get: vi.fn((_key: string) => 'Enabled' as string)
})
const settingStore = reactive({
get: vi.fn((_key: string) => 'Enabled')
})
🤖 Prompt for AI Agents
In `@src/composables/useBrowserTabTitle.test.ts` around lines 42 - 44, The test's
reactive mock `settingStore` includes a redundant type assertion "'Enabled' as
string"; remove the unnecessary "as string" so the `get` mock returns the string
literal directly (keep the vi.fn signature unchanged) — update the
`settingStore` definition in useBrowserTabTitle.test.ts where `get: vi.fn((_key:
string) => 'Enabled' as string)` appears to `get: vi.fn((_key: string) =>
'Enabled')`.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/graph/SelectionToolbox.test.ts (1)

385-404: Inline mock should also use explicit Partial cast.

This inline mock duplicates the pattern from createMockExtensionService but with different return values. Consider reusing the helper or applying the same Partial cast pattern for consistency.

♻️ Suggested approach
       mockExtensionService.mockReturnValue({
         extensionCommands: {
           value: new Map([
             ['test-command', { id: 'test-command', title: 'Test Command' }]
           ])
         },
         loadExtensions: vi.fn(),
         registerExtension: vi.fn(),
         invokeExtensions: vi.fn(() => ['test-command']),
         invokeExtensionsAsync: vi.fn()
-      } as ReturnType<typeof useExtensionService>)
+      } as Partial<ReturnType<typeof useExtensionService>> as ReturnType<typeof useExtensionService>)
🤖 Fix all issues with AI agents
In `@src/composables/graph/useSelectionState.test.ts`:
- Around line 91-104: The test mock for useCanvasStore is using an unsafe
double-cast ("as unknown as ReturnType<typeof useCanvasStore>"); change these to
explicit partial typings by casting the mock object to Partial<ReturnType<typeof
useCanvasStore>> (e.g., vi.mocked(useCanvasStore).mockReturnValue({ ... } as
Partial<ReturnType<typeof useCanvasStore>>)). Do the same for the other store
mocks in this file (the blocks around the mocked stores at the other ranges
referenced) so mocks remain explicit about missing properties while keeping
type-safety and readability; reference useCanvasStore and mockSelectedItems to
find the exact mock objects to update.

In `@src/composables/maskeditor/useCanvasTools.test.ts`:
- Around line 11-17: The mockStore uses unsafe null! assertions for
canvas/context fields; change its type to the real store type (e.g.,
ReturnType<typeof useMaskEditorStore>) or an explicit interface where the canvas
and context properties are nullable (CanvasRenderingContext2D | null and
HTMLCanvasElement | null), then initialize fields to null (no ! cast) so tests
can assign real elements later; update the same pattern at the other occurrences
(lines referenced) to replace "null! as ..." with properly typed nullable fields
on mockStore.

In `@src/composables/node/useNodePricing.test.ts`:
- Around line 723-744: The inline verbose mock in the test should be extracted
to a helper: either add a new helper function
createMockNodeWithPriceBadge(nodeName, priceBadge, widgets, inputs) or extend
the existing createMockNode to accept a price_badge in its nodeData parameter;
then replace the long inline createMockNode call in useNodePricing.test.ts with
a call to createMockNodeWithPriceBadge (or the extended createMockNode) passing
the same name, the price_badge object (engine/expr/depends_on) and the
simplified inputs array (use connected:true/false instead of link values) so the
test remains concise and the unique symbols to update are createMockNode,
createMockNodeWithPriceBadge, and the price_badge nodeData structure.

In `@src/composables/useCoreCommands.test.ts`:
- Around line 174-195: Extract the duplicated Pinia mock into a helper: create a
function createMockSettingStore(getReturnValue: boolean): ReturnType<typeof
useSettingStore> that returns the common mock object (with get mocked to return
getReturnValue and all other methods/fields copied from the existing mock), then
replace the two vi.mocked(useSettingStore).mockReturnValue(...) calls with
vi.mocked(useSettingStore).mockReturnValue(createMockSettingStore(false)) and
vi.mocked(useSettingStore).mockReturnValue(createMockSettingStore(true))
respectively; ensure the helper includes get, addSetting, loadSettingValues,
set, exists, getDefaultValue, settingValues, settingsById, $id, $state, $patch,
$reset, $subscribe, $onAction, $dispose, _customProperties and _p to match the
original mock shape.
- Line 162: The test-level mockSubgraph is created once at module scope using
createMockSubgraph(), which lets vi.fn() instances retain call history across
tests; move the call to createMockSubgraph() into the test-level setup (e.g.,
inside beforeEach) or create it inline within each test so each test gets a
fresh mockSubgraph instance; update references to the module-scoped mockSubgraph
in tests to use the newly created local variable to ensure isolation and avoid
relying solely on vi.clearAllMocks().

In `@src/utils/__tests__/litegraphTestUtils.ts`:
- Around line 9-47: The helpers return concrete objects with a direct cast; make
the "partial mock" intent explicit by constructing a const partial: Partial<T>
inside each helper and then return partial as Partial<T> as T; update
createMockLGraphNode, createMockPositionable, and createMockLGraphGroup to build
a partial object (including current default fields and overrides) typed as
Partial<LGraphNode>/Partial<Positionable>/Partial<LGraphGroup> and return it
using the explicit Partial<T> as T cast.
♻️ Duplicate comments (13)
src/components/sidebar/tabs/queue/ResultGallery.test.ts (1)

95-95: Consider using the double-cast pattern for explicit partial indication.

Based on learnings, when creating mock objects that partially implement an interface, prefer as Partial<T>[] as T[] to make the incomplete implementation explicit. Since MockResultItem is already defined as Partial<ResultItemImpl> & {...}, the double-cast would better communicate intent.

♻️ Suggested improvement
-        allGalleryItems: mockGalleryItems as ResultItemImpl[],
+        allGalleryItems: mockGalleryItems as Partial<ResultItemImpl>[] as ResultItemImpl[],
src/composables/maskeditor/useImageLoader.test.ts (2)

10-30: Consider explicit mock types instead of unknown fields.

Typing mockStore/mockDataStore as unknown forces repeated casts later. Prefer explicit mock shapes or Partial<MaskEditorStore> as MaskEditorStore to keep type intent clear. Based on learnings, explicit partial types are preferred over unknown with inline casts.


117-133: Inline casts can be eliminated with stronger mock typing.

The repeated (mockStore.* as { ... }) casts are noisy; once mock types are explicit, these assertions can be simplified. Based on learnings, explicit partial mock types are preferred.

Also applies to: 205-208

src/composables/graph/useGraphHierarchy.test.ts (1)

37-56: Avoid the unknown escape hatch in the store mock.
Use an explicit Partial<ReturnType<typeof useCanvasStore>> and a single cast.

♻️ Suggested update
-    } as unknown as Partial<ReturnType<typeof useCanvasStore>>
+    } as Partial<ReturnType<typeof useCanvasStore>>
 
     vi.mocked(useCanvasStore).mockReturnValue(
-      mockCanvasStore as ReturnType<typeof useCanvasStore>
+      mockCanvasStore as Partial<ReturnType<typeof useCanvasStore>> as ReturnType<
+        typeof useCanvasStore
+      >
     )
Based on learnings, keep partial mock intent explicit.
src/components/graph/SelectionToolbox.test.ts (2)

14-21: Incorrect type reference: useCanvasStore.prototype.canvas is invalid.

useCanvasStore is a Pinia store composable function, not a class, so it doesn't have a prototype property. This cast is misleading and won't provide type safety.

♻️ Suggested fix
-function createMockCanvas(): typeof useCanvasStore.prototype.canvas {
-  return {
-    setDirty: vi.fn(),
-    state: {
-      selectionChanged: false
-    }
-  } as typeof useCanvasStore.prototype.canvas
-}
+function createMockCanvas() {
+  return {
+    setDirty: vi.fn(),
+    state: {
+      selectionChanged: false
+    }
+  } as Partial<ReturnType<typeof useCanvasStore>['canvas']> as ReturnType<typeof useCanvasStore>['canvas']
+}

23-31: Use explicit Partial cast for incomplete mock.

The mock only implements a subset of useExtensionService return type. Based on learnings, prefer as Partial<ReturnType<typeof useExtensionService>> as ReturnType<typeof useExtensionService> to make the incomplete implementation explicit.

♻️ Suggested fix
 function createMockExtensionService(): ReturnType<typeof useExtensionService> {
   return {
     extensionCommands: { value: new Map() },
     loadExtensions: vi.fn(),
     registerExtension: vi.fn(),
     invokeExtensions: vi.fn(() => []),
     invokeExtensionsAsync: vi.fn()
-  } as ReturnType<typeof useExtensionService>
+  } as Partial<ReturnType<typeof useExtensionService>> as ReturnType<typeof useExtensionService>
 }
src/components/graph/selectionToolbox/ColorPickerButton.test.ts (1)

16-25: Apply explicit Partial cast for incomplete workflow mock.

The mock only provides changeTracker but LoadedComfyWorkflow has additional required fields. Based on learnings, use the two-step cast to make the incomplete implementation explicit.

♻️ Suggested fix
 function createMockWorkflow(
   overrides: Partial<LoadedComfyWorkflow> = {}
 ): LoadedComfyWorkflow {
   return {
     changeTracker: {
       checkState: vi.fn() as Mock
     },
     ...overrides
-  } as LoadedComfyWorkflow
+  } as Partial<LoadedComfyWorkflow> as LoadedComfyWorkflow
 }
src/components/graph/selectionToolbox/BypassButton.test.ts (1)

15-15: Module-level mock may affect test isolation.

mockLGraphNode is created once at module scope and reused across all tests. If any test mutates this object, it could affect subsequent tests. Consider creating the mock in beforeEach or using a factory function.

♻️ Suggested improvement
-const mockLGraphNode = createMockLGraphNode({ type: 'TestNode' })
+function getMockLGraphNode() {
+  return createMockLGraphNode({ type: 'TestNode' })
+}

Then call getMockLGraphNode() in each test that needs it.

src/components/graph/selectionToolbox/ExecuteButton.test.ts (1)

47-49: MockCommandStore type intersection is misleading.

The type intersects ReturnType<typeof useCommandStore> with { execute: Mock }, but the mock object only provides execute. Based on learnings, prefer explicit Partial pattern.

♻️ Suggested pattern
-type MockCommandStore = ReturnType<typeof useCommandStore> & {
-  execute: Mock
-}
+// Remove type alias and use inline cast:

Then at line 97-99:

     mockCommandStore = {
       execute: vi.fn()
-    } as MockCommandStore
+    } as Partial<ReturnType<typeof useCommandStore>> as ReturnType<typeof useCommandStore>
src/composables/useBrowserTabTitle.test.ts (1)

42-44: Redundant type assertion on string literal.

The as string cast on 'Enabled' is unnecessary since string literals already satisfy the string type.

♻️ Minor cleanup
 const settingStore = reactive({
-  get: vi.fn((_key: string) => 'Enabled' as string)
+  get: vi.fn((_key: string) => 'Enabled')
 })
src/composables/queue/useJobMenu.test.ts (1)

104-106: Replace ad-hoc type with real ComfyNodeDefImpl.

The { id: string } shape is incomplete and risks drift from the actual store definition. Import ComfyNodeDefImpl from the store and use Record<string, Partial<ComfyNodeDefImpl>> to acknowledge the incomplete mock while maintaining type safety.

♻️ Suggested refactor
+import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
+
 const nodeDefStoreMock = {
-  nodeDefsByName: {} as Record<string, { id: string }>
+  nodeDefsByName: {} as Record<string, Partial<ComfyNodeDefImpl>>
 }
src/composables/functional/useChainCallback.ts (2)

8-13: Function expression vs function declaration already flagged.

The concern about using a function expression instead of a function declaration per coding guidelines has been noted in a previous review comment. Please address that feedback regarding whether the arrow function's this binding semantics are intentionally required here.


17-24: Return type mismatch already flagged.

The concern that the function is cast to return Ret (line 24) but never actually returns the original callback's result has been noted in a previous review comment. The current implementation discards any return value from originalCallback, making the Ret return type misleading. Please address that feedback by either capturing and returning the result or changing the return type to void.

Comment on lines 91 to +104
vi.mocked(useCanvasStore).mockReturnValue({
selectedItems: mockSelectedItems,
// Add minimal required properties for the store
$id: 'canvas',
$state: {} as any,
$state: {
selectedItems: mockSelectedItems
},
$patch: vi.fn(),
$reset: vi.fn(),
$subscribe: vi.fn(),
$onAction: vi.fn(),
$dispose: vi.fn(),
_customProperties: new Set(),
_p: {} as any
} as any)
_p: {}
} as unknown as ReturnType<typeof useCanvasStore>)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Prefer Partial<ReturnType<...>> over unknown casts for store mocks.

You can keep these mocks explicit about incompleteness without as unknown as. This improves test readability and matches our test-mock typing guidance.

♻️ Suggested pattern (apply to all store mocks in this block)
-    } as unknown as ReturnType<typeof useCanvasStore>)
+    } as Partial<ReturnType<typeof useCanvasStore>> as ReturnType<
+      typeof useCanvasStore
+    >)
...
-    } as unknown as ReturnType<typeof useNodeDefStore>)
+    } as Partial<ReturnType<typeof useNodeDefStore>> as ReturnType<
+      typeof useNodeDefStore
+    >)
...
-    } as unknown as ReturnType<typeof useSidebarTabStore>)
+    } as Partial<ReturnType<typeof useSidebarTabStore>> as ReturnType<
+      typeof useSidebarTabStore
+    >)
...
-    } as unknown as ReturnType<typeof useNodeHelpStore>)
+    } as Partial<ReturnType<typeof useNodeHelpStore>> as ReturnType<
+      typeof useNodeHelpStore
+    >)

Based on learnings, this makes partial mocks explicit without unsafe double-casts.

Also applies to: 107-123, 127-139, 144-160

🤖 Prompt for AI Agents
In `@src/composables/graph/useSelectionState.test.ts` around lines 91 - 104, The
test mock for useCanvasStore is using an unsafe double-cast ("as unknown as
ReturnType<typeof useCanvasStore>"); change these to explicit partial typings by
casting the mock object to Partial<ReturnType<typeof useCanvasStore>> (e.g.,
vi.mocked(useCanvasStore).mockReturnValue({ ... } as Partial<ReturnType<typeof
useCanvasStore>>)). Do the same for the other store mocks in this file (the
blocks around the mocked stores at the other ranges referenced) so mocks remain
explicit about missing properties while keeping type-safety and readability;
reference useCanvasStore and mockSelectedItems to find the exact mock objects to
update.

Comment on lines 11 to +17
const mockStore = {
maskCtx: null as any,
imgCtx: null as any,
maskCanvas: null as any,
imgCanvas: null as any,
rgbCtx: null as any,
rgbCanvas: null as any,
maskCtx: null! as CanvasRenderingContext2D,
imgCtx: null! as CanvasRenderingContext2D,
maskCanvas: null! as HTMLCanvasElement,
imgCanvas: null! as HTMLCanvasElement,
rgbCtx: null! as CanvasRenderingContext2D,
rgbCanvas: null! as HTMLCanvasElement,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Avoid null! assertions by typing the mock store with nullable fields.

The repeated null! as ... assignments reintroduce unsafe assertions and add noise. Consider typing mockStore as the real store type (or ReturnType<typeof useMaskEditorStore>) with nullable canvas/context fields so tests can assign null directly and avoid assertions.

Also applies to: 167-167, 252-252, 372-372, 382-382, 404-404, 415-415

🤖 Prompt for AI Agents
In `@src/composables/maskeditor/useCanvasTools.test.ts` around lines 11 - 17, The
mockStore uses unsafe null! assertions for canvas/context fields; change its
type to the real store type (e.g., ReturnType<typeof useMaskEditorStore>) or an
explicit interface where the canvas and context properties are nullable
(CanvasRenderingContext2D | null and HTMLCanvasElement | null), then initialize
fields to null (no ! cast) so tests can assign real elements later; update the
same pattern at the other occurrences (lines referenced) to replace "null! as
..." with properly typed nullable fields on mockStore.

Comment on lines +723 to +744
const node = createMockNode(
{
name: 'TestInputGroupNode',
api_node: true,
price_badge: {
engine: 'jsonata',
expr: '{"type":"usd","usd": inputGroups.videos * 0.05}',
depends_on: {
widgets: [],
inputs: [],
input_groups: ['videos']
}
}
},
[],
[
{ name: 'videos.clip1', link: 1 }, // connected
{ name: 'videos.clip2', link: 2 }, // connected
{ name: 'videos.clip3', link: null }, // disconnected
{ name: 'other_input', link: 3 } // connected but not in group
],
constructor: {
nodeData: {
name: 'TestInputGroupNode',
api_node: true,
price_badge: {
engine: 'jsonata',
expr: '{"type":"usd","usd": inputGroups.videos * 0.05}',
depends_on: {
widgets: [],
inputs: [],
input_groups: ['videos']
}
}
}
}
}
]
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider extracting complex mock to helper.

This inline mock construction for input_groups test is verbose. Consider using createMockNodeWithPriceBadge with the appropriate parameters, or extending createMockNode to accept price_badge in nodeData.

♻️ Potential simplification

The test could use createMockNodeWithPriceBadge if inputs are added:

const node = createMockNodeWithPriceBadge(
  'TestInputGroupNode',
  {
    engine: 'jsonata',
    expr: '{"type":"usd","usd": inputGroups.videos * 0.05}',
    depends_on: { widgets: [], inputs: [], input_groups: ['videos'] }
  },
  [],
  [
    { name: 'videos.clip1', connected: true },
    { name: 'videos.clip2', connected: true },
    { name: 'videos.clip3', connected: false },
    { name: 'other_input', connected: true }
  ]
)
🤖 Prompt for AI Agents
In `@src/composables/node/useNodePricing.test.ts` around lines 723 - 744, The
inline verbose mock in the test should be extracted to a helper: either add a
new helper function createMockNodeWithPriceBadge(nodeName, priceBadge, widgets,
inputs) or extend the existing createMockNode to accept a price_badge in its
nodeData parameter; then replace the long inline createMockNode call in
useNodePricing.test.ts with a call to createMockNodeWithPriceBadge (or the
extended createMockNode) passing the same name, the price_badge object
(engine/expr/depends_on) and the simplified inputs array (use
connected:true/false instead of link values) so the test remains concise and the
unique symbols to update are createMockNode, createMockNodeWithPriceBadge, and
the price_badge nodeData structure.

} as Partial<typeof app.canvas.subgraph> as typeof app.canvas.subgraph
}

const mockSubgraph = createMockSubgraph()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Module-level mock may affect test isolation.

mockSubgraph is created once at module scope and reused. Since createMockSubgraph() creates mocks with vi.fn(), these mock functions accumulate call history across tests. While vi.clearAllMocks() in beforeEach resets call counts, consider creating a fresh subgraph per test for better isolation.

♻️ Suggested improvement

Move the creation into beforeEach or create inline in tests:

-const mockSubgraph = createMockSubgraph()
+let mockSubgraph: ReturnType<typeof createMockSubgraph>

 beforeEach(() => {
   vi.clearAllMocks()
   setActivePinia(createPinia())
+  mockSubgraph = createMockSubgraph()
   app.canvas.subgraph = undefined
   // ...
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const mockSubgraph = createMockSubgraph()
let mockSubgraph: ReturnType<typeof createMockSubgraph>
beforeEach(() => {
vi.clearAllMocks()
setActivePinia(createPinia())
mockSubgraph = createMockSubgraph()
app.canvas.subgraph = undefined
// ...
})
🤖 Prompt for AI Agents
In `@src/composables/useCoreCommands.test.ts` at line 162, The test-level
mockSubgraph is created once at module scope using createMockSubgraph(), which
lets vi.fn() instances retain call history across tests; move the call to
createMockSubgraph() into the test-level setup (e.g., inside beforeEach) or
create it inline within each test so each test gets a fresh mockSubgraph
instance; update references to the module-scoped mockSubgraph in tests to use
the newly created local variable to ensure isolation and avoid relying solely on
vi.clearAllMocks().

Comment on lines 174 to +195
vi.mocked(useSettingStore).mockReturnValue({
get: vi.fn().mockReturnValue(false) // Skip confirmation dialog
} as any)
get: vi.fn().mockReturnValue(false), // Skip confirmation dialog
addSetting: vi.fn(),
loadSettingValues: vi.fn(),
set: vi.fn(),
exists: vi.fn(),
getDefaultValue: vi.fn(),
settingValues: {},
settingsById: {},
$id: 'setting',
$state: {
settingValues: {},
settingsById: {}
},
$patch: vi.fn(),
$reset: vi.fn(),
$subscribe: vi.fn(),
$onAction: vi.fn(),
$dispose: vi.fn(),
_customProperties: new Set(),
_p: {}
} as ReturnType<typeof useSettingStore>)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Extract duplicated Pinia store mock to a helper.

The useSettingStore mock configuration is duplicated between lines 174-195 and 244-265, differing only in the get return value. Extract to a helper function to reduce duplication.

♻️ Suggested refactor
function createMockSettingStore(
  getReturnValue: boolean
): ReturnType<typeof useSettingStore> {
  return {
    get: vi.fn().mockReturnValue(getReturnValue),
    addSetting: vi.fn(),
    loadSettingValues: vi.fn(),
    set: vi.fn(),
    exists: vi.fn(),
    getDefaultValue: vi.fn(),
    settingValues: {},
    settingsById: {},
    $id: 'setting',
    $state: { settingValues: {}, settingsById: {} },
    $patch: vi.fn(),
    $reset: vi.fn(),
    $subscribe: vi.fn(),
    $onAction: vi.fn(),
    $dispose: vi.fn(),
    _customProperties: new Set(),
    _p: {}
  } as ReturnType<typeof useSettingStore>
}

Then use:

vi.mocked(useSettingStore).mockReturnValue(createMockSettingStore(false))
// and
vi.mocked(useSettingStore).mockReturnValue(createMockSettingStore(true))

Also applies to: 244-265

🤖 Prompt for AI Agents
In `@src/composables/useCoreCommands.test.ts` around lines 174 - 195, Extract the
duplicated Pinia mock into a helper: create a function
createMockSettingStore(getReturnValue: boolean): ReturnType<typeof
useSettingStore> that returns the common mock object (with get mocked to return
getReturnValue and all other methods/fields copied from the existing mock), then
replace the two vi.mocked(useSettingStore).mockReturnValue(...) calls with
vi.mocked(useSettingStore).mockReturnValue(createMockSettingStore(false)) and
vi.mocked(useSettingStore).mockReturnValue(createMockSettingStore(true))
respectively; ensure the helper includes get, addSetting, loadSettingValues,
set, exists, getDefaultValue, settingValues, settingsById, $id, $state, $patch,
$reset, $subscribe, $onAction, $dispose, _customProperties and _p to match the
original mock shape.

Comment on lines +9 to +47
export function createMockLGraphNode(
overrides: Partial<LGraphNode> | Record<string, unknown> = {}
): LGraphNode {
const partial = {
id: 1,
pos: [0, 0],
size: [100, 100],
title: 'Test Node',
mode: LGraphEventMode.ALWAYS,
...(overrides as Partial<LGraphNode>)
}
return partial as LGraphNode
}

/**
* Creates a mock Positionable object
*/
export function createMockPositionable(
overrides: Partial<Positionable> = {}
): Positionable {
return {
id: 1,
pos: [0, 0],
...overrides
} as Positionable
}

/**
* Creates a mock LGraphGroup with minimal required properties
*/
export function createMockLGraphGroup(
overrides: Partial<LGraphGroup> = {}
): LGraphGroup {
return {
id: 1,
pos: [0, 0],
boundingRect: new Rectangle(0, 0, 100, 100),
...overrides
} as LGraphGroup
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Make partial mocks explicit to match test guidelines.
These helpers return incomplete shapes; prefer the explicit Partial<T> as T pattern for clarity.

♻️ Proposed refactor
 export function createMockLGraphNode(
   overrides: Partial<LGraphNode> | Record<string, unknown> = {}
 ): LGraphNode {
-  const partial = {
+  const partial: Partial<LGraphNode> = {
     id: 1,
     pos: [0, 0],
     size: [100, 100],
     title: 'Test Node',
     mode: LGraphEventMode.ALWAYS,
     ...(overrides as Partial<LGraphNode>)
   }
-  return partial as LGraphNode
+  return partial as Partial<LGraphNode> as LGraphNode
 }
@@
 export function createMockPositionable(
   overrides: Partial<Positionable> = {}
 ): Positionable {
-  return {
+  return {
     id: 1,
     pos: [0, 0],
     ...overrides
-  } as Positionable
+  } as Partial<Positionable> as Positionable
 }
@@
 export function createMockLGraphGroup(
   overrides: Partial<LGraphGroup> = {}
 ): LGraphGroup {
-  return {
+  return {
     id: 1,
     pos: [0, 0],
     boundingRect: new Rectangle(0, 0, 100, 100),
     ...overrides
-  } as LGraphGroup
+  } as Partial<LGraphGroup> as LGraphGroup
 }
Based on learnings, make partial mock intent explicit.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function createMockLGraphNode(
overrides: Partial<LGraphNode> | Record<string, unknown> = {}
): LGraphNode {
const partial = {
id: 1,
pos: [0, 0],
size: [100, 100],
title: 'Test Node',
mode: LGraphEventMode.ALWAYS,
...(overrides as Partial<LGraphNode>)
}
return partial as LGraphNode
}
/**
* Creates a mock Positionable object
*/
export function createMockPositionable(
overrides: Partial<Positionable> = {}
): Positionable {
return {
id: 1,
pos: [0, 0],
...overrides
} as Positionable
}
/**
* Creates a mock LGraphGroup with minimal required properties
*/
export function createMockLGraphGroup(
overrides: Partial<LGraphGroup> = {}
): LGraphGroup {
return {
id: 1,
pos: [0, 0],
boundingRect: new Rectangle(0, 0, 100, 100),
...overrides
} as LGraphGroup
export function createMockLGraphNode(
overrides: Partial<LGraphNode> | Record<string, unknown> = {}
): LGraphNode {
const partial: Partial<LGraphNode> = {
id: 1,
pos: [0, 0],
size: [100, 100],
title: 'Test Node',
mode: LGraphEventMode.ALWAYS,
...(overrides as Partial<LGraphNode>)
}
return partial as Partial<LGraphNode> as LGraphNode
}
/**
* Creates a mock Positionable object
*/
export function createMockPositionable(
overrides: Partial<Positionable> = {}
): Positionable {
return {
id: 1,
pos: [0, 0],
...overrides
} as Partial<Positionable> as Positionable
}
/**
* Creates a mock LGraphGroup with minimal required properties
*/
export function createMockLGraphGroup(
overrides: Partial<LGraphGroup> = {}
): LGraphGroup {
return {
id: 1,
pos: [0, 0],
boundingRect: new Rectangle(0, 0, 100, 100),
...overrides
} as Partial<LGraphGroup> as LGraphGroup
}
🤖 Prompt for AI Agents
In `@src/utils/__tests__/litegraphTestUtils.ts` around lines 9 - 47, The helpers
return concrete objects with a direct cast; make the "partial mock" intent
explicit by constructing a const partial: Partial<T> inside each helper and then
return partial as Partial<T> as T; update createMockLGraphNode,
createMockPositionable, and createMockLGraphGroup to build a partial object
(including current default fields and overrides) typed as
Partial<LGraphNode>/Partial<Positionable>/Partial<LGraphGroup> and return it
using the explicit Partial<T> as T cast.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants