Skip to content

test: stabilize cloud template filtering e2e#12999

Merged
jaeone94 merged 3 commits into
mainfrom
jaeone/fix-cloud-template-assets-e2e
Jun 19, 2026
Merged

test: stabilize cloud template filtering e2e#12999
jaeone94 merged 3 commits into
mainfrom
jaeone/fix-cloud-template-assets-e2e

Conversation

@jaeone94

@jaeone94 jaeone94 commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

Stabilizes the cloud template filtering E2E by making the test own both startup asset API responses and the complete template universe it asserts against.

Changes

  • What: Uses the existing createCloudAssetsFixture([]) fixture so startup /api/assets calls do not create an unrelated error toast that can intercept the Clear Filters click.
  • What: Extends TemplateHelper.mockIndex() to also mock /api/workflow_templates as an empty custom-template map, so tests that configure a core template index do not accidentally include custom templates from the local backend.
  • Dependencies: None.

Review Focus

Please focus on fixture ownership. This spec asserts exact template counts, so templateApi.mockIndex() should isolate the core template index and the custom workflow-template endpoint together. The asset fixture change is intentionally scoped to this cloud spec and reuses existing infrastructure instead of dismissing arbitrary toasts or forcing clicks.

Verification:

  • pnpm exec oxfmt --check browser_tests/tests/templateFilteringCount.spec.ts browser_tests/fixtures/helpers/TemplateHelper.ts browser_tests/fixtures/helpers/WorkflowHelper.ts
  • pnpm exec eslint browser_tests/tests/templateFilteringCount.spec.ts browser_tests/fixtures/helpers/TemplateHelper.ts browser_tests/fixtures/helpers/WorkflowHelper.ts
  • pnpm typecheck:browser
  • PLAYWRIGHT_LOCAL=1 PLAYWRIGHT_TEST_URL=http://localhost:8188 PLAYWRIGHT_SETUP_API_URL=http://localhost:8188 pnpm exec playwright test browser_tests/tests/templateFilteringCount.spec.ts --grep "clear filters button resets" --project=cloud --repeat-each=5
  • PLAYWRIGHT_LOCAL=1 PLAYWRIGHT_TEST_URL=http://localhost:8188 PLAYWRIGHT_SETUP_API_URL=http://localhost:8188 pnpm exec playwright test browser_tests/tests/templateFilteringCount.spec.ts --project=cloud

Screenshots (if applicable)

N/A

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

TemplateHelper.mockIndex() gains a new Playwright route handler for **/api/workflow_templates that returns an empty customTemplates JSON response. The templateFilteringCount spec switches its base fixture from comfyPageFixture to createCloudAssetsFixture([]). WorkflowHelper.ts corrects the AppMode import path.

Changes

Template Mock Route and Fixture Update

Layer / File(s) Summary
workflow_templates route handler and spec fixture wiring
browser_tests/fixtures/helpers/TemplateHelper.ts, browser_tests/tests/templateFilteringCount.spec.ts
TemplateHelper.mockIndex() registers a new route handler for **/api/workflow_templates returning 200 JSON with an empty customTemplates object. The spec replaces comfyPageFixture with mergeTests(createCloudAssetsFixture([]), templateApiFixture).
WorkflowHelper import path fix
browser_tests/fixtures/helpers/WorkflowHelper.ts
AppMode import source updated from @/composables/useAppMode to @/utils/appMode; ComfyApiWorkflow/ComfyWorkflowJSON import block reformatted with no source change.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Suggested labels

size:XS, cloud/1.46

Suggested reviewers

  • huang47
  • AustinMroz

Poem

🐇 A route for templates, tiny and neat,
A fixture swapped in — oh what a feat!
The mock returns JSON, an empty delight,
Import paths corrected, now pointing just right.
Hop hop, little tests, all passing tonight! 🌙

🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main change: stabilizing the cloud template filtering E2E test through fixture improvements.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
End-To-End Regression Coverage For Fixes ✅ Passed No bug-fix language found in commit subject "test: stabilize cloud template filtering e2e", and all changes are confined to browser_tests/. Check for E2E regression coverage only applies to bug fix...
Adr Compliance For Entity/Litegraph Changes ✅ Passed PR modifies only browser test fixtures and specs (browser_tests/), not src/lib/litegraph/, src/ecs/, or graph entity files, so ADR compliance check does not apply.
Description check ✅ Passed The pull request description follows the required template structure with all necessary sections: Summary, Changes, Review Focus, and Screenshots. Content is comprehensive and detailed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jaeone/fix-cloud-template-assets-e2e

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

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown

🎭 Playwright: ✅ 1670 passed, 0 failed · 2 flaky

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

📦 Bundle: 7.45 MB gzip 🟢 -5 B

Details

Summary

  • Raw size: 31.3 MB baseline 31.3 MB — ⚪ 0 B
  • Gzip: 7.45 MB baseline 7.45 MB — 🟢 -5 B
  • Brotli: 5.1 MB baseline 5.1 MB — 🔴 +380 B
  • Bundles: 280 current • 280 baseline • 126 added / 126 removed

Category Glance
Vendor & Third-Party ⚪ 0 B (15.3 MB) · Other ⚪ 0 B (10.4 MB) · Utilities & Hooks ⚪ 0 B (3.32 MB) · Graph Workspace ⚪ 0 B (1.25 MB) · Panels & Settings ⚪ 0 B (525 kB) · Data & Services ⚪ 0 B (268 kB) · + 5 more

App Entry Points — 46.7 kB (baseline 46.7 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-BlRDFcat.js (removed) 46.7 kB 🟢 -46.7 kB 🟢 -13.7 kB 🟢 -11.8 kB
assets/index-c0-9TDi3.js (new) 46.7 kB 🔴 +46.7 kB 🔴 +13.7 kB 🔴 +11.9 kB

Status: 1 added / 1 removed

Graph Workspace — 1.25 MB (baseline 1.25 MB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-CKWZ-nHT.js (removed) 1.25 MB 🟢 -1.25 MB 🟢 -266 kB 🟢 -200 kB
assets/GraphView-DKOvH7OD.js (new) 1.25 MB 🔴 +1.25 MB 🔴 +266 kB 🔴 +201 kB

Status: 1 added / 1 removed

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-CwJcOHPX.js (new) 19.5 kB 🔴 +19.5 kB 🔴 +5.06 kB 🔴 +4.49 kB
assets/CloudSurveyView-npG9ZZlc.js (removed) 19.5 kB 🟢 -19.5 kB 🟢 -5.06 kB 🟢 -4.49 kB
assets/CloudLoginView-7PY0CKJr.js (removed) 11.4 kB 🟢 -11.4 kB 🟢 -3.06 kB 🟢 -2.67 kB
assets/CloudLoginView-86nJzZuI.js (new) 11.4 kB 🔴 +11.4 kB 🔴 +3.06 kB 🔴 +2.69 kB
assets/CloudSignupView-15BeGg-d.js (new) 9.7 kB 🔴 +9.7 kB 🔴 +2.71 kB 🔴 +2.38 kB
assets/CloudSignupView-BRXqxRyY.js (removed) 9.7 kB 🟢 -9.7 kB 🟢 -2.71 kB 🟢 -2.38 kB
assets/CloudLayoutView-AXSA6JpW.js (new) 9.36 kB 🔴 +9.36 kB 🔴 +2.34 kB 🔴 +2.03 kB
assets/CloudLayoutView-CTQokPuP.js (removed) 9.36 kB 🟢 -9.36 kB 🟢 -2.34 kB 🟢 -2.02 kB
assets/UserCheckView-C0yAG9VC.js (removed) 8.8 kB 🟢 -8.8 kB 🟢 -2.22 kB 🟢 -1.93 kB
assets/UserCheckView-oK71-TDE.js (new) 8.8 kB 🔴 +8.8 kB 🔴 +2.22 kB 🔴 +1.93 kB
assets/UserSelectView-DB6qHmt9.js (new) 6 kB 🔴 +6 kB 🔴 +2.15 kB 🔴 +1.89 kB
assets/UserSelectView-DCaIRiTG.js (removed) 6 kB 🟢 -6 kB 🟢 -2.15 kB 🟢 -1.88 kB
assets/CloudForgotPasswordView-Be7dGrwk.js (new) 5.15 kB 🔴 +5.15 kB 🔴 +1.75 kB 🔴 +1.53 kB
assets/CloudForgotPasswordView-DIPicxap.js (removed) 5.15 kB 🟢 -5.15 kB 🟢 -1.75 kB 🟢 -1.54 kB
assets/CloudAuthTimeoutView-CVmPVhyI.js (new) 4.49 kB 🔴 +4.49 kB 🔴 +1.57 kB 🔴 +1.37 kB
assets/CloudAuthTimeoutView-tU7flsnI.js (removed) 4.49 kB 🟢 -4.49 kB 🟢 -1.57 kB 🟢 -1.36 kB
assets/CloudSubscriptionRedirectView-Blb0EZ6m.js (new) 4.3 kB 🔴 +4.3 kB 🔴 +1.57 kB 🔴 +1.38 kB
assets/CloudSubscriptionRedirectView-CNnMMpVG.js (removed) 4.3 kB 🟢 -4.3 kB 🟢 -1.57 kB 🟢 -1.39 kB

Status: 9 added / 9 removed / 3 unchanged

Panels & Settings — 525 kB (baseline 525 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/KeybindingPanel-915OmTYi.js (removed) 49.4 kB 🟢 -49.4 kB 🟢 -9.96 kB 🟢 -8.82 kB
assets/KeybindingPanel-BsodS3x4.js (new) 49.4 kB 🔴 +49.4 kB 🔴 +9.96 kB 🔴 +8.81 kB
assets/SecretsPanel-BBACYE31.js (removed) 24.2 kB 🟢 -24.2 kB 🟢 -5.76 kB 🟢 -5.06 kB
assets/SecretsPanel-p-a7QeI5.js (new) 24.2 kB 🔴 +24.2 kB 🔴 +5.76 kB 🔴 +5.07 kB
assets/LegacyCreditsPanel-BGvJe0_n.js (new) 20.9 kB 🔴 +20.9 kB 🔴 +5.52 kB 🔴 +4.85 kB
assets/LegacyCreditsPanel-DrIXzw_U.js (removed) 20.9 kB 🟢 -20.9 kB 🟢 -5.52 kB 🟢 -4.84 kB
assets/SubscriptionPanel--IXd6A_V.js (new) 19.2 kB 🔴 +19.2 kB 🔴 +5.04 kB 🔴 +4.42 kB
assets/SubscriptionPanel-DQHgNRq_.js (removed) 19.2 kB 🟢 -19.2 kB 🟢 -5.04 kB 🟢 -4.41 kB
assets/AboutPanel-BA3qhAmO.js (removed) 11.7 kB 🟢 -11.7 kB 🟢 -3.22 kB 🟢 -2.88 kB
assets/AboutPanel-CFgXKUrQ.js (new) 11.7 kB 🔴 +11.7 kB 🔴 +3.22 kB 🔴 +2.89 kB
assets/ExtensionPanel-CjngeymC.js (new) 9.03 kB 🔴 +9.03 kB 🔴 +2.49 kB 🔴 +2.2 kB
assets/ExtensionPanel-DxGONJMV.js (removed) 9.03 kB 🟢 -9.03 kB 🟢 -2.49 kB 🟢 -2.2 kB
assets/ServerConfigPanel-chSMzht6.js (removed) 6.15 kB 🟢 -6.15 kB 🟢 -1.98 kB 🟢 -1.77 kB
assets/ServerConfigPanel-UkEDqDXt.js (new) 6.15 kB 🔴 +6.15 kB 🔴 +1.98 kB 🔴 +1.77 kB
assets/UserPanel-BjcAoyhu.js (new) 5.78 kB 🔴 +5.78 kB 🔴 +1.82 kB 🔴 +1.58 kB
assets/UserPanel-DpbFquXl.js (removed) 5.78 kB 🟢 -5.78 kB 🟢 -1.82 kB 🟢 -1.58 kB
assets/refreshRemoteConfig-CtizvwAA.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.06 kB 🟢 -942 B
assets/refreshRemoteConfig-CWkGz6rX.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.06 kB 🔴 +943 B
assets/cloudRemoteConfig-B3u0Uehi.js (removed) 990 B 🟢 -990 B 🟢 -540 B 🟢 -455 B
assets/cloudRemoteConfig-DNZZ3A4Y.js (new) 990 B 🔴 +990 B 🔴 +545 B 🔴 +453 B
assets/refreshRemoteConfig-a6KN2fO4.js (removed) 110 B 🟢 -110 B 🟢 -89 B 🟢 -83 B
assets/refreshRemoteConfig-BLXSR2sa.js (new) 110 B 🔴 +110 B 🔴 +89 B 🔴 +82 B

Status: 11 added / 11 removed / 15 unchanged

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

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-BAIigzAM.js (removed) 3.69 kB 🟢 -3.69 kB 🟢 -1.3 kB 🟢 -1.13 kB
assets/auth-BVhhQcjQ.js (new) 3.69 kB 🔴 +3.69 kB 🔴 +1.31 kB 🔴 +1.13 kB
assets/usePostAuthRedirect-DRLyM_fH.js (removed) 3.33 kB 🟢 -3.33 kB 🟢 -1.28 kB 🟢 -1.11 kB
assets/usePostAuthRedirect-ZiydP3xq.js (new) 3.33 kB 🔴 +3.33 kB 🔴 +1.27 kB 🔴 +1.11 kB
assets/SignUpForm-CDPHxSKu.js (new) 3.19 kB 🔴 +3.19 kB 🔴 +1.29 kB 🔴 +1.15 kB
assets/SignUpForm-CMqjkDS1.js (removed) 3.19 kB 🟢 -3.19 kB 🟢 -1.29 kB 🟢 -1.15 kB
assets/UpdatePasswordContent-BMZEVjiI.js (removed) 1.92 kB 🟢 -1.92 kB 🟢 -878 B 🟢 -768 B
assets/UpdatePasswordContent-CoLwKu_u.js (new) 1.92 kB 🔴 +1.92 kB 🔴 +877 B 🔴 +765 B
assets/authStore-Vm9I-e7M.js (removed) 130 B 🟢 -130 B 🟢 -109 B 🟢 -106 B
assets/authStore-y5I8eons.js (new) 130 B 🔴 +130 B 🔴 +109 B 🔴 +110 B
assets/auth-Biwooich.js (new) 105 B 🔴 +105 B 🔴 +96 B 🔴 +84 B
assets/auth-UmoWdOna.js (removed) 105 B 🟢 -105 B 🟢 -96 B 🟢 -82 B

Status: 6 added / 6 removed / 3 unchanged

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

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyHubPublishDialog-B72EemjL.js (removed) 86 kB 🟢 -86 kB 🟢 -18.6 kB 🟢 -15.9 kB
assets/ComfyHubPublishDialog-CU7bMbrU.js (new) 86 kB 🔴 +86 kB 🔴 +18.6 kB 🔴 +15.9 kB
assets/useShareDialog-CqSSNr5-.js (removed) 23.4 kB 🟢 -23.4 kB 🟢 -5.54 kB 🟢 -4.91 kB
assets/useShareDialog-CuI-sS5j.js (new) 23.4 kB 🔴 +23.4 kB 🔴 +5.54 kB 🔴 +4.92 kB
assets/ComfyHubPublishDialog-B_uZmtpq.js (removed) 143 B 🟢 -143 B 🟢 -105 B 🟢 -92 B
assets/ComfyHubPublishDialog-CwUz0Kez.js (new) 143 B 🔴 +143 B 🔴 +105 B 🔴 +89 B
assets/useSubscriptionDialog-CjYZkAIb.js (new) 110 B 🔴 +110 B 🔴 +102 B 🔴 +90 B
assets/useSubscriptionDialog-DrMCC8J7.js (removed) 110 B 🟢 -110 B 🟢 -102 B 🟢 -97 B

Status: 4 added / 4 removed / 1 unchanged

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-CSG4REM9.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.82 kB 🟢 -3.42 kB
assets/ComfyQueueButton-s3Yq5DHq.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.83 kB 🔴 +3.42 kB
assets/useTerminalTabs-ByvsJkVO.js (removed) 12.1 kB 🟢 -12.1 kB 🟢 -3.84 kB 🟢 -3.39 kB
assets/useTerminalTabs-n_4fGd2b.js (new) 12.1 kB 🔴 +12.1 kB 🔴 +3.84 kB 🔴 +3.39 kB
assets/SubscribeButton-Dp5nVqk8.js (removed) 2.44 kB 🟢 -2.44 kB 🟢 -1.05 kB 🟢 -930 B
assets/SubscribeButton-rLraekn0.js (new) 2.44 kB 🔴 +2.44 kB 🔴 +1.05 kB 🔴 +948 B
assets/cloudFeedbackTopbarButton-CiqU0X9V.js (new) 829 B 🔴 +829 B 🔴 +498 B 🔴 +453 B
assets/cloudFeedbackTopbarButton-D2B2muPp.js (removed) 829 B 🟢 -829 B 🟢 -497 B 🟢 -449 B
assets/ComfyQueueButton-CVZhxYAp.js (new) 128 B 🔴 +128 B 🔴 +99 B 🔴 +90 B
assets/ComfyQueueButton-hQKcTiKV.js (removed) 128 B 🟢 -128 B 🟢 -99 B 🟢 -91 B

Status: 5 added / 5 removed / 8 unchanged

Data & Services — 268 kB (baseline 268 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/load3dService-BViio8OK.js (new) 127 kB 🔴 +127 kB 🔴 +27.9 kB 🔴 +23.6 kB
assets/load3dService-jVR7Whto.js (removed) 127 kB 🟢 -127 kB 🟢 -27.9 kB 🟢 -23.6 kB
assets/api-16mL1ve6.js (removed) 83.9 kB 🟢 -83.9 kB 🟢 -22.5 kB 🟢 -19.5 kB
assets/api-BrCD8X-T.js (new) 83.9 kB 🔴 +83.9 kB 🔴 +22.5 kB 🔴 +19.4 kB
assets/workflowShareService-D26m2AaU.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.91 kB 🟢 -4.35 kB
assets/workflowShareService-PB07fIES.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.91 kB 🔴 +4.35 kB
assets/keybindingService-CPWjEJnQ.js (removed) 13.8 kB 🟢 -13.8 kB 🟢 -3.67 kB 🟢 -3.22 kB
assets/keybindingService-DGfTu8Kr.js (new) 13.8 kB 🔴 +13.8 kB 🔴 +3.67 kB 🔴 +3.22 kB
assets/releaseStore-CPsCdlog.js (new) 8.29 kB 🔴 +8.29 kB 🔴 +2.34 kB 🔴 +2.04 kB
assets/releaseStore-D0hBZh7n.js (removed) 8.29 kB 🟢 -8.29 kB 🟢 -2.33 kB 🟢 -2.04 kB
assets/extensionStore-C5SnrqKm.js (removed) 5.29 kB 🟢 -5.29 kB 🟢 -1.86 kB 🟢 -1.58 kB
assets/extensionStore-CbcIzJ8M.js (new) 5.29 kB 🔴 +5.29 kB 🔴 +1.86 kB 🔴 +1.58 kB
assets/userStore-OgX-cpH5.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -930 B 🟢 -816 B
assets/userStore-OIdqYcDg.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +932 B 🔴 +816 B
assets/audioService-C_HqFkH4.js (new) 1.76 kB 🔴 +1.76 kB 🔴 +864 B 🔴 +748 B
assets/audioService-C4soFc6Q.js (removed) 1.76 kB 🟢 -1.76 kB 🟢 -862 B 🟢 -751 B
assets/dialogService-Cwc_sk0y.js (removed) 100 B 🟢 -100 B 🟢 -99 B 🟢 -99 B
assets/dialogService-Dy-XD4CB.js (new) 100 B 🔴 +100 B 🔴 +99 B 🔴 +92 B
assets/settingStore-DGY7iaXA.js (new) 98 B 🔴 +98 B 🔴 +98 B 🔴 +98 B
assets/settingStore-HjsCqLnC.js (removed) 98 B 🟢 -98 B 🟢 -98 B 🟢 -91 B
assets/assetsStore-BVt5MsOZ.js (removed) 96 B 🟢 -96 B 🟢 -97 B 🟢 -87 B
assets/assetsStore-DLHNVTmb.js (new) 96 B 🔴 +96 B 🔴 +97 B 🔴 +100 B
assets/releaseStore-DOifcYUa.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +83 B
assets/releaseStore-l5tY74HW.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -86 B
assets/api-CTSNdKcm.js (removed) 62 B 🟢 -62 B 🟢 -74 B 🟢 -66 B
assets/api-DAz4Zd2_.js (new) 62 B 🔴 +62 B 🔴 +74 B 🔴 +66 B

Status: 13 added / 13 removed / 3 unchanged

Utilities & Hooks — 3.32 MB (baseline 3.32 MB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/promotionUtils-BGEFNx_h.js (new) 2.97 MB 🔴 +2.97 MB 🔴 +686 kB 🔴 +517 kB
assets/promotionUtils-DNdZwxe5.js (removed) 2.97 MB 🟢 -2.97 MB 🟢 -686 kB 🟢 -517 kB
assets/useConflictDetection-BPV8AiO1.js (removed) 233 kB 🟢 -233 kB 🟢 -52 kB 🟢 -42.3 kB
assets/useConflictDetection-CkC5sSDq.js (new) 233 kB 🔴 +233 kB 🔴 +52 kB 🔴 +42.4 kB
assets/useLoad3d-Bbm_EOAR.js (new) 25.5 kB 🔴 +25.5 kB 🔴 +5.76 kB 🔴 +5.1 kB
assets/useLoad3d-CCOWg4pZ.js (removed) 25.5 kB 🟢 -25.5 kB 🟢 -5.75 kB 🟢 -5.09 kB
assets/useLoad3dViewer-BcHQUPlI.js (new) 21.1 kB 🔴 +21.1 kB 🔴 +4.98 kB 🔴 +4.37 kB
assets/useLoad3dViewer-DNktJcDq.js (removed) 21.1 kB 🟢 -21.1 kB 🟢 -4.98 kB 🟢 -4.35 kB
assets/useFeatureFlags-CTqSXm6-.js (removed) 5.37 kB 🟢 -5.37 kB 🟢 -1.65 kB 🟢 -1.41 kB
assets/useFeatureFlags-DKhuJXR6.js (new) 5.37 kB 🔴 +5.37 kB 🔴 +1.65 kB 🔴 +1.4 kB
assets/useSessionCookie-D5IeIwl-.js (new) 3.33 kB 🔴 +3.33 kB 🔴 +1.15 kB 🔴 +980 B
assets/useSessionCookie-DWunSf1d.js (removed) 3.33 kB 🟢 -3.33 kB 🟢 -1.15 kB 🟢 -977 B
assets/subscriptionCheckoutUtil-B_oAQfDI.js (removed) 3.31 kB 🟢 -3.31 kB 🟢 -1.36 kB 🟢 -1.19 kB
assets/subscriptionCheckoutUtil-C8VRMPev.js (new) 3.31 kB 🔴 +3.31 kB 🔴 +1.36 kB 🔴 +1.19 kB
assets/assetPreviewUtil-Bfk_-IAf.js (removed) 2.41 kB 🟢 -2.41 kB 🟢 -1 kB 🟢 -876 B
assets/assetPreviewUtil-CVb-md3t.js (new) 2.41 kB 🔴 +2.41 kB 🔴 +1.01 kB 🔴 +878 B
assets/useUpstreamValue-D8hR8B85.js (new) 2.04 kB 🔴 +2.04 kB 🔴 +794 B 🔴 +708 B
assets/useUpstreamValue-DtU2OIMW.js (removed) 2.04 kB 🟢 -2.04 kB 🟢 -793 B 🟢 -708 B
assets/useWorkspaceSwitch-BWnKAdPC.js (new) 748 B 🔴 +748 B 🔴 +386 B 🔴 +339 B
assets/useWorkspaceSwitch-CN4JFlkH.js (removed) 748 B 🟢 -748 B 🟢 -387 B 🟢 -339 B
assets/useLoad3d-D0uE2G98.js (new) 311 B 🔴 +311 B 🔴 +163 B 🔴 +147 B
assets/useLoad3d-nRYjdAkb.js (removed) 311 B 🟢 -311 B 🟢 -164 B 🟢 -147 B
assets/useSessionCookie-5ts7U6G-.js (new) 101 B 🔴 +101 B 🔴 +86 B 🔴 +86 B
assets/useSessionCookie-CHKzHpAr.js (removed) 101 B 🟢 -101 B 🟢 -86 B 🟢 -80 B
assets/useLoad3dViewer-CLbl0KOj.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -82 B
assets/useLoad3dViewer-DL-orlBn.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +86 B
assets/useCurrentUser-BYGJLZwk.js (new) 96 B 🔴 +96 B 🔴 +97 B 🔴 +84 B
assets/useCurrentUser-hVfhwIon.js (removed) 96 B 🟢 -96 B 🟢 -97 B 🟢 -94 B

Status: 14 added / 14 removed / 16 unchanged

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

External libraries and shared vendor chunks

Status: 16 unchanged

Other — 10.4 MB (baseline 10.4 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-B_oUXQK3.js (new) 118 kB 🔴 +118 kB 🔴 +30.4 kB 🔴 +25.8 kB
assets/core-VoTym1gH.js (removed) 118 kB 🟢 -118 kB 🟢 -30.5 kB 🟢 -25.8 kB
assets/WidgetSelect-CGPCN0Dg.js (removed) 82.6 kB 🟢 -82.6 kB 🟢 -18.1 kB 🟢 -15.6 kB
assets/WidgetSelect-D54cAdwi.js (new) 82.6 kB 🔴 +82.6 kB 🔴 +18.1 kB 🔴 +15.6 kB
assets/SubscriptionRequiredDialogContentWorkspace-BwoFsEKs.js (new) 47.8 kB 🔴 +47.8 kB 🔴 +9.08 kB 🔴 +7.84 kB
assets/SubscriptionRequiredDialogContentWorkspace-Dm0bLJyl.js (removed) 47.8 kB 🟢 -47.8 kB 🟢 -9.08 kB 🟢 -7.84 kB
assets/Load3DControls-BsS3D19D.js (new) 46.8 kB 🔴 +46.8 kB 🔴 +7.57 kB 🔴 +6.63 kB
assets/Load3DControls-CztBKsJ8.js (removed) 46.8 kB 🟢 -46.8 kB 🟢 -7.57 kB 🟢 -6.61 kB
assets/WorkspacePanelContent-BmZ2rmPs.js (removed) 33.3 kB 🟢 -33.3 kB 🟢 -6.96 kB 🟢 -6.16 kB
assets/WorkspacePanelContent-Do4a7tnx.js (new) 33.3 kB 🔴 +33.3 kB 🔴 +6.96 kB 🔴 +6.16 kB
assets/WidgetPainter-B0spIlvK.js (removed) 32.6 kB 🟢 -32.6 kB 🟢 -7.86 kB 🟢 -6.99 kB
assets/WidgetPainter-DGzO2K8H.js (new) 32.6 kB 🔴 +32.6 kB 🔴 +7.86 kB 🔴 +6.98 kB
assets/Load3dViewerContent-1ZFAxCAb.js (removed) 30.9 kB 🟢 -30.9 kB 🟢 -6.3 kB 🟢 -5.47 kB
assets/Load3dViewerContent-CqpscheO.js (new) 30.9 kB 🔴 +30.9 kB 🔴 +6.3 kB 🔴 +5.47 kB
assets/SubscriptionRequiredDialogContent-CkKc_mBt.js (removed) 26.6 kB 🟢 -26.6 kB 🟢 -6.56 kB 🟢 -5.79 kB
assets/SubscriptionRequiredDialogContent-IYuSIEbP.js (new) 26.6 kB 🔴 +26.6 kB 🔴 +6.56 kB 🔴 +5.8 kB
assets/WidgetImageCrop-Cxr21WPm.js (new) 23.3 kB 🔴 +23.3 kB 🔴 +5.75 kB 🔴 +5.04 kB
assets/WidgetImageCrop-CzlBySF7.js (removed) 23.3 kB 🟢 -23.3 kB 🟢 -5.75 kB 🟢 -5.05 kB
assets/SubscriptionPanelContentWorkspace-CeDT2q8X.js (removed) 22.1 kB 🟢 -22.1 kB 🟢 -5.16 kB 🟢 -4.55 kB
assets/SubscriptionPanelContentWorkspace-D_qOJ6EW.js (new) 22.1 kB 🔴 +22.1 kB 🔴 +5.16 kB 🔴 +4.55 kB
assets/load3d-a4kfy3tj.js (removed) 21.2 kB 🟢 -21.2 kB 🟢 -5.18 kB 🟢 -4.49 kB
assets/load3d-BFpa4dRZ.js (new) 21.2 kB 🔴 +21.2 kB 🔴 +5.18 kB 🔴 +4.49 kB
assets/CurrentUserPopoverWorkspace-Btv-ymGA.js (new) 20.5 kB 🔴 +20.5 kB 🔴 +4.67 kB 🔴 +4.18 kB
assets/CurrentUserPopoverWorkspace-MS6JnSZ-.js (removed) 20.5 kB 🟢 -20.5 kB 🟢 -4.68 kB 🟢 -4.18 kB
assets/SignInContent-CAnWYQzR.js (new) 19.9 kB 🔴 +19.9 kB 🔴 +5 kB 🔴 +4.36 kB
assets/SignInContent-EcKC2RZf.js (removed) 19.9 kB 🟢 -19.9 kB 🟢 -5 kB 🟢 -4.37 kB
assets/Load3D-c1g_2w1P.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.52 kB 🟢 -3.93 kB
assets/Load3D-CyDwivul.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.51 kB 🔴 +3.94 kB
assets/WidgetInputNumber-BiEvSez3.js (new) 19 kB 🔴 +19 kB 🔴 +4.79 kB 🔴 +4.25 kB
assets/WidgetInputNumber-o-q988r6.js (removed) 19 kB 🟢 -19 kB 🟢 -4.79 kB 🟢 -4.25 kB
assets/WidgetRecordAudio-BFzd88U_.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.63 kB 🟢 -4.14 kB
assets/WidgetRecordAudio-D5ZODxe8.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.63 kB 🔴 +4.14 kB
assets/WidgetRange-B3l5dKM8.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -4.17 kB 🟢 -3.73 kB
assets/WidgetRange-DXQ9PXQq.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +4.17 kB 🔴 +3.73 kB
assets/WaveAudioPlayer-B4GqQ7xv.js (new) 12.8 kB 🔴 +12.8 kB 🔴 +3.48 kB 🔴 +3.06 kB
assets/WaveAudioPlayer-Cz0xBZuB.js (removed) 12.8 kB 🟢 -12.8 kB 🟢 -3.48 kB 🟢 -3.05 kB
assets/WidgetCurve-07BQ-jqr.js (new) 11.3 kB 🔴 +11.3 kB 🔴 +3.5 kB 🔴 +3.17 kB
assets/WidgetCurve-of3vDJDw.js (removed) 11.3 kB 🟢 -11.3 kB 🟢 -3.51 kB 🟢 -3.17 kB
assets/TeamWorkspacesDialogContent-D8EiDaHZ.js (new) 10.4 kB 🔴 +10.4 kB 🔴 +3.01 kB 🔴 +2.68 kB
assets/TeamWorkspacesDialogContent-DGksjvc8.js (removed) 10.4 kB 🟢 -10.4 kB 🟢 -3.01 kB 🟢 -2.67 kB
assets/Load3DConfiguration-CnNYvXlj.js (removed) 9.02 kB 🟢 -9.02 kB 🟢 -2.66 kB 🟢 -2.35 kB
assets/Load3DConfiguration-DVI424EU.js (new) 9.02 kB 🔴 +9.02 kB 🔴 +2.66 kB 🔴 +2.35 kB
assets/nodeTemplates-BOLQnhCb.js (new) 8.33 kB 🔴 +8.33 kB 🔴 +2.88 kB 🔴 +2.54 kB
assets/nodeTemplates-DAuJzlJq.js (removed) 8.33 kB 🟢 -8.33 kB 🟢 -2.88 kB 🟢 -2.54 kB
assets/onboardingCloudRoutes-CfStbl98.js (removed) 8.2 kB 🟢 -8.2 kB 🟢 -2.54 kB 🟢 -2.19 kB
assets/onboardingCloudRoutes-CYiAgCtZ.js (new) 8.2 kB 🔴 +8.2 kB 🔴 +2.54 kB 🔴 +2.19 kB
assets/NightlySurveyController-DC1_cBcU.js (new) 7.95 kB 🔴 +7.95 kB 🔴 +2.7 kB 🔴 +2.4 kB
assets/NightlySurveyController-DK3muNcg.js (removed) 7.95 kB 🟢 -7.95 kB 🟢 -2.7 kB 🟢 -2.4 kB
assets/InviteMemberDialogContent-CFs9P3Ka.js (removed) 7.03 kB 🟢 -7.03 kB 🟢 -2.13 kB 🟢 -1.85 kB
assets/InviteMemberDialogContent-D2mpij3C.js (new) 7.03 kB 🔴 +7.03 kB 🔴 +2.14 kB 🔴 +1.85 kB
assets/WidgetWithControl-CQv3x6wH.js (new) 6.3 kB 🔴 +6.3 kB 🔴 +2.54 kB 🔴 +2.26 kB
assets/WidgetWithControl-zSYHE-io.js (removed) 6.3 kB 🟢 -6.3 kB 🟢 -2.54 kB 🟢 -2.25 kB
assets/load3dPreviewExtensions-CXmRRtva.js (removed) 5.38 kB 🟢 -5.38 kB 🟢 -1.75 kB 🟢 -1.55 kB
assets/load3dPreviewExtensions-WjhRNzfp.js (new) 5.38 kB 🔴 +5.38 kB 🔴 +1.75 kB 🔴 +1.55 kB
assets/CreateWorkspaceDialogContent-CAyRihTH.js (new) 5.19 kB 🔴 +5.19 kB 🔴 +1.83 kB 🔴 +1.59 kB
assets/CreateWorkspaceDialogContent-DwJKdX2u.js (removed) 5.19 kB 🟢 -5.19 kB 🟢 -1.83 kB 🟢 -1.59 kB
assets/missingModelDownload-Dttgw-Yi.js (new) 5.07 kB 🔴 +5.07 kB 🔴 +1.98 kB 🔴 +1.72 kB
assets/missingModelDownload-DWpGth00.js (removed) 5.07 kB 🟢 -5.07 kB 🟢 -1.98 kB 🟢 -1.72 kB
assets/FreeTierDialogContent-Cl0Ku2Bj.js (removed) 5.02 kB 🟢 -5.02 kB 🟢 -1.69 kB 🟢 -1.49 kB
assets/FreeTierDialogContent-X15soeLC.js (new) 5.02 kB 🔴 +5.02 kB 🔴 +1.69 kB 🔴 +1.49 kB
assets/EditWorkspaceDialogContent-BchmhQBs.js (new) 5 kB 🔴 +5 kB 🔴 +1.79 kB 🔴 +1.55 kB
assets/EditWorkspaceDialogContent-DSEIp-ZS.js (removed) 5 kB 🟢 -5 kB 🟢 -1.8 kB 🟢 -1.56 kB
assets/WidgetTextarea-BMf0XUe6.js (new) 4.86 kB 🔴 +4.86 kB 🔴 +1.89 kB 🔴 +1.67 kB
assets/WidgetTextarea-CCuiDdRX.js (removed) 4.86 kB 🟢 -4.86 kB 🟢 -1.89 kB 🟢 -1.66 kB
assets/saveMesh-BnrfxSNF.js (new) 4.79 kB 🔴 +4.79 kB 🔴 +1.54 kB 🔴 +1.36 kB
assets/saveMesh-CWNsUUnf.js (removed) 4.79 kB 🟢 -4.79 kB 🟢 -1.55 kB 🟢 -1.36 kB
assets/Preview3d-0zYZb5T-.js (new) 4.59 kB 🔴 +4.59 kB 🔴 +1.43 kB 🔴 +1.23 kB
assets/Preview3d-DR1nN1Pv.js (removed) 4.59 kB 🟢 -4.59 kB 🟢 -1.43 kB 🟢 -1.23 kB
assets/ValueControlPopover-B05B3Bji.js (removed) 4.55 kB 🟢 -4.55 kB 🟢 -1.59 kB 🟢 -1.41 kB
assets/ValueControlPopover-DQLfoNGA.js (new) 4.55 kB 🔴 +4.55 kB 🔴 +1.59 kB 🔴 +1.41 kB
assets/CancelSubscriptionDialogContent-BtPBSPiV.js (new) 4.54 kB 🔴 +4.54 kB 🔴 +1.66 kB 🔴 +1.44 kB
assets/CancelSubscriptionDialogContent-CMB8iuLC.js (removed) 4.54 kB 🟢 -4.54 kB 🟢 -1.66 kB 🟢 -1.44 kB
assets/tierBenefits-BoUNFMnO.js (new) 4.46 kB 🔴 +4.46 kB 🔴 +1.58 kB 🔴 +1.37 kB
assets/tierBenefits-DDXhnycX.js (removed) 4.46 kB 🟢 -4.46 kB 🟢 -1.58 kB 🟢 -1.36 kB
assets/DeleteWorkspaceDialogContent-CUN7ahRi.js (new) 3.91 kB 🔴 +3.91 kB 🔴 +1.47 kB 🔴 +1.26 kB
assets/DeleteWorkspaceDialogContent-D5h6L_M8.js (removed) 3.91 kB 🟢 -3.91 kB 🟢 -1.47 kB 🟢 -1.27 kB
assets/LeaveWorkspaceDialogContent-CgBn6kbu.js (new) 3.73 kB 🔴 +3.73 kB 🔴 +1.42 kB 🔴 +1.22 kB
assets/LeaveWorkspaceDialogContent-DtlUpZIw.js (removed) 3.73 kB 🟢 -3.73 kB 🟢 -1.42 kB 🟢 -1.22 kB
assets/RemoveMemberDialogContent-BhYeT_sq.js (removed) 3.71 kB 🟢 -3.71 kB 🟢 -1.37 kB 🟢 -1.19 kB
assets/RemoveMemberDialogContent-DRB-mor1.js (new) 3.71 kB 🔴 +3.71 kB 🔴 +1.37 kB 🔴 +1.18 kB
assets/RevokeInviteDialogContent-BBMf6cEg.js (removed) 3.63 kB 🟢 -3.63 kB 🟢 -1.38 kB 🟢 -1.2 kB
assets/RevokeInviteDialogContent-r57YRAf3.js (new) 3.63 kB 🔴 +3.63 kB 🔴 +1.38 kB 🔴 +1.2 kB
assets/InviteMemberUpsellDialogContent-5hpPZNUq.js (new) 3.48 kB 🔴 +3.48 kB 🔴 +1.24 kB 🔴 +1.07 kB
assets/InviteMemberUpsellDialogContent-ALrbnUSY.js (removed) 3.48 kB 🟢 -3.48 kB 🟢 -1.24 kB 🟢 -1.08 kB
assets/Media3DTop-BJK9zdPt.js (new) 3.26 kB 🔴 +3.26 kB 🔴 +1.3 kB 🔴 +1.13 kB
assets/Media3DTop-S9kvEtik.js (removed) 3.26 kB 🟢 -3.26 kB 🟢 -1.3 kB 🟢 -1.13 kB
assets/GlobalToast-MEHL46rF.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.26 kB 🟢 -1.08 kB
assets/GlobalToast-nqxmAxTF.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.26 kB 🔴 +1.12 kB
assets/load3dAdvanced-BovHiYti.js (new) 2.85 kB 🔴 +2.85 kB 🔴 +1.11 kB 🔴 +974 B
assets/load3dAdvanced-BQFyIohq.js (removed) 2.85 kB 🟢 -2.85 kB 🟢 -1.12 kB 🟢 -974 B
assets/SubscribeToRun-CV6NiHcg.js (new) 2.53 kB 🔴 +2.53 kB 🔴 +1.1 kB 🔴 +974 B
assets/SubscribeToRun-SBfLKZ5M.js (removed) 2.53 kB 🟢 -2.53 kB 🟢 -1.1 kB 🟢 -989 B
assets/graphHasMissingNodes-D0GnskTh.js (removed) 1.93 kB 🟢 -1.93 kB 🟢 -907 B 🟢 -791 B
assets/graphHasMissingNodes-XT_TW6G5.js (new) 1.93 kB 🔴 +1.93 kB 🔴 +908 B 🔴 +793 B
assets/MediaAudioTop-e4h0c0LW.js (new) 1.67 kB 🔴 +1.67 kB 🔴 +837 B 🔴 +691 B
assets/MediaAudioTop-pZjG6atp.js (removed) 1.67 kB 🟢 -1.67 kB 🟢 -837 B 🟢 -692 B
assets/CloudRunButtonWrapper-CcfwZJA2.js (new) 1.13 kB 🔴 +1.13 kB 🔴 +552 B 🔴 +516 B
assets/CloudRunButtonWrapper-CvDxMtPb.js (removed) 1.13 kB 🟢 -1.13 kB 🟢 -550 B 🟢 -519 B
assets/cloudSessionCookie-BdQ_HoyB.js (removed) 991 B 🟢 -991 B 🟢 -469 B 🟢 -411 B
assets/cloudSessionCookie-Cp5Lwi9x.js (new) 991 B 🔴 +991 B 🔴 +466 B 🔴 +416 B
assets/cloudBadges-Ce__9tQF.js (removed) 973 B 🟢 -973 B 🟢 -550 B 🟢 -497 B
assets/cloudBadges-wDkjK4Co.js (new) 973 B 🔴 +973 B 🔴 +552 B 🔴 +502 B
assets/cloudSubscription-B__x2YMd.js (removed) 820 B 🟢 -820 B 🟢 -455 B 🟢 -366 B
assets/cloudSubscription-CHsZdvaG.js (new) 820 B 🔴 +820 B 🔴 +453 B 🔴 +363 B
assets/Load3DAdvanced-BnNoPvIi.js (new) 813 B 🔴 +813 B 🔴 +453 B 🔴 +404 B
assets/Load3DAdvanced-CWz034a4.js (removed) 813 B 🟢 -813 B 🟢 -455 B 🟢 -409 B
assets/nightlyBadges-4Xw5OKUJ.js (removed) 464 B 🟢 -464 B 🟢 -307 B 🟢 -255 B
assets/nightlyBadges-Bt4ZwSJw.js (new) 464 B 🔴 +464 B 🔴 +307 B 🔴 +254 B
assets/missingModelDownload-C_R7jbUb.js (removed) 228 B 🟢 -228 B 🟢 -148 B 🟢 -129 B
assets/missingModelDownload-CkpXdqef.js (new) 228 B 🔴 +228 B 🔴 +147 B 🔴 +128 B
assets/SubscriptionPanelContentWorkspace-BKTqtjTK.js (removed) 179 B 🟢 -179 B 🟢 -117 B 🟢 -104 B
assets/SubscriptionPanelContentWorkspace-CAZTbjit.js (new) 179 B 🔴 +179 B 🔴 +117 B 🔴 +104 B
assets/Load3dViewerContent-6Gg__Dcs.js (new) 137 B 🔴 +137 B 🔴 +103 B 🔴 +91 B
assets/Load3dViewerContent-BfFKKdNl.js (removed) 137 B 🟢 -137 B 🟢 -103 B 🟢 -92 B
assets/Load3DAdvanced-BhURmrt8.js (new) 122 B 🔴 +122 B 🔴 +97 B 🔴 +91 B
assets/Load3DAdvanced-Kjmqrs_H.js (removed) 122 B 🟢 -122 B 🟢 -97 B 🟢 -86 B
assets/WidgetLegacy-BycRzayY.js (removed) 119 B 🟢 -119 B 🟢 -108 B 🟢 -104 B
assets/WidgetLegacy-DD6mrygY.js (new) 119 B 🔴 +119 B 🔴 +108 B 🔴 +95 B
assets/workflowDraftStoreV2-Bc3p-OCk.js (removed) 113 B 🟢 -113 B 🟢 -105 B 🟢 -109 B
assets/workflowDraftStoreV2-D5UHqOoP.js (new) 113 B 🔴 +113 B 🔴 +105 B 🔴 +107 B
assets/Load3D-GxHgPLmV.js (new) 98 B 🔴 +98 B 🔴 +89 B 🔴 +79 B
assets/Load3D-vKovbDbO.js (removed) 98 B 🟢 -98 B 🟢 -89 B 🟢 -73 B
assets/changeTracker-7rtKDWVi.js (new) 93 B 🔴 +93 B 🔴 +95 B 🔴 +84 B
assets/changeTracker-B1m6geQA.js (removed) 93 B 🟢 -93 B 🟢 -95 B 🟢 -82 B

Status: 62 added / 62 removed / 89 unchanged

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 53.8 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 48.9 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 57.5 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 58.0 MB heap
large-graph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 59.8 MB heap
large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 74.1 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 68.4 MB heap
minimap-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.8 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 63.7 MB heap
subgraph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 53.7 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 45.7 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 176ms TBT · 76.4 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 69.8 MB heap
vue-large-graph-idle: · 57.1 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 487ms TBT · 160.2 MB heap
vue-large-graph-pan: · 57.1 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 3ms TBT · 167.2 MB heap
workflow-execution: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.3 MB heap

⚠️ 10 regressions detected

Show regressions
Metric Baseline PR (median) Δ Sig
canvas-idle: task duration 353ms 483ms +37% ⚠️ z=2.9
canvas-zoom-sweep: layout duration 1ms 1ms +25% ⚠️ z=3.0
canvas-zoom-sweep: task duration 304ms 387ms +27% ⚠️ z=2.6
large-graph-idle: task duration 484ms 675ms +39% ⚠️ z=2.5
large-graph-pan: style recalc duration 19ms 20ms +1% ⚠️ z=2.9
large-graph-pan: task duration 981ms 1261ms +29% ⚠️ z=4.2
large-graph-pan: script duration 343ms 451ms +31% ⚠️ z=2.1
minimap-idle: task duration 495ms 655ms +32% ⚠️ z=2.7
minimap-idle: script duration 84ms 118ms +40% ⚠️ z=2.0
subgraph-idle: task duration 342ms 459ms +34% ⚠️ z=2.8
All metrics
Metric Baseline PR (median) Δ Sig
canvas-idle: avg frame time 17ms 17ms -0% z=-0.5
canvas-idle: p95 frame time 17ms 17ms +0%
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 8ms 10ms +27% z=-1.0
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 11 10 -14% z=-2.9
canvas-idle: task duration 353ms 483ms +37% ⚠️ z=2.9
canvas-idle: script duration 17ms 29ms +66% z=1.5
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: heap used 53.7 MB 53.8 MB +0%
canvas-idle: DOM nodes 22 19 -14% z=-2.8
canvas-idle: event listeners 4 5 +25% z=-1.4
canvas-mouse-sweep: avg frame time 17ms 17ms +0% z=-0.4
canvas-mouse-sweep: p95 frame time 17ms 17ms +0%
canvas-mouse-sweep: layout duration 3ms 4ms +10% z=0.1
canvas-mouse-sweep: style recalc duration 35ms 44ms +28% z=0.5
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 74 77 +4% z=-0.7
canvas-mouse-sweep: task duration 726ms 886ms +22% z=0.4
canvas-mouse-sweep: script duration 112ms 144ms +29% z=1.3
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: heap used 49.2 MB 48.9 MB -0%
canvas-mouse-sweep: DOM nodes 55 60 +9% z=-0.9
canvas-mouse-sweep: event listeners 4 5 +25% z=-0.8
canvas-zoom-sweep: avg frame time 17ms 17ms +0% z=0.5
canvas-zoom-sweep: p95 frame time 17ms 17ms +0%
canvas-zoom-sweep: layout duration 1ms 1ms +25% ⚠️ z=3.0
canvas-zoom-sweep: style recalc duration 16ms 20ms +28% z=0.5
canvas-zoom-sweep: layout count 6 6 +0%
canvas-zoom-sweep: style recalc count 30 32 +5% z=0.5
canvas-zoom-sweep: task duration 304ms 387ms +27% ⚠️ z=2.6
canvas-zoom-sweep: script duration 17ms 30ms +74% z=1.0
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: heap used 57.6 MB 57.5 MB -0%
canvas-zoom-sweep: DOM nodes 77 77 +0% z=-2.8
canvas-zoom-sweep: event listeners 19 19 +0% z=-0.9
dom-widget-clipping: avg frame time 17ms 17ms -0% z=-0.2
dom-widget-clipping: p95 frame time 17ms 17ms -0%
dom-widget-clipping: layout duration 0ms 0ms +0%
dom-widget-clipping: style recalc duration 8ms 10ms +33% z=0.2
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 12 13 +4% z=-1.2
dom-widget-clipping: task duration 333ms 390ms +17% z=1.5
dom-widget-clipping: script duration 57ms 67ms +16% z=-0.4
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: heap used 62.9 MB 58.0 MB -8%
dom-widget-clipping: DOM nodes 20 21 +5% z=-0.8
dom-widget-clipping: event listeners 0 2 variance too high
large-graph-idle: avg frame time 17ms 17ms -0% z=-0.6
large-graph-idle: p95 frame time 17ms 17ms -1%
large-graph-idle: layout duration 0ms 0ms +0%
large-graph-idle: style recalc duration 9ms 10ms +14% z=-1.9
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 12 10 -17% z=-5.1
large-graph-idle: task duration 484ms 675ms +39% ⚠️ z=2.5
large-graph-idle: script duration 79ms 121ms +54% z=1.8
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: heap used 59.2 MB 59.8 MB +1%
large-graph-idle: DOM nodes 24 20 -17% z=-5.2
large-graph-idle: event listeners 4 6 +50% z=-3.3
large-graph-pan: avg frame time 17ms 17ms +0% z=0.3
large-graph-pan: p95 frame time 17ms 17ms -0%
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 19ms 20ms +1% ⚠️ z=2.9
large-graph-pan: layout count 0 0 +0%
large-graph-pan: style recalc count 69 69 -1% z=-1.7
large-graph-pan: task duration 981ms 1261ms +29% ⚠️ z=4.2
large-graph-pan: script duration 343ms 451ms +31% ⚠️ z=2.1
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: heap used 78.7 MB 74.1 MB -6%
large-graph-pan: DOM nodes 20 -127 -733% z=-88.2
large-graph-pan: event listeners 6 -79 -1408% z=-100.8
large-graph-zoom: avg frame time 17ms 17ms -0%
large-graph-zoom: p95 frame time 17ms 17ms +0%
large-graph-zoom: layout duration 8ms 8ms +6%
large-graph-zoom: style recalc duration 20ms 20ms -1%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 67 64 -4%
large-graph-zoom: task duration 1228ms 1511ms +23%
large-graph-zoom: script duration 462ms 566ms +23%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: heap used 64.6 MB 68.4 MB +6%
large-graph-zoom: DOM nodes 16 10 -38%
large-graph-zoom: event listeners 8 8 +0%
minimap-idle: avg frame time 17ms 17ms -0% z=0.1
minimap-idle: p95 frame time 17ms 17ms -0%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 8ms 10ms +20% z=-0.0
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 10 9 -10% z=-0.8
minimap-idle: task duration 495ms 655ms +32% ⚠️ z=2.7
minimap-idle: script duration 84ms 118ms +40% ⚠️ z=2.0
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: heap used 61.9 MB 65.8 MB +6%
minimap-idle: DOM nodes 20 18 -10% z=-0.8
minimap-idle: event listeners 4 6 +50% z=2.2
subgraph-dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.1
subgraph-dom-widget-clipping: p95 frame time 17ms 17ms -0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms +0%
subgraph-dom-widget-clipping: style recalc duration 10ms 13ms +26% z=0.3
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 47 48 +1% z=-0.8
subgraph-dom-widget-clipping: task duration 342ms 402ms +18% z=1.3
subgraph-dom-widget-clipping: script duration 119ms 126ms +6% z=-0.3
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: heap used 63.1 MB 63.7 MB +1%
subgraph-dom-widget-clipping: DOM nodes 20 21 +5% z=-1.1
subgraph-dom-widget-clipping: event listeners 6 8 +33% z=-1.4
subgraph-idle: avg frame time 17ms 17ms -0% z=-0.2
subgraph-idle: p95 frame time 17ms 17ms -1%
subgraph-idle: layout duration 0ms 0ms +0%
subgraph-idle: style recalc duration 8ms 10ms +24% z=-0.4
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 10 11 +5% z=-0.6
subgraph-idle: task duration 342ms 459ms +34% ⚠️ z=2.8
subgraph-idle: script duration 17ms 24ms +44% z=1.5
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: heap used 56.7 MB 53.7 MB -5%
subgraph-idle: DOM nodes 20 21 +5% z=-0.5
subgraph-idle: event listeners 4 4 +0% variance too high
subgraph-mouse-sweep: avg frame time 17ms 17ms +0% z=0.4
subgraph-mouse-sweep: p95 frame time 17ms 17ms -0%
subgraph-mouse-sweep: layout duration 4ms 4ms +12% z=-1.0
subgraph-mouse-sweep: style recalc duration 33ms 39ms +18% z=-1.2
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 76 76 -1% z=-2.4
subgraph-mouse-sweep: task duration 619ms 751ms +21% z=-0.2
subgraph-mouse-sweep: script duration 82ms 103ms +26% z=0.3
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: heap used 45.8 MB 45.7 MB -0%
subgraph-mouse-sweep: DOM nodes 65 63 -3% z=-1.8
subgraph-mouse-sweep: event listeners 4 4 +0% variance too high
subgraph-transition-enter: avg frame time 17ms 17ms +0%
subgraph-transition-enter: p95 frame time 17ms 17ms -1%
subgraph-transition-enter: layout duration 13ms 15ms +19%
subgraph-transition-enter: style recalc duration 28ms 29ms +5%
subgraph-transition-enter: layout count 5 4 -20%
subgraph-transition-enter: style recalc count 18 15 -17%
subgraph-transition-enter: task duration 715ms 874ms +22%
subgraph-transition-enter: script duration 26ms 44ms +68%
subgraph-transition-enter: TBT 139ms 176ms +27%
subgraph-transition-enter: heap used 76.2 MB 76.4 MB +0%
subgraph-transition-enter: DOM nodes 13833 13833 +0%
subgraph-transition-enter: event listeners 2527 2529 +0%
viewport-pan-sweep: avg frame time 17ms 17ms -0%
viewport-pan-sweep: p95 frame time 17ms 17ms -1%
viewport-pan-sweep: layout duration 0ms 0ms +0%
viewport-pan-sweep: style recalc duration 58ms 64ms +10%
viewport-pan-sweep: layout count 0 0 +0%
viewport-pan-sweep: style recalc count 250 251 +0%
viewport-pan-sweep: task duration 3408ms 4506ms +32%
viewport-pan-sweep: script duration 1123ms 1527ms +36%
viewport-pan-sweep: TBT 0ms 0ms +0%
viewport-pan-sweep: heap used 64.3 MB 69.8 MB +9%
viewport-pan-sweep: DOM nodes 22 19 -14%
viewport-pan-sweep: event listeners 20 21 +5%
vue-large-graph-idle: avg frame time 17ms 17ms +2%
vue-large-graph-idle: p95 frame time 17ms 17ms -0%
vue-large-graph-idle: layout duration 0ms 2ms
vue-large-graph-idle: style recalc duration 0ms 1ms
vue-large-graph-idle: layout count 0 1
vue-large-graph-idle: style recalc count 0 1
vue-large-graph-idle: task duration 12695ms 13444ms +6%
vue-large-graph-idle: script duration 553ms 675ms +22%
vue-large-graph-idle: TBT 0ms 487ms
vue-large-graph-idle: heap used 161.7 MB 160.2 MB -1%
vue-large-graph-idle: DOM nodes -3308 -3306 -0%
vue-large-graph-idle: event listeners -16472 -16470 -0%
vue-large-graph-pan: avg frame time 17ms 17ms +2%
vue-large-graph-pan: p95 frame time 17ms 17ms -0%
vue-large-graph-pan: layout duration 0ms 0ms +0%
vue-large-graph-pan: style recalc duration 19ms 21ms +8%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 75 79 +5%
vue-large-graph-pan: task duration 15259ms 15527ms +2%
vue-large-graph-pan: script duration 827ms 920ms +11%
vue-large-graph-pan: TBT 0ms 3ms
vue-large-graph-pan: heap used 161.6 MB 167.2 MB +3%
vue-large-graph-pan: DOM nodes -3308 -3306 -0%
vue-large-graph-pan: event listeners -16468 -16469 +0%
workflow-execution: avg frame time 17ms 17ms -0% z=-0.4
workflow-execution: p95 frame time 17ms 17ms -1%
workflow-execution: layout duration 1ms 2ms +38% z=1.8
workflow-execution: style recalc duration 25ms 25ms +2% z=0.3
workflow-execution: layout count 5 6 +10% z=1.0
workflow-execution: style recalc count 18 15 -17% z=-1.4
workflow-execution: task duration 113ms 125ms +10% z=0.2
workflow-execution: script duration 17ms 22ms +35% z=-2.3
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: heap used 62.0 MB 61.3 MB -1%
workflow-execution: DOM nodes 157 157 +0% z=-0.5
workflow-execution: event listeners 69 53 -23% z=0.3
Historical variance (last 15 runs)
Metric μ σ CV
canvas-idle: avg frame time 17ms 0ms 0.0%
canvas-idle: layout duration 0ms 0ms 0.0%
canvas-idle: style recalc duration 11ms 1ms 8.2%
canvas-idle: layout count 0 0 0.0%
canvas-idle: style recalc count 11 1 5.0%
canvas-idle: task duration 395ms 31ms 7.9%
canvas-idle: script duration 25ms 2ms 8.8%
canvas-idle: TBT 0ms 0ms 0.0%
canvas-idle: DOM nodes 23 1 5.6%
canvas-idle: event listeners 12 5 40.9%
canvas-mouse-sweep: avg frame time 17ms 0ms 0.0%
canvas-mouse-sweep: layout duration 4ms 0ms 5.4%
canvas-mouse-sweep: style recalc duration 43ms 3ms 7.4%
canvas-mouse-sweep: layout count 12 0 0.0%
canvas-mouse-sweep: style recalc count 79 2 3.0%
canvas-mouse-sweep: task duration 865ms 58ms 6.7%
canvas-mouse-sweep: script duration 136ms 6ms 4.8%
canvas-mouse-sweep: TBT 0ms 0ms 0.0%
canvas-mouse-sweep: DOM nodes 62 3 4.2%
canvas-mouse-sweep: event listeners 8 4 49.4%
canvas-zoom-sweep: avg frame time 17ms 0ms 0.0%
canvas-zoom-sweep: layout duration 1ms 0ms 7.0%
canvas-zoom-sweep: style recalc duration 19ms 2ms 8.0%
canvas-zoom-sweep: layout count 6 0 0.0%
canvas-zoom-sweep: style recalc count 31 0 1.5%
canvas-zoom-sweep: task duration 327ms 23ms 7.1%
canvas-zoom-sweep: script duration 27ms 3ms 11.1%
canvas-zoom-sweep: TBT 0ms 0ms 0.0%
canvas-zoom-sweep: DOM nodes 79 1 1.0%
canvas-zoom-sweep: event listeners 24 5 21.8%
dom-widget-clipping: avg frame time 17ms 0ms 0.0%
dom-widget-clipping: layout duration 0ms 0ms 0.0%
dom-widget-clipping: style recalc duration 10ms 1ms 8.0%
dom-widget-clipping: layout count 0 0 0.0%
dom-widget-clipping: style recalc count 13 0 3.8%
dom-widget-clipping: task duration 365ms 16ms 4.5%
dom-widget-clipping: script duration 68ms 3ms 4.8%
dom-widget-clipping: TBT 0ms 0ms 0.0%
dom-widget-clipping: DOM nodes 22 1 6.4%
dom-widget-clipping: event listeners 8 6 81.2%
large-graph-idle: avg frame time 17ms 0ms 0.0%
large-graph-idle: layout duration 0ms 0ms 0.0%
large-graph-idle: style recalc duration 12ms 1ms 8.6%
large-graph-idle: layout count 0 0 0.0%
large-graph-idle: style recalc count 12 0 2.7%
large-graph-idle: task duration 542ms 54ms 10.0%
large-graph-idle: script duration 102ms 11ms 10.3%
large-graph-idle: TBT 0ms 0ms 0.0%
large-graph-idle: DOM nodes 25 1 3.7%
large-graph-idle: event listeners 26 6 23.2%
large-graph-pan: avg frame time 17ms 0ms 0.0%
large-graph-pan: layout duration 0ms 0ms 0.0%
large-graph-pan: style recalc duration 17ms 1ms 4.6%
large-graph-pan: layout count 0 0 0.0%
large-graph-pan: style recalc count 70 1 0.9%
large-graph-pan: task duration 1082ms 43ms 4.0%
large-graph-pan: script duration 408ms 20ms 4.8%
large-graph-pan: TBT 0ms 0ms 0.0%
large-graph-pan: DOM nodes 19 2 8.7%
large-graph-pan: event listeners 5 1 16.8%
minimap-idle: avg frame time 17ms 0ms 0.0%
minimap-idle: layout duration 0ms 0ms 0.0%
minimap-idle: style recalc duration 10ms 1ms 8.6%
minimap-idle: layout count 0 0 0.0%
minimap-idle: style recalc count 10 1 7.1%
minimap-idle: task duration 527ms 47ms 9.0%
minimap-idle: script duration 98ms 10ms 10.1%
minimap-idle: TBT 0ms 0ms 0.0%
minimap-idle: DOM nodes 19 1 7.1%
minimap-idle: event listeners 5 1 14.4%
subgraph-dom-widget-clipping: avg frame time 17ms 0ms 0.0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms 0.0%
subgraph-dom-widget-clipping: style recalc duration 13ms 1ms 7.4%
subgraph-dom-widget-clipping: layout count 0 0 0.0%
subgraph-dom-widget-clipping: style recalc count 48 1 1.2%
subgraph-dom-widget-clipping: task duration 378ms 18ms 4.9%
subgraph-dom-widget-clipping: script duration 128ms 6ms 4.9%
subgraph-dom-widget-clipping: TBT 0ms 0ms 0.0%
subgraph-dom-widget-clipping: DOM nodes 22 1 5.0%
subgraph-dom-widget-clipping: event listeners 16 6 36.0%
subgraph-idle: avg frame time 17ms 0ms 0.0%
subgraph-idle: layout duration 0ms 0ms 0.0%
subgraph-idle: style recalc duration 10ms 1ms 7.5%
subgraph-idle: layout count 0 0 0.0%
subgraph-idle: style recalc count 11 1 6.0%
subgraph-idle: task duration 370ms 31ms 8.5%
subgraph-idle: script duration 20ms 3ms 13.2%
subgraph-idle: TBT 0ms 0ms 0.0%
subgraph-idle: DOM nodes 22 1 6.9%
subgraph-idle: event listeners 10 7 64.5%
subgraph-mouse-sweep: avg frame time 17ms 0ms 0.0%
subgraph-mouse-sweep: layout duration 5ms 0ms 6.8%
subgraph-mouse-sweep: style recalc duration 42ms 3ms 7.8%
subgraph-mouse-sweep: layout count 16 0 0.0%
subgraph-mouse-sweep: style recalc count 80 2 2.4%
subgraph-mouse-sweep: task duration 766ms 69ms 9.0%
subgraph-mouse-sweep: script duration 101ms 7ms 6.5%
subgraph-mouse-sweep: TBT 0ms 0ms 0.0%
subgraph-mouse-sweep: DOM nodes 67 2 3.3%
subgraph-mouse-sweep: event listeners 8 4 52.6%
workflow-execution: avg frame time 17ms 0ms 0.0%
workflow-execution: layout duration 2ms 0ms 9.4%
workflow-execution: style recalc duration 24ms 2ms 9.1%
workflow-execution: layout count 5 1 11.0%
workflow-execution: style recalc count 18 2 11.5%
workflow-execution: task duration 123ms 11ms 8.8%
workflow-execution: script duration 29ms 3ms 10.2%
workflow-execution: TBT 0ms 0ms 0.0%
workflow-execution: DOM nodes 161 7 4.4%
workflow-execution: event listeners 52 4 8.4%
Trend (last 15 commits on main)
Metric Trend Dir Latest
canvas-idle: avg frame time ▆▃▆▁▆▃▆█▆▆▄▃▃▄▃ ➡️ 17ms
canvas-idle: p95 frame time ➡️ NaNms
canvas-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: style recalc duration ▇▇▆▆▃█▄▃▄▃▇▄▁▆▇ ➡️ 11ms
canvas-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
canvas-idle: style recalc count █▃▅▂▅▆▃▁▂▁▂▅▆▅▆ ➡️ 12
canvas-idle: task duration ▃▃▃▆▂▃▃▅▆▂█▃▁▃▃ ➡️ 391ms
canvas-idle: script duration ▄▃▅▇▂▅▃▆▇▅█▄▁▅▆ ➡️ 27ms
canvas-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: heap used ➡️ NaN MB
canvas-idle: DOM nodes █▇▆▅▃▇▃▁▂▂▅▆▆▆▇ ➡️ 24
canvas-idle: event listeners ▅█▅▄▁▅▁▁▁▄▅▅▁▅▄ 📉 11
canvas-mouse-sweep: avg frame time ▆█▆▃▁▃▁▆▆▁▃▆▆▃▃ ➡️ 17ms
canvas-mouse-sweep: p95 frame time ➡️ NaNms
canvas-mouse-sweep: layout duration ▁▃▂▄▁▂▁▃▆▂█▇▆▄▃ ➡️ 4ms
canvas-mouse-sweep: style recalc duration ▄▄▂▄▁▂▃▃▅▄█▆▂▄▄ ➡️ 43ms
canvas-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 12
canvas-mouse-sweep: style recalc count █▅▄▃▂▂▁▄▄▅▆▅▂▇▄ ➡️ 79
canvas-mouse-sweep: task duration █▆▄▂▂▃▂▄▄▅█▆▁▆▄ ➡️ 868ms
canvas-mouse-sweep: script duration ▄▅▄▆▄▆▆▆▅▅█▆▁▅▆ ➡️ 139ms
canvas-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-mouse-sweep: heap used ➡️ NaN MB
canvas-mouse-sweep: DOM nodes █▅▃▃▁▂▂▃▂▄▆▅▃▅▅ ➡️ 64
canvas-mouse-sweep: event listeners █▁▁▁▁▁▇▁▁▁██▇▁█ 📈 13
canvas-zoom-sweep: avg frame time ▅▅█▄▅▁▁▁▅▁▁▅▄▅▁ ➡️ 17ms
canvas-zoom-sweep: p95 frame time ➡️ NaNms
canvas-zoom-sweep: layout duration ▆▅▅▄▁▁█▅▃▅▇▆▁▂▆ ➡️ 1ms
canvas-zoom-sweep: style recalc duration ▆▅▄▆▅▃█▆▇▅▇▄▁▃▅ ➡️ 20ms
canvas-zoom-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 6
canvas-zoom-sweep: style recalc count ▁▁▃▄▆▃▆█▄▄▆▁▆▁▆ ➡️ 32
canvas-zoom-sweep: task duration ▄▂▁▇▂▂▄▅▆▃█▄▁▁▅ ➡️ 338ms
canvas-zoom-sweep: script duration ▃▃▂▇▂▂▅▇▆▅█▄▁▂▆ ➡️ 30ms
canvas-zoom-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-zoom-sweep: heap used ➡️ NaN MB
canvas-zoom-sweep: DOM nodes ▄▃▁▅█▁▃▆▄▅▅▃▃▄▃ ➡️ 79
canvas-zoom-sweep: event listeners ▁▁▂▅█▂▁▅▁▅▅▄▁▅▁ ➡️ 19
dom-widget-clipping: avg frame time ▂▄▅▅▂▄█▇▅▇▇▅▅▁▇ ➡️ 17ms
dom-widget-clipping: p95 frame time ➡️ NaNms
dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: style recalc duration ▆▆▂▆▄▃██▄▁▆▇▆▃▅ ➡️ 10ms
dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
dom-widget-clipping: style recalc count ▇█▅█▅▄█▇▇▁▇▄▇▂▅ ➡️ 13
dom-widget-clipping: task duration ▃▃▁▅▄▃▅▆▅▂▇█▁▅▅ ➡️ 371ms
dom-widget-clipping: script duration ▅▄▄▆▆▅▇▇▆▃█▇▁▇▇ ➡️ 71ms
dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: heap used ➡️ NaN MB
dom-widget-clipping: DOM nodes ▇▇▄▇▅▄█▇▅▁▅▄▇▃▄ ➡️ 21
dom-widget-clipping: event listeners ▅▅▅▅▁▅██▁▁▁▁█▁▁ 📉 2
large-graph-idle: avg frame time ▅▅▅▅▅▂▁▂▄▅▄▂▂▅█ ➡️ 17ms
large-graph-idle: p95 frame time ➡️ NaNms
large-graph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: style recalc duration ▅▅▅▆▄▅▃▄▅▅▆█▁▄▆ ➡️ 13ms
large-graph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-idle: style recalc count █▆█▃▃▁▃▆▃▆▆▃▆██ ➡️ 12
large-graph-idle: task duration ▂▃▂▆▂▃▃▇▅▃██▁▂▅ ➡️ 569ms
large-graph-idle: script duration ▄▅▄▆▄▅▅▇▆▅█▆▁▃▆ ➡️ 110ms
large-graph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: heap used ➡️ NaN MB
large-graph-idle: DOM nodes ▆█▅▂▅▃▁▂▃▅▅▆▂▆▅ ➡️ 25
large-graph-idle: event listeners ███▇██▄▁▄▇▇█▂█▇ ➡️ 29
large-graph-pan: avg frame time ▆▃▃▆█▃▁█▆▆▆▆█▁▆ ➡️ 17ms
large-graph-pan: p95 frame time ➡️ NaNms
large-graph-pan: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: style recalc duration ▃▂▄▄▁▅▂▂▁▄▄█▃▁▂ ➡️ 17ms
large-graph-pan: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-pan: style recalc count ▆▃█▂▃▂▂▂▁▇▅▃█▆▃ ➡️ 69
large-graph-pan: task duration ▄▃▄▆▄▄▄▆▄▄█▆▁▂▅ ➡️ 1100ms
large-graph-pan: script duration ▅▄▅▆▆▅▄▆▄▅█▄▁▄▅ ➡️ 413ms
large-graph-pan: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: heap used ➡️ NaN MB
large-graph-pan: DOM nodes ▅▃▆▂▄▁▃▁▁▅▁▂█▅▂ ➡️ 18
large-graph-pan: event listeners █▆█▁▁▆▁▁▃▆▁▃██▃ ➡️ 5
minimap-idle: avg frame time ▃▆▆▃█▁█▆▆▃▃▆█▆█ ➡️ 17ms
minimap-idle: p95 frame time ➡️ NaNms
minimap-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: style recalc duration ▄█▁█▅▅█▅▅▃▅▁▁▄▆ ➡️ 10ms
minimap-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
minimap-idle: style recalc count ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 9
minimap-idle: task duration ▃▄▁▅▁▃▄▅▇▃█▅▁▁▅ ➡️ 547ms
minimap-idle: script duration ▄▆▃▇▃▅▆▆▇▅█▅▁▃▆ ➡️ 106ms
minimap-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: heap used ➡️ NaN MB
minimap-idle: DOM nodes ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 19
minimap-idle: event listeners ▃▃▆▁▁▁▃▁▁▆▁▃█▆▁ ➡️ 4
subgraph-dom-widget-clipping: avg frame time ▅▄▄▄▄▄█▄▄▄▃▁▆▃▃ ➡️ 17ms
subgraph-dom-widget-clipping: p95 frame time ➡️ NaNms
subgraph-dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: style recalc duration ▂▄▃▅▅▃▂▅▇▃▄█▁▄▆ ➡️ 14ms
subgraph-dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-dom-widget-clipping: style recalc count ▇█▆▃▆▃▁▆█▇▃▆▇█▅ ➡️ 48
subgraph-dom-widget-clipping: task duration ▂▃▃▆▅▅▂▅█▂▆█▁▂▇ ➡️ 398ms
subgraph-dom-widget-clipping: script duration ▃▃▃▄▅▅▂▄█▂▅▇▁▂▅ ➡️ 131ms
subgraph-dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: heap used ➡️ NaN MB
subgraph-dom-widget-clipping: DOM nodes ▅▇▅▂▅▂▁▅▅▅▁▇▅█▄ ➡️ 22
subgraph-dom-widget-clipping: event listeners ▅▅▅▂▅▁▅██▁▁█▅█▅ 📈 16
subgraph-idle: avg frame time ▆▆█▁▆▃▆▆▆▃▆▁▃▆█ ➡️ 17ms
subgraph-idle: p95 frame time ➡️ NaNms
subgraph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: style recalc duration ▁▇▃▆▂▄▂▃▃▆▆▄▃▇█ ➡️ 12ms
subgraph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-idle: style recalc count ▃▆▃▃▂▅▁▂▁▆▃▃██▇ ➡️ 12
subgraph-idle: task duration ▁▃▁▇▁▁▃▆▅▂█▅▁▁▄ ➡️ 378ms
subgraph-idle: script duration ▁▃▂▇▁▂▃▇▆▂█▅▂▁▅ ➡️ 22ms
subgraph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: heap used ➡️ NaN MB
subgraph-idle: DOM nodes ▃▅▃▂▁▄▁▂▁▅▃▂▇█▇ ➡️ 24
subgraph-idle: event listeners ▁▅▁▁▁▁▁▁▁▅▄▁███ 📈 21
subgraph-mouse-sweep: avg frame time ▅▄▁▃▃▄▆▄▆▃▃█▁▃▃ ➡️ 17ms
subgraph-mouse-sweep: p95 frame time ➡️ NaNms
subgraph-mouse-sweep: layout duration ▁▄▄▄▃▃▅▅▅▂█▇▂▃▆ ➡️ 5ms
subgraph-mouse-sweep: style recalc duration ▃▂▄▅▂▃▄▅█▃█▆▁▂▅ ➡️ 43ms
subgraph-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 16
subgraph-mouse-sweep: style recalc count ▅▂▅▅▁▄▃▅█▅▆▄▂▄▅ ➡️ 81
subgraph-mouse-sweep: task duration ▃▂▄▅▂▄▄▅▇▄█▆▁▃▅ ➡️ 785ms
subgraph-mouse-sweep: script duration ▄▅▄▇▅▅▆▇▆▅██▁▄▆ ➡️ 105ms
subgraph-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-mouse-sweep: heap used ➡️ NaN MB
subgraph-mouse-sweep: DOM nodes ▅▁▄▅▁▄▃▃█▅▅▄▂▅▃ ➡️ 66
subgraph-mouse-sweep: event listeners ▇▁▂▇▁▂▂▂█▇▂▂▇▇▂ 📈 5
workflow-execution: avg frame time ▆▆▆▄▆▆▃▄▁▄█▆▅▄▆ ➡️ 17ms
workflow-execution: p95 frame time ➡️ NaNms
workflow-execution: layout duration ▁▆▁▃▂▄▃▂▃▃▅█▄▂▅ ➡️ 2ms
workflow-execution: style recalc duration ▃▇▅▇▁▅▆▇█▁██▂▄▆ ➡️ 25ms
workflow-execution: layout count ▁█▂▃▂▃▃▁▃▃▄▃▂▃▂ ➡️ 5
workflow-execution: style recalc count ▃█▅▇▁▄▅▆▅▅▅▅▄▄▂ ➡️ 15
workflow-execution: task duration ▂▅▄▅▁▄▆▆▆▁▇█▁▃▃ ➡️ 120ms
workflow-execution: script duration ▄▃▄▄▃▅▄▅▆▂▇█▁▃▄ ➡️ 29ms
workflow-execution: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
workflow-execution: heap used ➡️ NaN MB
workflow-execution: DOM nodes ▂█▃▆▁▄▃▅▃█▃▃▄▃▁ ➡️ 152
workflow-execution: event listeners ▅███▁▅███▁██▅█▅ ➡️ 49
Raw data
{
  "timestamp": "2026-06-19T15:32:30.780Z",
  "gitSha": "5c8b0e06d60ac94684661592c01c77e92251fe10",
  "branch": "jaeone/fix-cloud-template-assets-e2e",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2032.3700000000144,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 10.241999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 497.925,
      "heapDeltaBytes": -2079108,
      "heapUsedBytes": 56472056,
      "domNodes": 20,
      "jsHeapTotalBytes": 24641536,
      "scriptDurationMs": 29.918,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "canvas-idle",
      "durationMs": 2013.4259999999813,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 9.661,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 468.65900000000005,
      "heapDeltaBytes": -2406824,
      "heapUsedBytes": 56285692,
      "domNodes": 18,
      "jsHeapTotalBytes": 26214400,
      "scriptDurationMs": 27.413999999999998,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1940.6490000000076,
      "styleRecalcs": 78,
      "styleRecalcDurationMs": 46.117,
      "layouts": 12,
      "layoutDurationMs": 3.633,
      "taskDurationMs": 933.474,
      "heapDeltaBytes": -7371176,
      "heapUsedBytes": 51376808,
      "domNodes": 61,
      "jsHeapTotalBytes": 26214400,
      "scriptDurationMs": 149.54000000000002,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1839.3429999999853,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 42.198,
      "layouts": 12,
      "layoutDurationMs": 3.6359999999999997,
      "taskDurationMs": 838.844,
      "heapDeltaBytes": -7058348,
      "heapUsedBytes": 51276276,
      "domNodes": 59,
      "jsHeapTotalBytes": 26214400,
      "scriptDurationMs": 138.393,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1726.1780000000044,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 19.505000000000003,
      "layouts": 6,
      "layoutDurationMs": 0.806,
      "taskDurationMs": 384.407,
      "heapDeltaBytes": 1479704,
      "heapUsedBytes": 60195600,
      "domNodes": 76,
      "jsHeapTotalBytes": 25690112,
      "scriptDurationMs": 28.456,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1748.6410000000205,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 20.255000000000003,
      "layouts": 6,
      "layoutDurationMs": 0.755,
      "taskDurationMs": 388.967,
      "heapDeltaBytes": 1724648,
      "heapUsedBytes": 60301852,
      "domNodes": 78,
      "jsHeapTotalBytes": 26738688,
      "scriptDurationMs": 31.552999999999997,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 587.9560000000197,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 10.095,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 382.315,
      "heapDeltaBytes": 7611316,
      "heapUsedBytes": 66126260,
      "domNodes": 22,
      "jsHeapTotalBytes": 17301504,
      "scriptDurationMs": 65.026,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 606.7669999999907,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 9.964999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 397.093,
      "heapDeltaBytes": -14166424,
      "heapUsedBytes": 55469956,
      "domNodes": 20,
      "jsHeapTotalBytes": 23379968,
      "scriptDurationMs": 68.134,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2035.2080000000115,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 10.736000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 696.329,
      "heapDeltaBytes": -7598136,
      "heapUsedBytes": 62657812,
      "domNodes": 20,
      "jsHeapTotalBytes": 10891264,
      "scriptDurationMs": 128.577,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2018.4619999999995,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 9.802999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 653.559,
      "heapDeltaBytes": -9016896,
      "heapUsedBytes": 62662256,
      "domNodes": 20,
      "jsHeapTotalBytes": 9580544,
      "scriptDurationMs": 113.588,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2217.1389999999747,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 19.738000000000003,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1301.5159999999998,
      "heapDeltaBytes": 9247848,
      "heapUsedBytes": 72080920,
      "domNodes": -267,
      "jsHeapTotalBytes": 6246400,
      "scriptDurationMs": 476.342,
      "eventListeners": -161,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2126.871999999935,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 19.432000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1221.2969999999998,
      "heapDeltaBytes": 10318560,
      "heapUsedBytes": 83408868,
      "domNodes": 14,
      "jsHeapTotalBytes": 9232384,
      "scriptDurationMs": 424.736,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3198.3109999999897,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 19.479,
      "layouts": 60,
      "layoutDurationMs": 8.331000000000001,
      "taskDurationMs": 1471.4910000000002,
      "heapDeltaBytes": 15139728,
      "heapUsedBytes": 70640884,
      "domNodes": 10,
      "jsHeapTotalBytes": 5505024,
      "scriptDurationMs": 537.63,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3279.390000000035,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 20.465,
      "layouts": 60,
      "layoutDurationMs": 8.572,
      "taskDurationMs": 1551.142,
      "heapDeltaBytes": 17117608,
      "heapUsedBytes": 72779580,
      "domNodes": 10,
      "jsHeapTotalBytes": 7864320,
      "scriptDurationMs": 594.248,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2021.19399999998,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 10.276,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 674.6220000000001,
      "heapDeltaBytes": 12049040,
      "heapUsedBytes": 74111404,
      "domNodes": 18,
      "jsHeapTotalBytes": 13950976,
      "scriptDurationMs": 120.63399999999999,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "minimap-idle",
      "durationMs": 2004.9870000000283,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.809000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 634.8130000000001,
      "heapDeltaBytes": -9544692,
      "heapUsedBytes": 63966604,
      "domNodes": 18,
      "jsHeapTotalBytes": 7483392,
      "scriptDurationMs": 115.427,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 617.3320000000331,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 14.351,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 416.447,
      "heapDeltaBytes": 8037408,
      "heapUsedBytes": 66823840,
      "domNodes": 22,
      "jsHeapTotalBytes": 17825792,
      "scriptDurationMs": 130.816,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 583.4290000000237,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 11.709000000000003,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 388.377,
      "heapDeltaBytes": 8002056,
      "heapUsedBytes": 66823188,
      "domNodes": 20,
      "jsHeapTotalBytes": 18874368,
      "scriptDurationMs": 121.74100000000001,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 1990.6070000000113,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.46,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 466.19699999999995,
      "heapDeltaBytes": -2680484,
      "heapUsedBytes": 56077720,
      "domNodes": 22,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 24.142,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-idle",
      "durationMs": 1990.4109999999946,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 9.791,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 451.658,
      "heapDeltaBytes": -2246904,
      "heapUsedBytes": 56542052,
      "domNodes": 20,
      "jsHeapTotalBytes": 26214400,
      "scriptDurationMs": 24.499999999999996,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1706.0529999999972,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 37.95399999999999,
      "layouts": 16,
      "layoutDurationMs": 4.335,
      "taskDurationMs": 744.2869999999999,
      "heapDeltaBytes": -10706056,
      "heapUsedBytes": 47961368,
      "domNodes": 65,
      "jsHeapTotalBytes": 26214400,
      "scriptDurationMs": 103.623,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1690.5380000000605,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 39.283,
      "layouts": 16,
      "layoutDurationMs": 4.399,
      "taskDurationMs": 758.1610000000001,
      "heapDeltaBytes": -10923136,
      "heapUsedBytes": 47851928,
      "domNodes": 61,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 102.505,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 1400.6299999999783,
      "styleRecalcs": 15,
      "styleRecalcDurationMs": 29.327000000000005,
      "layouts": 4,
      "layoutDurationMs": 15.045,
      "taskDurationMs": 874.273,
      "heapDeltaBytes": 4581560,
      "heapUsedBytes": 80088520,
      "domNodes": 13833,
      "jsHeapTotalBytes": 17039360,
      "scriptDurationMs": 43.646,
      "eventListeners": 2529,
      "totalBlockingTimeMs": 176,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8262.75499999997,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 60.855000000000004,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4317.233,
      "heapDeltaBytes": -2671332,
      "heapUsedBytes": 67485584,
      "domNodes": 20,
      "jsHeapTotalBytes": 19456000,
      "scriptDurationMs": 1373.665,
      "eventListeners": 20,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8338.943000000087,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 67.023,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4694.521,
      "heapDeltaBytes": 7001172,
      "heapUsedBytes": 78916968,
      "domNodes": 18,
      "jsHeapTotalBytes": 23650304,
      "scriptDurationMs": 1680.367,
      "eventListeners": 22,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 13725.139000000014,
      "styleRecalcs": 1,
      "styleRecalcDurationMs": 1.5899999999999803,
      "layouts": 1,
      "layoutDurationMs": 3.392999999999993,
      "taskDurationMs": 13696.340000000002,
      "heapDeltaBytes": -37232852,
      "heapUsedBytes": 169761320,
      "domNodes": -3307,
      "jsHeapTotalBytes": 26447872,
      "scriptDurationMs": 687.2640000000001,
      "eventListeners": -16467,
      "totalBlockingTimeMs": 974,
      "frameDurationMs": 17.776666666666763,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 13212.455999999975,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 13192.634999999998,
      "heapDeltaBytes": -42214548,
      "heapUsedBytes": 166234724,
      "domNodes": -3304,
      "jsHeapTotalBytes": 20418560,
      "scriptDurationMs": 663.24,
      "eventListeners": -16473,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.219999999999953,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 15512.685000000034,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 20.506999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 15484.577000000001,
      "heapDeltaBytes": -36941812,
      "heapUsedBytes": 171695152,
      "domNodes": -3308,
      "jsHeapTotalBytes": 17711104,
      "scriptDurationMs": 908.859,
      "eventListeners": -16467,
      "totalBlockingTimeMs": 5,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 15597.392000000014,
      "styleRecalcs": 80,
      "styleRecalcDurationMs": 21.10500000000004,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 15570.088000000002,
      "heapDeltaBytes": -15366748,
      "heapUsedBytes": 178970168,
      "domNodes": -3303,
      "jsHeapTotalBytes": 17711104,
      "scriptDurationMs": 931.357,
      "eventListeners": -16470,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.223333333333237,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 469.0409999999474,
      "styleRecalcs": 19,
      "styleRecalcDurationMs": 28.171,
      "layouts": 6,
      "layoutDurationMs": 1.8110000000000002,
      "taskDurationMs": 142.75499999999997,
      "heapDeltaBytes": 5539712,
      "heapUsedBytes": 65281476,
      "domNodes": 168,
      "jsHeapTotalBytes": 3145728,
      "scriptDurationMs": 25.253999999999998,
      "eventListeners": 69,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 145.13800000008814,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 21.714000000000006,
      "layouts": 5,
      "layoutDurationMs": 1.817,
      "taskDurationMs": 107.61900000000001,
      "heapDeltaBytes": 3418316,
      "heapUsedBytes": 63335304,
      "domNodes": 146,
      "jsHeapTotalBytes": 1572864,
      "scriptDurationMs": 19.504,
      "eventListeners": 37,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.700000000000273
    }
  ]
}

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 19, 2026
@codecov

codecov Bot commented Jun 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

@@            Coverage Diff             @@
##             main   #12999      +/-   ##
==========================================
- Coverage   76.35%   76.13%   -0.22%     
==========================================
  Files        1573     1574       +1     
  Lines       88149    95451    +7302     
  Branches    26621    28756    +2135     
==========================================
+ Hits        67305    72672    +5367     
- Misses      20190    21991    +1801     
- Partials      654      788     +134     
Flag Coverage Δ
unit 62.98% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.
see 129 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jaeone94 jaeone94 marked this pull request as ready for review June 19, 2026 11:23
@jaeone94 jaeone94 requested a review from a team June 19, 2026 11:23
@dosubot dosubot Bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Jun 19, 2026
@jaeone94 jaeone94 requested a review from DrJKL June 19, 2026 12:41

@DrJKL DrJKL left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approving. Validated the route interception against the production path: workflowTemplatesStore.loadWorkflowTemplates()api.getWorkflowTemplates()fetchApi('/workflow_templates')apiURL() prepends /api, so the request resolves to <api_base>/api/workflow_templates, which the glob matches on both cloud and local. The empty {} body matches the declared { [name: string]: string[] } shape, and the mock is necessary — switching to createCloudAssetsFixture([]) runs these as @cloud, so without it the real custom templates would leak into the exact-count assertions. Cleanup is correct (handler is pushed to routeHandlers and unrouted in clearMocks).

All inline notes below are non-blocking polish.

}

async mockIndex(): Promise<void> {
const customTemplatesHandler = async (route: Route) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Route interception is correct and necessary here — confirmed it matches <api_base>/api/workflow_templates and that the empty {} keeps the asserted template counts deterministic.

Nit (optional): this custom-templates mock lives inside mockIndex(), which otherwise only concerns the core index. It works because every test calls mockIndex(), but a dedicated mockCustomTemplates() invoked from mock() would read more truthfully.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed, this is a valid readability cleanup. I kept the custom templates mock colocated with the existing template index mocking in this PR because the change was intentionally scoped to stabilizing the cloud template count E2E, and I wanted to avoid widening it into fixture refactoring while we continue the missing model detection work before .46 becomes stable.

This would be better handled as follow-up cleanup rather than mixed into this stabilization PR.

@coderabbitai please create an issue for this and assign it to me.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

gh issue create \
  --repo "Comfy-Org/ComfyUI_frontend" \
  --title "Refactor TemplateHelper: extract mockCustomTemplates() from mockIndex()" \
  --assignee "jaeone94" \
  --body "## Summary

Currently, \`TemplateHelper.mockIndex()\` in \`browser_tests/fixtures/helpers/TemplateHelper.ts\` contains two responsibilities:
1. Mocking the core template index (\`**/templates/index.json\`)
2. Mocking the custom templates endpoint (\`**/api/workflow_templates\`)

For readability and separation of concerns, the custom-templates mock should be extracted into a dedicated \`mockCustomTemplates()\` method that is invoked from the top-level \`mock()\` method (alongside \`mockIndex()\` and \`mockThumbnails()\`).

## Proposed change

Extract the \`customTemplatesHandler\` block from \`mockIndex()\` into a new \`mockCustomTemplates(): Promise<void>\` method, and call it from \`mock()\`.

## Context

Identified during review of PR `#12999` (comment: https://github.com/Comfy-Org/ComfyUI_frontend/pull/12999#discussion_r3443589794).
The current colocated placement was intentional in that PR to keep the stabilization change scoped — this refactor is deferred as follow-up cleanup."

Length of output: 1310



@jaeone94, the follow-up issue has been created and assigned to you: #13016 — Refactor TemplateHelper: extract mockCustomTemplates() from mockIndex(). It includes the full context from this discussion so nothing gets lost.


🧠 Learnings used
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8248
File: src/platform/assets/schemas/assetSchema.ts:109-118
Timestamp: 2026-01-22T23:44:59.888Z
Learning: Do not export declarations (e.g., schemas, constants, types) unless they are actually used elsewhere in the codebase. Keep the public API surface minimal by exporting only items with concrete usage. This reduces coupling and keeps imports explicit. In src/platform/assets/schemas/assetSchema.ts, ensure only necessary exports are exposed; remove unused exports or switch to non-exported/internal where appropriate.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8722
File: src/composables/maskeditor/useBrushDrawing.ts:5-5
Timestamp: 2026-02-08T03:19:12.009Z
Learning: Treat unresolved import warnings caused by pnpm workspace catalog mappings (pnpm-workspace.yaml) and unplugin-typegpu in vite.config.mts as false positives. Do not flag these in PR reviews; they are expected in sandboxes without node_modules and are not indicative of actual missing dependencies in the TS codebase.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8966
File: src/extensions/core/load3d.ts:427-430
Timestamp: 2026-02-19T02:06:23.468Z
Learning: In TypeScript, you can use typeof SomeClass in type annotation positions (e.g., param: typeof LGraphNode) even when SomeClass is imported with import type. This is a type query that only exists at compile time and is erased in runtime, so it is safe to combine with type-only imports. Apply this pattern to TS files broadly when you need a type that references the shape of a class or constructor function without importing the value at runtime.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8966
File: src/extensions/core/uploadAudio.ts:91-94
Timestamp: 2026-02-19T02:06:38.395Z
Learning: In TypeScript files, you can use a type annotation like 'nodeType: typeof MyClass' even if MyClass is imported via 'import type'. Both the type-only import and 'typeof' operate at the type level and are erased at compile time. This pattern is commonly used for constructor types (e.g., 'nodeType: typeof LGraphNode'). Apply this pattern across TypeScript files in the repository (src/**/*.ts) as appropriate, ensuring the imported symbol is a type-only import when possible for clarity and to avoid runtime imports.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8992
File: src/lib/litegraph/src/widgets/GradientSliderWidget.ts:18-18
Timestamp: 2026-02-20T21:08:19.814Z
Learning: When drawing with CanvasRenderingContext2D in TypeScript/JavaScript, wrap the drawing logic with ctx.save() at the start and ctx.restore() at the end to preserve and restore the canvas state. Do not manually destructure and restore individual properties (e.g., fillStyle, strokeStyle); rely on save/restore to manage state changes in a scoped manner. This should be applied to all TS files that perform canvas drawing.

Learnt from: dante01yoon
Repo: Comfy-Org/ComfyUI_frontend PR: 9075
File: src/scripts/api.featureFlags.test.ts:237-268
Timestamp: 2026-02-22T04:27:33.379Z
Learning: In Vite/Vitest, import.meta.env.DEV is true for any mode that is not 'production' (i.e., DEV is the opposite of PROD, and can be true in 'test', 'development', etc.). Do not assume DEV implies only 'development' mode. When reviewing code and tests, treat DEV as a non-production flag and verify environment-specific logic accordingly. Reference: https://vite.dev/guide/env-and-mode#modes

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 9427
File: src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownMenuFilter.vue:33-33
Timestamp: 2026-03-06T00:53:28.835Z
Learning: When reviewing code, note that the enforce-canonical-classes (better-tailwindcss) rule may auto-fix Tailwind v3 !class-name syntax by converting it to v4 class-name! syntax. Do not treat these auto-fixed class-name! instances as newly introduced issues; the perceived change is in syntax placement, not in usage or intent. This guidance applies across all .vue and .ts files in the repository.

Learnt from: sonnybox
Repo: Comfy-Org/ComfyUI_frontend PR: 9446
File: src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue:45-45
Timestamp: 2026-03-06T01:55:00.013Z
Learning: Treat wrap-break-word as a valid Tailwind CSS utility for overflow-wrap: break-word in Tailwind v4+ projects. Do not flag this class as invalid in any Vue (.vue) or TypeScript (.ts/.tsx) files within the repository (e.g., Comfy-Org/ComfyUI_frontend) or other Tailwind v4+ projects. When reviewing, verify that the class is used to enable word breaking in long text content and reference the Tailwind docs: https://tailwindcss.com/docs/overflow-wrap.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 9554
File: browser_tests/fixtures/ComfyPage.ts:189-193
Timestamp: 2026-03-12T10:03:55.383Z
Learning: In browser_tests, seed localStorage-based feature flags at init time using FeatureFlagHelper.seedFlags() (which uses page.addInitScript) before any navigation. Ensure this happens before comfyPage.setup() is called. The comfyPageFixture currently yields after calling comfyPage.setup(), so do not defer setup() from the fixture or add a pre-setup hook, as changing this would break existing tests.

Learnt from: Yourz
Repo: Comfy-Org/ComfyUI_frontend PR: 10310
File: browser_tests/tests/topbarMenuDismissal.spec.ts:0-0
Timestamp: 2026-03-19T16:16:40.350Z
Learning: In Comfy-Org/ComfyUI_frontend, when reviewing changes limited to adding/revising `:modal="false"` (or similar modal/non-modal behavior props) on reakit-ui/reka-ui primitives such as `ContextMenuRoot` and `DropdownMenuRoot`, do not request Playwright/E2E regression coverage solely for that prop-level change. The dismissal behavior for modal vs non-modal is documented and tested upstream in the reka-ui library; only ask for E2E tests when the change affects ComfyUI_frontend behavior beyond these primitive prop wiring differences (e.g., custom logic, integration behavior, or new user flows not covered upstream).

Learnt from: jaeone94
Repo: Comfy-Org/ComfyUI_frontend PR: 10741
File: browser_tests/fixtures/helpers/boundsUtils.ts:32-45
Timestamp: 2026-03-31T12:17:31.232Z
Learning: In this codebase’s Playwright E2E test helpers under `browser_tests/fixtures/helpers/`, prefer measuring collapsed node dimensions directly from the DOM using `offsetWidth`/`offsetHeight`. Do not access Pinia stores from within `page.evaluate` blocks in E2E helpers (e.g., avoid calling `getNodeCollapsedSize()` or reading from `layoutStore`). This is intentional: E2E helpers should validate the final user-visible result, while Pinia store synchronization correctness is expected to be covered by unit tests.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/bottomPanelLogs.spec.ts:4-4
Timestamp: 2026-04-08T18:09:35.787Z
Learning: In this repo’s E2E browser tests, do not flag `import-x/no-unresolved` for imports using the `e2e/*` path alias. CodeRabbit sandbox reports these as unresolved because it may not run a full `pnpm install`; `e2e/*` is defined in the root `tsconfig.json` and the related `apps/website/tsconfig.json`/workspace dependency resolution only works when dependencies are installed. Apply this only to `browser_tests/**/*.ts` files.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/subgraph/subgraphSearch.spec.ts:3-4
Timestamp: 2026-04-08T18:09:50.771Z
Learning: In Comfy-Org/ComfyUI_frontend browser tests (browser_tests/**/*.ts), do not report `import-x/no-unresolved` for imports using the `e2e/*` alias. The alias is defined in the root tsconfig.json as `"e2e/*": ["./browser_tests/*"]`, and eslint.config.ts includes the correct tsconfig `project` list; lint passes locally and in CI. Treat any `e2e/*` unresolved-import findings in the CodeRabbit sandbox as false positives.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/rightClickMenu.spec.ts:3-5
Timestamp: 2026-04-08T18:10:12.748Z
Learning: In Comfy-Org/ComfyUI_frontend, `import-x/no-unresolved` errors caused by `@/` (src alias) and `e2e/` (browser_tests alias) imports inside `browser_tests/**/*.ts` are false positives in CodeRabbit’s sandbox because the sandbox cannot resolve the root `tsconfig.json` (it extends `astro/tsconfigs/strict`), which breaks the TypeScript import resolver. Since ESLint passes clean locally and in CI, do not treat these specific `@/` and `e2e/` unresolved import findings as real issues, and do not recommend adding `browser_tests/tsconfig.json` (or similar) to ESLint/CodeRabbit resolver project lists for this case.

Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 11531
File: src/composables/maskeditor/brushDrawingUtils.ts:14-14
Timestamp: 2026-04-22T04:06:01.353Z
Learning: In the Comfy-Org/ComfyUI_frontend codebase, `knip` is used to detect unused exports. When reviewing TypeScript/TSX code, avoid recommending or introducing exported types/functions/constants that have no concrete external consumers (e.g., they’re only used within the same module). Only recommend exporting when there is an actual external usage outside the module. If something might be needed externally later, keep it non-exported for now and defer exporting until an external consumer is added.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 12197
File: src/renderer/extensions/linearMode/AppInput.vue:23-23
Timestamp: 2026-05-14T21:10:45.382Z
Learning: In the ComfyUI_frontend repo, `WidgetEntityId` is a branded template-literal type (e.g., `${UUID}:${NodeId}:${string}`) and should be treated as structurally non-empty when valid—so an empty string is invalid and must be treated as “absent”. When handling optional `entityId?: WidgetEntityId` values (e.g., for Vue props or TS function parameters), guard missing/invalid IDs with a truthy check (e.g., `if (!entityId) return`) rather than `if (entityId === undefined)`. Rationale: `=== undefined` would allow empty-string values through into stores such as `appModeStore.selectedInputs`, creating rows that can’t resolve back to a widget.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 12197
File: src/core/schemas/parseNodePropertyArray.ts:1-1
Timestamp: 2026-05-18T21:34:41.153Z
Learning: In TypeScript, it is correct to use `import type { z } from 'zod'` when the imported symbol `z` is used exclusively in type-annotation/type-only positions (e.g., `schema: z.ZodType<T[]>`, `z.infer<typeof schema>`, `type X = z.AnyZodObject`, etc.). Because `import type` is fully erased at compile time and requires no runtime value, code reviewers should not flag `import type { z }` as an error (e.g., as an unused value import or incorrect runtime import) in TypeScript/React projects when `z` is only referenced in type positions. If `z` is referenced in a value/runtime position, it should instead be imported with a normal `import { z } from 'zod'`.

Comment on lines +73 to +76
const customTemplates: Record<string, string[]> = {}
await route.fulfill({
status: 200,
body: JSON.stringify(customTemplates),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The typed local customTemplates then JSON.stringify(customTemplates) is indirection for an empty object — inline it.

Suggested change
const customTemplates: Record<string, string[]> = {}
await route.fulfill({
status: 200,
body: JSON.stringify(customTemplates),
await route.fulfill({
status: 200,
body: '{}',

@jaeone94 jaeone94 Jun 19, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed, this is a valid nit. The inline body: '{}' form is simpler for this fixed empty response. I left it as-is here because I wanted to avoid another non-functional review round on this already-approved stabilization PR while we continue toward the missing model detection changes before .46 becomes stable.

@coderabbitai please create an issue for this and assign it to me.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

gh issue create \
  --repo "Comfy-Org/ComfyUI_frontend" \
  --title "Simplify TemplateHelper.mockIndex(): inline '{}' instead of JSON.stringify(customTemplates)" \
  --assignee "jaeone94" \
  --body "## Summary

In \`browser_tests/fixtures/helpers/TemplateHelper.ts\`, the \`mockIndex()\` method constructs an unnecessary intermediate variable before serializing it:

\`\`\`ts
const customTemplates: Record<string, string[]> = {}
await route.fulfill({
  status: 200,
  body: JSON.stringify(customTemplates),
  ...
})
\`\`\`

Since the response is always a fixed empty object, the typed local variable and \`JSON.stringify\` call are indirection that can be replaced with an inlined string literal:

\`\`\`ts
await route.fulfill({
  status: 200,
  body: '{}',
  ...
})
\`\`\`

## Context

This was flagged as a nit during review of PR `#12999` (comment: https://github.com/Comfy-Org/ComfyUI_frontend/pull/12999#discussion_r3443589801). It was deferred from that PR to avoid a non-functional review round on an already-approved stabilization PR.

Requested by `@jaeone94`."

Length of output: 1202



@jaeone94, I've created the follow-up issue and assigned it to you: #13014

🐇 (ᵔᴥᵔ)


🧠 Learnings used
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8248
File: src/platform/assets/schemas/assetSchema.ts:109-118
Timestamp: 2026-01-22T23:44:59.888Z
Learning: Do not export declarations (e.g., schemas, constants, types) unless they are actually used elsewhere in the codebase. Keep the public API surface minimal by exporting only items with concrete usage. This reduces coupling and keeps imports explicit. In src/platform/assets/schemas/assetSchema.ts, ensure only necessary exports are exposed; remove unused exports or switch to non-exported/internal where appropriate.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8722
File: src/composables/maskeditor/useBrushDrawing.ts:5-5
Timestamp: 2026-02-08T03:19:12.009Z
Learning: Treat unresolved import warnings caused by pnpm workspace catalog mappings (pnpm-workspace.yaml) and unplugin-typegpu in vite.config.mts as false positives. Do not flag these in PR reviews; they are expected in sandboxes without node_modules and are not indicative of actual missing dependencies in the TS codebase.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8966
File: src/extensions/core/load3d.ts:427-430
Timestamp: 2026-02-19T02:06:23.468Z
Learning: In TypeScript, you can use typeof SomeClass in type annotation positions (e.g., param: typeof LGraphNode) even when SomeClass is imported with import type. This is a type query that only exists at compile time and is erased in runtime, so it is safe to combine with type-only imports. Apply this pattern to TS files broadly when you need a type that references the shape of a class or constructor function without importing the value at runtime.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8966
File: src/extensions/core/uploadAudio.ts:91-94
Timestamp: 2026-02-19T02:06:38.395Z
Learning: In TypeScript files, you can use a type annotation like 'nodeType: typeof MyClass' even if MyClass is imported via 'import type'. Both the type-only import and 'typeof' operate at the type level and are erased at compile time. This pattern is commonly used for constructor types (e.g., 'nodeType: typeof LGraphNode'). Apply this pattern across TypeScript files in the repository (src/**/*.ts) as appropriate, ensuring the imported symbol is a type-only import when possible for clarity and to avoid runtime imports.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8992
File: src/lib/litegraph/src/widgets/GradientSliderWidget.ts:18-18
Timestamp: 2026-02-20T21:08:19.814Z
Learning: When drawing with CanvasRenderingContext2D in TypeScript/JavaScript, wrap the drawing logic with ctx.save() at the start and ctx.restore() at the end to preserve and restore the canvas state. Do not manually destructure and restore individual properties (e.g., fillStyle, strokeStyle); rely on save/restore to manage state changes in a scoped manner. This should be applied to all TS files that perform canvas drawing.

Learnt from: dante01yoon
Repo: Comfy-Org/ComfyUI_frontend PR: 9075
File: src/scripts/api.featureFlags.test.ts:237-268
Timestamp: 2026-02-22T04:27:33.379Z
Learning: In Vite/Vitest, import.meta.env.DEV is true for any mode that is not 'production' (i.e., DEV is the opposite of PROD, and can be true in 'test', 'development', etc.). Do not assume DEV implies only 'development' mode. When reviewing code and tests, treat DEV as a non-production flag and verify environment-specific logic accordingly. Reference: https://vite.dev/guide/env-and-mode#modes

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 9427
File: src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownMenuFilter.vue:33-33
Timestamp: 2026-03-06T00:53:28.835Z
Learning: When reviewing code, note that the enforce-canonical-classes (better-tailwindcss) rule may auto-fix Tailwind v3 !class-name syntax by converting it to v4 class-name! syntax. Do not treat these auto-fixed class-name! instances as newly introduced issues; the perceived change is in syntax placement, not in usage or intent. This guidance applies across all .vue and .ts files in the repository.

Learnt from: sonnybox
Repo: Comfy-Org/ComfyUI_frontend PR: 9446
File: src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue:45-45
Timestamp: 2026-03-06T01:55:00.013Z
Learning: Treat wrap-break-word as a valid Tailwind CSS utility for overflow-wrap: break-word in Tailwind v4+ projects. Do not flag this class as invalid in any Vue (.vue) or TypeScript (.ts/.tsx) files within the repository (e.g., Comfy-Org/ComfyUI_frontend) or other Tailwind v4+ projects. When reviewing, verify that the class is used to enable word breaking in long text content and reference the Tailwind docs: https://tailwindcss.com/docs/overflow-wrap.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 9554
File: browser_tests/fixtures/ComfyPage.ts:189-193
Timestamp: 2026-03-12T10:03:55.383Z
Learning: In browser_tests, seed localStorage-based feature flags at init time using FeatureFlagHelper.seedFlags() (which uses page.addInitScript) before any navigation. Ensure this happens before comfyPage.setup() is called. The comfyPageFixture currently yields after calling comfyPage.setup(), so do not defer setup() from the fixture or add a pre-setup hook, as changing this would break existing tests.

Learnt from: Yourz
Repo: Comfy-Org/ComfyUI_frontend PR: 10310
File: browser_tests/tests/topbarMenuDismissal.spec.ts:0-0
Timestamp: 2026-03-19T16:16:40.350Z
Learning: In Comfy-Org/ComfyUI_frontend, when reviewing changes limited to adding/revising `:modal="false"` (or similar modal/non-modal behavior props) on reakit-ui/reka-ui primitives such as `ContextMenuRoot` and `DropdownMenuRoot`, do not request Playwright/E2E regression coverage solely for that prop-level change. The dismissal behavior for modal vs non-modal is documented and tested upstream in the reka-ui library; only ask for E2E tests when the change affects ComfyUI_frontend behavior beyond these primitive prop wiring differences (e.g., custom logic, integration behavior, or new user flows not covered upstream).

Learnt from: jaeone94
Repo: Comfy-Org/ComfyUI_frontend PR: 10741
File: browser_tests/fixtures/helpers/boundsUtils.ts:32-45
Timestamp: 2026-03-31T12:17:31.232Z
Learning: In this codebase’s Playwright E2E test helpers under `browser_tests/fixtures/helpers/`, prefer measuring collapsed node dimensions directly from the DOM using `offsetWidth`/`offsetHeight`. Do not access Pinia stores from within `page.evaluate` blocks in E2E helpers (e.g., avoid calling `getNodeCollapsedSize()` or reading from `layoutStore`). This is intentional: E2E helpers should validate the final user-visible result, while Pinia store synchronization correctness is expected to be covered by unit tests.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/bottomPanelLogs.spec.ts:4-4
Timestamp: 2026-04-08T18:09:35.787Z
Learning: In this repo’s E2E browser tests, do not flag `import-x/no-unresolved` for imports using the `e2e/*` path alias. CodeRabbit sandbox reports these as unresolved because it may not run a full `pnpm install`; `e2e/*` is defined in the root `tsconfig.json` and the related `apps/website/tsconfig.json`/workspace dependency resolution only works when dependencies are installed. Apply this only to `browser_tests/**/*.ts` files.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/subgraph/subgraphSearch.spec.ts:3-4
Timestamp: 2026-04-08T18:09:50.771Z
Learning: In Comfy-Org/ComfyUI_frontend browser tests (browser_tests/**/*.ts), do not report `import-x/no-unresolved` for imports using the `e2e/*` alias. The alias is defined in the root tsconfig.json as `"e2e/*": ["./browser_tests/*"]`, and eslint.config.ts includes the correct tsconfig `project` list; lint passes locally and in CI. Treat any `e2e/*` unresolved-import findings in the CodeRabbit sandbox as false positives.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/rightClickMenu.spec.ts:3-5
Timestamp: 2026-04-08T18:10:12.748Z
Learning: In Comfy-Org/ComfyUI_frontend, `import-x/no-unresolved` errors caused by `@/` (src alias) and `e2e/` (browser_tests alias) imports inside `browser_tests/**/*.ts` are false positives in CodeRabbit’s sandbox because the sandbox cannot resolve the root `tsconfig.json` (it extends `astro/tsconfigs/strict`), which breaks the TypeScript import resolver. Since ESLint passes clean locally and in CI, do not treat these specific `@/` and `e2e/` unresolved import findings as real issues, and do not recommend adding `browser_tests/tsconfig.json` (or similar) to ESLint/CodeRabbit resolver project lists for this case.

Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 11531
File: src/composables/maskeditor/brushDrawingUtils.ts:14-14
Timestamp: 2026-04-22T04:06:01.353Z
Learning: In the Comfy-Org/ComfyUI_frontend codebase, `knip` is used to detect unused exports. When reviewing TypeScript/TSX code, avoid recommending or introducing exported types/functions/constants that have no concrete external consumers (e.g., they’re only used within the same module). Only recommend exporting when there is an actual external usage outside the module. If something might be needed externally later, keep it non-exported for now and defer exporting until an external consumer is added.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 12197
File: src/renderer/extensions/linearMode/AppInput.vue:23-23
Timestamp: 2026-05-14T21:10:45.382Z
Learning: In the ComfyUI_frontend repo, `WidgetEntityId` is a branded template-literal type (e.g., `${UUID}:${NodeId}:${string}`) and should be treated as structurally non-empty when valid—so an empty string is invalid and must be treated as “absent”. When handling optional `entityId?: WidgetEntityId` values (e.g., for Vue props or TS function parameters), guard missing/invalid IDs with a truthy check (e.g., `if (!entityId) return`) rather than `if (entityId === undefined)`. Rationale: `=== undefined` would allow empty-string values through into stores such as `appModeStore.selectedInputs`, creating rows that can’t resolve back to a widget.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 12197
File: src/core/schemas/parseNodePropertyArray.ts:1-1
Timestamp: 2026-05-18T21:34:41.153Z
Learning: In TypeScript, it is correct to use `import type { z } from 'zod'` when the imported symbol `z` is used exclusively in type-annotation/type-only positions (e.g., `schema: z.ZodType<T[]>`, `z.infer<typeof schema>`, `type X = z.AnyZodObject`, etc.). Because `import type` is fully erased at compile time and requires no runtime value, code reviewers should not flag `import type { z }` as an error (e.g., as an unused value import or incorrect runtime import) in TypeScript/React projects when `z` is only referenced in type positions. If `z` is referenced in a value/runtime position, it should instead be imported with a normal `import { z } from 'zod'`.

}
})
}
const customTemplatesPattern = '**/api/workflow_templates'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Convention nit (non-blocking): sibling fixtures anchor with regex (/\/api\/assets(?:\?.*)?$/, /\/api\/prompt$/). The glob is fine here — it matches the README's **/api/object_info style, has no trailing wildcard so it won't catch the per-template .json fetches, and there are no query strings on this endpoint. Just noting the mixed convention.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed. The current glob is safe for this endpoint, but the mixed route pattern convention is a valid cleanup concern. Since that is more of a fixture consistency/refactor pass than part of the E2E stabilization itself, I think it is better handled in a follow-up PR.

@coderabbitai please create an issue for this and assign it to me.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

gh issue create \
  --repo "Comfy-Org/ComfyUI_frontend" \
  --assignee "jaeone94" \
  --title "Refactor: Standardize Playwright route pattern convention in E2E fixture helpers" \
  --body "## Summary

Fixture helpers under \`browser_tests/fixtures/helpers/\` currently use a mixed convention for Playwright route patterns:

- Some fixtures (e.g. the assets and prompt handlers) anchor routes with regex patterns such as \`/\/api\/assets(?:\?.*)?$/\` and \`/\/api\/prompt$/\`.
- The \`TemplateHelper.mockIndex()\` handler added in `#12999` uses a glob pattern (\`**/api/workflow_templates\`) consistent with the \`README\`-documented \`**/api/object_info\` style.

Both approaches work correctly, but the inconsistency makes the fixture layer harder to maintain and reason about. A follow-up refactor pass should align all route patterns to a single convention (either regex or glob) across the fixture helpers.

## References

- PR: `#12999`
- Comment: https://github.com/Comfy-Org/ComfyUI_frontend/pull/12999#discussion_r3443589817
- Requested by: `@jaeone94`
"

Length of output: 1191



@jaeone94, the follow-up issue has been created and assigned to you: Refactor: Standardize Playwright route pattern convention in E2E fixture helpers#13015

(ᵔᴥᵔ)~🐇


🧠 Learnings used
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8248
File: src/platform/assets/schemas/assetSchema.ts:109-118
Timestamp: 2026-01-22T23:44:59.888Z
Learning: Do not export declarations (e.g., schemas, constants, types) unless they are actually used elsewhere in the codebase. Keep the public API surface minimal by exporting only items with concrete usage. This reduces coupling and keeps imports explicit. In src/platform/assets/schemas/assetSchema.ts, ensure only necessary exports are exposed; remove unused exports or switch to non-exported/internal where appropriate.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8722
File: src/composables/maskeditor/useBrushDrawing.ts:5-5
Timestamp: 2026-02-08T03:19:12.009Z
Learning: Treat unresolved import warnings caused by pnpm workspace catalog mappings (pnpm-workspace.yaml) and unplugin-typegpu in vite.config.mts as false positives. Do not flag these in PR reviews; they are expected in sandboxes without node_modules and are not indicative of actual missing dependencies in the TS codebase.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8966
File: src/extensions/core/load3d.ts:427-430
Timestamp: 2026-02-19T02:06:23.468Z
Learning: In TypeScript, you can use typeof SomeClass in type annotation positions (e.g., param: typeof LGraphNode) even when SomeClass is imported with import type. This is a type query that only exists at compile time and is erased in runtime, so it is safe to combine with type-only imports. Apply this pattern to TS files broadly when you need a type that references the shape of a class or constructor function without importing the value at runtime.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8966
File: src/extensions/core/uploadAudio.ts:91-94
Timestamp: 2026-02-19T02:06:38.395Z
Learning: In TypeScript files, you can use a type annotation like 'nodeType: typeof MyClass' even if MyClass is imported via 'import type'. Both the type-only import and 'typeof' operate at the type level and are erased at compile time. This pattern is commonly used for constructor types (e.g., 'nodeType: typeof LGraphNode'). Apply this pattern across TypeScript files in the repository (src/**/*.ts) as appropriate, ensuring the imported symbol is a type-only import when possible for clarity and to avoid runtime imports.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8992
File: src/lib/litegraph/src/widgets/GradientSliderWidget.ts:18-18
Timestamp: 2026-02-20T21:08:19.814Z
Learning: When drawing with CanvasRenderingContext2D in TypeScript/JavaScript, wrap the drawing logic with ctx.save() at the start and ctx.restore() at the end to preserve and restore the canvas state. Do not manually destructure and restore individual properties (e.g., fillStyle, strokeStyle); rely on save/restore to manage state changes in a scoped manner. This should be applied to all TS files that perform canvas drawing.

Learnt from: dante01yoon
Repo: Comfy-Org/ComfyUI_frontend PR: 9075
File: src/scripts/api.featureFlags.test.ts:237-268
Timestamp: 2026-02-22T04:27:33.379Z
Learning: In Vite/Vitest, import.meta.env.DEV is true for any mode that is not 'production' (i.e., DEV is the opposite of PROD, and can be true in 'test', 'development', etc.). Do not assume DEV implies only 'development' mode. When reviewing code and tests, treat DEV as a non-production flag and verify environment-specific logic accordingly. Reference: https://vite.dev/guide/env-and-mode#modes

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 9427
File: src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownMenuFilter.vue:33-33
Timestamp: 2026-03-06T00:53:28.835Z
Learning: When reviewing code, note that the enforce-canonical-classes (better-tailwindcss) rule may auto-fix Tailwind v3 !class-name syntax by converting it to v4 class-name! syntax. Do not treat these auto-fixed class-name! instances as newly introduced issues; the perceived change is in syntax placement, not in usage or intent. This guidance applies across all .vue and .ts files in the repository.

Learnt from: sonnybox
Repo: Comfy-Org/ComfyUI_frontend PR: 9446
File: src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue:45-45
Timestamp: 2026-03-06T01:55:00.013Z
Learning: Treat wrap-break-word as a valid Tailwind CSS utility for overflow-wrap: break-word in Tailwind v4+ projects. Do not flag this class as invalid in any Vue (.vue) or TypeScript (.ts/.tsx) files within the repository (e.g., Comfy-Org/ComfyUI_frontend) or other Tailwind v4+ projects. When reviewing, verify that the class is used to enable word breaking in long text content and reference the Tailwind docs: https://tailwindcss.com/docs/overflow-wrap.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 9554
File: browser_tests/fixtures/ComfyPage.ts:189-193
Timestamp: 2026-03-12T10:03:55.383Z
Learning: In browser_tests, seed localStorage-based feature flags at init time using FeatureFlagHelper.seedFlags() (which uses page.addInitScript) before any navigation. Ensure this happens before comfyPage.setup() is called. The comfyPageFixture currently yields after calling comfyPage.setup(), so do not defer setup() from the fixture or add a pre-setup hook, as changing this would break existing tests.

Learnt from: Yourz
Repo: Comfy-Org/ComfyUI_frontend PR: 10310
File: browser_tests/tests/topbarMenuDismissal.spec.ts:0-0
Timestamp: 2026-03-19T16:16:40.350Z
Learning: In Comfy-Org/ComfyUI_frontend, when reviewing changes limited to adding/revising `:modal="false"` (or similar modal/non-modal behavior props) on reakit-ui/reka-ui primitives such as `ContextMenuRoot` and `DropdownMenuRoot`, do not request Playwright/E2E regression coverage solely for that prop-level change. The dismissal behavior for modal vs non-modal is documented and tested upstream in the reka-ui library; only ask for E2E tests when the change affects ComfyUI_frontend behavior beyond these primitive prop wiring differences (e.g., custom logic, integration behavior, or new user flows not covered upstream).

Learnt from: jaeone94
Repo: Comfy-Org/ComfyUI_frontend PR: 10741
File: browser_tests/fixtures/helpers/boundsUtils.ts:32-45
Timestamp: 2026-03-31T12:17:31.232Z
Learning: In this codebase’s Playwright E2E test helpers under `browser_tests/fixtures/helpers/`, prefer measuring collapsed node dimensions directly from the DOM using `offsetWidth`/`offsetHeight`. Do not access Pinia stores from within `page.evaluate` blocks in E2E helpers (e.g., avoid calling `getNodeCollapsedSize()` or reading from `layoutStore`). This is intentional: E2E helpers should validate the final user-visible result, while Pinia store synchronization correctness is expected to be covered by unit tests.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/bottomPanelLogs.spec.ts:4-4
Timestamp: 2026-04-08T18:09:35.787Z
Learning: In this repo’s E2E browser tests, do not flag `import-x/no-unresolved` for imports using the `e2e/*` path alias. CodeRabbit sandbox reports these as unresolved because it may not run a full `pnpm install`; `e2e/*` is defined in the root `tsconfig.json` and the related `apps/website/tsconfig.json`/workspace dependency resolution only works when dependencies are installed. Apply this only to `browser_tests/**/*.ts` files.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/subgraph/subgraphSearch.spec.ts:3-4
Timestamp: 2026-04-08T18:09:50.771Z
Learning: In Comfy-Org/ComfyUI_frontend browser tests (browser_tests/**/*.ts), do not report `import-x/no-unresolved` for imports using the `e2e/*` alias. The alias is defined in the root tsconfig.json as `"e2e/*": ["./browser_tests/*"]`, and eslint.config.ts includes the correct tsconfig `project` list; lint passes locally and in CI. Treat any `e2e/*` unresolved-import findings in the CodeRabbit sandbox as false positives.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/rightClickMenu.spec.ts:3-5
Timestamp: 2026-04-08T18:10:12.748Z
Learning: In Comfy-Org/ComfyUI_frontend, `import-x/no-unresolved` errors caused by `@/` (src alias) and `e2e/` (browser_tests alias) imports inside `browser_tests/**/*.ts` are false positives in CodeRabbit’s sandbox because the sandbox cannot resolve the root `tsconfig.json` (it extends `astro/tsconfigs/strict`), which breaks the TypeScript import resolver. Since ESLint passes clean locally and in CI, do not treat these specific `@/` and `e2e/` unresolved import findings as real issues, and do not recommend adding `browser_tests/tsconfig.json` (or similar) to ESLint/CodeRabbit resolver project lists for this case.

Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 11531
File: src/composables/maskeditor/brushDrawingUtils.ts:14-14
Timestamp: 2026-04-22T04:06:01.353Z
Learning: In the Comfy-Org/ComfyUI_frontend codebase, `knip` is used to detect unused exports. When reviewing TypeScript/TSX code, avoid recommending or introducing exported types/functions/constants that have no concrete external consumers (e.g., they’re only used within the same module). Only recommend exporting when there is an actual external usage outside the module. If something might be needed externally later, keep it non-exported for now and defer exporting until an external consumer is added.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 12197
File: src/renderer/extensions/linearMode/AppInput.vue:23-23
Timestamp: 2026-05-14T21:10:45.382Z
Learning: In the ComfyUI_frontend repo, `WidgetEntityId` is a branded template-literal type (e.g., `${UUID}:${NodeId}:${string}`) and should be treated as structurally non-empty when valid—so an empty string is invalid and must be treated as “absent”. When handling optional `entityId?: WidgetEntityId` values (e.g., for Vue props or TS function parameters), guard missing/invalid IDs with a truthy check (e.g., `if (!entityId) return`) rather than `if (entityId === undefined)`. Rationale: `=== undefined` would allow empty-string values through into stores such as `appModeStore.selectedInputs`, creating rows that can’t resolve back to a widget.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 12197
File: src/core/schemas/parseNodePropertyArray.ts:1-1
Timestamp: 2026-05-18T21:34:41.153Z
Learning: In TypeScript, it is correct to use `import type { z } from 'zod'` when the imported symbol `z` is used exclusively in type-annotation/type-only positions (e.g., `schema: z.ZodType<T[]>`, `z.infer<typeof schema>`, `type X = z.AnyZodObject`, etc.). Because `import type` is fully erased at compile time and requires no runtime value, code reviewers should not flag `import type { z }` as an error (e.g., as an unused value import or incorrect runtime import) in TypeScript/React projects when `z` is only referenced in type positions. If `z` is referenced in a value/runtime position, it should instead be imported with a normal `import { z } from 'zod'`.

Comment on lines +84 to +88
this.routeHandlers.push({
pattern: customTemplatesPattern,
handler: customTemplatesHandler
})
await this.page.route(customTemplatesPattern, customTemplatesHandler)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All three handlers (customTemplates, index, thumbnails) repeat this routeHandlers.push({pattern, handler}) + page.route(pattern, handler) pair. Extracting a small private helper would DRY it up and prevent the easy mistake of routing without registering for cleanup:

private async registerRoute(
  pattern: string,
  handler: (route: Route) => Promise<void>
): Promise<void> {
  this.routeHandlers.push({ pattern, handler })
  await this.page.route(pattern, handler)
}

Then each call site collapses to await this.registerRoute(pattern, handler).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed, this helper extraction would make the route registration safer and clearer. I did not want to broaden this PR from a targeted E2E stabilization into a TemplateHelper refactor, especially since the immediate goal was to stop cloud-only runtime requests from leaking into exact-count assertions.

This is a good follow-up cleanup.

@coderabbitai please create an issue for this and assign it to me.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

gh issue create \
  --repo Comfy-Org/ComfyUI_frontend \
  --title "Refactor: Extract registerRoute private helper in TemplateHelper" \
  --assignee jaeone94 \
  --body "## Summary

In \`browser_tests/fixtures/helpers/TemplateHelper.ts\`, the pattern of pushing to \`routeHandlers\` and calling \`page.route()\` is repeated across all three route registrations (\`customTemplates\`, \`index\`, \`thumbnails\`). Extracting a small private helper would DRY this up and prevent the easy mistake of routing without registering for cleanup.

## Proposed change

\`\`\`ts
private async registerRoute(
  pattern: string,
  handler: (route: Route) => Promise<void>
): Promise<void> {
  this.routeHandlers.push({ pattern, handler })
  await this.page.route(pattern, handler)
}
\`\`\`

Each call site (\`mockIndex\`, \`mockThumbnails\`) then collapses to:
\`\`\`ts
await this.registerRoute(pattern, handler)
\`\`\`

## Context

Identified during review of PR `#12999` (comment: https://github.com/Comfy-Org/ComfyUI_frontend/pull/12999#discussion_r3443589821).

The current PR was intentionally scoped to E2E test stabilization; this cleanup is deferred as a follow-up.

## Related

- PR: https://github.com/Comfy-Org/ComfyUI_frontend/pull/12999
- File: \`browser_tests/fixtures/helpers/TemplateHelper.ts\`
"

Length of output: 1429



@jaeone94 Done! I've created the follow-up issue and assigned it to you: #13017

(ノ◕ヮ◕)ノ*:・゚✧


🧠 Learnings used
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8248
File: src/platform/assets/schemas/assetSchema.ts:109-118
Timestamp: 2026-01-22T23:44:59.888Z
Learning: Do not export declarations (e.g., schemas, constants, types) unless they are actually used elsewhere in the codebase. Keep the public API surface minimal by exporting only items with concrete usage. This reduces coupling and keeps imports explicit. In src/platform/assets/schemas/assetSchema.ts, ensure only necessary exports are exposed; remove unused exports or switch to non-exported/internal where appropriate.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8722
File: src/composables/maskeditor/useBrushDrawing.ts:5-5
Timestamp: 2026-02-08T03:19:12.009Z
Learning: Treat unresolved import warnings caused by pnpm workspace catalog mappings (pnpm-workspace.yaml) and unplugin-typegpu in vite.config.mts as false positives. Do not flag these in PR reviews; they are expected in sandboxes without node_modules and are not indicative of actual missing dependencies in the TS codebase.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8966
File: src/extensions/core/load3d.ts:427-430
Timestamp: 2026-02-19T02:06:23.468Z
Learning: In TypeScript, you can use typeof SomeClass in type annotation positions (e.g., param: typeof LGraphNode) even when SomeClass is imported with import type. This is a type query that only exists at compile time and is erased in runtime, so it is safe to combine with type-only imports. Apply this pattern to TS files broadly when you need a type that references the shape of a class or constructor function without importing the value at runtime.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8966
File: src/extensions/core/uploadAudio.ts:91-94
Timestamp: 2026-02-19T02:06:38.395Z
Learning: In TypeScript files, you can use a type annotation like 'nodeType: typeof MyClass' even if MyClass is imported via 'import type'. Both the type-only import and 'typeof' operate at the type level and are erased at compile time. This pattern is commonly used for constructor types (e.g., 'nodeType: typeof LGraphNode'). Apply this pattern across TypeScript files in the repository (src/**/*.ts) as appropriate, ensuring the imported symbol is a type-only import when possible for clarity and to avoid runtime imports.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8992
File: src/lib/litegraph/src/widgets/GradientSliderWidget.ts:18-18
Timestamp: 2026-02-20T21:08:19.814Z
Learning: When drawing with CanvasRenderingContext2D in TypeScript/JavaScript, wrap the drawing logic with ctx.save() at the start and ctx.restore() at the end to preserve and restore the canvas state. Do not manually destructure and restore individual properties (e.g., fillStyle, strokeStyle); rely on save/restore to manage state changes in a scoped manner. This should be applied to all TS files that perform canvas drawing.

Learnt from: dante01yoon
Repo: Comfy-Org/ComfyUI_frontend PR: 9075
File: src/scripts/api.featureFlags.test.ts:237-268
Timestamp: 2026-02-22T04:27:33.379Z
Learning: In Vite/Vitest, import.meta.env.DEV is true for any mode that is not 'production' (i.e., DEV is the opposite of PROD, and can be true in 'test', 'development', etc.). Do not assume DEV implies only 'development' mode. When reviewing code and tests, treat DEV as a non-production flag and verify environment-specific logic accordingly. Reference: https://vite.dev/guide/env-and-mode#modes

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 9427
File: src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownMenuFilter.vue:33-33
Timestamp: 2026-03-06T00:53:28.835Z
Learning: When reviewing code, note that the enforce-canonical-classes (better-tailwindcss) rule may auto-fix Tailwind v3 !class-name syntax by converting it to v4 class-name! syntax. Do not treat these auto-fixed class-name! instances as newly introduced issues; the perceived change is in syntax placement, not in usage or intent. This guidance applies across all .vue and .ts files in the repository.

Learnt from: sonnybox
Repo: Comfy-Org/ComfyUI_frontend PR: 9446
File: src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue:45-45
Timestamp: 2026-03-06T01:55:00.013Z
Learning: Treat wrap-break-word as a valid Tailwind CSS utility for overflow-wrap: break-word in Tailwind v4+ projects. Do not flag this class as invalid in any Vue (.vue) or TypeScript (.ts/.tsx) files within the repository (e.g., Comfy-Org/ComfyUI_frontend) or other Tailwind v4+ projects. When reviewing, verify that the class is used to enable word breaking in long text content and reference the Tailwind docs: https://tailwindcss.com/docs/overflow-wrap.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 9554
File: browser_tests/fixtures/ComfyPage.ts:189-193
Timestamp: 2026-03-12T10:03:55.383Z
Learning: In browser_tests, seed localStorage-based feature flags at init time using FeatureFlagHelper.seedFlags() (which uses page.addInitScript) before any navigation. Ensure this happens before comfyPage.setup() is called. The comfyPageFixture currently yields after calling comfyPage.setup(), so do not defer setup() from the fixture or add a pre-setup hook, as changing this would break existing tests.

Learnt from: Yourz
Repo: Comfy-Org/ComfyUI_frontend PR: 10310
File: browser_tests/tests/topbarMenuDismissal.spec.ts:0-0
Timestamp: 2026-03-19T16:16:40.350Z
Learning: In Comfy-Org/ComfyUI_frontend, when reviewing changes limited to adding/revising `:modal="false"` (or similar modal/non-modal behavior props) on reakit-ui/reka-ui primitives such as `ContextMenuRoot` and `DropdownMenuRoot`, do not request Playwright/E2E regression coverage solely for that prop-level change. The dismissal behavior for modal vs non-modal is documented and tested upstream in the reka-ui library; only ask for E2E tests when the change affects ComfyUI_frontend behavior beyond these primitive prop wiring differences (e.g., custom logic, integration behavior, or new user flows not covered upstream).

Learnt from: jaeone94
Repo: Comfy-Org/ComfyUI_frontend PR: 10741
File: browser_tests/fixtures/helpers/boundsUtils.ts:32-45
Timestamp: 2026-03-31T12:17:31.232Z
Learning: In this codebase’s Playwright E2E test helpers under `browser_tests/fixtures/helpers/`, prefer measuring collapsed node dimensions directly from the DOM using `offsetWidth`/`offsetHeight`. Do not access Pinia stores from within `page.evaluate` blocks in E2E helpers (e.g., avoid calling `getNodeCollapsedSize()` or reading from `layoutStore`). This is intentional: E2E helpers should validate the final user-visible result, while Pinia store synchronization correctness is expected to be covered by unit tests.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/bottomPanelLogs.spec.ts:4-4
Timestamp: 2026-04-08T18:09:35.787Z
Learning: In this repo’s E2E browser tests, do not flag `import-x/no-unresolved` for imports using the `e2e/*` path alias. CodeRabbit sandbox reports these as unresolved because it may not run a full `pnpm install`; `e2e/*` is defined in the root `tsconfig.json` and the related `apps/website/tsconfig.json`/workspace dependency resolution only works when dependencies are installed. Apply this only to `browser_tests/**/*.ts` files.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/subgraph/subgraphSearch.spec.ts:3-4
Timestamp: 2026-04-08T18:09:50.771Z
Learning: In Comfy-Org/ComfyUI_frontend browser tests (browser_tests/**/*.ts), do not report `import-x/no-unresolved` for imports using the `e2e/*` alias. The alias is defined in the root tsconfig.json as `"e2e/*": ["./browser_tests/*"]`, and eslint.config.ts includes the correct tsconfig `project` list; lint passes locally and in CI. Treat any `e2e/*` unresolved-import findings in the CodeRabbit sandbox as false positives.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/rightClickMenu.spec.ts:3-5
Timestamp: 2026-04-08T18:10:12.748Z
Learning: In Comfy-Org/ComfyUI_frontend, `import-x/no-unresolved` errors caused by `@/` (src alias) and `e2e/` (browser_tests alias) imports inside `browser_tests/**/*.ts` are false positives in CodeRabbit’s sandbox because the sandbox cannot resolve the root `tsconfig.json` (it extends `astro/tsconfigs/strict`), which breaks the TypeScript import resolver. Since ESLint passes clean locally and in CI, do not treat these specific `@/` and `e2e/` unresolved import findings as real issues, and do not recommend adding `browser_tests/tsconfig.json` (or similar) to ESLint/CodeRabbit resolver project lists for this case.

Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 11531
File: src/composables/maskeditor/brushDrawingUtils.ts:14-14
Timestamp: 2026-04-22T04:06:01.353Z
Learning: In the Comfy-Org/ComfyUI_frontend codebase, `knip` is used to detect unused exports. When reviewing TypeScript/TSX code, avoid recommending or introducing exported types/functions/constants that have no concrete external consumers (e.g., they’re only used within the same module). Only recommend exporting when there is an actual external usage outside the module. If something might be needed externally later, keep it non-exported for now and defer exporting until an external consumer is added.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 12197
File: src/renderer/extensions/linearMode/AppInput.vue:23-23
Timestamp: 2026-05-14T21:10:45.382Z
Learning: In the ComfyUI_frontend repo, `WidgetEntityId` is a branded template-literal type (e.g., `${UUID}:${NodeId}:${string}`) and should be treated as structurally non-empty when valid—so an empty string is invalid and must be treated as “absent”. When handling optional `entityId?: WidgetEntityId` values (e.g., for Vue props or TS function parameters), guard missing/invalid IDs with a truthy check (e.g., `if (!entityId) return`) rather than `if (entityId === undefined)`. Rationale: `=== undefined` would allow empty-string values through into stores such as `appModeStore.selectedInputs`, creating rows that can’t resolve back to a widget.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 12197
File: src/core/schemas/parseNodePropertyArray.ts:1-1
Timestamp: 2026-05-18T21:34:41.153Z
Learning: In TypeScript, it is correct to use `import type { z } from 'zod'` when the imported symbol `z` is used exclusively in type-annotation/type-only positions (e.g., `schema: z.ZodType<T[]>`, `z.infer<typeof schema>`, `type X = z.AnyZodObject`, etc.). Because `import type` is fully erased at compile time and requires no runtime value, code reviewers should not flag `import type { z }` as an error (e.g., as an unused value import or incorrect runtime import) in TypeScript/React projects when `z` is only referenced in type positions. If `z` is referenced in a value/runtime position, it should instead be imported with a normal `import { z } from 'zod'`.

import { templateApiFixture } from '@e2e/fixtures/templateApiFixture'

const test = mergeTests(comfyPageFixture, templateApiFixture)
const test = mergeTests(createCloudAssetsFixture([]), templateApiFixture)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is the line that makes the new **/api/workflow_templates mock necessary: createCloudAssetsFixture([]) runs the suite as @cloud, so the store now actually calls /workflow_templates. Good change — just flagging the coupling for future readers.

@jaeone94 jaeone94 Jun 19, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, exactly. Switching this suite to createCloudAssetsFixture([]) is what exposes the cloud runtime path, so the /api/workflow_templates mock is needed to keep the exact-count assertions deterministic. Thanks for calling out that coupling for future readers.

@DrJKL DrJKL assigned jaeone94 and unassigned DrJKL Jun 19, 2026
}
})
}
const customTemplatesPattern = '**/api/workflow_templates'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also, if this is a constant, could you pull it out to module scope and name it something like ROUTE_PATTERN_WORKFLOW_TEMPLATES?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed. Pulling the workflow templates route pattern to module scope would be a valid cleanup, and it likely makes the most sense together with normalizing the other TemplateHelper route patterns rather than changing only this new one. I kept that refactor out of this stabilization PR for scope control.

@coderabbitai please create an issue for this and assign it to me.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

gh issue create \
  --repo "Comfy-Org/ComfyUI_frontend" \
  --title "Refactor: Extract TemplateHelper route patterns to named module-scope constants" \
  --assignee "jaeone94" \
  --body "## Summary

The route pattern strings inside \`TemplateHelper\` in \`browser_tests/fixtures/helpers/TemplateHelper.ts\` are currently defined as inline \`const\` variables inside method bodies. These should be lifted to module-scope named constants (e.g., \`ROUTE_PATTERN_WORKFLOW_TEMPLATES\`, \`ROUTE_PATTERN_TEMPLATE_INDEX\`, \`ROUTE_PATTERN_TEMPLATE_THUMBNAILS\`) to:

- Improve readability and discoverability
- Enable reuse across tests without duplication
- Make intent explicit through descriptive names

## Scope

Normalize **all three** existing route patterns in \`TemplateHelper\` at the same time:
- \`'**/api/workflow_templates'\`
- \`'**/templates/index.json'\`
- \`'**/templates/**.webp'\`

## Background

Identified during review of PR `#12999` (comment: https://github.com/Comfy-Org/ComfyUI_frontend/pull/12999#discussion_r3443639562). The refactor was intentionally kept out of that stabilization PR for scope control.

Requested by: `@jaeone94`"

Length of output: 1283



@jaeone94 Done! The follow-up issue has been created and assigned to you: #13018Refactor: Extract TemplateHelper route patterns to named module-scope constants.

It covers normalizing all three existing route patterns in TemplateHelper at once, as you suggested. 🐇


🧠 Learnings used
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8248
File: src/platform/assets/schemas/assetSchema.ts:109-118
Timestamp: 2026-01-22T23:44:59.888Z
Learning: Do not export declarations (e.g., schemas, constants, types) unless they are actually used elsewhere in the codebase. Keep the public API surface minimal by exporting only items with concrete usage. This reduces coupling and keeps imports explicit. In src/platform/assets/schemas/assetSchema.ts, ensure only necessary exports are exposed; remove unused exports or switch to non-exported/internal where appropriate.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8722
File: src/composables/maskeditor/useBrushDrawing.ts:5-5
Timestamp: 2026-02-08T03:19:12.009Z
Learning: Treat unresolved import warnings caused by pnpm workspace catalog mappings (pnpm-workspace.yaml) and unplugin-typegpu in vite.config.mts as false positives. Do not flag these in PR reviews; they are expected in sandboxes without node_modules and are not indicative of actual missing dependencies in the TS codebase.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8966
File: src/extensions/core/load3d.ts:427-430
Timestamp: 2026-02-19T02:06:23.468Z
Learning: In TypeScript, you can use typeof SomeClass in type annotation positions (e.g., param: typeof LGraphNode) even when SomeClass is imported with import type. This is a type query that only exists at compile time and is erased in runtime, so it is safe to combine with type-only imports. Apply this pattern to TS files broadly when you need a type that references the shape of a class or constructor function without importing the value at runtime.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 8966
File: src/extensions/core/uploadAudio.ts:91-94
Timestamp: 2026-02-19T02:06:38.395Z
Learning: In TypeScript files, you can use a type annotation like 'nodeType: typeof MyClass' even if MyClass is imported via 'import type'. Both the type-only import and 'typeof' operate at the type level and are erased at compile time. This pattern is commonly used for constructor types (e.g., 'nodeType: typeof LGraphNode'). Apply this pattern across TypeScript files in the repository (src/**/*.ts) as appropriate, ensuring the imported symbol is a type-only import when possible for clarity and to avoid runtime imports.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 8992
File: src/lib/litegraph/src/widgets/GradientSliderWidget.ts:18-18
Timestamp: 2026-02-20T21:08:19.814Z
Learning: When drawing with CanvasRenderingContext2D in TypeScript/JavaScript, wrap the drawing logic with ctx.save() at the start and ctx.restore() at the end to preserve and restore the canvas state. Do not manually destructure and restore individual properties (e.g., fillStyle, strokeStyle); rely on save/restore to manage state changes in a scoped manner. This should be applied to all TS files that perform canvas drawing.

Learnt from: dante01yoon
Repo: Comfy-Org/ComfyUI_frontend PR: 9075
File: src/scripts/api.featureFlags.test.ts:237-268
Timestamp: 2026-02-22T04:27:33.379Z
Learning: In Vite/Vitest, import.meta.env.DEV is true for any mode that is not 'production' (i.e., DEV is the opposite of PROD, and can be true in 'test', 'development', etc.). Do not assume DEV implies only 'development' mode. When reviewing code and tests, treat DEV as a non-production flag and verify environment-specific logic accordingly. Reference: https://vite.dev/guide/env-and-mode#modes

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 9427
File: src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownMenuFilter.vue:33-33
Timestamp: 2026-03-06T00:53:28.835Z
Learning: When reviewing code, note that the enforce-canonical-classes (better-tailwindcss) rule may auto-fix Tailwind v3 !class-name syntax by converting it to v4 class-name! syntax. Do not treat these auto-fixed class-name! instances as newly introduced issues; the perceived change is in syntax placement, not in usage or intent. This guidance applies across all .vue and .ts files in the repository.

Learnt from: sonnybox
Repo: Comfy-Org/ComfyUI_frontend PR: 9446
File: src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue:45-45
Timestamp: 2026-03-06T01:55:00.013Z
Learning: Treat wrap-break-word as a valid Tailwind CSS utility for overflow-wrap: break-word in Tailwind v4+ projects. Do not flag this class as invalid in any Vue (.vue) or TypeScript (.ts/.tsx) files within the repository (e.g., Comfy-Org/ComfyUI_frontend) or other Tailwind v4+ projects. When reviewing, verify that the class is used to enable word breaking in long text content and reference the Tailwind docs: https://tailwindcss.com/docs/overflow-wrap.

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 9554
File: browser_tests/fixtures/ComfyPage.ts:189-193
Timestamp: 2026-03-12T10:03:55.383Z
Learning: In browser_tests, seed localStorage-based feature flags at init time using FeatureFlagHelper.seedFlags() (which uses page.addInitScript) before any navigation. Ensure this happens before comfyPage.setup() is called. The comfyPageFixture currently yields after calling comfyPage.setup(), so do not defer setup() from the fixture or add a pre-setup hook, as changing this would break existing tests.

Learnt from: Yourz
Repo: Comfy-Org/ComfyUI_frontend PR: 10310
File: browser_tests/tests/topbarMenuDismissal.spec.ts:0-0
Timestamp: 2026-03-19T16:16:40.350Z
Learning: In Comfy-Org/ComfyUI_frontend, when reviewing changes limited to adding/revising `:modal="false"` (or similar modal/non-modal behavior props) on reakit-ui/reka-ui primitives such as `ContextMenuRoot` and `DropdownMenuRoot`, do not request Playwright/E2E regression coverage solely for that prop-level change. The dismissal behavior for modal vs non-modal is documented and tested upstream in the reka-ui library; only ask for E2E tests when the change affects ComfyUI_frontend behavior beyond these primitive prop wiring differences (e.g., custom logic, integration behavior, or new user flows not covered upstream).

Learnt from: jaeone94
Repo: Comfy-Org/ComfyUI_frontend PR: 10741
File: browser_tests/fixtures/helpers/boundsUtils.ts:32-45
Timestamp: 2026-03-31T12:17:31.232Z
Learning: In this codebase’s Playwright E2E test helpers under `browser_tests/fixtures/helpers/`, prefer measuring collapsed node dimensions directly from the DOM using `offsetWidth`/`offsetHeight`. Do not access Pinia stores from within `page.evaluate` blocks in E2E helpers (e.g., avoid calling `getNodeCollapsedSize()` or reading from `layoutStore`). This is intentional: E2E helpers should validate the final user-visible result, while Pinia store synchronization correctness is expected to be covered by unit tests.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/bottomPanelLogs.spec.ts:4-4
Timestamp: 2026-04-08T18:09:35.787Z
Learning: In this repo’s E2E browser tests, do not flag `import-x/no-unresolved` for imports using the `e2e/*` path alias. CodeRabbit sandbox reports these as unresolved because it may not run a full `pnpm install`; `e2e/*` is defined in the root `tsconfig.json` and the related `apps/website/tsconfig.json`/workspace dependency resolution only works when dependencies are installed. Apply this only to `browser_tests/**/*.ts` files.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/subgraph/subgraphSearch.spec.ts:3-4
Timestamp: 2026-04-08T18:09:50.771Z
Learning: In Comfy-Org/ComfyUI_frontend browser tests (browser_tests/**/*.ts), do not report `import-x/no-unresolved` for imports using the `e2e/*` alias. The alias is defined in the root tsconfig.json as `"e2e/*": ["./browser_tests/*"]`, and eslint.config.ts includes the correct tsconfig `project` list; lint passes locally and in CI. Treat any `e2e/*` unresolved-import findings in the CodeRabbit sandbox as false positives.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 10958
File: browser_tests/tests/rightClickMenu.spec.ts:3-5
Timestamp: 2026-04-08T18:10:12.748Z
Learning: In Comfy-Org/ComfyUI_frontend, `import-x/no-unresolved` errors caused by `@/` (src alias) and `e2e/` (browser_tests alias) imports inside `browser_tests/**/*.ts` are false positives in CodeRabbit’s sandbox because the sandbox cannot resolve the root `tsconfig.json` (it extends `astro/tsconfigs/strict`), which breaks the TypeScript import resolver. Since ESLint passes clean locally and in CI, do not treat these specific `@/` and `e2e/` unresolved import findings as real issues, and do not recommend adding `browser_tests/tsconfig.json` (or similar) to ESLint/CodeRabbit resolver project lists for this case.

Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 11531
File: src/composables/maskeditor/brushDrawingUtils.ts:14-14
Timestamp: 2026-04-22T04:06:01.353Z
Learning: In the Comfy-Org/ComfyUI_frontend codebase, `knip` is used to detect unused exports. When reviewing TypeScript/TSX code, avoid recommending or introducing exported types/functions/constants that have no concrete external consumers (e.g., they’re only used within the same module). Only recommend exporting when there is an actual external usage outside the module. If something might be needed externally later, keep it non-exported for now and defer exporting until an external consumer is added.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 12197
File: src/renderer/extensions/linearMode/AppInput.vue:23-23
Timestamp: 2026-05-14T21:10:45.382Z
Learning: In the ComfyUI_frontend repo, `WidgetEntityId` is a branded template-literal type (e.g., `${UUID}:${NodeId}:${string}`) and should be treated as structurally non-empty when valid—so an empty string is invalid and must be treated as “absent”. When handling optional `entityId?: WidgetEntityId` values (e.g., for Vue props or TS function parameters), guard missing/invalid IDs with a truthy check (e.g., `if (!entityId) return`) rather than `if (entityId === undefined)`. Rationale: `=== undefined` would allow empty-string values through into stores such as `appModeStore.selectedInputs`, creating rows that can’t resolve back to a widget.

Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 12197
File: src/core/schemas/parseNodePropertyArray.ts:1-1
Timestamp: 2026-05-18T21:34:41.153Z
Learning: In TypeScript, it is correct to use `import type { z } from 'zod'` when the imported symbol `z` is used exclusively in type-annotation/type-only positions (e.g., `schema: z.ZodType<T[]>`, `z.infer<typeof schema>`, `type X = z.AnyZodObject`, etc.). Because `import type` is fully erased at compile time and requires no runtime value, code reviewers should not flag `import type { z }` as an error (e.g., as an unused value import or incorrect runtime import) in TypeScript/React projects when `z` is only referenced in type positions. If `z` is referenced in a value/runtime position, it should instead be imported with a normal `import { z } from 'zod'`.

@DrJKL

DrJKL commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Follow-up observation (non-blocking, not specific to this diff):

The routeHandlers collection + unroute loop in TemplateHelper.clearMocks() isn't strictly necessary here. clearMocks() only runs at fixture teardown (after use()), and the Playwright page fixture is function-scoped — a fresh page/context per test. When the test ends the page is closed and all its routes are discarded automatically, so the unroute loop is undoing routes on a page that's about to be thrown away. The this.templates = [] / this.index = null resets are likewise moot since createTemplateHelper(page) builds a new helper per test.

It would only matter if the page were reused across tests (worker/context-scoped) or if clearMocks() were called mid-test to let requests hit the real endpoint — neither happens today. The pattern isn't wrong (keeping handler refs is the correct way to unroute selectively), just unused given the lifecycle.

This is an established convention across several helpers (AssetHelper, ModelLibraryHelper, PublishApiHelper, etc.), so it's better cleaned up uniformly rather than in this PR. Filed as FE-1106https://linear.app/comfyorg/issue/FE-1106/remove-redundant-clearmocksunroute-teardown-from-function-scoped-e2e

No change requested here; approval stands.

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

Labels

size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants