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,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/models-and-core/core-ai-agent-context-and-prompt-discipline
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Keep AI agent prompts, tool schemas, and data formatters deterministic, token-efficient, and decoupled from UI and locale state
|
|
8
|
+
- **Look for**: Localized `i18nString` calls or verbose boilerplate prose inside AI data formatters, unsorted flag/property lists in prompt serializers, AI tools missing permission policy declarations, or monolithic trace models passed to response widgets.
|
|
9
|
+
- **Do not flag**: User-facing UI labels rendered in the AI assistance panel chrome rather than sent to the LLM.
|
|
10
|
+
|
|
11
|
+
**Why.** AI agent data formatters (`models/ai_assistance/data_formatters/`) must produce deterministic, unlocalized, concise text representations decoupled from UI widgets and trace insight models, while tools must declare explicit permission policies and flatten verbose CDP types.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
export function formatInsightForPrompt(insight: Insight): string {
|
|
19
|
+
return `Here is a detailed explanation: ${i18nString(UIStrings.localizedSummary)}`;
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Good:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
export function formatInsightForPrompt(insight: Insight): string {
|
|
27
|
+
return `metric=${insight.metricValue}ms, savings=${insight.estimatedSavings}ms`;
|
|
28
|
+
}
|
|
29
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/models-and-core/core-cdp-and-extension-error-handling
|
|
3
|
+
rubric: correctness
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Handle CDP ProtocolResponseWithError and ContentDataOrError explicitly, release RemoteObject handles in finally blocks, and return Promises
|
|
8
|
+
- **Look for**: `try { await ...invoke_*() }` or `try { await request.requestContentData() }` blocks, `Runtime.evaluate` calls creating `RemoteObject`s without `release()` in `finally`, callback-taking SDK methods instead of `Promise`, or `reject(rawObject)` in `ExtensionAPI.ts`.
|
|
9
|
+
- **Do not flag**: `try/catch` blocks that wrap subsequent throwing operations like `JSON.parse()`. Properties marked required (non-optional) in generated `front_end/generated/protocol.ts` CDP types (do not ask for redundant runtime null/undefined checks on them), or `node.shadowRoots()[0]` accesses (elements have at most one shadow root; the array return type is a legacy Shadow DOM v0 artifact).
|
|
10
|
+
|
|
11
|
+
**Why.** CDP agent calls and `requestContentData()` resolve to error-bearing response objects (`getError()`, `ContentData.isError()`) rather than throwing, so wrapping them in `try/catch` is misleading. Furthermore, temporary `RemoteObject` handles must be released in `finally` blocks, and extension APIs must reject with sanitized `Error` instances.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
try {
|
|
19
|
+
const content = await request.requestContentData();
|
|
20
|
+
process(content.text);
|
|
21
|
+
} catch (err) {
|
|
22
|
+
console.error(err);
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Good:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
const contentData = await request.requestContentData();
|
|
30
|
+
if (TextUtils.ContentData.ContentData.isError(contentData)) {
|
|
31
|
+
return {error: contentData.error};
|
|
32
|
+
}
|
|
33
|
+
process(contentData.text);
|
|
34
|
+
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/models-and-core/core-gn-build-and-module-layering
|
|
3
|
+
rubric: correctness
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Enforce strict GN bundle visibility, declare complete deps/ts_deps, and never import UI or panel modules from foundation layers
|
|
8
|
+
- **Look for**: Imports of `ui/` or `panels/` inside `core/` or `models/`, `visibility = [ "*" ]` on new panel `BUILD.gn` targets, direct internal file imports across module boundaries instead of `:bundle` namespace imports, or missing `foundation_unittests` entries.
|
|
9
|
+
- **Do not flag**: Core utility libraries intentionally exposed to the entire codebase with `visibility = [ "*" ]`.
|
|
10
|
+
|
|
11
|
+
**Why.** DevTools enforces a strict DAG where `core/` and `models/` (`foundation`) must never depend on `ui/` or `panels/`. In `BUILD.gn`, modules must depend on `:bundle` targets across directories, register new files in `devtools_grd_files.gni` and `foundation_unittests`, and restrict panel `visibility`.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
devtools_entrypoint("bundle") {
|
|
19
|
+
entrypoint = "my_panel.ts"
|
|
20
|
+
deps = [ ":my_panel" ]
|
|
21
|
+
visibility = [ "*" ]
|
|
22
|
+
}
|
|
23
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/models-and-core/core-runtime-neutrality-and-platform-utils
|
|
3
|
+
rubric: correctness
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Maintain runtime neutrality in foundation modules using Platform.HostRuntime, globalThis, and centralized core/platform utilities
|
|
8
|
+
- **Look for**: `navigator.userAgent`, `window.setTimeout`, `window.atob`, manual `new Promise(r => { resolve = r; })` deferreds instead of `Promise.withResolvers()`, or ad-hoc MIME/escaping regexes in `core/` and `models/`.
|
|
9
|
+
- **Do not flag**: Browser-only UI components in `front_end/panels/` or `front_end/ui/`.
|
|
10
|
+
|
|
11
|
+
**Why.** Foundation modules (`core/` and `models/`) run in both browser DevTools and headless Node.js/worker environments (such as trace analysis and MCP servers). Accessing `window`, `navigator.userAgent`, or `document` directly breaks non-browser runtimes, and duplicating MIME/string/deferred utilities causes subtle bugs.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const ua = navigator.userAgent;
|
|
19
|
+
let resolve!: () => void;
|
|
20
|
+
const promise = new Promise<void>(r => { resolve = r; });
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Good:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
const ua = Platform.HostRuntime.HOST_RUNTIME.getUserAgent();
|
|
27
|
+
const {promise, resolve} = Promise.withResolvers<void>();
|
|
28
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/models-and-core/core-sdk-model-and-target-lifecycle
|
|
3
|
+
rubric: correctness
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Manage SDK model and sub-target state on scoped manager instances using O(1) indexed maps rather than module globals or linear scans
|
|
8
|
+
- **Look for**: Module-level `const tracked = new Map/Set()` in `core/sdk/` or `models/bindings/`, linear DOM tree traversals for frame/node lookups instead of indexed `Map`s, or target listeners that ignore sub-target attachment/detachment.
|
|
9
|
+
- **Do not flag**: Immutable module-level `Set` or `Map` lookup tables of constant string literals. Properties marked required (non-optional) in generated `front_end/generated/protocol.ts` CDP types (do not ask for redundant runtime null/undefined checks on them), or `node.shadowRoots()[0]` accesses (elements have at most one shadow root; the array return type is a legacy Shadow DOM v0 artifact).
|
|
10
|
+
|
|
11
|
+
**Why.** Storing model tracking collections (`Set`/`Map`) at module scope leaks state across multiple `TestUniverse` instances and targets, while failing to track OOPIF/worker sub-targets or scanning DOM trees linearly for frame nodes causes bugs and $O(N)$ bottlenecks.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const trackedSourceCodes = new Set<Workspace.UISourceCode.UISourceCode>();
|
|
19
|
+
export class NetworkProjectManager {
|
|
20
|
+
add(uiSourceCode: Workspace.UISourceCode.UISourceCode) {
|
|
21
|
+
trackedSourceCodes.add(uiSourceCode);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Good:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
export class NetworkProjectManager {
|
|
30
|
+
readonly #trackedSourceCodes = new Set<Workspace.UISourceCode.UISourceCode>();
|
|
31
|
+
add(uiSourceCode: Workspace.UISourceCode.UISourceCode): void {
|
|
32
|
+
this.#trackedSourceCodes.add(uiSourceCode);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/models-and-core/core-security-origin-and-capability-guards
|
|
3
|
+
rubric: security
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Enforce security origin validation, enterprise policy guards, and branded UrlString types in the model and host layers
|
|
8
|
+
- **Look for**: Unbranded `string` URLs in model/agent interfaces instead of `Platform.DevToolsPath.UrlString`, security origin checks performed only in UI views, or resource lookup errors returned before permission checks in `ExtensionServer`.
|
|
9
|
+
- **Do not flag**: Internal display-only label strings that are never used for resource resolution or security checks.
|
|
10
|
+
|
|
11
|
+
**Why.** Security origin checks (SOP), workspace access boundaries, and enterprise/geo-restriction capability checks must be enforced in `core/` and `models/` using `SecurityOrigin`, `Common.ParsedURL`, and `Platform.DevToolsPath.UrlString` rather than relying on UI-layer checks or unvalidated source URLs.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
export interface SourceFile {
|
|
19
|
+
url: string;
|
|
20
|
+
}
|
|
21
|
+
// Derive security origin from untrusted sourceMappingURL comment:
|
|
22
|
+
const origin = Common.ParsedURL.ParsedURL.extractOrigin(script.sourceURL);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Good:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
export interface SourceFile {
|
|
29
|
+
url: Platform.DevToolsPath.UrlString;
|
|
30
|
+
}
|
|
31
|
+
// Derive security origin from trusted execution context or frame metadata:
|
|
32
|
+
const origin = script.executionContext()?.securityOrigin;
|
|
33
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/models-and-core/core-settings-and-storage-migration
|
|
3
|
+
rubric: correctness
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Guard settings and storage migrations with try/catch, preserve user preferences across renames, and clean up obsolete flags
|
|
8
|
+
- **Look for**: Unprotected `JSON.parse()` in `Settings.ts` or storage classes, setting key renames that discard previously stored user preferences, or experiment removals that leave orphaned `localStorage` keys behind.
|
|
9
|
+
- **Do not flag**: In-memory parsing of static constant JSON fixtures.
|
|
10
|
+
|
|
11
|
+
**Why.** Corrupted `localStorage` payloads or legacy setting schemas can throw during `JSON.parse` and break DevTools startup unless caught and reset. When migrating setting keys or storage formats, existing user selections must be migrated rather than overwritten.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const stored = JSON.parse(setting.get());
|
|
19
|
+
setting.set(defaultConfig); // Overwrites user customization!
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Good:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
try {
|
|
26
|
+
const stored = JSON.parse(rawSettingValue);
|
|
27
|
+
migratedSetting.set({...defaultConfig, ...stored});
|
|
28
|
+
} catch {
|
|
29
|
+
setting.remove();
|
|
30
|
+
}
|
|
31
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/models-and-core/core-sourcemap-and-workspace-mapping
|
|
3
|
+
rubric: correctness
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Handle source map parsing, inline script offset translation, and scope tree resolution fault-tolerantly
|
|
8
|
+
- **Look for**: `window.btoa` on source map strings containing UTF-8, raw script locations passed to source map lookups without `rawLocationToRelativeLocation`, or unguarded `encodeURIComponent` / `JSON.parse` on external source map payloads.
|
|
9
|
+
- **Do not flag**: ASCII-only binary buffer encoding via `Common.Base64.encode`.
|
|
10
|
+
|
|
11
|
+
**Why.** Real-world source maps and inline `<script>` tags frequently contain malformed fields, UTF-8 characters, or non-zero line/column offsets. Source map consumers must translate raw inline script locations to relative locations, use UTF-8-safe URI encoding (`encodeURIComponent` with `try/catch` instead of `btoa`), and guard scope stack traversals.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const dataUrl = `data:application/json;base64,${btoa(sourceMapJson)}`;
|
|
19
|
+
const entry = sourceMap.findEntry(rawLocation.lineNumber, rawLocation.columnNumber);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Good:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
const dataUrl = `data:application/json;charset=utf-8,${encodeURIComponent(sourceMapJson)}`;
|
|
26
|
+
const rel = script.rawLocationToRelativeLocation(rawLocation);
|
|
27
|
+
const entry = sourceMap.findEntry(rel.lineNumber, rel.columnNumber);
|
|
28
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/models-and-core/core-trace-engine-handler-invariants
|
|
3
|
+
rubric: correctness
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Normalize and precompute trace events in handler finalize passes using Types.Events.is* guards while keeping raw events immutable
|
|
8
|
+
- **Look for**: In-place property mutation of raw trace events, repeated full-trace `.filter()` scans inside insight calculators instead of handler precomputation, or ad-hoc property checks instead of `Types.Events.is*` (or `Trace.Types.Events.is*`) type guards.
|
|
9
|
+
- **Do not flag**: Constructing new synthetic trace event objects owned by the handler during `finalize()`.
|
|
10
|
+
|
|
11
|
+
**Why.** Trace handlers (`front_end/models/trace/handlers/`) must normalize synthetic event fields, validate bounds, and group events once during `finalize()` so downstream insights and UI tracks do not repeatedly filter the raw trace array or mutate raw trace event objects.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
export function generateInsight(events: readonly Types.Events.Event[]) {
|
|
19
|
+
for (const event of events) {
|
|
20
|
+
(event as any).args.normalized = true; // Mutates raw trace event!
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Good:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
// In handler finalize(): precompute and store in handler state without mutating raw events
|
|
29
|
+
if (Types.Events.isTraceEventNavigationStart(event)) {
|
|
30
|
+
navigations.push(createSyntheticNavigation(event));
|
|
31
|
+
}
|
|
32
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/models-and-core/core-trace-insight-models-and-timing-types
|
|
3
|
+
rubric: correctness
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Enforce branded timing types (Micro, Milli) in trace models and keep types.ts and insight models free of executable or presentation logic
|
|
8
|
+
- **Look for**: Manual `/ 1000` or `* 1000` arithmetic on trace timestamps, executable functions placed in `models/trace/**/types.ts`, or CSS/DOM/AI markdown formatting inside `models/trace/insights/`.
|
|
9
|
+
- **Do not flag**: Type guard functions (`is*`) in `Trace.Types.Events` that only perform type predicate checks.
|
|
10
|
+
|
|
11
|
+
**Why.** Mixing microseconds and milliseconds causes 1000x calculation bugs across trace insights; branded types (`Types.Timing.Micro`, `Types.Timing.Milli`) and canonical conversion helpers (such as `Trace.Helpers.Timing.microToMilli` or `Platform.Timing.microSecondsToMilliSeconds`) prevent unit confusion. Placing executable functions in `types.ts` or UI/AI formatting in insight models violates trace architecture.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const durationMs = (event.ts + event.dur - startTs) / 1000;
|
|
19
|
+
// Or in models/trace/insights/types.ts:
|
|
20
|
+
export function computeSavings(insight: InsightModel): number { ... }
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Good:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
const durationMs = Trace.Helpers.Timing.microToMilli(
|
|
27
|
+
Types.Timing.Micro(event.ts + (event.dur ?? 0) - startTs));
|
|
28
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/tests/test-cleanup-mutated-globals-and-widgets
|
|
3
|
+
rubric: testing
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Restore mutated global properties and detach manually instantiated widgets or singletons in afterEach or finally blocks
|
|
8
|
+
- **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`.
|
|
9
|
+
- **Do not flag**: Widgets mounted directly via `renderElementIntoDOM(widget)`, which detaches widgets automatically during global harness teardown.
|
|
10
|
+
|
|
11
|
+
**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`.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
it('handles custom global state', () => {
|
|
19
|
+
(window as any).customFlag = true;
|
|
20
|
+
const panel = Panel.instance({forceNew: true});
|
|
21
|
+
panel.markAsRoot();
|
|
22
|
+
panel.show(document.body);
|
|
23
|
+
assert.isTrue(panel.isShowing());
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Good:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
delete (window as any).customFlag;
|
|
32
|
+
panel?.detach();
|
|
33
|
+
});
|
|
34
|
+
it('handles custom global state', () => {
|
|
35
|
+
(window as any).customFlag = true;
|
|
36
|
+
panel = Panel.instance({forceNew: true});
|
|
37
|
+
renderElementIntoDOM(panel);
|
|
38
|
+
assert.isTrue(panel.isShowing());
|
|
39
|
+
});
|
|
40
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/tests/test-deterministic-async-synchronization
|
|
3
|
+
rubric: testing
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Synchronize asynchronous test assertions using lifecycle promises, expectCall, or raf instead of arbitrary setTimeout delays
|
|
8
|
+
- **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.
|
|
9
|
+
- **Do not flag**: Tests specifically verifying debounce/throttle timer expiration using `sinon.useFakeTimers()`.
|
|
10
|
+
|
|
11
|
+
**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()`.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
widget.data = newData;
|
|
19
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
20
|
+
assert.isTrue(callbackStub.calledOnce);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Good:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
const called = expectCall(callbackStub);
|
|
27
|
+
widget.data = newData;
|
|
28
|
+
await widget.updateComplete;
|
|
29
|
+
await called;
|
|
30
|
+
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/tests/test-modular-hooks-and-test-universe
|
|
3
|
+
rubric: testing
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Use lightweight modular setup hooks and TestUniverse instead of heavyweight describeWithEnvironment wrappers
|
|
8
|
+
- **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(...)`.
|
|
9
|
+
- **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.
|
|
10
|
+
|
|
11
|
+
**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`.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
describeWithEnvironment('MyFormatter', () => {
|
|
19
|
+
it('formats localized text', () => {
|
|
20
|
+
const universe = new TestUniverse();
|
|
21
|
+
Object.assign(Root.Runtime.hostConfig, {devToolsFeature: {enabled: true}});
|
|
22
|
+
assert.strictEqual(format(), 'Expected');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Good:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
describe('MyFormatter', () => {
|
|
31
|
+
setupLocaleHooks();
|
|
32
|
+
it('formats localized text', () => {
|
|
33
|
+
updateHostConfig({devToolsFeature: {enabled: true}});
|
|
34
|
+
const universe = new TestUniverse();
|
|
35
|
+
assert.strictEqual(format(universe), 'Expected');
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/tests/test-public-api-and-encapsulation
|
|
3
|
+
rubric: testing
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Exercise classes through public APIs and constructor-injected dependencies rather than accessing private members or stubbing unused singletons
|
|
8
|
+
- **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.
|
|
9
|
+
- **Do not flag**: Intentional negative type tests documented with an explanatory `@ts-expect-error` comment.
|
|
10
|
+
|
|
11
|
+
**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.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
sinon.stub(Model, 'instance').returns(mockModel);
|
|
19
|
+
const tool = new MyTool(mockModel);
|
|
20
|
+
// @ts-expect-error testing private helper
|
|
21
|
+
assert.isTrue(tool.validateInternal());
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Good:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
const tool = new MyTool(mockModel);
|
|
28
|
+
const result = await tool.execute();
|
|
29
|
+
assert.isTrue(result.isValid);
|
|
30
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/tests/test-shared-fixture-and-helper-reuse
|
|
3
|
+
rubric: testing
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Reuse canonical front_end/testing helpers and beforeEach setup without mutating cached shared fixtures
|
|
8
|
+
- **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)`.
|
|
9
|
+
- **Do not flag**: Specialized test helpers inside `front_end/testing/` that define the canonical factory implementations themselves.
|
|
10
|
+
|
|
11
|
+
**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.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const parsedTrace = await TraceLoader.traceEngine(this, 'web-dev.json.gz');
|
|
19
|
+
(parsedTrace.Meta as any).mainFrameId = 'custom-id'; // Mutates shared cached trace!
|
|
20
|
+
const container = document.createElement('div');
|
|
21
|
+
widget.show(container);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Good:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
const parsedTrace = await TraceLoader.traceEngine(this, 'web-dev.json.gz');
|
|
28
|
+
renderElementIntoDOM(widget, {includeCommonStyles: true});
|
|
29
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/tests/test-single-responsibility-and-conciseness
|
|
3
|
+
rubric: testing
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Keep each it() block focused on a single behavior and prune duplicate or obsolete tests when features change
|
|
8
|
+
- **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.
|
|
9
|
+
- **Do not flag**: Multi-step stateful workflow tests where earlier steps are required preconditions to reach the state under test.
|
|
10
|
+
|
|
11
|
+
**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.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
it('toggles setting on/off and expands details card', async () => {
|
|
19
|
+
toggleSetting();
|
|
20
|
+
assert.isTrue(setting.get());
|
|
21
|
+
expandCard();
|
|
22
|
+
assert.isTrue(card.expanded);
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Good:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
it('toggles setting on and off', () => {
|
|
30
|
+
toggleSetting();
|
|
31
|
+
assert.isTrue(setting.get());
|
|
32
|
+
});
|
|
33
|
+
it('expands details card when clicked', () => {
|
|
34
|
+
expandCard();
|
|
35
|
+
assert.isTrue(card.expanded);
|
|
36
|
+
});
|
|
37
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/tests/test-strict-assertions-and-literal-expectations
|
|
3
|
+
rubric: testing
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Use strict Chai and Sinon assertions against literal expected values rather than assert.isNotNull on undefined-unions or conditional guards
|
|
8
|
+
- **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.
|
|
9
|
+
- **Do not flag**: Variables whose static return type is strictly `T | null` (and never `undefined`).
|
|
10
|
+
|
|
11
|
+
**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.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const item = list.find(x => x.id === 'a');
|
|
19
|
+
assert.isNotNull(item);
|
|
20
|
+
if (item) {
|
|
21
|
+
assert.strictEqual(item.label, formatLabel('a'));
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Good:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
const item = list.find(x => x.id === 'a');
|
|
29
|
+
assert.isOk(item);
|
|
30
|
+
assert.strictEqual(item.label, 'Expected literal label');
|
|
31
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/tests/test-type-safe-mocks-and-events
|
|
3
|
+
rubric: testing
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Construct typed stubs and real DOM or event instances instead of casting fake objects with as unknown as
|
|
8
|
+
- **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.
|
|
9
|
+
- **Do not flag**: Tests explicitly verifying runtime handling of malformed untrusted payloads or narrow generic type parameters inside shared `front_end/testing/` helpers.
|
|
10
|
+
|
|
11
|
+
**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.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const fakeNode = {securityOrigin: () => 'https://example.com'} as unknown as SDK.DOMModel.DOMNode;
|
|
19
|
+
const fakeEvent = {clipboardData: {getData: () => 'text'}} as unknown as ClipboardEvent;
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Good:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
const node = sinon.createStubInstance(SDK.DOMModel.DOMNode);
|
|
26
|
+
node.securityOrigin.returns('https://example.com');
|
|
27
|
+
const dataTransfer = new DataTransfer();
|
|
28
|
+
dataTransfer.setData('text/plain', 'text');
|
|
29
|
+
const event = new ClipboardEvent('paste', {clipboardData: dataTransfer});
|
|
30
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/tests/test-view-and-presenter-isolation
|
|
3
|
+
rubric: testing
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Test presenters via createViewFunctionStub and test pure view functions directly without piercing internal DOM structures
|
|
8
|
+
- **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.
|
|
9
|
+
- **Do not flag**: Legacy widgets that have not yet separated their template rendering into a standalone `DEFAULT_VIEW` function.
|
|
10
|
+
|
|
11
|
+
**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.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const widget = new MyWidget();
|
|
19
|
+
renderElementIntoDOM(widget);
|
|
20
|
+
widget.contentElement.querySelector('devtools-button')!.click();
|
|
21
|
+
assert.include(widget.contentElement.textContent, 'Updated');
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Good:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
const view = createViewFunctionStub(MyWidget);
|
|
28
|
+
const widget = new MyWidget(undefined, view);
|
|
29
|
+
widget.wasShown();
|
|
30
|
+
view.input.onActionClick();
|
|
31
|
+
assert.strictEqual((await view.nextInput).statusText, 'Updated');
|
|
32
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-accessibility-and-semantic-html
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Use native semantic HTML controls with accurate ARIA attributes, keyboard handlers, and !event.isComposing guards
|
|
8
|
+
- **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.
|
|
9
|
+
- **Do not flag**: Delegating click listeners on container elements that handle bubbled events from child buttons.
|
|
10
|
+
|
|
11
|
+
**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.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
html`
|
|
19
|
+
<div class="custom-btn" @click=${onSubmit}>Submit</div>
|
|
20
|
+
<textarea @keydown=${(e: KeyboardEvent) => e.key === 'Enter' && onSubmit()}></textarea>
|
|
21
|
+
`
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Good:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
html`
|
|
28
|
+
<devtools-button @click=${onSubmit}>Submit</devtools-button>
|
|
29
|
+
<textarea aria-label=${i18nString(UIStrings.prompt)}
|
|
30
|
+
@keydown=${(e: KeyboardEvent) => e.key === 'Enter' && !e.isComposing && onSubmit()}></textarea>
|
|
31
|
+
`
|
|
32
|
+
```
|