Bug 1438274 - Fix browser and page actions clearance when navigating r=mixedpuppy
authorOriol Brufau <oriol-bugzilla@hotmail.com>
Thu, 15 Feb 2018 02:57:53 +0100
changeset 404203 81617ea852ba672742f87dd247c0182f151aa882
parent 404202 7b08a8b076fdc347fb507f923d243ab1c23b1f78
child 404204 06c8e6e3303cb4787fb15038d074301e84342726
push id33456
push userrgurzau@mozilla.com
push dateFri, 16 Feb 2018 22:08:24 +0000
treeherdermozilla-central@030adb36e3da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmixedpuppy
bugs1438274
milestone60.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 1438274 - Fix browser and page actions clearance when navigating r=mixedpuppy MozReview-Commit-ID: Jb43H65LmFB
browser/components/extensions/ext-browser.js
browser/components/extensions/test/browser/browser_ext_browserAction_context.js
browser/components/extensions/test/browser/browser_ext_pageAction_context.js
browser/components/extensions/test/browser/browser_ext_pageAction_title.js
--- a/browser/components/extensions/ext-browser.js
+++ b/browser/components/extensions/ext-browser.js
@@ -109,17 +109,16 @@ global.makeWidgetId = id => {
 global.TabContext = class extends EventEmitter {
   constructor(getDefaults, extension) {
     super();
 
     this.extension = extension;
     this.getDefaults = getDefaults;
 
     this.tabData = new WeakMap();
-    this.lastLocation = new WeakMap();
 
     windowTracker.addListener("progress", this);
     windowTracker.addListener("TabSelect", this);
   }
 
   get(nativeTab) {
     if (!this.tabData.has(nativeTab)) {
       this.tabData.set(nativeTab, this.getDefaults(nativeTab));
@@ -135,34 +134,24 @@ global.TabContext = class extends EventE
   handleEvent(event) {
     if (event.type == "TabSelect") {
       let nativeTab = event.target;
       this.emit("tab-select", nativeTab);
       this.emit("location-change", nativeTab);
     }
   }
 
-  onStateChange(browser, webProgress, request, stateFlags, statusCode) {
-    let flags = Ci.nsIWebProgressListener;
-
-    if (!(~stateFlags & (flags.STATE_IS_WINDOW | flags.STATE_START) ||
-          this.lastLocation.has(browser))) {
-      this.lastLocation.set(browser, request.URI);
-    }
-  }
-
   onLocationChange(browser, webProgress, request, locationURI, flags) {
     let gBrowser = browser.ownerGlobal.gBrowser;
-    let lastLocation = this.lastLocation.get(browser);
-    if (browser === gBrowser.selectedBrowser &&
-        !(lastLocation && lastLocation.equalsExceptRef(browser.currentURI))) {
-      let nativeTab = gBrowser.getTabForBrowser(browser);
-      this.emit("location-change", nativeTab, true);
+    if (browser === gBrowser.selectedBrowser) {
+      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);
     }
-    this.lastLocation.set(browser, browser.currentURI);
   }
 
   shutdown() {
     windowTracker.removeListener("progress", this);
     windowTracker.removeListener("TabSelect", this);
   }
 };
 
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
@@ -221,16 +221,27 @@ add_task(async function testTabSwitchCon
         {"icon": browser.runtime.getURL("default-2.png"),
          "popup": browser.runtime.getURL("default-2.html"),
          "title": "Default Title 2",
          "badge": "d2",
          "badgeBackgroundColor": [0, 0xff, 0, 0xff],
          "disabled": false},
       ];
 
+      let promiseTabLoad = details => {
+        return new Promise(resolve => {
+          browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
+            if (tabId == details.id && changed.url == details.url) {
+              browser.tabs.onUpdated.removeListener(listener);
+              resolve();
+            }
+          });
+        });
+      };
+
       return [
         async expect => {
           browser.test.log("Initial state, expect default properties.");
 
           await expectDefaults(details[0]);
           expect(details[0]);
         },
         async expect => {
@@ -240,16 +251,23 @@ add_task(async function testTabSwitchCon
           await expectDefaults(details[0]);
           expect(details[1]);
         },
         async expect => {
           browser.test.log("Create a new tab. Expect default properties.");
           let tab = await browser.tabs.create({active: true, url: "about:blank?0"});
           tabs.push(tab.id);
 
+          browser.test.log("Await tab load.");
+          let promise = promiseTabLoad({id: tabs[1], url: "about:blank?0"});
+          let {url} = await browser.tabs.get(tabs[1]);
+          if (url === "about:blank") {
+            await promise;
+          }
+
           await expectDefaults(details[0]);
           expect(details[0]);
         },
         async expect => {
           browser.test.log("Change properties. Expect new properties.");
           let tabId = tabs[1];
           browser.browserAction.setIcon({tabId, path: "2.png"});
           browser.browserAction.setPopup({tabId, popup: "2.html"});
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_context.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_context.js
@@ -95,18 +95,23 @@ add_task(async function testTabSwitchCon
           expect(details[1]);
         },
         async expect => {
           browser.test.log("Create a new tab. No icon visible.");
           let tab = await browser.tabs.create({active: true, url: "about:blank?0"});
           tabs.push(tab.id);
           expect(null);
         },
-        expect => {
+        async expect => {
           browser.test.log("Await tab load. No icon visible.");
+          let promise = promiseTabLoad({id: tabs[1], url: "about:blank?0"});
+          let {url} = await browser.tabs.get(tabs[1]);
+          if (url === "about:blank") {
+            await promise;
+          }
           expect(null);
         },
         async expect => {
           browser.test.log("Change properties. Expect new properties.");
           let tabId = tabs[1];
           await browser.pageAction.show(tabId);
 
           browser.pageAction.setIcon({tabId, path: "2.png"});
@@ -188,8 +193,101 @@ add_task(async function testTabSwitchCon
             "unable to set popup to about:addons");
 
           expect(null);
         },
       ];
     },
   });
 });
+
+add_task(async function testNavigationClearsData() {
+  let url = "http://example.com/";
+  let default_title = "Default title";
+  let tab_title = "Tab title";
+
+  let {Management: {global: {tabTracker}}} = ChromeUtils.import("resource://gre/modules/Extension.jsm", {});
+  let extension, tab, tabId, tabs = [];
+  async function addTab(...args) {
+    tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, ...args);
+    tabId = tabTracker.getId(tab);
+    tabs.push(tab);
+  }
+  async function locationChange(url, task) {
+    let locationChanged = BrowserTestUtils.waitForLocationChange(gBrowser, url);
+    await ContentTask.spawn(tab.linkedBrowser, url, task);
+    await locationChanged;
+  }
+  function setUrl(url) {
+    return locationChange(url, (url) => { content.location.href = url; });
+  }
+  function historyPushState(url) {
+    return locationChange(url, (url) => { content.history.pushState(null, null, url); });
+  }
+  async function sendMessage(method, param, expect, msg) {
+    extension.sendMessage({method, param, expect, msg});
+    await extension.awaitMessage("done");
+  }
+  async function expectTabSpecificData(msg) {
+    await sendMessage("isShown", {tabId}, true, msg);
+    await sendMessage("getTitle", {tabId}, tab_title, msg);
+  }
+  async function expectDefaultData(msg) {
+    await sendMessage("isShown", {tabId}, false, msg);
+    await sendMessage("getTitle", {tabId}, default_title, msg);
+  }
+  async function setTabSpecificData() {
+    await expectDefaultData("Expect default data before setting tab-specific data.");
+    await sendMessage("show", tabId);
+    await sendMessage("setTitle", {tabId, title: tab_title});
+    await expectTabSpecificData("Expect tab-specific data after setting it.");
+  }
+
+  info("Load a tab before installing the extension");
+  await addTab(url, true, true);
+
+  extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      page_action: {default_title},
+    },
+    background: function() {
+      browser.test.onMessage.addListener(async ({method, param, expect, msg}) => {
+        let result = await browser.pageAction[method](param);
+        if (expect !== undefined) {
+          browser.test.assertEq(expect, result, msg);
+        }
+        browser.test.sendMessage("done");
+      });
+    },
+  });
+  await extension.startup();
+
+  info("Set tab-specific data to the existing tab.");
+  await setTabSpecificData();
+
+  info("Add a hash. Does not cause navigation.");
+  await setUrl(url + "#hash");
+  await expectTabSpecificData("Adding a hash does not clear tab-specific data");
+
+  info("Remove the hash. Causes navigation.");
+  await setUrl(url);
+  await expectDefaultData("Removing hash clears tab-specific data");
+
+  info("Open a new tab, set tab-specific data to it.");
+  await addTab("about:newtab", false, false);
+  await setTabSpecificData();
+
+  info("Load a page in that tab.");
+  await setUrl(url);
+  await expectDefaultData("Loading a page clears tab-specific data.");
+
+  info("Set tab-specific data.");
+  await setTabSpecificData();
+
+  info("Push history state. Does not cause navigation.");
+  await historyPushState(url + "/path");
+  await expectTabSpecificData("history.pushState() does not clear tab-specific data");
+
+  for (let tab of tabs) {
+    await BrowserTestUtils.removeTab(tab);
+  }
+  await extension.unload();
+});
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_title.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_title.js
@@ -96,18 +96,23 @@ add_task(async function testTabSwitchCon
           expect(details[1]);
         },
         async expect => {
           browser.test.log("Create a new tab. No icon visible.");
           let tab = await browser.tabs.create({active: true, url: "about:blank?0"});
           tabs.push(tab.id);
           expect(null);
         },
-        expect => {
+        async expect => {
           browser.test.log("Await tab load. No icon visible.");
+          let promise = promiseTabLoad({id: tabs[1], url: "about:blank?0"});
+          let {url} = await browser.tabs.get(tabs[1]);
+          if (url === "about:blank") {
+            await promise;
+          }
           expect(null);
         },
         async expect => {
           browser.test.log("Change properties. Expect new properties.");
           let tabId = tabs[1];
 
           await browser.pageAction.show(tabId);
           browser.pageAction.setIcon({tabId, path: "2.png"});