Bug 1190663: [webext] Add tests for window.close() in browserAction and pageAction popups. r=rpl
☠☠ backed out by 38d23f016898 ☠ ☠
authorKris Maglione <maglione.k@gmail.com>
Sat, 27 Feb 2016 15:29:42 -0800
changeset 322778 09d8e3caf51daf1554673799609b575de4383a02
parent 322777 6a355b46c68b43c0df96978a25b36b661dd98737
child 322779 38d23f0168980b27bb88bf20a8cba7f907bc495e
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrpl
bugs1190663
milestone47.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 1190663: [webext] Add tests for window.close() in browserAction and pageAction popups. r=rpl MozReview-Commit-ID: 8r08YRw7IGr
browser/components/extensions/ext-utils.js
browser/components/extensions/test/browser/browser_ext_browserAction_popup.js
browser/components/extensions/test/browser/browser_ext_pageAction_popup.js
browser/components/extensions/test/browser/head.js
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -120,16 +120,29 @@ global.IconDetails = {
 };
 
 global.makeWidgetId = id => {
   id = id.toLowerCase();
   // FIXME: This allows for collisions.
   return id.replace(/[^a-z0-9_-]/g, "_");
 };
 
+function promisePopupShown(popup) {
+  return new Promise(resolve => {
+    if (popup.state == "open") {
+      resolve();
+    } else {
+      popup.addEventListener("popupshown", function onPopupShown(event) {
+        popup.removeEventListener("popupshown", onPopupShown);
+        resolve();
+      });
+    }
+  });
+}
+
 class BasePopup {
   constructor(extension, viewNode, popupURL) {
     let popupURI = Services.io.newURI(popupURL, null, extension.baseURI);
 
     Services.scriptSecurityManager.checkLoadURIWithPrincipal(
       extension.principal, popupURI,
       Services.scriptSecurityManager.DISALLOW_SCRIPT);
 
@@ -249,16 +262,20 @@ class BasePopup {
       this.browser.addEventListener("load", this, true);
       this.browser.addEventListener("DOMTitleChanged", this, true);
       this.browser.addEventListener("DOMWindowClose", this, true);
     });
   }
 
   // Resizes the browser to match the preferred size of the content.
   resizeBrowser() {
+    if (!this.browser) {
+      return;
+    }
+
     let width, height;
     try {
       let w = {}, h = {};
       this.browser.docShell.contentViewer.getContentSize(w, h);
 
       width = w.value / this.window.devicePixelRatio;
       height = h.value / this.window.devicePixelRatio;
 
@@ -305,17 +322,22 @@ global.PanelPopup = class PanelPopup ext
   }
 
   destroy() {
     super.destroy();
     this.viewNode.remove();
   }
 
   closePopup() {
-    this.viewNode.hidePopup();
+    promisePopupShown(this.viewNode).then(() => {
+      // Make sure we're not already destroyed.
+      if (this.viewNode) {
+        this.viewNode.hidePopup();
+      }
+    });
   }
 };
 
 global.ViewPopup = class ViewPopup extends BasePopup {
   get DESTROY_EVENT() {
     return "ViewHiding";
   }
 
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_popup.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_popup.js
@@ -1,35 +1,42 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 function* testInArea(area) {
+  let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head></html>`;
+
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "background": {
         "page": "data/background.html",
       },
       "browser_action": {
         "default_popup": "popup-a.html",
       },
     },
 
     files: {
-      "popup-a.html": `<script src="popup-a.js"></script>`,
+      "popup-a.html": scriptPage("popup-a.js"),
       "popup-a.js": function() {
         browser.runtime.sendMessage("from-popup-a");
+        browser.runtime.onMessage.addListener(msg => {
+          if (msg == "close-popup") {
+            window.close();
+          }
+        });
       },
 
-      "data/popup-b.html": `<script src="popup-b.js"></script>`,
+      "data/popup-b.html": scriptPage("popup-b.js"),
       "data/popup-b.js": function() {
         browser.runtime.sendMessage("from-popup-b");
       },
 
-      "data/background.html": `<script src="background.js"></script>`,
+      "data/background.html": scriptPage("background.js"),
 
       "data/background.js": function() {
         let sendClick;
         let tests = [
           () => {
             sendClick({expectEvent: false, expectPopup: "a"});
           },
           () => {
@@ -46,36 +53,47 @@ function* testInArea(area) {
             browser.browserAction.setPopup({popup: ""});
             sendClick({expectEvent: true, expectPopup: null});
           },
           () => {
             sendClick({expectEvent: true, expectPopup: null});
           },
           () => {
             browser.browserAction.setPopup({popup: "/popup-a.html"});
-            sendClick({expectEvent: false, expectPopup: "a"});
+            sendClick({expectEvent: false, expectPopup: "a", runNextTest: true});
+          },
+          () => {
+            browser.test.sendMessage("next-test", {expectClosed: true});
+            browser.runtime.sendMessage("close-popup");
           },
         ];
 
         let expect = {};
-        sendClick = ({expectEvent, expectPopup}) => {
-          expect = {event: expectEvent, popup: expectPopup};
+        sendClick = ({expectEvent, expectPopup, runNextTest}) => {
+          expect = {event: expectEvent, popup: expectPopup, runNextTest};
           browser.test.sendMessage("send-click");
         };
 
         browser.runtime.onMessage.addListener(msg => {
-          if (expect.popup) {
+          if (msg == "close-popup") {
+            return;
+          } else if (expect.popup) {
             browser.test.assertEq(msg, `from-popup-${expect.popup}`,
                                   "expected popup opened");
           } else {
-            browser.test.fail("unexpected popup");
+            browser.test.fail(`unexpected popup: ${msg}`);
           }
 
           expect.popup = null;
-          browser.test.sendMessage("next-test");
+          if (expect.runNextTest) {
+            expect.runNextTest = false;
+            tests.shift()();
+          } else {
+            browser.test.sendMessage("next-test");
+          }
         });
 
         browser.browserAction.onClicked.addListener(() => {
           if (expect.event) {
             browser.test.succeed("expected click event received");
           } else {
             browser.test.fail("unexpected click event");
           }
@@ -102,23 +120,30 @@ function* testInArea(area) {
     },
   });
 
   extension.onMessage("send-click", () => {
     clickBrowserAction(extension);
   });
 
   let widget;
-  extension.onMessage("next-test", Task.async(function* () {
+  extension.onMessage("next-test", Task.async(function* (expecting = {}) {
     if (!widget) {
       widget = getBrowserActionWidget(extension);
       CustomizableUI.addWidgetToArea(widget.id, area);
     }
-
-    yield closeBrowserAction(extension);
+    if (expecting.expectClosed) {
+      let panel = getBrowserActionPopup(extension);
+      ok(panel, "Expect panel to exist");
+      yield promisePopupShown(panel);
+      yield promisePopupHidden(panel);
+      ok(true, "Panel is closed");
+    } else {
+      yield closeBrowserAction(extension);
+    }
 
     extension.sendMessage("next-test");
   }));
 
   yield Promise.all([extension.startup(), extension.awaitFinish("browseraction-tests-done")]);
 
   yield extension.unload();
 
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_popup.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_popup.js
@@ -14,16 +14,21 @@ add_task(function* testPageActionPopup()
         "default_popup": "popup-a.html",
       },
     },
 
     files: {
       "popup-a.html": scriptPage("popup-a.js"),
       "popup-a.js": function() {
         browser.runtime.sendMessage("from-popup-a");
+        browser.runtime.onMessage.addListener(msg => {
+          if (msg == "close-popup") {
+            window.close();
+          }
+        });
       },
 
       "data/popup-b.html": scriptPage("popup-b.js"),
       "data/popup-b.js": function() {
         browser.runtime.sendMessage("from-popup-b");
       },
 
       "data/background.html": scriptPage("background.js"),
@@ -50,36 +55,47 @@ add_task(function* testPageActionPopup()
             browser.pageAction.setPopup({tabId, popup: ""});
             sendClick({expectEvent: true, expectPopup: null});
           },
           () => {
             sendClick({expectEvent: true, expectPopup: null});
           },
           () => {
             browser.pageAction.setPopup({tabId, popup: "/popup-a.html"});
-            sendClick({expectEvent: false, expectPopup: "a"});
+            sendClick({expectEvent: false, expectPopup: "a", runNextTest: true});
+          },
+          () => {
+            browser.test.sendMessage("next-test", {expectClosed: true});
+            browser.runtime.sendMessage("close-popup");
           },
         ];
 
         let expect = {};
-        sendClick = ({expectEvent, expectPopup}) => {
-          expect = {event: expectEvent, popup: expectPopup};
+        sendClick = ({expectEvent, expectPopup, runNextTest}) => {
+          expect = {event: expectEvent, popup: expectPopup, runNextTest};
           browser.test.sendMessage("send-click");
         };
 
         browser.runtime.onMessage.addListener(msg => {
-          if (expect.popup) {
+          if (msg == "close-popup") {
+            return;
+          } else if (expect.popup) {
             browser.test.assertEq(msg, `from-popup-${expect.popup}`,
                                   "expected popup opened");
           } else {
-            browser.test.fail("unexpected popup");
+            browser.test.fail(`unexpected popup: ${msg}`);
           }
 
           expect.popup = null;
-          browser.test.sendMessage("next-test");
+          if (expect.runNextTest) {
+            expect.runNextTest = false;
+            tests.shift()();
+          } else {
+            browser.test.sendMessage("next-test");
+          }
         });
 
         browser.pageAction.onClicked.addListener(() => {
           if (expect.event) {
             browser.test.succeed("expected click event received");
           } else {
             browser.test.fail("unexpected click event");
           }
@@ -113,22 +129,29 @@ add_task(function* testPageActionPopup()
 
   let pageActionId = makeWidgetId(extension.id) + "-page-action";
   let panelId = makeWidgetId(extension.id) + "-panel";
 
   extension.onMessage("send-click", () => {
     clickPageAction(extension);
   });
 
-  extension.onMessage("next-test", Task.async(function* () {
+  extension.onMessage("next-test", Task.async(function* (expecting = {}) {
     let panel = document.getElementById(panelId);
-    if (panel) {
+    if (expecting.expectClosed) {
+      ok(panel, "Expect panel to exist");
+      yield promisePopupShown(panel);
+      yield promisePopupHidden(panel);
+      ok(true, `Panel is closed`);
+    } else if (panel) {
       yield promisePopupShown(panel);
       panel.hidePopup();
+    }
 
+    if (panel) {
       panel = document.getElementById(panelId);
       is(panel, null, "panel successfully removed from document after hiding");
     }
 
     extension.sendMessage("next-test");
   }));
 
 
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -2,17 +2,17 @@
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 /* exported CustomizableUI makeWidgetId focusWindow forceGC
  *          getBrowserActionWidget
  *          clickBrowserAction clickPageAction
  *          getBrowserActionPopup getPageActionPopup
  *          closeBrowserAction closePageAction
- *          promisePopupShown
+ *          promisePopupShown promisePopupHidden
  */
 
 var {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm");
 var {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm");
 
 // Bug 1239884: Our tests occasionally hit a long GC pause at unpredictable
 // times in debug builds, which results in intermittent timeouts. Until we have
 // a better solution, we force a GC after certain strategic tests, which tend to
@@ -54,25 +54,37 @@ function promisePopupShown(popup) {
         popup.removeEventListener("popupshown", onPopupShown);
         resolve();
       };
       popup.addEventListener("popupshown", onPopupShown);
     }
   });
 }
 
+function promisePopupHidden(popup) {
+  return new Promise(resolve => {
+    let onPopupHidden = event => {
+      popup.removeEventListener("popuphidden", onPopupHidden);
+      resolve();
+    };
+    popup.addEventListener("popuphidden", onPopupHidden);
+  });
+}
+
 function getBrowserActionWidget(extension) {
   return CustomizableUI.getWidget(makeWidgetId(extension.id) + "-browser-action");
 }
 
 function getBrowserActionPopup(extension, win = window) {
   let group = getBrowserActionWidget(extension);
 
   if (group.areaType == CustomizableUI.TYPE_TOOLBAR) {
     return win.document.getElementById("customizationui-widget-panel");
+  } else {
+    return win.PanelUI.panel;
   }
   return null;
 }
 
 var clickBrowserAction = Task.async(function* (extension, win = window) {
   let group = getBrowserActionWidget(extension);
   let widget = group.forWindow(win);