Bug 1325830 - Initialize tabListener if needed. r=kmag, a=jcristau
authorRob Wu <rob@robwu.nl>
Mon, 26 Dec 2016 12:30:50 +0100
changeset 353629 628947537e8580846ac24b32ec37aed903a77ed7
parent 353628 d75736de7c46c359937ef7875b3435ade6717cde
child 353630 b628307561a31b4e89721fab9b3577c77c9941b5
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag, jcristau
bugs1325830
milestone52.0a2
Bug 1325830 - Initialize tabListener if needed. r=kmag, a=jcristau To verify, run the test in isolation: mach mochitest browser/components/extensions/test/browser/browser_ext_tabs_executeScript_no_create.js Without the fix, the test fails in e10s; with the fix, the test passes. MozReview-Commit-ID: Imf0Ue7ORHd
browser/components/extensions/ext-tabs.js
browser/components/extensions/test/browser/browser_ext_tabs_executeScript_no_create.js
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -245,28 +245,30 @@ let tabListener = {
         this.tabReadyPromises.delete(tab);
       }
     }
   },
 
   /**
    * Returns a promise that resolves when the tab is ready.
    * Tabs created via the `tabs.create` method are "ready" once the location
-   * changed to the requested URL. Other tabs are always assumed to be ready.
+   * changes to the requested URL. Other tabs are assumed to be ready once their
+   * inner window ID is known.
    *
    * @param {XULElement} tab The <tab> element.
    * @returns {Promise} Resolves with the given tab once ready.
    */
   awaitTabReady(tab) {
     let deferred = this.tabReadyPromises.get(tab);
     if (!deferred) {
       deferred = PromiseUtils.defer();
       if (!this.initializingTabs.has(tab) && tab.linkedBrowser.innerWindowID) {
         deferred.resolve(tab);
       } else {
+        this.initTabReady();
         this.tabReadyPromises.set(tab, deferred);
       }
     }
     return deferred.promise;
   },
 };
 
 /* eslint-disable mozilla/balanced-listeners */
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_no_create.js
@@ -0,0 +1,67 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+add_task(function* testExecuteScriptAtOnUpdated() {
+  const BASE = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/";
+  const URL = BASE + "file_iframe_document.html";
+  // This is a regression test for bug 1325830.
+  // The bug (executeScript not completing any more) occurred when executeScript
+  // was called early at the onUpdated event, unless the tabs.create method is
+  // called. So this test does not use tabs.create to open new tabs.
+  // Note that if this test is run together with other tests that do call
+  // tabs.create, then this test case does not properly test the conditions of
+  // the regression any more. To verify that the regression has been resolved,
+  // this test must be run in isolation.
+
+  function background() {
+    // Using variables to prevent listeners from running more than once, instead
+    // of removing the listener. This is to minimize any IPC, since the bug that
+    // is being tested is sensitive to timing.
+    let ignore = false;
+    let url;
+    browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
+      if (changeInfo.status === "loading" && tab.url === url && !ignore) {
+        ignore = true;
+        browser.tabs.executeScript(tabId, {
+          code: "document.URL",
+        }).then(results => {
+          browser.test.assertEq(url, results[0], "Content script should run");
+          browser.test.notifyPass("executeScript-at-onUpdated");
+        }, error => {
+          browser.test.fail(`Unexpected error: ${error} :: ${error.stack}`);
+          browser.test.notifyFail("executeScript-at-onUpdated");
+        });
+        // (running this log call after executeScript to minimize IPC between
+        //  onUpdated and executeScript.)
+        browser.test.log(`Found expected navigation to ${url}`);
+      } else {
+        // The bug occurs when executeScript is called before a tab is
+        // initialized.
+        browser.tabs.executeScript(tabId, {code: ""});
+      }
+    });
+    browser.test.onMessage.addListener(testUrl => {
+      url = testUrl;
+      browser.test.sendMessage("open-test-tab");
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "permissions": ["http://mochi.test/", "tabs"],
+    },
+    background,
+  });
+
+  yield extension.startup();
+  extension.sendMessage(URL);
+  yield extension.awaitMessage("open-test-tab");
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, URL, true);
+
+  yield extension.awaitFinish("executeScript-at-onUpdated");
+
+  yield extension.unload();
+
+  yield BrowserTestUtils.removeTab(tab);
+});