chrome-devtools-frontend 1.0.1656897 → 1.0.1657110

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.
Files changed (54) hide show
  1. package/AUTHORS +2 -0
  2. package/docs/get_the_code.md +6 -6
  3. package/front_end/Tests.js +1 -1
  4. package/front_end/core/common/Settings.ts +0 -8
  5. package/front_end/core/host/Platform.ts +4 -0
  6. package/front_end/core/sdk/CSSMetadata.ts +11 -0
  7. package/front_end/core/sdk/CSSModel.ts +3 -0
  8. package/front_end/core/sdk/DOMModel.ts +37 -8
  9. package/front_end/core/sdk/DebuggerModel.ts +5 -4
  10. package/front_end/core/sdk/EmulationModel.ts +6 -4
  11. package/front_end/core/sdk/NetworkManager.ts +21 -14
  12. package/front_end/core/sdk/RuntimeModel.ts +1 -1
  13. package/front_end/core/sdk/TargetManager.ts +10 -0
  14. package/front_end/design_system_tokens.css +6 -0
  15. package/front_end/entrypoints/inspector_main/InspectorMain.ts +1 -11
  16. package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +1 -1
  17. package/front_end/entrypoints/main/GlobalAiButton.ts +29 -35
  18. package/front_end/entrypoints/main/MainImpl.ts +1 -1
  19. package/front_end/entrypoints/main/main-meta.ts +1 -1
  20. package/front_end/entrypoints/node_app/app/NodeConnectionsPanel.ts +2 -3
  21. package/front_end/foundation/Universe.ts +33 -1
  22. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +2 -1
  23. package/front_end/models/emulation/DeviceModeModel.ts +43 -24
  24. package/front_end/models/live-metrics/LiveMetrics.ts +47 -23
  25. package/front_end/models/project_settings/ProjectSettingsModel.ts +2 -37
  26. package/front_end/models/workspace/FileManager.ts +9 -6
  27. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +2 -1
  28. package/front_end/panels/application/ServiceWorkersView.ts +9 -20
  29. package/front_end/panels/application/components/StorageMetadataView.ts +7 -2
  30. package/front_end/panels/common/BadgeNotification.ts +1 -1
  31. package/front_end/panels/console/ConsoleInsightTeaser.ts +2 -1
  32. package/front_end/panels/elements/ElementsTreeElement.ts +208 -143
  33. package/front_end/panels/elements/ElementsTreeOutline.ts +3 -2
  34. package/front_end/panels/elements/components/AdornerManager.ts +1 -0
  35. package/front_end/panels/emulation/DeviceModeToolbar.ts +19 -19
  36. package/front_end/panels/explain/components/ConsoleInsight.ts +2 -1
  37. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +13 -12
  38. package/front_end/panels/mobile_throttling/ThrottlingManager.ts +8 -7
  39. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +6 -7
  40. package/front_end/panels/mobile_throttling/mobile_throttling-meta.ts +3 -2
  41. package/front_end/panels/settings/components/SyncSection.ts +2 -1
  42. package/front_end/panels/timeline/AppenderUtils.ts +12 -4
  43. package/front_end/panels/timeline/ThreadAppender.ts +3 -3
  44. package/front_end/panels/timeline/TimelinePanel.ts +5 -5
  45. package/front_end/panels/timeline/timelineFlameChartView.css +2 -1
  46. package/front_end/third_party/chromium/README.chromium +1 -1
  47. package/front_end/third_party/chromium/ahem/ahem.js +792 -0
  48. package/front_end/tsconfig.json +7 -1
  49. package/front_end/ui/legacy/ActionRegistration.ts +1 -1
  50. package/front_end/ui/legacy/InspectorView.ts +1 -1
  51. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +109 -23
  52. package/front_end/ui/legacy/theme_support/ThemeSupport.ts +2 -2
  53. package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
  54. package/package.json +1 -1
package/AUTHORS CHANGED
@@ -24,6 +24,7 @@ Anna Agoha <annaagoha@gmail.com>
24
24
  Anthony Xie <anthonyxie64@gmail.com>
25
25
  Axel Chong <haxatron1@gmail.com>
26
26
  Anton Bershanskyi <bershanskyi@gmail.com>
27
+ Aviv Keller <me@aviv.sh>
27
28
  Biboswan Roy <biboswan98@gmail.com>
28
29
  Boris Verkhovskiy <boris.verk@gmail.com>
29
30
  Carl Espe <carl@cpespe.com>
@@ -62,6 +63,7 @@ Juba Borgohain <chromiumjuba@gmail.com>
62
63
  Julian Geppert <spctstr@gmail.com>
63
64
  Junseo Yoo <joon.yoo181@berkeley.edu>
64
65
  Kanishk Ranjan <kanishkranjan17@gmail.com>
66
+ Karim El Harim <karimelharim@gmail.com>
65
67
  Karntino Areros <karntino.c.areros@gmail.com>
66
68
  Kohei Ueno <kohei.ueno119@gmail.com>
67
69
  Krishnal Ciccolella <ciccolella.krishnal@gmail.com>
@@ -53,10 +53,10 @@ a build time cost. If you want an even fast fast build, you might want to opt
53
53
  out of bundling by setting `devtools_bundle` to `false`
54
54
 
55
55
  ```bash
56
- gn gen out/fast-build --args="devtools_skip_typecheck=true devtools_bundle=false"
56
+ gn gen out/Fast --args="devtools_skip_typecheck=true devtools_bundle=false"
57
57
  ```
58
58
 
59
- and use `npm run build -- -t fast-build` to build this target.
59
+ and use `npm run build -- -t Fast` to build this target.
60
60
 
61
61
  ### Rebuilding automatically
62
62
 
@@ -111,10 +111,10 @@ The `.env.template` file lists all supported variables. Copy it to `.env` to get
111
111
  cp .env.template .env
112
112
  ```
113
113
 
114
- As mentioned earlier, you might create a fast build target. Instead of always typing `npm run build -- -t fast-build`, to remove the flag repetition you simple run `npm run build` you can set the following variable in your `.env` file:
114
+ As mentioned earlier, you might create a fast build target. Instead of always typing `npm run build -- -t Fast`, to remove the flag repetition you simple run `npm run build` you can set the following variable in your `.env` file:
115
115
 
116
116
  ```shell
117
- DEVTOOLS_TARGET=fast-build
117
+ DEVTOOLS_TARGET=Fast
118
118
  ```
119
119
 
120
120
  Another example - by default running `npm start` auto-opens DevTools for new Tabs.
@@ -468,8 +468,8 @@ In the `custom_deps` section, insert this line:
468
468
  "src/third_party/devtools-frontend/src": None,
469
469
  ```
470
470
 
471
- For the integrated checkout, create a single gclient project that automatically gclient sync's all dependencies for both
472
- repositories. After checking out chromium, modify the .gclient file for `chromium/src` to add the DevTools project:
471
+ For the integrated checkout, create a single gclient project that automatically `gclient sync`s all dependencies for both
472
+ repositories. After checking out chromium, modify the `.gclient` file for `chromium/src` to add the DevTools project:
473
473
 
474
474
  ```python
475
475
  solutions = [
@@ -761,7 +761,7 @@
761
761
  this.releaseControl();
762
762
  });
763
763
 
764
- Common.Settings.moduleSetting('active-keybind-set').set('vsCode');
764
+ Common.Settings.Settings.instance().moduleSetting('active-keybind-set').set('vsCode');
765
765
  };
766
766
 
767
767
  TestSuite.prototype.testDispatchKeyEventDoesNotCrash = function() {
@@ -715,14 +715,6 @@ export const enum SettingStorageType {
715
715
  SESSION = 'Session',
716
716
  }
717
717
 
718
- export function moduleSetting(settingName: string): Setting<unknown> {
719
- return Settings.instance().moduleSetting(settingName);
720
- }
721
-
722
- export function settingForTest(settingName: string): Setting<unknown> {
723
- return Settings.instance().settingForTest(settingName);
724
- }
725
-
726
718
  export {
727
719
  getLocalizedSettingsCategory,
728
720
  maybeRemoveSettingExtension,
@@ -65,3 +65,7 @@ export function fontFamily(): string {
65
65
  }
66
66
  return _fontFamily;
67
67
  }
68
+
69
+ export function setFontFamilyForTests(family: string): void {
70
+ _fontFamily = family;
71
+ }
@@ -1517,6 +1517,17 @@ const extraPropertyValues = new Map<string, Set<string>>([
1517
1517
  'ex alphabetic',
1518
1518
  ]),
1519
1519
  ],
1520
+ [
1521
+ 'text-wrap',
1522
+ new Set([
1523
+ 'auto',
1524
+ 'wrap',
1525
+ 'nowrap',
1526
+ 'balance',
1527
+ 'pretty',
1528
+ 'stable',
1529
+ ]),
1530
+ ],
1520
1531
  [
1521
1532
  'corner-shape',
1522
1533
  new Set([
@@ -38,6 +38,7 @@ export interface LayoutProperties {
38
38
  isGrid: boolean;
39
39
  isSubgrid: boolean;
40
40
  isGridLanes: boolean;
41
+ isContents?: boolean;
41
42
  containerType?: string;
42
43
  hasScroll: boolean;
43
44
  }
@@ -392,6 +393,7 @@ export class CSSModel extends SDKModel<EventTypes> {
392
393
  }
393
394
 
394
395
  const display = styles.get('display');
396
+ const isContents = display === 'contents';
395
397
  const isFlex = display === 'flex' || display === 'inline-flex';
396
398
  const isGrid = display === 'grid' || display === 'inline-grid';
397
399
  const isSubgrid = (isGrid &&
@@ -408,6 +410,7 @@ export class CSSModel extends SDKModel<EventTypes> {
408
410
  isGrid,
409
411
  isSubgrid,
410
412
  isGridLanes,
413
+ isContents,
411
414
  containerType: isContainer ? containerType : undefined,
412
415
  hasScroll,
413
416
  };
@@ -38,6 +38,7 @@ import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
38
38
  import * as Protocol from '../../generated/protocol.js';
39
39
  import * as Common from '../common/common.js';
40
40
  import * as Platform from '../platform/platform.js';
41
+ import * as Root from '../root/root.js';
41
42
 
42
43
  import {CSSModel} from './CSSModel.js';
43
44
  import type {FrameManager} from './FrameManager.js';
@@ -1016,6 +1017,27 @@ export class DOMNode extends Common.ObjectWrapper.ObjectWrapper<DOMNodeEventType
1016
1017
  return Boolean(this.#xmlVersion);
1017
1018
  }
1018
1019
 
1020
+ isCustomElement(): boolean {
1021
+ if (this.nodeType() !== Node.ELEMENT_NODE || this.isXMLNode()) {
1022
+ return false;
1023
+ }
1024
+ const localName = this.localName() || this.nodeName().toLowerCase();
1025
+ if (localName.includes('-')) {
1026
+ const builtInExclusionList = [
1027
+ 'annotation-xml',
1028
+ 'color-profile',
1029
+ 'font-face',
1030
+ 'font-face-src',
1031
+ 'font-face-uri',
1032
+ 'font-face-format',
1033
+ 'font-face-name',
1034
+ 'missing-glyph',
1035
+ ];
1036
+ return !builtInExclusionList.includes(localName);
1037
+ }
1038
+ return this.getAttribute('is') !== undefined;
1039
+ }
1040
+
1019
1041
  setMarker(name: string, value: unknown): void {
1020
1042
  if (value === null) {
1021
1043
  if (!this.#markers.has(name)) {
@@ -1698,7 +1720,7 @@ export class DOMModel extends SDKModel<EventTypes> {
1698
1720
  } else {
1699
1721
  this.#document = null;
1700
1722
  }
1701
- DOMModelUndoStack.instance().dispose(this);
1723
+ this.#undoStack().dispose(this);
1702
1724
 
1703
1725
  if (!this.parentModel()) {
1704
1726
  this.dispatchEventToListeners(Events.DocumentUpdated, this);
@@ -2034,7 +2056,7 @@ export class DOMModel extends SDKModel<EventTypes> {
2034
2056
  }
2035
2057
 
2036
2058
  markUndoableState(minorChange?: boolean): void {
2037
- void DOMModelUndoStack.instance().markUndoableState(this, minorChange || false);
2059
+ void this.#undoStack().markUndoableState(this, minorChange || false);
2038
2060
  }
2039
2061
 
2040
2062
  async nodeForLocation(x: number, y: number, includeUserAgentShadowDOM: boolean): Promise<DOMNode|null> {
@@ -2071,7 +2093,16 @@ export class DOMModel extends SDKModel<EventTypes> {
2071
2093
 
2072
2094
  override dispose(): void {
2073
2095
  this.#resourceTreeModel?.removeEventListener(ResourceTreeModelEvents.DocumentOpened, this.onDocumentOpened, this);
2074
- DOMModelUndoStack.instance().dispose(this);
2096
+ this.#undoStack().dispose(this);
2097
+ }
2098
+
2099
+ // TODO(crbug.com/493763857): Remove fallback once all unit tests use TestUniverse.
2100
+ #undoStack(): DOMModelUndoStack {
2101
+ const context = this.target().targetManager().context;
2102
+ if ('has' in context && typeof context.has === 'function' && context.has(DOMModelUndoStack)) {
2103
+ return context.get(DOMModelUndoStack);
2104
+ }
2105
+ return DOMModelUndoStack.instance();
2075
2106
  }
2076
2107
 
2077
2108
  parentModel(): DOMModel|null {
@@ -2212,8 +2243,6 @@ class DOMDispatcher implements ProtocolProxyApi.DOMDispatcher {
2212
2243
  }
2213
2244
  }
2214
2245
 
2215
- let domModelUndoStackInstance: DOMModelUndoStack|null = null;
2216
-
2217
2246
  export class DOMModelUndoStack {
2218
2247
  #stack: DOMModel[];
2219
2248
  #index: number;
@@ -2228,11 +2257,11 @@ export class DOMModelUndoStack {
2228
2257
  forceNew: boolean|null,
2229
2258
  } = {forceNew: null}): DOMModelUndoStack {
2230
2259
  const {forceNew} = opts;
2231
- if (!domModelUndoStackInstance || forceNew) {
2232
- domModelUndoStackInstance = new DOMModelUndoStack();
2260
+ if (!Root.DevToolsContext.globalInstance().has(DOMModelUndoStack) || forceNew) {
2261
+ Root.DevToolsContext.globalInstance().set(DOMModelUndoStack, new DOMModelUndoStack());
2233
2262
  }
2234
2263
 
2235
- return domModelUndoStackInstance;
2264
+ return Root.DevToolsContext.globalInstance().get(DOMModelUndoStack);
2236
2265
  }
2237
2266
 
2238
2267
  async markUndoableState(model: DOMModel, minorChange: boolean): Promise<void> {
@@ -194,7 +194,8 @@ export class DebuggerModel extends SDKModel<EventTypes> {
194
194
  }
195
195
  }
196
196
 
197
- static selectSymbolSource(debugSymbols: Protocol.Debugger.DebugSymbols[]|null): Protocol.Debugger.DebugSymbols|null {
197
+ static selectSymbolSource(debugSymbols: Protocol.Debugger.DebugSymbols[]|null,
198
+ devToolsConsole: Common.Console.Console): Protocol.Debugger.DebugSymbols|null {
198
199
  if (!debugSymbols || debugSymbols.length === 0) {
199
200
  return null;
200
201
  }
@@ -221,8 +222,7 @@ export class DebuggerModel extends SDKModel<EventTypes> {
221
222
  debugSymbolsSource !== null,
222
223
  'Unknown symbol types. Front-end and back-end should be kept in sync regarding Protocol.Debugger.DebugSymbolTypes');
223
224
  if (debugSymbolsSource && debugSymbols.length > 1) {
224
- Common.Console.Console.instance().warn(
225
- `Multiple debug symbols for script were found. Using ${debugSymbolsSource.type}`);
225
+ devToolsConsole.warn(`Multiple debug symbols for script were found. Using ${debugSymbolsSource.type}`);
226
226
  }
227
227
  return debugSymbolsSource;
228
228
  }
@@ -661,7 +661,8 @@ export class DebuggerModel extends SDKModel<EventTypes> {
661
661
  isContentScript = !executionContextAuxData['isDefault'];
662
662
  }
663
663
 
664
- const selectedDebugSymbol = DebuggerModel.selectSymbolSource(debugSymbols);
664
+ const selectedDebugSymbol =
665
+ DebuggerModel.selectSymbolSource(debugSymbols, this.target().targetManager().getConsole());
665
666
  const script = new Script(
666
667
  this, scriptId, sourceURL, startLine, startColumn, endLine, endColumn, executionContextId, hash,
667
668
  isContentScript, isLiveEdit, sourceMapURL, hasSourceURLComment, length, isModule, originStackTrace, codeOffset,
@@ -6,7 +6,7 @@ import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
6
6
  import * as Protocol from '../../generated/protocol.js';
7
7
 
8
8
  import {CSSModel} from './CSSModel.js';
9
- import {MultitargetNetworkManager} from './NetworkManager.js';
9
+ import type {MultitargetNetworkManager} from './NetworkManager.js';
10
10
  import {Events, OverlayModel} from './OverlayModel.js';
11
11
  import {SDKModel} from './SDKModel.js';
12
12
  import {Capability, type Target} from './Target.js';
@@ -18,6 +18,7 @@ export const enum DataSaverOverride {
18
18
  }
19
19
 
20
20
  export class EmulationModel extends SDKModel<EmulationModelEventTypes> implements ProtocolProxyApi.EmulationDispatcher {
21
+ readonly #multitargetNetworkManager: MultitargetNetworkManager;
21
22
  readonly #emulationAgent: ProtocolProxyApi.EmulationApi;
22
23
  readonly #deviceOrientationAgent: ProtocolProxyApi.DeviceOrientationApi;
23
24
  #cssModel: CSSModel|null;
@@ -37,6 +38,7 @@ export class EmulationModel extends SDKModel<EmulationModelEventTypes> implement
37
38
 
38
39
  constructor(target: Target) {
39
40
  super(target);
41
+ this.#multitargetNetworkManager = target.targetManager().getNetworkManager();
40
42
  this.#emulationAgent = target.emulationAgent();
41
43
  this.#deviceOrientationAgent = target.deviceOrientationAgent();
42
44
  this.#screenOrientationLocked = false;
@@ -277,7 +279,7 @@ export class EmulationModel extends SDKModel<EmulationModelEventTypes> implement
277
279
  this.#emulationAgent.invoke_setTimezoneOverride({timezoneId: ''}),
278
280
  this.#emulationAgent.invoke_setLocaleOverride({locale: ''}),
279
281
  this.#emulationAgent.invoke_setUserAgentOverride(
280
- {userAgent: MultitargetNetworkManager.instance().currentUserAgent()}),
282
+ {userAgent: this.#multitargetNetworkManager.currentUserAgent()}),
281
283
  ]);
282
284
  } else if (location.unavailable) {
283
285
  await Promise.all([
@@ -285,7 +287,7 @@ export class EmulationModel extends SDKModel<EmulationModelEventTypes> implement
285
287
  this.#emulationAgent.invoke_setTimezoneOverride({timezoneId: ''}),
286
288
  this.#emulationAgent.invoke_setLocaleOverride({locale: ''}),
287
289
  this.#emulationAgent.invoke_setUserAgentOverride(
288
- {userAgent: MultitargetNetworkManager.instance().currentUserAgent()}),
290
+ {userAgent: this.#multitargetNetworkManager.currentUserAgent()}),
289
291
  ]);
290
292
  } else {
291
293
  function processEmulationResult(errorType: string, result: Protocol.ProtocolResponseWithError): Promise<void> {
@@ -319,7 +321,7 @@ export class EmulationModel extends SDKModel<EmulationModelEventTypes> implement
319
321
  .then(result => processEmulationResult('emulation-set-locale', result)),
320
322
  this.#emulationAgent
321
323
  .invoke_setUserAgentOverride({
322
- userAgent: MultitargetNetworkManager.instance().currentUserAgent(),
324
+ userAgent: this.#multitargetNetworkManager.currentUserAgent(),
323
325
  acceptLanguage: location.locale,
324
326
  })
325
327
  .then(result => processEmulationResult('emulation-set-user-agent', result)),
@@ -133,14 +133,13 @@ const CONNECTION_TYPES = new Map([
133
133
  * to in multiple places, and this ensures we don't have accidental typos which
134
134
  * mean extra settings get mistakenly created.
135
135
  */
136
- export function customUserNetworkConditionsSetting(
137
- settings: Common.Settings.Settings = Common.Settings.Settings.instance()): Common.Settings.Setting<Conditions[]> {
136
+ export function customUserNetworkConditionsSetting(settings: Common.Settings.Settings):
137
+ Common.Settings.Setting<Conditions[]> {
138
138
  return settings.moduleSetting<Conditions[]>('custom-network-conditions');
139
139
  }
140
140
 
141
- export function activeNetworkThrottlingKeySetting(
142
- settings: Common.Settings.Settings =
143
- Common.Settings.Settings.instance()): Common.Settings.Setting<ThrottlingConditionKey> {
141
+ export function activeNetworkThrottlingKeySetting(settings: Common.Settings.Settings):
142
+ Common.Settings.Setting<ThrottlingConditionKey> {
144
143
  return settings.createSetting('active-network-condition-key', PredefinedThrottlingConditionKey.NO_THROTTLING);
145
144
  }
146
145
 
@@ -578,10 +577,12 @@ const MAX_RESPONSE_BODY_TOTAL_BUFFER_LENGTH = 250 * 1024 * 1024; // bytes
578
577
  export class FetchDispatcher implements ProtocolProxyApi.FetchDispatcher {
579
578
  readonly #fetchAgent: ProtocolProxyApi.FetchApi;
580
579
  readonly #manager: NetworkManager;
580
+ readonly #multitargetNetworkManager;
581
581
 
582
582
  constructor(agent: ProtocolProxyApi.FetchApi, manager: NetworkManager) {
583
583
  this.#fetchAgent = agent;
584
584
  this.#manager = manager;
585
+ this.#multitargetNetworkManager = this.#manager.target().targetManager().getNetworkManager();
585
586
  }
586
587
 
587
588
  requestPaused({requestId, request, resourceType, responseStatusCode, responseHeaders, networkId}:
@@ -592,8 +593,9 @@ export class FetchDispatcher implements ProtocolProxyApi.FetchDispatcher {
592
593
  if (networkRequest?.originalResponseHeaders.length === 0 && responseHeaders) {
593
594
  networkRequest.originalResponseHeaders = responseHeaders;
594
595
  }
595
- void MultitargetNetworkManager.instance().requestIntercepted(new InterceptedRequest(
596
- this.#fetchAgent, request, resourceType, requestId, networkRequest, responseStatusCode, responseHeaders));
596
+ void this.#multitargetNetworkManager.requestIntercepted(
597
+ new InterceptedRequest(this.#multitargetNetworkManager, this.#fetchAgent, request, resourceType, requestId,
598
+ networkRequest, responseStatusCode, responseHeaders));
597
599
  }
598
600
 
599
601
  authRequired({}: Protocol.Fetch.AuthRequiredEvent): void {
@@ -602,6 +604,7 @@ export class FetchDispatcher implements ProtocolProxyApi.FetchDispatcher {
602
604
 
603
605
  export class NetworkDispatcher implements ProtocolProxyApi.NetworkDispatcher {
604
606
  readonly #manager: NetworkManager;
607
+ readonly #multitargetNetworkManager: MultitargetNetworkManager;
605
608
  readonly #requestsById = new Map<string, NetworkRequest>();
606
609
  readonly #requestsByURL = new Map<Platform.DevToolsPath.UrlString, NetworkRequest>();
607
610
  readonly #requestsByLoaderId = new Map<Protocol.Network.LoaderId, NetworkRequest>();
@@ -618,9 +621,10 @@ export class NetworkDispatcher implements ProtocolProxyApi.NetworkDispatcher {
618
621
 
619
622
  constructor(manager: NetworkManager) {
620
623
  this.#manager = manager;
624
+ this.#multitargetNetworkManager = this.#manager.target().targetManager().getNetworkManager();
621
625
 
622
- MultitargetNetworkManager.instance().addEventListener(
623
- MultitargetNetworkManager.Events.REQUEST_INTERCEPTED, this.#markAsIntercepted.bind(this));
626
+ this.#multitargetNetworkManager.addEventListener(MultitargetNetworkManager.Events.REQUEST_INTERCEPTED,
627
+ this.#markAsIntercepted.bind(this));
624
628
  }
625
629
 
626
630
  #markAsIntercepted(event: Common.EventTarget.EventTargetEvent<string>): void {
@@ -1178,7 +1182,7 @@ export class NetworkDispatcher implements ProtocolProxyApi.NetworkDispatcher {
1178
1182
  }
1179
1183
 
1180
1184
  private maybeAdoptMainResourceRequest(requestId: string): NetworkRequest|null {
1181
- const request = MultitargetNetworkManager.instance().inflightMainResourceRequests.get(requestId);
1185
+ const request = this.#multitargetNetworkManager.inflightMainResourceRequests.get(requestId);
1182
1186
  if (!request) {
1183
1187
  return null;
1184
1188
  }
@@ -1216,7 +1220,7 @@ export class NetworkDispatcher implements ProtocolProxyApi.NetworkDispatcher {
1216
1220
  // request to fetch the main worker script, the request ID is the future
1217
1221
  // worker target ID and, therefore, it is unique.
1218
1222
  if (networkRequest.loaderId === networkRequest.requestId() || networkRequest.loaderId === '') {
1219
- MultitargetNetworkManager.instance().inflightMainResourceRequests.set(networkRequest.requestId(), networkRequest);
1223
+ this.#multitargetNetworkManager.inflightMainResourceRequests.set(networkRequest.requestId(), networkRequest);
1220
1224
  }
1221
1225
 
1222
1226
  this.#manager.dispatchEventToListeners(Events.RequestStarted, {request: networkRequest, originalRequest});
@@ -1244,7 +1248,7 @@ export class NetworkDispatcher implements ProtocolProxyApi.NetworkDispatcher {
1244
1248
  }
1245
1249
  }
1246
1250
  this.#manager.dispatchEventToListeners(Events.RequestFinished, networkRequest);
1247
- MultitargetNetworkManager.instance().inflightMainResourceRequests.delete(networkRequest.requestId());
1251
+ this.#multitargetNetworkManager.inflightMainResourceRequests.delete(networkRequest.requestId());
1248
1252
 
1249
1253
  const settings = this.#manager.target().targetManager().settings;
1250
1254
  if (settings.moduleSetting('monitoring-xhr-enabled').get() &&
@@ -2385,6 +2389,7 @@ export namespace MultitargetNetworkManager {
2385
2389
  }
2386
2390
 
2387
2391
  export class InterceptedRequest {
2392
+ readonly #multitargetNetworkManager: MultitargetNetworkManager;
2388
2393
  readonly #fetchAgent: ProtocolProxyApi.FetchApi;
2389
2394
  #hasResponded = false;
2390
2395
  request: Protocol.Network.Request;
@@ -2395,6 +2400,7 @@ export class InterceptedRequest {
2395
2400
  networkRequest: NetworkRequest|null;
2396
2401
 
2397
2402
  constructor(
2403
+ multitargetNetworkManager: MultitargetNetworkManager,
2398
2404
  fetchAgent: ProtocolProxyApi.FetchApi,
2399
2405
  request: Protocol.Network.Request,
2400
2406
  resourceType: Protocol.Network.ResourceType,
@@ -2403,6 +2409,7 @@ export class InterceptedRequest {
2403
2409
  responseStatusCode?: number,
2404
2410
  responseHeaders?: Protocol.Fetch.HeaderEntry[],
2405
2411
  ) {
2412
+ this.#multitargetNetworkManager = multitargetNetworkManager;
2406
2413
  this.#fetchAgent = fetchAgent;
2407
2414
  this.request = request;
2408
2415
  this.resourceType = resourceType;
@@ -2494,8 +2501,8 @@ export class InterceptedRequest {
2494
2501
  }
2495
2502
 
2496
2503
  void this.#fetchAgent.invoke_fulfillRequest({requestId: this.requestId, responseCode, body, responseHeaders});
2497
- MultitargetNetworkManager.instance().dispatchEventToListeners(
2498
- MultitargetNetworkManager.Events.REQUEST_FULFILLED, this.request.url as Platform.DevToolsPath.UrlString);
2504
+ this.#multitargetNetworkManager.dispatchEventToListeners(MultitargetNetworkManager.Events.REQUEST_FULFILLED,
2505
+ this.request.url as Platform.DevToolsPath.UrlString);
2499
2506
  }
2500
2507
 
2501
2508
  continueRequestWithoutChange(): void {
@@ -337,7 +337,7 @@ export class RuntimeModel extends SDKModel<EventTypes> {
337
337
  const result = await this.queryObjects(object);
338
338
  object.release();
339
339
  if ('error' in result) {
340
- Common.Console.Console.instance().error(result.error);
340
+ this.target().targetManager().getConsole().error(result.error);
341
341
  return;
342
342
  }
343
343
  this.dispatchEventToListeners(Events.QueryObjectRequested, {objects: result.objects, executionContextId});
@@ -11,6 +11,7 @@ import type * as ProtocolClient from '../protocol_client/protocol_client.js';
11
11
  import * as Root from '../root/root.js';
12
12
 
13
13
  import {FrameManager} from './FrameManager.js';
14
+ import {MultitargetNetworkManager} from './NetworkManager.js';
14
15
  import {type RegistrationInfo, SDKModel, type SDKModelConstructor} from './SDKModel.js';
15
16
  import {Target, Type as TargetType} from './Target.js';
16
17
 
@@ -48,6 +49,15 @@ export class TargetManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes
48
49
  return this.context.get(FrameManager);
49
50
  }
50
51
 
52
+ // TODO(crbug.com/493763857): Remove fallback once all unit tests use TestUniverse.
53
+ getNetworkManager(): MultitargetNetworkManager {
54
+ if ('has' in this.context && typeof this.context.has === 'function' &&
55
+ !this.context.has(MultitargetNetworkManager)) {
56
+ return MultitargetNetworkManager.instance();
57
+ }
58
+ return this.context.get(MultitargetNetworkManager);
59
+ }
60
+
51
61
  /* eslint-disable @typescript-eslint/no-explicit-any */
52
62
  #modelListeners: Platform.MapUtilities.Multimap<string|symbol|number, {
53
63
  modelClass: SDKModelConstructor,
@@ -639,6 +639,12 @@
639
639
  }
640
640
 
641
641
  &.platform-screenshot-test {
642
+ --default-font-family: ahem;
643
+ --monospace-font-family: ahem;
644
+ --source-code-font-family: ahem;
645
+ }
646
+
647
+ &.platform-screenshot-e2e-test {
642
648
  --default-font-family: roboto;
643
649
  --monospace-font-family: roboto;
644
650
  --source-code-font-family: roboto;
@@ -207,12 +207,11 @@ export class NodeIndicator extends UI.Widget.Widget {
207
207
  }
208
208
  }
209
209
 
210
- let nodeIndicatorProviderInstance: NodeIndicatorProvider;
211
210
  export class NodeIndicatorProvider implements UI.Toolbar.Provider {
212
211
  #toolbarItem: UI.Toolbar.ToolbarItem;
213
212
  #widgetElement: UI.Widget.WidgetElement<NodeIndicator>;
214
213
 
215
- private constructor() {
214
+ constructor() {
216
215
  this.#widgetElement = document.createElement('devtools-widget') as UI.Widget.WidgetElement<NodeIndicator>;
217
216
  new NodeIndicator(this.#widgetElement);
218
217
 
@@ -223,15 +222,6 @@ export class NodeIndicatorProvider implements UI.Toolbar.Provider {
223
222
  item(): UI.Toolbar.ToolbarItem|null {
224
223
  return this.#toolbarItem;
225
224
  }
226
-
227
- static instance(opts: {forceNew: boolean|null} = {forceNew: null}): NodeIndicatorProvider {
228
- const {forceNew} = opts;
229
- if (!nodeIndicatorProviderInstance || forceNew) {
230
- nodeIndicatorProviderInstance = new NodeIndicatorProvider();
231
- }
232
-
233
- return nodeIndicatorProviderInstance;
234
- }
235
225
  }
236
226
 
237
227
  export class SourcesPanelIndicator {
@@ -257,7 +257,7 @@ Common.Settings.registerSettingExtension({
257
257
  UI.Toolbar.registerToolbarItem({
258
258
  async loadItem() {
259
259
  const InspectorMain = await loadInspectorMainModule();
260
- return InspectorMain.InspectorMain.NodeIndicatorProvider.instance();
260
+ return new InspectorMain.InspectorMain.NodeIndicatorProvider();
261
261
  },
262
262
  order: 2,
263
263
  location: UI.Toolbar.ToolbarItemLocation.MAIN_TOOLBAR_LEFT,
@@ -38,13 +38,12 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
38
38
  const DELAY_BEFORE_PROMOTION_COLLAPSE_IN_MS = 5000;
39
39
  const PROMOTION_END_DATE = new Date('2026-09-30');
40
40
 
41
- function getClickCountSetting(): Common.Settings.Setting<number> {
42
- return Common.Settings.Settings.instance().createSetting<number>(
43
- 'global-ai-button-click-count', 0, Common.Settings.SettingStorageType.SYNCED);
41
+ function getClickCountSetting(settings: Common.Settings.Settings): Common.Settings.Setting<number> {
42
+ return settings.createSetting<number>('global-ai-button-click-count', 0, Common.Settings.SettingStorageType.SYNCED);
44
43
  }
45
44
 
46
- function incrementClickCountSetting(): void {
47
- const setting = getClickCountSetting();
45
+ function incrementClickCountSetting(settings: Common.Settings.Settings): void {
46
+ const setting = getClickCountSetting(settings);
48
47
  setting.set(setting.get() + 1);
49
48
  }
50
49
 
@@ -89,10 +88,19 @@ export class GlobalAiButton extends UI.Widget.Widget {
89
88
  #buttonState: GlobalAiButtonState = GlobalAiButtonState.DEFAULT;
90
89
  #mouseOnMainToolbar = false;
91
90
  #returnToDefaultStateTimeout?: number;
92
-
93
- constructor(element?: HTMLElement, view?: View) {
91
+ readonly #settings: Common.Settings.Settings;
92
+ readonly #inspectorView: UI.InspectorView.InspectorView;
93
+ readonly #viewManager: UI.ViewManager.ViewManager;
94
+
95
+ constructor(element?: HTMLElement, view?: View,
96
+ settings: Common.Settings.Settings = Common.Settings.Settings.instance(),
97
+ inspectorView: UI.InspectorView.InspectorView = UI.InspectorView.InspectorView.instance(),
98
+ viewManager: UI.ViewManager.ViewManager = UI.ViewManager.ViewManager.instance()) {
94
99
  super(element);
95
100
  this.#view = view ?? DEFAULT_VIEW;
101
+ this.#settings = settings;
102
+ this.#inspectorView = inspectorView;
103
+ this.#viewManager = viewManager;
96
104
  this.requestUpdate();
97
105
 
98
106
  if (this.#shouldTriggerPromotion()) {
@@ -118,17 +126,13 @@ export class GlobalAiButton extends UI.Widget.Widget {
118
126
  };
119
127
 
120
128
  #addHoverEventListeners(): void {
121
- UI.InspectorView.InspectorView.instance().tabbedPane.headerElement().addEventListener(
122
- 'mouseenter', this.#handleMainToolbarMouseEnter);
123
- UI.InspectorView.InspectorView.instance().tabbedPane.headerElement().addEventListener(
124
- 'mouseleave', this.#handleMainToolbarMouseLeave);
129
+ this.#inspectorView.tabbedPane.headerElement().addEventListener('mouseenter', this.#handleMainToolbarMouseEnter);
130
+ this.#inspectorView.tabbedPane.headerElement().addEventListener('mouseleave', this.#handleMainToolbarMouseLeave);
125
131
  }
126
132
 
127
133
  #removeHoverEventListeners(): void {
128
- UI.InspectorView.InspectorView.instance().tabbedPane.headerElement().removeEventListener(
129
- 'mouseenter', this.#handleMainToolbarMouseEnter);
130
- UI.InspectorView.InspectorView.instance().tabbedPane.headerElement().removeEventListener(
131
- 'mouseleave', this.#handleMainToolbarMouseLeave);
134
+ this.#inspectorView.tabbedPane.headerElement().removeEventListener('mouseenter', this.#handleMainToolbarMouseEnter);
135
+ this.#inspectorView.tabbedPane.headerElement().removeEventListener('mouseleave', this.#handleMainToolbarMouseLeave);
132
136
  }
133
137
 
134
138
  // We only want to enable promotion when:
@@ -138,7 +142,7 @@ export class GlobalAiButton extends UI.Widget.Widget {
138
142
  #shouldTriggerPromotion(): boolean {
139
143
  const isFlagEnabled = Boolean(Root.Runtime.hostConfig.devToolsGlobalAiButton?.promotionEnabled);
140
144
  const isBeforeEndDate = (new Date()) < PROMOTION_END_DATE;
141
- return isFlagEnabled && isBeforeEndDate && getClickCountSetting().get() < 2;
145
+ return isFlagEnabled && isBeforeEndDate && getClickCountSetting(this.#settings).get() < 2;
142
146
  }
143
147
 
144
148
  #triggerPromotion(): void {
@@ -173,23 +177,21 @@ export class GlobalAiButton extends UI.Widget.Widget {
173
177
  }
174
178
 
175
179
  #onClick(): void {
176
- UI.ViewManager.ViewManager.instance().showViewInLocation('freestyler', 'drawer-view');
177
- incrementClickCountSetting();
180
+ this.#viewManager.showViewInLocation('freestyler', 'drawer-view');
181
+ incrementClickCountSetting(this.#settings);
178
182
 
179
- const hasExplicitUserPreference =
180
- UI.InspectorView.InspectorView.instance().isUserExplicitlyUpdatedDrawerOrientation();
183
+ const hasExplicitUserPreference = this.#inspectorView.isUserExplicitlyUpdatedDrawerOrientation();
181
184
  const isVerticalDrawerFeatureEnabled =
182
185
  Boolean(Root.Runtime.hostConfig.devToolsFlexibleLayout?.verticalDrawerEnabled);
183
186
  if (isVerticalDrawerFeatureEnabled && !hasExplicitUserPreference) {
184
187
  // This mimics what we're doing while showing the drawer via `ESC`.
185
188
  // There is a bug where opening the sidebar directly for the first time,
186
189
  // and triggering a drawer rotation without calling `showDrawer({focus: true})` makes the drawer disappear.
187
- UI.InspectorView.InspectorView.instance().showDrawer({
190
+ this.#inspectorView.showDrawer({
188
191
  focus: true,
189
192
  hasTargetDrawer: false,
190
193
  });
191
- UI.InspectorView.InspectorView.instance().toggleDrawerOrientation(
192
- {force: UI.InspectorView.DrawerOrientation.VERTICAL});
194
+ this.#inspectorView.toggleDrawerOrientation({force: UI.InspectorView.DrawerOrientation.VERTICAL});
193
195
  }
194
196
  }
195
197
 
@@ -203,14 +205,15 @@ export class GlobalAiButton extends UI.Widget.Widget {
203
205
  }
204
206
  }
205
207
 
206
- let globalAiButtonToolbarProviderInstance: GlobalAiButtonToolbarProvider;
207
208
  export class GlobalAiButtonToolbarProvider implements UI.Toolbar.Provider {
208
209
  #toolbarItem: UI.Toolbar.ToolbarItemWithCompactLayout;
209
210
  #widgetElement: UI.Widget.WidgetElement<GlobalAiButton>;
210
211
 
211
- private constructor() {
212
+ constructor(settings: Common.Settings.Settings = Common.Settings.Settings.instance(),
213
+ inspectorView: UI.InspectorView.InspectorView = UI.InspectorView.InspectorView.instance(),
214
+ viewManager: UI.ViewManager.ViewManager = UI.ViewManager.ViewManager.instance()) {
212
215
  this.#widgetElement = document.createElement('devtools-widget') as UI.Widget.WidgetElement<GlobalAiButton>;
213
- new GlobalAiButton(this.#widgetElement);
216
+ new GlobalAiButton(this.#widgetElement, undefined, settings, inspectorView, viewManager);
214
217
 
215
218
  this.#toolbarItem = new UI.Toolbar.ToolbarItemWithCompactLayout(this.#widgetElement);
216
219
  this.#toolbarItem.setVisible(false);
@@ -219,13 +222,4 @@ export class GlobalAiButtonToolbarProvider implements UI.Toolbar.Provider {
219
222
  item(): UI.Toolbar.ToolbarItem|null {
220
223
  return this.#toolbarItem;
221
224
  }
222
-
223
- static instance(opts: {forceNew: boolean|null} = {forceNew: null}): GlobalAiButtonToolbarProvider {
224
- const {forceNew} = opts;
225
- if (!globalAiButtonToolbarProviderInstance || forceNew) {
226
- globalAiButtonToolbarProviderInstance = new GlobalAiButtonToolbarProvider();
227
- }
228
-
229
- return globalAiButtonToolbarProviderInstance;
230
- }
231
225
  }