Bug 1357486: Part 0b - Fix inline options browser tests with OOP extensions. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Fri, 07 Jul 2017 18:19:33 -0700
changeset 605562 56bafa6b37a298e8b548d1ae74bb74177bae6db4
parent 605456 30a534be12015c49ccb7dd13dad41f498f230ba2
child 605563 7431a0ecced243a96ffb4cf1cc04adf6fbc17a4e
push id67457
push usermaglione.k@gmail.com
push dateSat, 08 Jul 2017 01:21:07 +0000
reviewersaswan
bugs1357486
milestone56.0a1
Bug 1357486: Part 0b - Fix inline options browser tests with OOP extensions. r?aswan MozReview-Commit-ID: Bc4hNFmVOlw
toolkit/mozapps/extensions/content/extensions.js
toolkit/mozapps/extensions/test/browser/browser_inlinesettings_browser.js
toolkit/mozapps/extensions/test/browser/browser_webext_options.js
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -107,91 +107,16 @@ XPCOMUtils.defineLazyPreferenceGetter(th
                                       raw => raw.split(","));
 XPCOMUtils.defineLazyPreferenceGetter(this, "legacyExtensionsEnabled",
                                       PREF_LEGACY_ENABLED, true,
                                       () => gLegacyView.refresh());
 
 document.addEventListener("load", initialize, true);
 window.addEventListener("unload", shutdown);
 
-class MessageDispatcher {
-  constructor(target) {
-    this.listeners = new Map();
-    this.target = target;
-  }
-
-  addMessageListener(name, handler) {
-    if (!this.listeners.has(name)) {
-      this.listeners.set(name, new Set());
-    }
-
-    this.listeners.get(name).add(handler);
-  }
-
-  removeMessageListener(name, handler) {
-    if (this.listeners.has(name)) {
-      this.listeners.get(name).delete(handler);
-    }
-  }
-
-  sendAsyncMessage(name, data) {
-    for (let handler of this.listeners.get(name) || new Set()) {
-      Promise.resolve().then(() => {
-        handler.receiveMessage({
-          name,
-          data,
-          target: this.target,
-        });
-      });
-    }
-  }
-}
-
-/**
- * A mock FrameMessageManager global to allow frame scripts to run in
- * non-top-level, non-remote <browser>s as if they were top-level or
- * remote.
- *
- * @param {Element} browser
- *        A XUL <browser> element.
- */
-class FakeFrameMessageManager {
-  constructor(browser) {
-    let dispatcher = new MessageDispatcher(browser);
-    let frameDispatcher = new MessageDispatcher(null);
-
-    let bind = (object, method) => object[method].bind(object);
-
-    this.sendAsyncMessage = bind(frameDispatcher, "sendAsyncMessage");
-    this.addMessageListener = bind(dispatcher, "addMessageListener");
-    this.removeMessageListener = bind(dispatcher, "removeMessageListener");
-
-    this.frame = {
-      get content() {
-        return browser.contentWindow;
-      },
-
-      get docShell() {
-        return browser.docShell;
-      },
-
-      addEventListener: bind(browser, "addEventListener"),
-      removeEventListener: bind(browser, "removeEventListener"),
-
-      sendAsyncMessage: bind(dispatcher, "sendAsyncMessage"),
-      addMessageListener: bind(frameDispatcher, "addMessageListener"),
-      removeMessageListener: bind(frameDispatcher, "removeMessageListener"),
-    }
-  }
-
-  loadFrameScript(url) {
-    Services.scriptloader.loadSubScript(url, Object.create(this.frame));
-  }
-}
-
 function promiseEvent(event, target, capture = false) {
   return new Promise(resolve => {
     target.addEventListener(event, resolve, {capture, once: true});
   });
 }
 
 var gPendingInitializations = 1;
 Object.defineProperty(this, "gIsInitializing", {
@@ -3782,16 +3707,17 @@ var gDetailView = {
     }
   },
 
   async createOptionsBrowser(parentNode) {
     let browser = document.createElement("browser");
     browser.setAttribute("type", "content");
     browser.setAttribute("disableglobalhistory", "true");
     browser.setAttribute("class", "inline-options-browser");
+    browser.setAttribute("forcemessagemanager", "true");
 
     let {optionsURL} = this._addon;
     let remote = !E10SUtils.canLoadURIInProcess(optionsURL, Services.appinfo.PROCESS_TYPE_DEFAULT);
 
     let readyPromise;
     if (remote) {
       browser.setAttribute("remote", "true");
       browser.setAttribute("remoteType", E10SUtils.EXTENSION_REMOTE_TYPE);
@@ -3801,31 +3727,29 @@ var gDetailView = {
     }
 
     parentNode.appendChild(browser);
 
     // Force bindings to apply synchronously.
     browser.clientTop;
 
     await readyPromise;
-    if (remote) {
-      ExtensionParent.apiManager.emit("extension-browser-inserted", browser);
-    }
+    ExtensionParent.apiManager.emit("extension-browser-inserted", browser);
 
     return new Promise(resolve => {
       let messageListener = {
         receiveMessage({name, data}) {
           if (name === "Extension:BrowserResized")
             browser.style.height = `${data.height}px`;
           else if (name === "Extension:BrowserContentLoaded")
             resolve(browser);
         },
       };
 
-      let mm = browser.messageManager || new FakeFrameMessageManager(browser);
+      let mm = browser.messageManager;
       mm.loadFrameScript("chrome://extensions/content/ext-browser-content.js",
                          false);
       mm.addMessageListener("Extension:BrowserContentLoaded", messageListener);
       mm.addMessageListener("Extension:BrowserResized", messageListener);
 
       let browserOptions = {
         fixedWidth: true,
         isInline: true,
--- a/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_browser.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_browser.js
@@ -1,16 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 /* globals TestUtils */
 
 var {Extension} = Components.utils.import("resource://gre/modules/Extension.jsm", {});
 
+Components.utils.import("resource://testing-common/ContentTask.jsm", {});
+
 var gAddon;
 var gOtherAddon;
 var gManagerWindow;
 var gCategoryUtilities;
 
 function installAddon(details) {
   let id = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)
                                               .generateUUID().number;
@@ -91,65 +93,74 @@ async function openDetailsBrowser(addonI
   is(gManagerWindow.gViewController.currentViewId,
      `addons://detail/${encodeURIComponent(addonId)}/preferences`,
      "Current view should scroll to preferences");
 
   var browser = gManagerWindow.document.querySelector(
     "#detail-grid > rows > .inline-options-browser");
   var rows = browser.parentNode;
 
+  let url = await ContentTask.spawn(browser, {}, () => content.location.href);
+
   ok(browser, "Grid should have a browser child");
   is(browser.localName, "browser", "Grid should have a browser child");
-  is(browser.currentURI.spec, addon.mAddon.optionsURL, "Browser has the expected options URL loaded")
+  is(url, addon.mAddon.optionsURL, "Browser has the expected options URL loaded")
 
   is(browser.clientWidth, rows.clientWidth,
      "Browser should be the same width as its parent node");
 
   button = gManagerWindow.document.getElementById("detail-prefs-btn");
   is_element_hidden(button, "Preferences button should not be visible");
 
   return browser;
 }
 
 
 add_task(async function test_inline_browser_addon() {
   let browser = await openDetailsBrowser(gAddon.id);
 
-  let body = browser.contentDocument.body;
+  function checkHeights(expected) {
+    let {clientHeight} = browser;
+    return ContentTask.spawn(browser, {expected, clientHeight}, ({expected, clientHeight}) => {
+      let {body} = content.document;
 
-  function checkHeights(expected) {
-    is(body.clientHeight, expected, `Document body should be ${expected}px tall`);
-    is(body.clientHeight, body.scrollHeight,
-       "Document body should be tall enough to fit its contents");
+      is(body.clientHeight, expected, `Document body should be ${expected}px tall`);
+      is(body.clientHeight, body.scrollHeight,
+         "Document body should be tall enough to fit its contents");
 
-    let heightDiff = browser.clientHeight - expected;
-    ok(heightDiff >= 0 && heightDiff < 50,
-       `Browser should be slightly taller than the document body (${browser.clientHeight} vs. ${expected})`);
+      let heightDiff = clientHeight - expected;
+      ok(heightDiff >= 0 && heightDiff < 50,
+         `Browser should be slightly taller than the document body (${clientHeight} vs. ${expected})`);
+    });
   }
 
   // Delay long enough to avoid hitting our resize rate limit.
   let delay = () => new Promise(resolve => setTimeout(resolve, 300));
 
   await delay();
 
-  checkHeights(300);
+  await checkHeights(300);
 
   info("Increase the document height, and expect the browser to grow correspondingly");
-  body.classList.toggle("bigger");
+  await ContentTask.spawn(browser, null, () => {
+    content.document.body.classList.toggle("bigger");
+  });
 
   await delay();
 
-  checkHeights(600);
+  await checkHeights(600);
 
   info("Decrease the document height, and expect the browser to shrink correspondingly");
-  body.classList.toggle("bigger");
+  await ContentTask.spawn(browser, null, () => {
+    content.document.body.classList.toggle("bigger");
+  });
 
   await delay();
 
-  checkHeights(300);
+  await checkHeights(300);
 
   await new Promise(resolve =>
     gCategoryUtilities.openType("extension", resolve));
 
   browser = gManagerWindow.document.querySelector(
     ".inline-options-browser");
 
   is(browser, null, "Options browser should be removed from the document");
--- a/toolkit/mozapps/extensions/test/browser/browser_webext_options.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_webext_options.js
@@ -1,12 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+Components.utils.import("resource://testing-common/ContentTask.jsm", {});
+
 // Wrapper to run a test that consists of:
 //  1. opening the add-ons manager viewing the list of extensions
 //  2. installing an extension (using the provider installer callable)
 //  3. opening the preferences panel for the new extension and verifying
 //     that it opens cleanly
 async function runTest(installer) {
   let mgrWindow = await open_manager("addons://list/extension");
 
@@ -26,19 +28,21 @@ async function runTest(installer) {
 
   is(mgrWindow.gViewController.currentViewId,
      `addons://detail/${encodeURIComponent(id)}/preferences`,
      "Current view should scroll to preferences");
 
   var browser = mgrWindow.document.querySelector("#detail-grid > rows > .inline-options-browser");
   var rows = browser.parentNode;
 
+  let url = await ContentTask.spawn(browser, {}, () => content.location.href);
+
   ok(browser, "Grid should have a browser child");
   is(browser.localName, "browser", "Grid should have a browser child");
-  is(browser.currentURI.spec, element.mAddon.optionsURL, "Browser has the expected options URL loaded")
+  is(url, element.mAddon.optionsURL, "Browser has the expected options URL loaded")
 
   is(browser.clientWidth, rows.clientWidth,
      "Browser should be the same width as its parent node");
 
   button = mgrWindow.document.getElementById("detail-prefs-btn");
   is_element_hidden(button, "Preferences button should not be visible");
 
   await close_manager(mgrWindow);