chrome-devtools-frontend 1.0.1717709 → 1.0.1721762
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/rules/models-and-core/core-ai-agent-context-and-prompt-discipline.md +29 -0
- package/.agents/rules/models-and-core/core-cdp-and-extension-error-handling.md +34 -0
- package/.agents/rules/models-and-core/core-gn-build-and-module-layering.md +23 -0
- package/.agents/rules/models-and-core/core-runtime-neutrality-and-platform-utils.md +28 -0
- package/.agents/rules/models-and-core/core-sdk-model-and-target-lifecycle.md +35 -0
- package/.agents/rules/models-and-core/core-security-origin-and-capability-guards.md +33 -0
- package/.agents/rules/models-and-core/core-settings-and-storage-migration.md +31 -0
- package/.agents/rules/models-and-core/core-sourcemap-and-workspace-mapping.md +28 -0
- package/.agents/rules/models-and-core/core-trace-engine-handler-invariants.md +32 -0
- package/.agents/rules/models-and-core/core-trace-insight-models-and-timing-types.md +28 -0
- package/.agents/rules/tests/test-cleanup-mutated-globals-and-widgets.md +40 -0
- package/.agents/rules/tests/test-deterministic-async-synchronization.md +30 -0
- package/.agents/rules/tests/test-modular-hooks-and-test-universe.md +38 -0
- package/.agents/rules/tests/test-public-api-and-encapsulation.md +30 -0
- package/.agents/rules/tests/test-shared-fixture-and-helper-reuse.md +29 -0
- package/.agents/rules/tests/test-single-responsibility-and-conciseness.md +37 -0
- package/.agents/rules/tests/test-strict-assertions-and-literal-expectations.md +31 -0
- package/.agents/rules/tests/test-type-safe-mocks-and-events.md +30 -0
- package/.agents/rules/tests/test-view-and-presenter-isolation.md +32 -0
- package/.agents/rules/ui-and-widgets/ui-accessibility-and-semantic-html.md +32 -0
- package/.agents/rules/ui-and-widgets/ui-await-update-complete-post-render.md +30 -0
- package/.agents/rules/ui-and-widgets/ui-css-scoping-and-flex-layout.md +27 -0
- package/.agents/rules/ui-and-widgets/ui-declarative-child-widget-composition.md +29 -0
- package/.agents/rules/ui-and-widgets/ui-lit-declarative-templates-and-directives.md +33 -0
- package/.agents/rules/ui-and-widgets/ui-localization-and-uistrings-hygiene.md +36 -0
- package/.agents/rules/ui-and-widgets/ui-modern-component-and-encapsulation-standards.md +32 -0
- package/.agents/rules/ui-and-widgets/ui-panel-and-meta-registration.md +35 -0
- package/.agents/rules/ui-and-widgets/ui-performance-and-flamechart-rendering.md +34 -0
- package/.agents/rules/ui-and-widgets/ui-pure-view-and-presenter-separation.md +31 -0
- package/.agents/rules/ui-and-widgets/ui-reactive-widget-update-lifecycle.md +34 -0
- package/.agents/rules/ui-and-widgets/ui-security-and-output-sanitization.md +28 -0
- package/.agents/rules/ui-and-widgets/ui-type-safety-and-exhaustiveness.md +37 -0
- package/.agents/rules/ui-and-widgets/ui-view-output-and-callback-contracts.md +35 -0
- package/.agents/rules/ui-and-widgets/ui-visual-logging-instrumentation.md +29 -0
- package/.agents/rules/ui-and-widgets/ui-weak-dom-references-and-observer-cleanup.md +29 -0
- package/.agents/rules/ui-and-widgets/ui-widget-dom-and-listener-lifecycle.md +38 -0
- package/.agents/skills/code-review/SKILL.md +3 -0
- package/.agents/skills/devtools-testing-guidance/SKILL.md +1 -0
- package/.agents/skills/review-models-core/SKILL.md +73 -0
- package/.agents/skills/review-tests/SKILL.md +67 -0
- package/.agents/skills/review-ui-widgets/SKILL.md +115 -0
- package/.agents/skills/ui-eng-vision-local-lit-renderer/SKILL.md +19 -3
- package/.agents/skills/ui-eng-vision-widget-promoter/SKILL.md +2 -1
- package/.agents/skills/ui-widgets/SKILL.md +3 -1
- package/AUTHORS +3 -0
- package/DIR_METADATA +51 -1
- package/eslint.config.mjs +63 -21
- package/front_end/core/platform/api/HostRuntime.ts +1 -0
- package/front_end/core/platform/browser/HostRuntime.ts +10 -0
- package/front_end/core/platform/node/HostRuntime.ts +1 -0
- package/front_end/core/sdk/CSSMatchedStyles.ts +60 -20
- package/front_end/core/sdk/CSSProperty.ts +2 -2
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +28 -9
- package/front_end/core/sdk/NetworkManager.ts +9 -3
- package/front_end/core/sdk/OverlayModel.ts +2 -8
- package/front_end/core/sdk/PrivateVerificationTokensModel.ts +79 -0
- package/front_end/core/sdk/SecurityOrigin.ts +1 -1
- package/front_end/core/sdk/SourceMapCache.ts +20 -15
- package/front_end/core/sdk/SourceMapManager.ts +28 -9
- package/front_end/core/sdk/TargetManager.ts +7 -4
- package/front_end/core/sdk/WebAuthnModel.ts +11 -2
- package/front_end/core/sdk/sdk.ts +2 -0
- package/front_end/entrypoints/inspector_main/InspectorMain.ts +0 -2
- package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +10 -0
- package/front_end/entrypoints/main/GlobalAiButton.ts +1 -1
- package/front_end/entrypoints/main/MainImpl.ts +5 -2
- package/front_end/foundation/Universe.ts +1 -1
- package/front_end/generated/Deprecation.ts +4 -0
- package/front_end/generated/InspectorBackendCommands.ts +3 -3
- package/front_end/generated/SupportedCSSProperties.ts +89 -17
- package/front_end/generated/protocol-mapping.d.ts +1 -0
- package/front_end/generated/protocol-proxy-api.d.ts +1 -0
- package/front_end/generated/protocol.ts +5 -3
- package/front_end/models/{ai_assistance → ai-utils}/AiHistoryStorage.ts +6 -5
- package/front_end/models/{ai_assistance → ai-utils}/AiUtils.ts +9 -0
- package/front_end/models/{ai_assistance → ai-utils}/BuiltInAi.ts +1 -1
- package/front_end/models/ai-utils/ai-utils.ts +17 -0
- package/front_end/models/ai_assistance/AiAgent2.ts +3 -1
- package/front_end/models/ai_assistance/AiConversation.ts +34 -22
- package/front_end/models/ai_assistance/AlwaysAllowedTools.ts +107 -0
- package/front_end/models/ai_assistance/ConversationSummary.ts +2 -1
- package/front_end/models/ai_assistance/PerformanceAnnotations.ts +3 -1
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +3 -1
- package/front_end/models/ai_assistance/agents/AiAgent.ts +15 -7
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +3 -1
- package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +3 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +1 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +3 -1
- package/front_end/models/ai_assistance/ai_assistance.ts +9 -10
- package/front_end/models/ai_assistance/data_formatters/FileFormatter.ts +27 -6
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +3 -3
- package/front_end/models/ai_assistance/skills/sources.md +3 -1
- package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +1 -0
- package/front_end/models/ai_assistance/tools/GetCookieValues.ts +1 -0
- package/front_end/models/ai_assistance/tools/GetInsightDetails.ts +3 -1
- package/front_end/models/ai_assistance/tools/GetSourceContent.ts +46 -4
- package/front_end/models/ai_assistance/tools/GetStorageValues.ts +1 -0
- package/front_end/models/ai_assistance/tools/Tool.ts +6 -0
- package/front_end/models/breakpoints/BreakpointManager.ts +0 -4
- package/front_end/models/change_tracker/ChangeTracker.ts +2 -0
- package/front_end/models/comment_manager/CommentManager.ts +12 -0
- package/front_end/models/comment_manager/CommentThread.ts +21 -1
- package/front_end/models/elements/ChangeTrackingUtils.ts +37 -0
- package/front_end/models/elements/DOMChanges.ts +24 -36
- package/front_end/models/elements/StyleChanges.ts +97 -0
- package/front_end/models/elements/elements.ts +4 -0
- package/front_end/models/emulation/DeviceModeModel.ts +19 -0
- package/front_end/models/javascript_metadata/NativeFunctions.ts +11 -1
- package/front_end/models/trace/EventsSerializer.ts +35 -2
- package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +17 -21
- package/front_end/models/trace/helpers/SyntheticEvents.ts +4 -2
- package/front_end/models/trace/lantern/core/NetworkAnalyzer.ts +12 -8
- package/front_end/models/trace/types/File.ts +20 -3
- package/front_end/models/trace/types/TraceEvents.ts +8 -3
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +14 -0
- package/front_end/panels/ai_assistance/README.md +1 -1
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +1 -1
- package/front_end/panels/ai_assistance/ai_assistance.ts +2 -0
- package/front_end/panels/ai_assistance/components/ChatInput.ts +5 -43
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +52 -147
- package/front_end/panels/ai_assistance/components/ChatView.ts +28 -3
- package/front_end/panels/ai_assistance/components/PermissionPrompt.ts +151 -0
- package/front_end/panels/ai_assistance/components/RelevantDataDisclaimer.ts +73 -0
- package/front_end/panels/ai_assistance/components/chatInput.css +0 -59
- package/front_end/panels/ai_assistance/components/chatMessage.css +0 -47
- package/front_end/panels/ai_assistance/components/chatView.css +5 -30
- package/front_end/panels/ai_assistance/components/permissionPrompt.css +55 -0
- package/front_end/panels/ai_assistance/components/relevantDataDisclaimer.css +35 -0
- package/front_end/panels/application/ApplicationPanelSidebar.ts +3 -7
- package/front_end/panels/application/BackgroundServiceView.ts +8 -8
- package/front_end/panels/application/IndexedDBViews.ts +102 -73
- package/front_end/panels/application/OpenedWindowDetailsView.ts +167 -130
- package/front_end/panels/application/ServiceWorkerCacheViews.ts +288 -346
- package/front_end/panels/application/StorageBucketsTreeElement.ts +22 -27
- package/front_end/panels/application/StorageItemsToolbar.ts +2 -2
- package/front_end/panels/application/components/StorageMetadataView.ts +207 -160
- package/front_end/panels/application/openedWindowDetailsView.css +7 -30
- package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +1 -1
- package/front_end/panels/changes/changesView.css +0 -6
- package/front_end/panels/console/ConsoleInsightTeaser.ts +5 -1
- package/front_end/panels/console/ConsolePinPane.ts +1 -1
- package/front_end/panels/console/ConsoleView.ts +1 -0
- package/front_end/panels/elements/CSSValueTraceView.ts +5 -5
- package/front_end/panels/elements/ColorSwatchPopoverIcon.ts +14 -6
- package/front_end/panels/elements/ComputedStyleWidget.ts +14 -5
- package/front_end/panels/elements/DOMTreeElementWidget.ts +2 -2
- package/front_end/panels/elements/DOMTreeWidget.ts +7 -3
- package/front_end/panels/elements/EventListenersWidget.ts +1 -1
- package/front_end/panels/elements/LayersWidget.ts +1 -1
- package/front_end/panels/elements/PropertyRenderer.ts +91 -16
- package/front_end/panels/elements/StandaloneStylesContainer.ts +33 -6
- package/front_end/panels/elements/StylePropertiesSection.ts +1 -0
- package/front_end/panels/elements/StylePropertyTreeElement.ts +211 -121
- package/front_end/panels/elements/StylesContainer.ts +2 -0
- package/front_end/panels/elements/StylesSidebarPane.ts +34 -16
- package/front_end/panels/elements/components/QueryContainer.ts +1 -1
- package/front_end/panels/elements/elementStatePaneWidget.css +1 -1
- package/front_end/panels/elements/stylePropertiesTreeOutline.css +1 -1
- package/front_end/panels/elements/stylesSidebarPane.css +4 -0
- package/front_end/panels/emulation/DeviceModeToolbar.ts +57 -25
- package/front_end/panels/emulation/DeviceModeView.ts +27 -1
- package/front_end/panels/emulation/InspectedPagePlaceholder.ts +6 -0
- package/front_end/panels/emulation/MediaQueryInspector.ts +14 -4
- package/front_end/panels/explain/components/ConsoleInsight.ts +2 -3
- package/front_end/panels/explain/explain-meta.ts +1 -1
- package/front_end/panels/issues/AffectedMetadataAllowedSitesView.ts +67 -34
- package/front_end/panels/issues/issues.ts +2 -0
- package/front_end/panels/layer_viewer/LayerTreeOutline.ts +7 -3
- package/front_end/panels/lighthouse/LighthouseController.ts +1 -1
- package/front_end/panels/media/PlayerMessagesView.ts +1 -1
- package/front_end/panels/mobile_throttling/CPUThrottlingSelector.ts +1 -1
- package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +45 -15
- package/front_end/panels/mobile_throttling/ThrottlingManager.ts +3 -3
- package/front_end/panels/network/BinaryResourceView.ts +54 -50
- package/front_end/panels/network/RequestHeadersView.ts +6 -2
- package/front_end/panels/network/RequestPreviewView.ts +28 -5
- package/front_end/panels/network/ResourceWebSocketFrameView.ts +1 -0
- package/front_end/panels/network/components/EditableSpan.ts +11 -30
- package/front_end/panels/network/components/HeaderSectionRow.ts +2 -2
- package/front_end/panels/performance_monitor/PerformanceMonitor.ts +10 -6
- package/front_end/panels/profiler/HeapDetachedElementsView.ts +112 -22
- package/front_end/panels/profiler/HeapProfileView.ts +3 -3
- package/front_end/panels/profiler/HeapSnapshotView.ts +12 -2
- package/front_end/panels/profiler/HeapTimelineOverview.ts +16 -2
- package/front_end/panels/profiler/profiler.ts +0 -2
- package/front_end/panels/protocol_monitor/JSONEditor.ts +1 -1
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +1 -1
- package/front_end/panels/recorder/CreateRecordingView.ts +1 -1
- package/front_end/panels/recorder/RecordingView.ts +3 -3
- package/front_end/panels/recorder/ReplaySection.ts +1 -1
- package/front_end/panels/screencast/ScreencastApp.ts +83 -57
- package/front_end/panels/screencast/screencastView.css +1 -1
- package/front_end/panels/settings/AISettingsTab.ts +107 -4
- package/front_end/panels/settings/aiSettingsTab.css +53 -0
- package/front_end/panels/settings/settings-meta.ts +1 -1
- package/front_end/panels/settings/settingsScreen.css +0 -4
- package/front_end/panels/sources/BreakpointsView.ts +2 -2
- package/front_end/panels/sources/DebuggerPlugin.ts +7 -0
- package/front_end/panels/sources/NavigatorView.ts +61 -18
- package/front_end/panels/sources/SourcesNavigator.ts +22 -7
- package/front_end/panels/sources/SourcesPanel.ts +1 -0
- package/front_end/panels/timeline/README.md +12 -0
- package/front_end/panels/timeline/StatusDialog.ts +1 -1
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -3
- package/front_end/panels/timeline/TimelineCommentController.ts +346 -0
- package/front_end/panels/timeline/TimelineDetailsView.ts +24 -1
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +34 -30
- package/front_end/panels/timeline/TimelineFlameChartView.ts +22 -1
- package/front_end/panels/timeline/TimelinePanel.ts +12 -5
- package/front_end/panels/timeline/TimelineTreeView.ts +28 -6
- package/front_end/panels/timeline/components/LiveMetricsView.ts +1 -1
- package/front_end/panels/timeline/components/fieldSettingsDialog.css +2 -2
- package/front_end/panels/timeline/components/insights/baseInsightComponent.css +1 -1
- package/front_end/panels/timeline/overlays/components/entriesLinkOverlay.css +2 -2
- package/front_end/panels/timeline/overlays/components/entryLabelOverlay.css +9 -9
- package/front_end/panels/timeline/timeline-meta.ts +2 -2
- package/front_end/panels/timeline/timeline.ts +4 -0
- package/front_end/panels/timeline/timelineFlamechartPopover.css +2 -2
- package/front_end/panels/timeline/timelinePanel.css +2 -2
- package/front_end/panels/web_audio/WebAudioView.ts +7 -4
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/codemirror.next/chunk/angular.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/angular.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/cpp.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/cpp.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/java.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/java.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/less.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/less.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/markdown.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/markdown.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/php.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/php.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/python.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/python.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/sass.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/sass.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/svelte.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/svelte.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/vue.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/vue.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/wast.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/wast.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/xml.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/xml.js.map +1 -1
- package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
- package/front_end/third_party/codemirror.next/rollup.config.mjs +1 -1
- package/front_end/tsconfig.json +1 -1
- package/front_end/ui/comments/CommentAnchorResolver.ts +1 -1
- package/front_end/ui/components/buttons/Button.ts +29 -18
- package/front_end/ui/components/code_highlighter/CodeHighlighter.ts +1 -1
- package/front_end/ui/components/dialogs/TypeToAllowDialog.ts +94 -39
- package/front_end/ui/components/dialogs/dialog.css +1 -1
- package/front_end/ui/components/menus/menuItem.css +11 -0
- package/front_end/ui/components/text_editor/AccessiblePlaceholder.ts +1 -1
- package/front_end/ui/components/text_editor/AiCodeCompletionTeaser.ts +1 -1
- package/front_end/ui/components/text_editor/config.ts +2 -1
- package/front_end/ui/components/text_editor/javascript.ts +2 -1
- package/front_end/ui/legacy/InspectorView.ts +4 -2
- package/front_end/ui/legacy/SplitWidget.ts +14 -16
- package/front_end/ui/legacy/TabbedPane.ts +9 -1
- package/front_end/ui/legacy/UIUtils.ts +60 -40
- package/front_end/ui/legacy/components/color_picker/spectrum.css +2 -2
- package/front_end/ui/legacy/components/data_grid/dataGrid.css +9 -0
- package/front_end/ui/legacy/components/inline_editor/CSSAngle.ts +0 -1
- package/front_end/ui/legacy/components/inline_editor/cssShadowEditor.css +5 -7
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +1 -1
- package/front_end/ui/legacy/components/perf_ui/PieChart.ts +11 -0
- package/front_end/ui/legacy/components/perf_ui/chartViewport.css +4 -4
- package/front_end/ui/legacy/components/quick_open/filteredListWidget.css +6 -0
- package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +1 -1
- package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +38 -13
- package/front_end/ui/legacy/dropTarget.css +1 -1
- package/front_end/ui/legacy/statusBar.css +7 -0
- package/front_end/ui/legacy/tabbedPane.css +0 -7
- package/front_end/ui/visual_logging/KnownContextValues.ts +13 -0
- package/inspector_overlay/main.ts +2 -15
- package/inspector_overlay/tool_persistent.ts +0 -14
- package/mcp/mcp.ts +3 -0
- package/package.json +1 -1
- package/front_end/panels/ai_assistance/components/StylingAgentMarkdownRenderer.ts +0 -178
- package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +0 -147
- package/front_end/panels/profiler/heapDetachedElementsDataGrid.css +0 -14
- package/front_end/ui/components/legacy_wrapper/LegacyWrapper.ts +0 -62
- package/front_end/ui/components/legacy_wrapper/legacy_wrapper.ts +0 -8
- package/inspector_overlay/tool_green_dev_anchors.css +0 -54
- package/inspector_overlay/tool_green_dev_anchors.ts +0 -164
- /package/front_end/models/{ai_assistance → ai-utils}/AiSetting.ts +0 -0
- /package/front_end/models/{ai_assistance → ai-utils}/debug.ts +0 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review-tests
|
|
3
|
+
description: >-
|
|
4
|
+
Reviews Chrome DevTools frontend changes in target directories (\.test\.ts$, ^test/, ^front_end/testing/),
|
|
5
|
+
strictly reflecting review standards, architectural invariants, and security boundaries
|
|
6
|
+
derived from historical code reviews.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Chrome DevTools frontend reviewer skill: tests
|
|
10
|
+
|
|
11
|
+
This skill provides review guidance for Chrome DevTools frontend changes matching the target directories (\.test\.ts$, ^test/, ^front_end/testing/). It focuses specifically on code review verification for test changes, complementing authoring guidance in `devtools-testing-guidance` and integrating with the general review checklist in `code-review`. Every rule below recurred in at least 5 CLs from 2 distinct reviewers in historical reviews; cite the rule id in findings.
|
|
12
|
+
|
|
13
|
+
## Path group `tests` (9 rules)
|
|
14
|
+
|
|
15
|
+
### `TEST_SHARED_FIXTURE_AND_HELPER_REUSE`: Reuse canonical front_end/testing helpers and beforeEach setup without mutating cached shared fixtures
|
|
16
|
+
- **Severity**: WARNING
|
|
17
|
+
- **Why**: Duplicating mock factories (`createTarget`, `createNetworkRequest`, `mockAidaClient`, `cleanTextContent`) or mutating cached objects returned by `TraceLoader` causes cross-test state corruption and maintenance drift across the test suite.
|
|
18
|
+
- **Look for**: Custom inline network request or AIDA client mocks in `.test.ts` files, in-place mutation of `parsedTrace` objects returned by `TraceLoader`, or manual `div` container creation around `renderElementIntoDOM(widget)`.
|
|
19
|
+
- **Do not flag**: Specialized test helpers inside `front_end/testing/` that define the canonical factory implementations themselves.
|
|
20
|
+
|
|
21
|
+
### `TEST_MODULAR_HOOKS_AND_TEST_UNIVERSE`: Use lightweight modular setup hooks and TestUniverse instead of heavyweight describeWithEnvironment wrappers
|
|
22
|
+
- **Severity**: WARNING
|
|
23
|
+
- **Why**: Wrapping unit tests in `describeWithEnvironment` initializes all DevTools global singletons and settings, slowing down tests and hiding implicit global dependencies. Tests should use `TestUniverse` or granular hooks (`setupLocaleHooks()`, `setupSettingsHooks()`, `updateHostConfig()`) and never mix `TestUniverse` with `describeWithEnvironment`.
|
|
24
|
+
- **Look for**: `describeWithEnvironment` in unit tests that only need locale, settings, or `TestUniverse`, or suites combining `new TestUniverse()` with `describeWithEnvironment`, or direct mutation of `Root.Runtime.hostConfig` instead of `updateHostConfig(...)`.
|
|
25
|
+
- **Do not flag**: Integration-style panel tests that exercise legacy singleton classes not yet migrated to `Universe` dependency injection. Bot-only CLI flags, credentials, or standalone runner scripts under `test/conductor/` or `test/ai_evals/` that do not run inside the standard Mocha unit test harness.
|
|
26
|
+
|
|
27
|
+
### `TEST_DETERMINISTIC_ASYNC_SYNCHRONIZATION`: Synchronize asynchronous test assertions using lifecycle promises, expectCall, or raf instead of arbitrary setTimeout delays
|
|
28
|
+
- **Severity**: ERROR
|
|
29
|
+
- **Why**: Waiting on wall-clock `setTimeout` delays or arbitrary microtask ticks makes unit tests slow and flaky under CPU contention on CI bots. Tests should await explicit widget update promises (`await widget.updateComplete`), event promises (`target.once(...)`), stub invocation helpers (`expectCall(stub)`), or `raf()`.
|
|
30
|
+
- **Look for**: `new Promise(r => setTimeout(r, ...))` in `.test.ts` files, synchronous DOM assertions immediately after `requestUpdate()`, or redundant `clock.tick()` calls when no fake timers are pending.
|
|
31
|
+
- **Do not flag**: Tests specifically verifying debounce/throttle timer expiration using `sinon.useFakeTimers()`.
|
|
32
|
+
|
|
33
|
+
### `TEST_STRICT_ASSERTIONS_AND_LITERAL_EXPECTATIONS`: Use strict Chai and Sinon assertions against literal expected values rather than assert.isNotNull on undefined-unions or conditional guards
|
|
34
|
+
- **Severity**: ERROR
|
|
35
|
+
- **Why**: Calling `assert.isNotNull(x)` on a value typed as `T | undefined` passes when `x` is `undefined`, silently skipping assertions. Similarly, wrapping assertions inside `if (el)` or computing expected values by calling the same production helper under test allows broken code to pass.
|
|
36
|
+
- **Look for**: `assert.isNotNull(...)` on `container?.querySelector` / `Map.get` / `Array.find` / optional properties, `if (el) { assert... }` blocks, `assert.isTrue(spy.called)` instead of `sinon.assert.calledWith`, or assertions comparing output against production formatting helpers.
|
|
37
|
+
- **Do not flag**: Variables whose static return type is strictly `T | null` (and never `undefined`).
|
|
38
|
+
|
|
39
|
+
### `TEST_VIEW_AND_PRESENTER_ISOLATION`: Test presenters via createViewFunctionStub and test pure view functions directly without piercing internal DOM structures
|
|
40
|
+
- **Severity**: WARNING
|
|
41
|
+
- **Why**: In DevTools' MVP (`UI.Widget` + `DEFAULT_VIEW`) architecture, presenter tests should follow the view stubbing conventions documented in [`docs/ui_engineering.md`](../../../docs/ui_engineering.md) by stubbing the view function with `createViewFunctionStub(Presenter)` and asserting on `await view.nextInput`, while view rendering tests should invoke `DEFAULT_VIEW(input, output, target)` directly or use screenshot assertions.
|
|
42
|
+
- **Look for**: Presenter tests instantiating full DOM trees and querying shadow/child DOM selectors to simulate clicks when the widget accepts a `view` function, or view tests instantiating full presenters just to test template markup.
|
|
43
|
+
- **Do not flag**: Legacy widgets that have not yet separated their template rendering into a standalone `DEFAULT_VIEW` function.
|
|
44
|
+
|
|
45
|
+
### `TEST_PUBLIC_API_AND_ENCAPSULATION`: Exercise classes through public APIs and constructor-injected dependencies rather than accessing private members or stubbing unused singletons
|
|
46
|
+
- **Severity**: WARNING
|
|
47
|
+
- **Why**: Accessing `#private` or `private` methods via `(instance as any)` or `@ts-expect-error`, piercing child component shadow roots, or stubbing `Class.instance()` when dependencies are already passed via constructor couples tests to internal implementation details.
|
|
48
|
+
- **Look for**: `@ts-expect-error` or `(obj as any).privateMethod()` calls in `.test.ts` files, `sinon.stub(Class, 'instance')` alongside `new UnderTest(mockInstance)`, or `child.shadowRoot.querySelector(...)` inside parent component tests.
|
|
49
|
+
- **Do not flag**: Intentional negative type tests documented with an explanatory `@ts-expect-error` comment.
|
|
50
|
+
|
|
51
|
+
### `TEST_SINGLE_RESPONSIBILITY_AND_CONCISENESS`: Keep each it() block focused on a single behavior and prune duplicate or obsolete tests when features change
|
|
52
|
+
- **Severity**: WARNING
|
|
53
|
+
- **Why**: Combining multiple independent user interactions or feature scenarios into a single monolithic `it()` block obscures failure root causes, while leaving duplicate or orphaned tests behind increases suite runtime and maintenance burden.
|
|
54
|
+
- **Look for**: `it('... and ...')` blocks testing multiple orthogonal interactions sequentially, nested `{ ... }` scope blocks inside a single `it()`, or identical test cases duplicated across `describe` blocks.
|
|
55
|
+
- **Do not flag**: Multi-step stateful workflow tests where earlier steps are required preconditions to reach the state under test.
|
|
56
|
+
|
|
57
|
+
### `TEST_TYPE_SAFE_MOCKS_AND_EVENTS`: Construct typed stubs and real DOM or event instances instead of casting fake objects with as unknown as
|
|
58
|
+
- **Severity**: WARNING
|
|
59
|
+
- **Why**: Casting partial object literals via `as unknown as T` or `as any` bypasses TypeScript compile-time checks, masks missing methods when interfaces evolve, and causes brittle runtime failures. Using `sinon.createStubInstance(Class)`, real DOM/Event constructors (`DataTransfer`, `ClipboardEvent`), or typed fixture helpers preserves type safety.
|
|
60
|
+
- **Look for**: `as unknown as` or `as any` casts on mock objects, fake DOM nodes, or synthetic events in `.test.ts` files, or untyped `querySelector(...) as HTMLElement` calls.
|
|
61
|
+
- **Do not flag**: Tests explicitly verifying runtime handling of malformed untrusted payloads or narrow generic type parameters inside shared `front_end/testing/` helpers.
|
|
62
|
+
|
|
63
|
+
### `TEST_CLEANUP_MUTATED_GLOBALS_AND_WIDGETS`: Restore mutated global properties and detach manually instantiated widgets or singletons in afterEach or finally blocks
|
|
64
|
+
- **Severity**: WARNING
|
|
65
|
+
- **Why**: While Sinon stubs are restored automatically, direct mutations to `window`, `globalThis`, prototypes, or `localStorage`, as well as widgets and panels instantiated with `.markAsRoot()` or `show()`, persist across tests and leak listeners unless explicitly cleaned up in `afterEach` or `try...finally`.
|
|
66
|
+
- **Look for**: Direct assignments to `window.*`, `globalThis.*`, `Object.prototype.*`, `localStorage.*`, or `panel.show(document.body)` in `.test.ts` files without a matching restoration or `detach()` in `afterEach` or `finally`.
|
|
67
|
+
- **Do not flag**: Widgets mounted directly via `renderElementIntoDOM(widget)`, which detaches widgets automatically during global harness teardown.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review-ui-widgets
|
|
3
|
+
description: >-
|
|
4
|
+
Reviews Chrome DevTools frontend changes in path group ui-and-widgets (^front_end/(ui|panels)/.*\.(ts|css)$),
|
|
5
|
+
strictly reflecting review standards, architectural invariants, and security boundaries
|
|
6
|
+
derived from historical code reviews.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Chrome DevTools frontend reviewer skill: ui-and-widgets
|
|
10
|
+
|
|
11
|
+
This skill provides review guidance for Chrome DevTools frontend changes matching the `ui-and-widgets` path group (^front_end/(ui|panels)/.*\.(ts|css)$). It focuses specifically on code review verification for UI and widget changes, complementing authoring guidance in `ui-widgets` and [`docs/ui_engineering.md`](../../../docs/ui_engineering.md), and integrating with the general review checklist in `code-review`. Every rule below recurred in at least 5 CLs from 2 distinct reviewers in historical reviews; cite the rule id in findings.
|
|
12
|
+
|
|
13
|
+
## Path group `ui-and-widgets` (17 rules)
|
|
14
|
+
|
|
15
|
+
### `UI_MODERN_COMPONENT_AND_ENCAPSULATION_STANDARDS`: Use modern DevTools UI primitives (`devtools-button`, `devtools-data-grid`, `devtools-icon`), #private fields, and module entrypoint imports
|
|
16
|
+
- **Severity**: WARNING
|
|
17
|
+
- **Why**: Legacy `UI.Fragment`, `DataGridImpl`, `LitElement`, `new Icon()`, and TypeScript `private` fields are superseded by standard `<devtools-*>` custom elements (imported via module entrypoints such as `import * as Buttons from '../../ui/components/buttons/buttons.js'` so custom tags register at runtime) and ECMAScript `#private` fields.
|
|
18
|
+
- **Look for**: `UI.Fragment.build`, legacy `DataGridImpl`, `extends LitElement`, `private ` keyword instead of `#` in new UI classes, or `<devtools-*>` tags in Lit templates without importing the corresponding component module entrypoint (e.g. `import * as Buttons from '../../ui/components/buttons/buttons.js'`).
|
|
19
|
+
- **Do not flag**: Overriding inherited `protected` lifecycle methods on framework base classes (e.g. extending `UI.Widget.Widget`).
|
|
20
|
+
|
|
21
|
+
### `UI_TYPE_SAFETY_AND_EXHAUSTIVENESS`: Model multi-state UI workflows with discriminated unions, Platform.assertNever exhaustiveness checks, and strict domain types
|
|
22
|
+
- **Severity**: WARNING
|
|
23
|
+
- **Why**: Representing mutually exclusive UI states with loose optional boolean flags or `any` types permits impossible states and silently misses new enum variants. Discriminated unions paired with `Platform.assertNever` in `default:` branches enforce compile-time exhaustiveness.
|
|
24
|
+
- **Look for**: `switch` statements over union/enum types missing `Platform.assertNever(x)` in `default:`, `any` or `declare` field modifiers in UI classes, or multiple boolean flags (`isLoading`, `isError`, `isEmpty`) representing mutually exclusive states.
|
|
25
|
+
- **Do not flag**: Switch statements that intentionally handle only a small subset of a large external protocol enum.
|
|
26
|
+
|
|
27
|
+
### `UI_PURE_VIEW_AND_PRESENTER_SEPARATION`: Keep UI.Widget view functions pure and stateless by computing presentation data in presenters, passing decoupled ViewInput data structures, and preserving helper topology
|
|
28
|
+
- **Severity**: WARNING
|
|
29
|
+
- **Why**: In DevTools' MVP architecture, `DEFAULT_VIEW` functions must be pure projections of `ViewInput` to Lit templates. Querying SDK models, reading global settings, mutating presenter state, or calling host/clipboard APIs inside the view couples rendering to global state and breaks isolated view testing. Additionally, deleting existing standalone/module-level DOM helper functions or async class update helpers and inlining them into `performUpdate()` or `DEFAULT_VIEW` during Lit migrations unnecessarily flattens the abstraction topology and inflates diffs.
|
|
30
|
+
- **Look for**: `DEFAULT_VIEW` or view helper functions calling `Common.Settings.Settings.instance()`, `SDK.*`, `Host.*`, mutating `input.*` arrays in place, accepting raw `SDK`/`Protocol` domain objects instead of decoupled presentation interfaces on `ViewInput`, or Lit migrations that delete existing standalone/class DOM helper functions and inline their logic into `performUpdate()` or `DEFAULT_VIEW` instead of converting them in place to return `LitTemplate` (or `Promise<LitTemplate|null>`).
|
|
31
|
+
- **Do not flag**: Legacy `UI.Widget` subclasses that have not yet migrated to a `DEFAULT_VIEW` function.
|
|
32
|
+
|
|
33
|
+
### `UI_LIT_DECLARATIVE_TEMPLATES_AND_DIRECTIVES`: Use Lit.nothing, repeat with keys, classMap/styleMap, and ifDefined in declarative templates while preserving modular helper functions
|
|
34
|
+
- **Severity**: WARNING
|
|
35
|
+
- **Why**: Mutating DOM elements via `appendChild`, `classList.toggle`, or `innerHTML` alongside Lit templates, or returning `''`/`null` instead of `Lit.nothing` in conditional branches, corrupts Lit's part tracking and creates unnecessary text nodes or wrapper `<div>`s. Conversely, collapsing existing standalone DOM helper functions (e.g., `linkifyIcon`, `maybeCreateLinkToElementsPanel`) or class rendering helpers into a single monolithic `DEFAULT_VIEW` template harms readability and reviewability compared to converting those helpers in place to return `LitTemplate`.
|
|
36
|
+
- **Look for**: Ternary branches returning `''` or `undefined` in `html` templates instead of `Lit.nothing`, unkeyed `.map()` on dynamic stateful lists instead of `repeat()`, `ifDefined` omissions on optional attributes, multiple `Lit.render()` calls mutating the same container, or Lit migrations that flatten/inline existing DOM helper functions and class helper methods instead of preserving them in their original locations returning `LitTemplate`.
|
|
37
|
+
- **Do not flag**: Static arrays of primitive labels where item identity never reorders.
|
|
38
|
+
|
|
39
|
+
### `UI_WIDGET_DOM_AND_LISTENER_LIFECYCLE`: Attach listeners to external models and managers in wasShown and detach them symmetrically in willHide
|
|
40
|
+
- **Severity**: ERROR
|
|
41
|
+
- **Why**: Subscribing to long-lived SDK `TargetManager`, `Settings`, or model events in a widget's constructor without unsubscribing in `willHide()` (or `onDetach()` / `onunbind()`) causes hidden panels to process background updates and leaks detached widget instances.
|
|
42
|
+
- **Look for**: `addEventListener`, `addModelListener`, or `addChangeListener` on singletons, models, or settings inside `UI.Widget` constructors or `wasShown()` without a matching `remove*` call in `willHide()` using the same function reference.
|
|
43
|
+
- **Do not flag**: Listeners attached to the widget's own internal DOM elements (`this.contentElement`), which are garbage-collected together with the widget.
|
|
44
|
+
|
|
45
|
+
### `UI_ACCESSIBILITY_AND_SEMANTIC_HTML`: Use native semantic HTML controls with accurate ARIA attributes, keyboard handlers, and !event.isComposing guards
|
|
46
|
+
- **Severity**: WARNING
|
|
47
|
+
- **Why**: Clickable `<div>`/`<span>` elements and nested interactive controls (`<button>` inside `<a>` or `<button>`) break keyboard navigation and screen readers. Interactive elements require semantic tags (`<button>`, `<details>`/`<summary>`, `<thead>`/`<tbody>`), synchronized ARIA state (`aria-expanded`, `aria-details` for rich tooltips vs `aria-describedby` for plain text), and `!event.isComposing` checks on `Enter` keydown handlers.
|
|
48
|
+
- **Look for**: `@click` on `<div>`/`<span>` without button semantics, `<button>` nested inside `<button>`/`<x-link>`, `Enter` keydown handlers missing `!event.isComposing`, or `aria-describedby` pointing to interactive `<devtools-tooltip>` elements.
|
|
49
|
+
- **Do not flag**: Delegating click listeners on container elements that handle bubbled events from child buttons.
|
|
50
|
+
|
|
51
|
+
### `UI_PERFORMANCE_AND_FLAMECHART_RENDERING`: Precompute expensive metrics outside render loops, use Set/Map for O(1) lookups, and debounce high-frequency UI updates
|
|
52
|
+
- **Severity**: WARNING
|
|
53
|
+
- **Why**: Performing linear `Array.includes`/`find` scans, sorting, or regex parsing inside FlameChart canvas draw loops, `ElementsTreeOutline` mutation callbacks, or Lit render passes causes frame drops and UI jank on large traces and DOM trees.
|
|
54
|
+
- **Look for**: `.includes()` / `.find()` / `.sort()` inside canvas draw or event iteration loops, repeated `ResizeObserver` registrations on individual child items instead of the parent container, or un-debounced filter/mutation handlers.
|
|
55
|
+
- **Do not flag**: One-time initialization passes over bounded small arrays (less than 20 items).
|
|
56
|
+
|
|
57
|
+
### `UI_LOCALIZATION_AND_UISTRINGS_HYGIENE`: Define user-facing strings in sentence-case UIStrings using complete sentences and i18nTemplate for embedded elements, and prune unused entries
|
|
58
|
+
- **Severity**: WARNING
|
|
59
|
+
- **Why**: Concatenating translated fragments breaks word order in non-English locales, title-Cased strings violate Chromium UX standards, translating English-only experimental strings wastes localization quota, and unused `UIStrings` entries bloat locale bundles.
|
|
60
|
+
- **Look for**: String concatenation around `i18nString(...)`, HTML/DOM elements interpolated without `i18nTemplate`, Title Case labels in `UIStrings`, unlocalized English literals in templates, or unused keys in `UIStrings`.
|
|
61
|
+
- **Do not flag**: Technical protocol identifiers, MIME types, or strings in `UIStringsNotTranslate` / `i18n.i18n.lockedString(...)`.
|
|
62
|
+
|
|
63
|
+
### `UI_REACTIVE_WIDGET_UPDATE_LIFECYCLE`: Schedule widget re-renders asynchronously via this.requestUpdate() and guard property setters with equality checks
|
|
64
|
+
- **Severity**: WARNING
|
|
65
|
+
- **Why**: Calling `this.performUpdate()` or invoking `this.#view(...)` synchronously inside property setters causes redundant synchronous DOM renders when multiple properties change in the same tick. Setters should short-circuit if the value is unchanged and call `this.requestUpdate()`.
|
|
66
|
+
- **Look for**: Widget property setters calling `this.performUpdate()` or `this.#view(...)` directly, or setters calling `this.requestUpdate()` without checking `if (this.#prop === value) return;`.
|
|
67
|
+
- **Do not flag**: Internal test helpers or synchronous initialization paths explicitly documented as requiring immediate flush.
|
|
68
|
+
|
|
69
|
+
### `UI_VISUAL_LOGGING_INSTRUMENTATION`: Instrument interactive UI elements and containers with kebab-case VisualLogging contexts registered in KnownContextValues
|
|
70
|
+
- **Severity**: WARNING
|
|
71
|
+
- **Why**: DevTools relies on Visual Elements (`jslog`) telemetry to measure feature usage. Omitting `jslog` on new buttons/toggles/menus, using localized or camelCase context strings, adding redundant panel prefixes inside already-logged containers, or dropping `jslog` during Lit refactors breaks analytics.
|
|
72
|
+
- **Look for**: Interactive elements (`<button>`, `<devtools-button>`, `<input>`, menus, drawers) missing `jslog` or `jslogContext`, non-kebab-case context names, or new context values missing from `KnownContextValues.ts`.
|
|
73
|
+
- **Do not flag**: Purely decorative icons or internal wrapper `<div>`s that represent neither a distinct visual section nor an interactive control.
|
|
74
|
+
|
|
75
|
+
### `UI_CSS_SCOPING_AND_FLEX_LAYOUT`: Scope light-DOM stylesheets and align elements using flexbox or grid rather than competing margin and position offsets
|
|
76
|
+
- **Severity**: INFO
|
|
77
|
+
- **Why**: Unscoped class or tag selectors in light-DOM widget stylesheets leak across the DevTools document, while combining `vertical-align`, negative margins, and `position: relative` offsets creates brittle layouts that break under font scaling or zoom.
|
|
78
|
+
- **Look for**: Unscoped generic selectors in light-DOM `.css` files (or `:host` inside `@scope` blocks instead of `:scope`), or CSS rules combining `vertical-align`, negative `margin-top`, and pixel offsets to center icons and buttons.
|
|
79
|
+
- **Do not flag**: Shadow DOM component stylesheets where `:host` scoping is native.
|
|
80
|
+
|
|
81
|
+
### `UI_VIEW_OUTPUT_AND_CALLBACK_CONTRACTS`: Encapsulate imperative DOM actions in ViewOutput callbacks and pass user actions via semantic ViewInput callbacks instead of raw DOM references
|
|
82
|
+
- **Severity**: WARNING
|
|
83
|
+
- **Why**: Exposing raw `HTMLElement` references on `ViewOutput` or passing raw `MouseEvent`/`KeyboardEvent` objects to presenter callbacks leaks DOM details into presenters. Views should populate narrow functional closures on `ViewOutput` (e.g. `output.focusInput = () => ...`) and unpack event values before calling `input.onSelect(value)`.
|
|
84
|
+
- **Look for**: `ViewOutput` interfaces containing `HTMLElement` or `Element` properties, or `ViewInput` callbacks typed as `(event: Event) => void` instead of semantic domain values.
|
|
85
|
+
- **Do not flag**: Third-party editor or canvas host containers that require a raw mount `HTMLElement`.
|
|
86
|
+
|
|
87
|
+
### `UI_PANEL_AND_META_REGISTRATION`: Follow DevTools panel directory conventions and register settings and views in the appropriate *-meta.ts scope
|
|
88
|
+
- **Severity**: WARNING
|
|
89
|
+
- **Why**: Panel-level `UI.Widget` views belong directly under `front_end/panels/<panel>/` (reserving `components/` for reusable leaf components), internal non-user-facing settings must use `SettingCategory.NONE` or model descriptors rather than appearing in Settings UI, and shared SDK settings belong in `sdk-meta.ts`.
|
|
90
|
+
- **Look for**: Panel-level `UI.Widget` views placed inside `panels/<panel>/components/`, internal state flags registered with user-facing titles in `*-meta.ts`, or `loadView` callbacks calling `.instance()` instead of using the passed `Universe` context.
|
|
91
|
+
- **Do not flag**: Standalone reusable leaf components inside `components/` or genuine user-configurable preferences.
|
|
92
|
+
|
|
93
|
+
### `UI_WEAK_DOM_REFERENCES_AND_OBSERVER_CLEANUP`: Store DOM node metadata in WeakMap or WeakRef collections and clean up observers when elements detach
|
|
94
|
+
- **Severity**: WARNING
|
|
95
|
+
- **Why**: Retaining DOM `Element` or `SDK.Target` references in strong `Map`/`Set` collections (or in `WeakMap` values that hold strong references back to their keys) prevents detached DOM trees from being garbage-collected, while leaving `ResizeObserver`, `MutationObserver`, or `Lit.Directives.ref` callbacks active after unmount leaks memory.
|
|
96
|
+
- **Look for**: Strong `Map<Element, ...>` / `Set<Element>` collections holding DOM/model associations, `WeakMap` values retaining strong references back to their DOM keys, `ResizeObserver`/`IntersectionObserver` without `.unobserve()`/`.disconnect()` on teardown, or `ref(el => ...)` callbacks that do not handle `el === undefined`.
|
|
97
|
+
- **Do not flag**: Module-level `WeakMap<Element, ...>` globals whose values do not strongly reference the key, or short-lived local maps created and discarded within a single synchronous function call.
|
|
98
|
+
|
|
99
|
+
### `UI_SECURITY_AND_OUTPUT_SANITIZATION`: Sanitize untrusted strings, URLs, CSS selectors, and Markdown exports before rendering or exporting
|
|
100
|
+
- **Severity**: ERROR
|
|
101
|
+
- **Why**: Interpolating untrusted network URLs, DOM attributes, or user strings into raw HTML snippets, `CSS.escape`-free attribute selectors, Markdown table exports, or `href` attributes without protocol validation risks injection, XSS, broken layout formatting, or text spoofing.
|
|
102
|
+
- **Look for**: Raw string interpolation in `querySelector('[attr="' + val + '"]')` without `CSS.escape`, `href` attribute bindings with unvalidated `javascript:` URLs, Markdown table cell serialization without escaping `|*_<>\`, or raw HTML snippet generation without HTML escaping.
|
|
103
|
+
- **Do not flag**: Standard Lit `html` text bindings (`${text}`), which escape HTML entities automatically.
|
|
104
|
+
|
|
105
|
+
### `UI_DECLARATIVE_CHILD_WIDGET_COMPOSITION`: Compose child UI.Widget instances declaratively in Lit templates using the two-argument widget(ChildWidget, {...}) directive instead of imperative show() calls or single-argument factory callbacks
|
|
106
|
+
- **Severity**: WARNING
|
|
107
|
+
- **Why**: Imperatively instantiating child widgets and calling `child.show(container)` inside presenters or views bypasses Lit reconciliation, complicates lifecycle management, and recreates widgets unnecessarily across renders. Similarly, single-argument factory callbacks `widget(element => ...)` only run on initial creation and fail to propagate updated properties on subsequent re-renders; strongly prefer the two-argument `widget(ChildWidget, {...})` form (converting `setFoo()` methods on the child widget into `set foo()` setters if needed).
|
|
108
|
+
- **Look for**: `new ChildWidget()` followed by `.show(...)` or `.appendChild(child.element)` inside Lit view functions or migrated `performUpdate()` methods, or `widget(element => ...)` factory callbacks configuring child widget properties imperatively instead of `<devtools-widget ${widget(ChildWidget, {...})}></devtools-widget>` (or `${widget(ChildWidget, {...})}`).
|
|
109
|
+
- **Do not flag**: Top-level legacy split widgets or tabbed panes that have not migrated to Lit views.
|
|
110
|
+
|
|
111
|
+
### `UI_AWAIT_UPDATE_COMPLETE_POST_RENDER`: Await this.updateComplete before executing post-render DOM measurements, focus changes, or scroll adjustments
|
|
112
|
+
- **Severity**: ERROR
|
|
113
|
+
- **Why**: Because `this.requestUpdate()` schedules rendering asynchronously in a microtask, querying DOM geometry, focusing newly rendered controls, or anchoring popovers immediately after `requestUpdate()` operates on stale pre-render DOM state.
|
|
114
|
+
- **Look for**: `this.requestUpdate()` followed synchronously by `.focus()`, `.getBoundingClientRect()`, `.scrollIntoView()`, or child widget measurement without `await this.updateComplete`.
|
|
115
|
+
- **Do not flag**: State updates that do not interact with rendered DOM nodes after scheduling the update.
|
|
@@ -18,6 +18,11 @@ existing element containers.
|
|
|
18
18
|
|
|
19
19
|
* Maintain the existing class hierarchy, helper class boundaries, and
|
|
20
20
|
logical groups.
|
|
21
|
+
* Preserve existing standalone/module-level DOM helper functions (e.g.,
|
|
22
|
+
`linkifyIcon`, `maybeCreateLinkToElementsPanel`) and class helper
|
|
23
|
+
methods in their original locations, converting DOM-returning helpers in
|
|
24
|
+
place to return `LitTemplate` (or `Promise<LitTemplate|null>`) rather
|
|
25
|
+
than deleting and inlining them into `performUpdate()` or `DEFAULT_VIEW`.
|
|
21
26
|
* Do not aggressively "flatten" classes or collapse helper abstractions
|
|
22
27
|
into the main view just to coerce a single master template. Pass 2
|
|
23
28
|
should only change the *implementation details* of rendering (imperative
|
|
@@ -119,9 +124,20 @@ existing element containers.
|
|
|
119
124
|
* The Gerrit Code Review UI cannot identify moved blocks of unchanged code.
|
|
120
125
|
* If blocks of code need to be reordered, create a "prefactoring" change that first extracts the code that needs to be reordered into a named helper functions and pause the migration, waiting user confirmation.
|
|
121
126
|
|
|
122
|
-
12. **
|
|
123
|
-
|
|
124
|
-
*
|
|
127
|
+
12. **Composing Child `UI.Widget`s & Pre-Existing Instances**:
|
|
128
|
+
|
|
129
|
+
* **Strongly Prefer Two-Argument `widget(ChildWidgetClass, {params})`**:
|
|
130
|
+
When instantiating child widgets in a Lit template, strongly prefer the
|
|
131
|
+
two-argument form `widget(ChildWidgetClass, {propA: input.a, propB: input.b})`
|
|
132
|
+
over the single-argument factory `widget(element => new ChildWidgetClass(element))`.
|
|
133
|
+
The two-argument form automatically propagates updated parameters and
|
|
134
|
+
schedules `requestUpdate()` on re-renders, whereas a factory callback only
|
|
135
|
+
runs once on initial creation. If the child widget currently uses
|
|
136
|
+
`setFoo()` methods instead of setters, convert them into `set foo()`
|
|
137
|
+
setters on the child widget so you can use the two-argument `widget()`
|
|
138
|
+
directive.
|
|
139
|
+
* **Pre-Existing Widget Instances (`UI.Widget.WrapperWidget`)**: Use
|
|
140
|
+
`${widget(UI.Widget.WrapperWidget, {widget: input.childWidget})}` when
|
|
125
141
|
embedding widgets owned by `UI.ViewManager`
|
|
126
142
|
(`TabbedViewLocation.tabbedPane()`, `StackLocation.widget()`) or when
|
|
127
143
|
conditionally moving a shared widget instance between containers
|
|
@@ -73,6 +73,7 @@ clean `UI.Widget` classes that use native update rendering delegates.
|
|
|
73
73
|
html`<devtools-widget ${widget(MyWidgetClass, {params})}></devtools-widget>`
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
+
* **Strongly prefer the two-argument `widget(MyWidgetClass, {params})` form** over the single-argument factory callback `widget(element => new MyWidgetClass(element, ...))`. The single-argument factory only runs on initial creation and does not update properties on subsequent re-renders. If the child widget only exposes `setFoo(...)` methods, convert them into `set foo(...)` setters so they can be passed via the second argument of `widget()`.
|
|
76
77
|
* Inspect instantiator files (e.g., `ApplicationPanelSidebar.ts`) and
|
|
77
78
|
decouple any direct accesses to `.element`.
|
|
78
79
|
|
|
@@ -81,7 +82,7 @@ clean `UI.Widget` classes that use native update rendering delegates.
|
|
|
81
82
|
## 2. Safety & Verification Rules
|
|
82
83
|
|
|
83
84
|
* **CRITICAL**: Never update screenshot goldens without explicit consent of the user. Most likely the failure points to an issue in the implementation or (less likely) the test itself. Look at the screenshot diffs to debug.
|
|
84
|
-
* **Minimal Code Movement**: When migrating, try to move code around as little as possible, in particular around the lit rendering helpers. This minimizes the git diff and improves reviewability.
|
|
85
|
+
* **Minimal Code Movement & Helper Topology**: When migrating, try to move code around as little as possible, in particular around the lit rendering helpers. Preserve existing standalone/module-level DOM helper functions (e.g., `linkifyIcon`, `maybeCreateLinkToElementsPanel`) and async class update helpers in their original locations, having DOM helpers return `LitTemplate` (or `Promise<LitTemplate|null>`) rather than deleting and inlining them into `performUpdate()` or `DEFAULT_VIEW`. This minimizes the git diff and improves reviewability.
|
|
85
86
|
|
|
86
87
|
--------------------------------------------------------------------------------
|
|
87
88
|
|
|
@@ -59,8 +59,10 @@ const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement)
|
|
|
59
59
|
### Composition
|
|
60
60
|
|
|
61
61
|
* To render a child widget, the parent's View MUST use the lit-html directive `UI.Widget.widget`.
|
|
62
|
+
* **Strongly prefer the two-argument `widget(WidgetClass, {params})` form** over the single-argument factory callback `widget(element => new WidgetClass(element, ...))`. The two-argument form automatically updates properties and calls `requestUpdate()` on subsequent renders, whereas a factory callback only runs once on initial instantiation.
|
|
63
|
+
* If a child widget currently exposes imperative setter methods (e.g., `setStorageKey(key)` or `setStorageBucket(bucket)`) instead of public properties/setters, convert them into standard TypeScript setters (`set storageKey(key)`, `set storageBucket(bucket)`) on the child widget so it can be instantiated and updated declaratively via the two-argument `widget(WidgetClass, {params})` directive.
|
|
62
64
|
* Configuration is passed via the parameters.
|
|
63
|
-
* Properties passed from a parent MUST be declared as public fields on the child presenter class.
|
|
65
|
+
* Properties passed from a parent MUST be declared as public fields or setters on the child presenter class.
|
|
64
66
|
* The framework automatically updates these properties and calls `requestUpdate()` on the child when the parent re-renders.
|
|
65
67
|
* **Pre-existing Widget Instances (`WrapperWidget`):** To render an existing `UI.Widget` instance (such as locations created by `UI.ViewManager`: `TabbedViewLocation.tabbedPane()`, `StackLocation.widget()`) declaratively without creating a custom wrapper class, use `${widget(UI.Widget.WrapperWidget, {widget: myWidgetInstance})}`. `WrapperWidget` automatically forwards constraints, handles attach/detach lifecycle, and supports dynamic widget replacement.
|
|
66
68
|
|
package/AUTHORS
CHANGED
|
@@ -35,6 +35,7 @@ Conner Turner <cturner@zyme.xyz>
|
|
|
35
35
|
Daniel bellfield <dnlbellfield@gmail.com>
|
|
36
36
|
Danny Eldridge <me@heardanieljames.com>
|
|
37
37
|
Derek Li <the.derekli@gmail.com>
|
|
38
|
+
DevTools AIRC Bot <devtools-airc-bot@mths-airc-433412.iam.gserviceaccount.com>
|
|
38
39
|
Dmitry Kryaklin <dmkryak@gmail.com>
|
|
39
40
|
Douglas Chiang <douglasdothnc@gmail.com>
|
|
40
41
|
Dragonish <no.web.developer@outlook.com>
|
|
@@ -85,6 +86,7 @@ Muhammad Mahad <mahadtxt@gmail.com>
|
|
|
85
86
|
Naoto Ono <onoto1998@gmail.com>
|
|
86
87
|
Navoda Munasinha <navoda.munasinha@codimite.com>
|
|
87
88
|
Nourhan Hasan <nourhan.m.hasan@gmail.com>
|
|
89
|
+
Omar Ramadan <omar@blockcast.net>
|
|
88
90
|
Paras Awasthi <awasthiparas6@gmail.com>
|
|
89
91
|
Paul Fisher <paul@pfish.zone>
|
|
90
92
|
Peng Zhou <zhoupeng.1996@bytedance.com>
|
|
@@ -111,6 +113,7 @@ Simon Siefke <simon.siefke@gmail.com>
|
|
|
111
113
|
Stephen Tsoi-A-Sue <stsoiasue@gmail.com>
|
|
112
114
|
Steve Harrison <steve@steveharrison.dev>
|
|
113
115
|
Sunnylost <sunnylost@gmail.com>
|
|
116
|
+
Sutthinon <mankhong.garden@gmail.com>
|
|
114
117
|
Suyoung Jung <tdhitbtd@gmail.com>
|
|
115
118
|
TaegeonKim <aksen5240@gmail.com>
|
|
116
119
|
Thomas Stokes <git@tombl.dev>
|
package/DIR_METADATA
CHANGED
|
@@ -17,6 +17,26 @@ agentic_review: {
|
|
|
17
17
|
".agents/skills/devtools-ux-writing-refactor/SKILL.md"
|
|
18
18
|
]
|
|
19
19
|
}
|
|
20
|
+
capability_groups: {
|
|
21
|
+
path_expression: [
|
|
22
|
+
"front_end/(core|models|entrypoints|generated)/.*\\.ts",
|
|
23
|
+
".*BUILD\\.gn",
|
|
24
|
+
".*\\.gni"
|
|
25
|
+
]
|
|
26
|
+
path_expression_exclusion: [".*\\.test\\.ts"]
|
|
27
|
+
rules: [
|
|
28
|
+
".agents/rules/models-and-core/core-trace-engine-handler-invariants.md",
|
|
29
|
+
".agents/rules/models-and-core/core-sdk-model-and-target-lifecycle.md",
|
|
30
|
+
".agents/rules/models-and-core/core-gn-build-and-module-layering.md",
|
|
31
|
+
".agents/rules/models-and-core/core-ai-agent-context-and-prompt-discipline.md",
|
|
32
|
+
".agents/rules/models-and-core/core-runtime-neutrality-and-platform-utils.md",
|
|
33
|
+
".agents/rules/models-and-core/core-cdp-and-extension-error-handling.md",
|
|
34
|
+
".agents/rules/models-and-core/core-security-origin-and-capability-guards.md",
|
|
35
|
+
".agents/rules/models-and-core/core-sourcemap-and-workspace-mapping.md",
|
|
36
|
+
".agents/rules/models-and-core/core-settings-and-storage-migration.md",
|
|
37
|
+
".agents/rules/models-and-core/core-trace-insight-models-and-timing-types.md"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
20
40
|
capability_groups: {
|
|
21
41
|
path_expression: ["front_end/(panels|ui)/.*\\.(ts|css)"]
|
|
22
42
|
path_expression_exclusion: [".*\\.test\\.ts"]
|
|
@@ -24,13 +44,43 @@ agentic_review: {
|
|
|
24
44
|
".agents/skills/ui-widgets/SKILL.md",
|
|
25
45
|
".agents/skills/ui-eng-vision-orchestrator/SKILL.md"
|
|
26
46
|
]
|
|
47
|
+
rules: [
|
|
48
|
+
".agents/rules/ui-and-widgets/ui-modern-component-and-encapsulation-standards.md",
|
|
49
|
+
".agents/rules/ui-and-widgets/ui-type-safety-and-exhaustiveness.md",
|
|
50
|
+
".agents/rules/ui-and-widgets/ui-pure-view-and-presenter-separation.md",
|
|
51
|
+
".agents/rules/ui-and-widgets/ui-lit-declarative-templates-and-directives.md",
|
|
52
|
+
".agents/rules/ui-and-widgets/ui-widget-dom-and-listener-lifecycle.md",
|
|
53
|
+
".agents/rules/ui-and-widgets/ui-accessibility-and-semantic-html.md",
|
|
54
|
+
".agents/rules/ui-and-widgets/ui-performance-and-flamechart-rendering.md",
|
|
55
|
+
".agents/rules/ui-and-widgets/ui-localization-and-uistrings-hygiene.md",
|
|
56
|
+
".agents/rules/ui-and-widgets/ui-reactive-widget-update-lifecycle.md",
|
|
57
|
+
".agents/rules/ui-and-widgets/ui-visual-logging-instrumentation.md",
|
|
58
|
+
".agents/rules/ui-and-widgets/ui-css-scoping-and-flex-layout.md",
|
|
59
|
+
".agents/rules/ui-and-widgets/ui-view-output-and-callback-contracts.md",
|
|
60
|
+
".agents/rules/ui-and-widgets/ui-panel-and-meta-registration.md",
|
|
61
|
+
".agents/rules/ui-and-widgets/ui-weak-dom-references-and-observer-cleanup.md",
|
|
62
|
+
".agents/rules/ui-and-widgets/ui-security-and-output-sanitization.md",
|
|
63
|
+
".agents/rules/ui-and-widgets/ui-declarative-child-widget-composition.md",
|
|
64
|
+
".agents/rules/ui-and-widgets/ui-await-update-complete-post-render.md"
|
|
65
|
+
]
|
|
27
66
|
}
|
|
28
67
|
capability_groups: {
|
|
29
|
-
path_expression: [".*\\.test\\.ts", "test/.*\\.ts"]
|
|
68
|
+
path_expression: [".*\\.test\\.ts", "test/.*\\.ts", "front_end/testing/.*\\.ts"]
|
|
30
69
|
review_capability_skills: [
|
|
31
70
|
".agents/skills/devtools-testing-guidance/SKILL.md",
|
|
32
71
|
".agents/skills/foundation-test-migration/SKILL.md",
|
|
33
72
|
".agents/skills/fix-tests/SKILL.md"
|
|
34
73
|
]
|
|
74
|
+
rules: [
|
|
75
|
+
".agents/rules/tests/test-shared-fixture-and-helper-reuse.md",
|
|
76
|
+
".agents/rules/tests/test-modular-hooks-and-test-universe.md",
|
|
77
|
+
".agents/rules/tests/test-deterministic-async-synchronization.md",
|
|
78
|
+
".agents/rules/tests/test-strict-assertions-and-literal-expectations.md",
|
|
79
|
+
".agents/rules/tests/test-view-and-presenter-isolation.md",
|
|
80
|
+
".agents/rules/tests/test-public-api-and-encapsulation.md",
|
|
81
|
+
".agents/rules/tests/test-single-responsibility-and-conciseness.md",
|
|
82
|
+
".agents/rules/tests/test-type-safe-mocks-and-events.md",
|
|
83
|
+
".agents/rules/tests/test-cleanup-mutated-globals-and-widgets.md"
|
|
84
|
+
]
|
|
35
85
|
}
|
|
36
86
|
}
|
package/eslint.config.mjs
CHANGED
|
@@ -267,8 +267,7 @@ export default defineConfig([
|
|
|
267
267
|
'error',
|
|
268
268
|
{
|
|
269
269
|
selector: 'ExportDefaultDeclaration',
|
|
270
|
-
message:
|
|
271
|
-
'Default exports are not allowed. Use named exports instead.',
|
|
270
|
+
message: 'Default exports are not allowed. Use named exports instead.',
|
|
272
271
|
},
|
|
273
272
|
],
|
|
274
273
|
/**
|
|
@@ -309,8 +308,8 @@ export default defineConfig([
|
|
|
309
308
|
'error',
|
|
310
309
|
{
|
|
311
310
|
definedTags: [
|
|
312
|
-
'attribute',
|
|
313
|
-
'meaning',
|
|
311
|
+
'attribute', // @attribute is used by lit-analyzer (through web-component-analyzer)
|
|
312
|
+
'meaning', // @meaning is used by localization
|
|
314
313
|
],
|
|
315
314
|
},
|
|
316
315
|
],
|
|
@@ -341,11 +340,11 @@ export default defineConfig([
|
|
|
341
340
|
parserOptions: {
|
|
342
341
|
allowAutomaticSingleRunInference: true,
|
|
343
342
|
project: join(
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
343
|
+
import.meta.dirname,
|
|
344
|
+
'config',
|
|
345
|
+
'typescript',
|
|
346
|
+
'tsconfig.eslint.json',
|
|
347
|
+
),
|
|
349
348
|
},
|
|
350
349
|
},
|
|
351
350
|
|
|
@@ -588,12 +587,12 @@ export default defineConfig([
|
|
|
588
587
|
{
|
|
589
588
|
// Enforce that any import of models/trace/trace.js names the import Trace.
|
|
590
589
|
modulePath: join(
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
590
|
+
import.meta.dirname,
|
|
591
|
+
'front_end',
|
|
592
|
+
'models',
|
|
593
|
+
'trace',
|
|
594
|
+
'trace.js',
|
|
595
|
+
),
|
|
597
596
|
importName: 'Trace',
|
|
598
597
|
},
|
|
599
598
|
],
|
|
@@ -668,6 +667,8 @@ export default defineConfig([
|
|
|
668
667
|
],
|
|
669
668
|
'@devtools/static-custom-event-names': 'error',
|
|
670
669
|
'@devtools/lit-no-attribute-quotes': 'error',
|
|
670
|
+
'@devtools/lit-no-non-latin1': 'error',
|
|
671
|
+
'@devtools/no-boolean-input-checked-attr': 'error',
|
|
671
672
|
'@devtools/lit-template-result-or-nothing': 'error',
|
|
672
673
|
'@devtools/inject-checkbox-styles': 'error',
|
|
673
674
|
'@devtools/jslog-context-list': 'error',
|
|
@@ -792,6 +793,7 @@ export default defineConfig([
|
|
|
792
793
|
'@devtools/prefer-url-string': 'error',
|
|
793
794
|
'@devtools/trace-engine-test-timeouts': 'error',
|
|
794
795
|
'@devtools/no-document-body-mutation': 'error',
|
|
796
|
+
'@devtools/no-manual-sinon-restore': 'error',
|
|
795
797
|
// Don't update the KnownContext with test data.
|
|
796
798
|
'@devtools/jslog-context-list': 'off',
|
|
797
799
|
'@devtools/enforce-custom-element-definitions-location': 'off',
|
|
@@ -821,10 +823,16 @@ export default defineConfig([
|
|
|
821
823
|
{
|
|
822
824
|
name: 'Use private class members rule',
|
|
823
825
|
files: [
|
|
826
|
+
'front_end/core/**/*.ts',
|
|
827
|
+
'front_end/models/**/*.ts',
|
|
824
828
|
'front_end/panels/**/components/*.ts',
|
|
825
829
|
'front_end/ui/components/**/*.ts',
|
|
826
830
|
'front_end/entrypoints/**/*.ts',
|
|
827
831
|
],
|
|
832
|
+
ignores: [
|
|
833
|
+
'front_end/core/**/*.test.ts',
|
|
834
|
+
'front_end/models/**/*.test.ts',
|
|
835
|
+
],
|
|
828
836
|
|
|
829
837
|
rules: {
|
|
830
838
|
'@devtools/prefer-private-class-members': 'error',
|
|
@@ -833,6 +841,29 @@ export default defineConfig([
|
|
|
833
841
|
{
|
|
834
842
|
name: 'Ignore private class members rule',
|
|
835
843
|
files: [
|
|
844
|
+
'front_end/core/common/**/*.ts',
|
|
845
|
+
'front_end/core/host/**/*.ts',
|
|
846
|
+
'front_end/core/platform/**/*.ts',
|
|
847
|
+
'front_end/core/protocol_client/**/*.ts',
|
|
848
|
+
'front_end/core/sdk/**/*.ts',
|
|
849
|
+
'front_end/core/text_utils/**/*.ts',
|
|
850
|
+
'front_end/models/bindings/**/*.ts',
|
|
851
|
+
'front_end/models/breakpoints/**/*.ts',
|
|
852
|
+
'front_end/models/computed_style/**/*.ts',
|
|
853
|
+
'front_end/models/cpu_profile/**/*.ts',
|
|
854
|
+
'front_end/models/elements/**/*.ts',
|
|
855
|
+
'front_end/models/emulation/**/*.ts',
|
|
856
|
+
'front_end/models/extensions/**/*.ts',
|
|
857
|
+
'front_end/models/formatter/**/*.ts',
|
|
858
|
+
'front_end/models/har/**/*.ts',
|
|
859
|
+
'front_end/models/javascript_metadata/**/*.ts',
|
|
860
|
+
'front_end/models/logs/**/*.ts',
|
|
861
|
+
'front_end/models/persistence/**/*.ts',
|
|
862
|
+
'front_end/models/source_map_scopes/**/*.ts',
|
|
863
|
+
'front_end/models/trace/**/*.ts',
|
|
864
|
+
'front_end/models/trace_source_maps_resolver/**/*.ts',
|
|
865
|
+
'front_end/models/workspace/**/*.ts',
|
|
866
|
+
'front_end/models/workspace_diff/**/*.ts',
|
|
836
867
|
'front_end/panels/recorder/**/*.ts',
|
|
837
868
|
'front_end/ui/components/suggestion_input/*.ts',
|
|
838
869
|
],
|
|
@@ -899,12 +930,12 @@ export default defineConfig([
|
|
|
899
930
|
bannedImportPaths: [
|
|
900
931
|
{
|
|
901
932
|
bannedPath: join(
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
933
|
+
import.meta.dirname,
|
|
934
|
+
'front_end',
|
|
935
|
+
'core',
|
|
936
|
+
'sdk',
|
|
937
|
+
'sdk.js',
|
|
938
|
+
),
|
|
908
939
|
allowTypeImports: true,
|
|
909
940
|
},
|
|
910
941
|
],
|
|
@@ -963,4 +994,15 @@ export default defineConfig([
|
|
|
963
994
|
'no-restricted-syntax': 'off',
|
|
964
995
|
},
|
|
965
996
|
},
|
|
997
|
+
{
|
|
998
|
+
name: 'Mocha test harness setup files',
|
|
999
|
+
files: [
|
|
1000
|
+
'front_end/testing/test_setup.ts',
|
|
1001
|
+
'test/unit/mocha-hooks.ts',
|
|
1002
|
+
],
|
|
1003
|
+
rules: {
|
|
1004
|
+
// Global Mocha test harness restores Sinon stubs and timers after each test.
|
|
1005
|
+
'@devtools/no-manual-sinon-restore': 'off',
|
|
1006
|
+
},
|
|
1007
|
+
},
|
|
966
1008
|
]);
|
|
@@ -36,6 +36,7 @@ export interface HostRuntime {
|
|
|
36
36
|
getCacheStorage(): CacheStorageLike|undefined;
|
|
37
37
|
getDevicePixelRatio(): number;
|
|
38
38
|
saveScreenshot(options: ScreenshotOptions): Promise<void>;
|
|
39
|
+
copyScreenshot(options: ScreenshotOptions): Promise<void>;
|
|
39
40
|
revokeLastScreenshotUrl(): void;
|
|
40
41
|
loadTextFile(url: URL): Promise<string>;
|
|
41
42
|
evaluateCSS(dataValue: string|null, customExpr: string): string|null;
|
|
@@ -130,6 +130,15 @@ async function saveScreenshot(options: Api.HostRuntime.ScreenshotOptions): Promi
|
|
|
130
130
|
link.click();
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
async function copyScreenshot(options: Api.HostRuntime.ScreenshotOptions): Promise<void> {
|
|
134
|
+
const response = await fetch('data:image/png;base64,' + options.base64Png);
|
|
135
|
+
const blob = await response.blob();
|
|
136
|
+
|
|
137
|
+
await navigator.clipboard.write([
|
|
138
|
+
new ClipboardItem({'image/png': blob}),
|
|
139
|
+
]);
|
|
140
|
+
}
|
|
141
|
+
|
|
133
142
|
let cssEvaluationElement: HTMLElement|null = null;
|
|
134
143
|
|
|
135
144
|
export const HOST_RUNTIME: Api.HostRuntime.HostRuntime = {
|
|
@@ -155,6 +164,7 @@ export const HOST_RUNTIME: Api.HostRuntime.HostRuntime = {
|
|
|
155
164
|
return window.devicePixelRatio;
|
|
156
165
|
},
|
|
157
166
|
saveScreenshot,
|
|
167
|
+
copyScreenshot,
|
|
158
168
|
revokeLastScreenshotUrl,
|
|
159
169
|
async loadTextFile(url: URL): Promise<string> {
|
|
160
170
|
const response = await fetch(url);
|
|
@@ -137,6 +137,7 @@ export const HOST_RUNTIME: Api.HostRuntime.HostRuntime = {
|
|
|
137
137
|
return 1;
|
|
138
138
|
},
|
|
139
139
|
async saveScreenshot(_options: Api.HostRuntime.ScreenshotOptions): Promise<void>{},
|
|
140
|
+
async copyScreenshot(_options: Api.HostRuntime.ScreenshotOptions): Promise<void>{},
|
|
140
141
|
revokeLastScreenshotUrl(): void{},
|
|
141
142
|
async loadTextFile(url: URL): Promise<string> {
|
|
142
143
|
return await Fs.promises.readFile(Url.fileURLToPath(url), 'utf-8');
|