Bug 1493470 - pageAction icon should not be reset on subframe navigations. r=mixedpuppy
authorLuca Greco <lgreco@mozilla.com>
Wed, 03 Oct 2018 18:46:36 +0000
changeset 439557 22788736d03621751a3bf7a8f281cc5fe52bd8a2
parent 439556 ff0aee3fd2ae32e5fb88ebd4636988b717c5d9c4
child 439558 44cc1c10c5308cc36df0b2b6f4a5c63add05b968
push id70390
push userluca.greco@alcacoop.it
push dateThu, 04 Oct 2018 09:45:47 +0000
treeherderautoland@22788736d036 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmixedpuppy
bugs1493470
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1493470 - pageAction icon should not be reset on subframe navigations. r=mixedpuppy Differential Revision: https://phabricator.services.mozilla.com/D7600
browser/components/extensions/parent/ext-browser.js
browser/components/extensions/test/browser/browser_ext_pageAction_simple.js
--- a/browser/components/extensions/parent/ext-browser.js
+++ b/browser/components/extensions/parent/ext-browser.js
@@ -184,16 +184,22 @@ global.TabContext = class extends EventE
     if (event.type == "TabSelect") {
       let nativeTab = event.target;
       this.emit("tab-select", nativeTab);
       this.emit("location-change", nativeTab);
     }
   }
 
   onLocationChange(browser, webProgress, request, locationURI, flags) {
+    if (!webProgress.isTopLevel) {
+      // Only pageAction and browserAction are consuming the "location-change" event
+      // to update their per-tab status, and they should only do so in response of
+      // location changes related to the top level frame (See Bug 1493470 for a rationale).
+      return;
+    }
     let gBrowser = browser.ownerGlobal.gBrowser;
     let tab = gBrowser.getTabForBrowser(browser);
     // fromBrowse will be false in case of e.g. a hash change or history.pushState
     let fromBrowse = !(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT);
     this.emit("location-change", tab, fromBrowse);
   }
 
   /**
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_simple.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_simple.js
@@ -1,14 +1,16 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 ChromeUtils.import("resource:///modules/PageActions.jsm");
 
+const BASE = "http://example.com/browser/browser/components/extensions/test/browser/";
+
 add_task(async function test_pageAction_basic() {
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "page_action": {
         "default_popup": "popup.html",
         "unrecognized_property": "with-a-random-value",
       },
     },
@@ -101,8 +103,88 @@ add_task(async function test_pageAction_
 
   // There are plenty of tests for the main action button, we just verify
   // that we've properly set the pinned value to false.
   let action = PageActions.actionForID(makeWidgetId(extension.id));
   ok(action && !action.pinnedToUrlbar, "pageAction is in main pageaction menu");
 
   await extension.unload();
 });
+
+add_task(async function test_pageAction_icon_on_subframe_navigation() {
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "page_action": {
+        "default_popup": "popup.html",
+      },
+    },
+
+    files: {
+      "popup.html": `
+      <!DOCTYPE html>
+      <html><body>
+      </body></html>
+      `,
+    },
+
+    background: function() {
+      browser.tabs.query({active: true, currentWindow: true}, tabs => {
+        let tabId = tabs[0].id;
+
+        browser.pageAction.show(tabId).then(() => {
+          browser.test.sendMessage("page-action-shown");
+        });
+      });
+    },
+  });
+
+  await navigateTab(gBrowser.selectedTab, "data:text/html,<h1>Top Level Frame</h1>");
+
+  await extension.startup();
+  await extension.awaitMessage("page-action-shown");
+
+  const pageActionId = BrowserPageActions.urlbarButtonNodeIDForActionID(makeWidgetId(extension.id));
+
+  await BrowserTestUtils.waitForCondition(() => {
+    return document.getElementById(pageActionId);
+  }, "pageAction is initially visible");
+
+  info("Create a sub-frame");
+
+  let subframeURL = `${BASE}#subframe-url-1`;
+  await ContentTask.spawn(gBrowser.selectedBrowser, subframeURL, async (url) => {
+    const iframe = this.content.document.createElement("iframe");
+    iframe.setAttribute("id", "test-subframe");
+    iframe.setAttribute("src", url);
+    iframe.setAttribute("style", "height: 200px; width: 200px");
+
+    // Await the initial url to be loaded in the subframe.
+    await new Promise(resolve => {
+      iframe.onload = resolve;
+      this.content.document.body.appendChild(iframe);
+    });
+  });
+
+  await BrowserTestUtils.waitForCondition(() => {
+    return document.getElementById(pageActionId);
+  }, "pageAction should be visible when a subframe is created");
+
+  info("Navigating the sub-frame");
+
+  subframeURL = `${BASE}/file_dummy.html#subframe-url-2`;
+  await ContentTask.spawn(gBrowser.selectedBrowser, subframeURL, async (url) => {
+    const iframe = this.content.document.querySelector("iframe#test-subframe");
+
+    // Await the subframe navigation.
+    await new Promise(resolve => {
+      iframe.onload = resolve;
+      iframe.setAttribute("src", url);
+    });
+  });
+
+  info("Subframe location changed");
+
+  await BrowserTestUtils.waitForCondition(() => {
+    return document.getElementById(pageActionId);
+  }, "pageAction should be visible after a subframe navigation");
+
+  await extension.unload();
+});