[go: nahoru, domu]

Use scoped TargetManager API in the InspectElementModeController

Bug: 1417112
Change-Id: I195cd7b7af55f9316f557eb82cb92bf82565f23f
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/4307578
Reviewed-by: Wolfgang Beyer <wolfi@chromium.org>
Commit-Queue: Danil Somsikov <dsv@chromium.org>
Auto-Submit: Danil Somsikov <dsv@chromium.org>
diff --git a/front_end/panels/elements/InspectElementModeController.ts b/front_end/panels/elements/InspectElementModeController.ts
index 44cdbfc..ccad9c0 100644
--- a/front_end/panels/elements/InspectElementModeController.ts
+++ b/front_end/panels/elements/InspectElementModeController.ts
@@ -50,9 +50,9 @@
         SDK.TargetManager.Events.SuspendStateChanged, this.suspendStateChanged, this);
     SDK.TargetManager.TargetManager.instance().addModelListener(
         SDK.OverlayModel.OverlayModel, SDK.OverlayModel.Events.ExitedInspectMode,
-        () => this.setMode(Protocol.Overlay.InspectMode.None));
+        () => this.setMode(Protocol.Overlay.InspectMode.None), undefined, {scoped: true});
     SDK.OverlayModel.OverlayModel.setInspectNodeHandler(this.inspectNode.bind(this));
-    SDK.TargetManager.TargetManager.instance().observeModels(SDK.OverlayModel.OverlayModel, this);
+    SDK.TargetManager.TargetManager.instance().observeModels(SDK.OverlayModel.OverlayModel, this, {scoped: true});
 
     this.showDetailedInspectTooltipSetting =
         Common.Settings.Settings.instance().moduleSetting('showDetailedInspectTooltip');
@@ -117,7 +117,8 @@
       return;
     }
     this.mode = mode;
-    for (const overlayModel of SDK.TargetManager.TargetManager.instance().models(SDK.OverlayModel.OverlayModel)) {
+    for (const overlayModel of SDK.TargetManager.TargetManager.instance().models(
+             SDK.OverlayModel.OverlayModel, {scoped: true})) {
       void overlayModel.setInspectMode(mode, this.showDetailedInspectTooltipSetting.get());
     }
     if (this.toggleSearchAction) {
diff --git a/test/unittests/front_end/panels/elements/BUILD.gn b/test/unittests/front_end/panels/elements/BUILD.gn
index 69897d5..4250641 100644
--- a/test/unittests/front_end/panels/elements/BUILD.gn
+++ b/test/unittests/front_end/panels/elements/BUILD.gn
@@ -12,6 +12,7 @@
     "CSSRuleValidator_test.ts",
     "ClassesPaneWidget_test.ts",
     "ElementsPanel_test.ts",
+    "InspectElementModeController_test.ts",
     "LayoutSidebarPane_test.ts",
     "StylePropertyHighlighter_test.ts",
     "StylePropertyTreeElement_test.ts",
diff --git a/test/unittests/front_end/panels/elements/InspectElementModeController_test.ts b/test/unittests/front_end/panels/elements/InspectElementModeController_test.ts
new file mode 100644
index 0000000..9b8a959
--- /dev/null
+++ b/test/unittests/front_end/panels/elements/InspectElementModeController_test.ts
@@ -0,0 +1,81 @@
+// Copyright 2023 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import * as SDK from '../../../../../front_end/core/sdk/sdk.js';
+import * as Elements from '../../../../../front_end/panels/elements/elements.js';
+
+import type * as Protocol from '../../../../../front_end/generated/protocol.js';
+import {createTarget, stubNoopSettings} from '../../helpers/EnvironmentHelpers.js';
+import {assertNotNullOrUndefined} from '../../../../../front_end/core/platform/platform.js';
+import {describeWithMockConnection, setMockConnectionResponseHandler} from '../../helpers/MockConnection.js';
+
+const {assert} = chai;
+
+const NODE_ID = 1 as Protocol.DOM.NodeId;
+
+describeWithMockConnection('InspectElementModeController', () => {
+  let inScopeTarget: SDK.Target.Target;
+  let inScopeSubTarget: SDK.Target.Target;
+  let outOfScopeTarget: SDK.Target.Target;
+  let outOfScopeSubTarget: SDK.Target.Target;
+  let modeController: Elements.InspectElementModeController.InspectElementModeController;
+
+  function onModeToggle(target: SDK.Target.Target) {
+    const model = target.model(SDK.OverlayModel.OverlayModel);
+    assertNotNullOrUndefined(model);
+    return model.once(SDK.OverlayModel.Events.InspectModeWillBeToggled);
+  }
+
+  function failOnModeToggle(target: SDK.Target.Target) {
+    const model = target.model(SDK.OverlayModel.OverlayModel);
+    assertNotNullOrUndefined(model);
+    model.addEventListener(
+        SDK.OverlayModel.Events.InspectModeWillBeToggled,
+        () => assert.fail('Unexected mode toggle on out of scope target'));
+  }
+
+  beforeEach(() => {
+    stubNoopSettings();
+    const tabTarget = createTarget({type: SDK.Target.Type.Tab});
+    inScopeTarget = createTarget({parentTarget: tabTarget});
+    inScopeSubTarget = createTarget({parentTarget: inScopeTarget});
+    outOfScopeTarget = createTarget({parentTarget: tabTarget});
+    outOfScopeSubTarget = createTarget({parentTarget: outOfScopeTarget});
+    failOnModeToggle(outOfScopeTarget);
+    failOnModeToggle(outOfScopeSubTarget);
+    SDK.TargetManager.TargetManager.instance().setScopeTarget(inScopeTarget);
+    modeController = new Elements.InspectElementModeController.InspectElementModeController();
+    setMockConnectionResponseHandler('DOM.getDocument', () => ({root: {nodeId: NODE_ID}}));
+  });
+
+  it('synchronises mode for in scope models', async () => {
+    for (const target of SDK.TargetManager.TargetManager.instance().targets()) {
+      assert.isFalse(Boolean(target.model(SDK.OverlayModel.OverlayModel)?.inspectModeEnabled()));
+    }
+
+    modeController.toggleInspectMode();
+    await Promise.all([onModeToggle(inScopeTarget), onModeToggle(inScopeSubTarget)]);
+
+    const anotherInScopeSubTarget = createTarget({parentTarget: inScopeTarget});
+    await onModeToggle(anotherInScopeSubTarget);
+
+    const anotherOutOfScopeSubTarget = createTarget({parentTarget: inScopeTarget});
+    failOnModeToggle(anotherOutOfScopeSubTarget);
+
+    let expectToggle = false;
+    const modeToggles =
+        Promise.all([inScopeTarget, inScopeSubTarget, anotherInScopeSubTarget].map(t => onModeToggle(t).then(() => {
+          assert.isTrue(expectToggle);
+        })));
+    outOfScopeTarget.model(SDK.OverlayModel.OverlayModel)
+        ?.dispatchEventToListeners(SDK.OverlayModel.Events.ExitedInspectMode);
+
+    await new Promise<void>(resolve => queueMicrotask(resolve));
+
+    expectToggle = true;
+    inScopeTarget.model(SDK.OverlayModel.OverlayModel)
+        ?.dispatchEventToListeners(SDK.OverlayModel.Events.ExitedInspectMode);
+    await modeToggles;
+  });
+});