Bug 1406585 - Close the autocomplete popup when the crash of a content page or Message Manager disconnection happens. r=MattN draft
authorSean Lee <selee@mozilla.com>
Fri, 10 Nov 2017 17:00:33 +0800
changeset 712195 3c7e0e9940d81b899c65eda9bad3006ae79d4580
parent 710476 a44e04c26913c97a61375a6fcd5867b965e1ce2a
child 743989 cf69ee3ded4915238f9e8de4d35594469e071651
push id93265
push userbmo:selee@mozilla.com
push dateFri, 15 Dec 2017 19:48:26 +0000
reviewersMattN
bugs1406585
milestone59.0a1
Bug 1406585 - Close the autocomplete popup when the crash of a content page or Message Manager disconnection happens. r=MattN MozReview-Commit-ID: DjSc4R0WBQP
toolkit/components/satchel/AutoCompletePopup.jsm
toolkit/components/satchel/test/browser/browser.ini
toolkit/components/satchel/test/browser/browser_close_tab.js
--- a/toolkit/components/satchel/AutoCompletePopup.jsm
+++ b/toolkit/components/satchel/AutoCompletePopup.jsm
@@ -96,22 +96,35 @@ this.AutoCompletePopup = {
     "FormAutoComplete:RemoveEntry",
     "FormAutoComplete:Invalidate",
   ],
 
   init() {
     for (let msg of this.MESSAGES) {
       Services.mm.addMessageListener(msg, this);
     }
+    Services.obs.addObserver(this, "message-manager-disconnect");
   },
 
   uninit() {
     for (let msg of this.MESSAGES) {
       Services.mm.removeMessageListener(msg, this);
     }
+    Services.obs.removeObserver(this, "message-manager-disconnect");
+  },
+
+  observe(subject, topic, data) {
+    switch (topic) {
+      case "message-manager-disconnect": {
+        if (this.openedPopup) {
+          this.openedPopup.closePopup();
+        }
+        break;
+      }
+    }
   },
 
   handleEvent(evt) {
     switch (evt.type) {
       case "popupshowing": {
         this.sendMessageToBrowser("FormAutoComplete:PopupOpened");
         break;
       }
@@ -307,18 +320,24 @@ this.AutoCompletePopup = {
    *        The name of the message to send.
    * @param {object} data
    *        The optional data to send with the message.
    */
   sendMessageToBrowser(msgName, data) {
     let browser = this.weakBrowser ?
       this.weakBrowser.get() :
       null;
-    if (browser) {
+    if (!browser) {
+      return;
+    }
+
+    if (browser.messageManager) {
       browser.messageManager.sendAsyncMessage(msgName, data);
+    } else {
+      Cu.reportError(`AutoCompletePopup: No messageManager for message "${msgName}"`);
     }
   },
 
   stopSearch() {},
 
   /**
    * Sends a message to the browser requesting that the input
    * that the AutoCompletePopup is open for be focused.
--- a/toolkit/components/satchel/test/browser/browser.ini
+++ b/toolkit/components/satchel/test/browser/browser.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 support-files =
   !/toolkit/components/satchel/test/subtst_privbrowsing.html
 
+[browser_close_tab.js]
 [browser_popup_mouseover.js]
 [browser_privbrowsing_perwindowpb.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/satchel/test/browser/browser_close_tab.js
@@ -0,0 +1,59 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const {FormHistory} = Cu.import("resource://gre/modules/FormHistory.jsm", {});
+
+add_task(async function test() {
+  const url = `data:text/html,<input type="text" name="field1">`;
+
+  // Open a dummy tab.
+  await BrowserTestUtils.withNewTab({gBrowser, url}, async function(browser) {});
+
+  await BrowserTestUtils.withNewTab({gBrowser, url}, async function(browser) {
+    const {autoCompletePopup} = browser;
+    const mockHistory = [
+      {op: "add", fieldname: "field1", value: "value1"},
+    ];
+
+    await new Promise(resolve =>
+      FormHistory.update([{op: "remove"}, ...mockHistory],
+                         {handleCompletion: resolve})
+    );
+    await ContentTask.spawn(browser, {}, async function() {
+      const input = content.document.querySelector("input");
+
+      input.focus();
+    });
+
+    // show popup
+    await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
+    await TestUtils.waitForCondition(() => {
+      return autoCompletePopup.popupOpen;
+    });
+
+    let listener;
+    let errorLogPromise = new Promise(resolve => {
+      listener = ({message}) => {
+        const ERROR_MSG = "AutoCompletePopup: No messageManager for " +
+                          "message \"FormAutoComplete:PopupClosed\"";
+        if (message.includes(ERROR_MSG)) {
+          Assert.ok(true, "Got the error message for inexistent messageManager.");
+          Services.console.unregisterListener(listener);
+          resolve();
+        }
+      };
+    });
+    Services.console.registerListener(listener);
+
+    gBrowser.removeCurrentTab();
+
+    await TestUtils.waitForCondition(() => {
+      return !autoCompletePopup.popupOpen;
+    });
+
+    Assert.ok(!autoCompletePopup.popupOpen, "Ensure the popup is closed.");
+
+    await errorLogPromise;
+  });
+});