Bug 1253604 fix share breakage after canceling share on fb, r=markh a=ritu
authorShane Caraveo <scaraveo@mozilla.com>
Wed, 27 Apr 2016 09:47:01 -0700
changeset 332724 0123e9f41cedbcded87d8f6c3743ff6a4c1d8e5b
parent 332723 f1960a9049728175f7d880a9caacc6db3f0e6052
child 332725 d664dd496ba25607d920c54895cb6e4f74d435e1
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarkh, ritu
bugs1253604
milestone48.0a2
Bug 1253604 fix share breakage after canceling share on fb, r=markh a=ritu
browser/base/content/browser-social.js
browser/base/content/social-content.js
browser/base/content/test/social/browser.ini
browser/base/content/test/social/browser_share.js
browser/base/content/test/social/head.js
browser/base/content/test/social/share.html
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -484,17 +484,16 @@ SocialShare = {
       return;
     this.panel.hidden = false;
     // create and initialize the panel for this window
     let iframe = document.createElement("browser");
     iframe.setAttribute("type", "content");
     iframe.setAttribute("class", "social-share-frame");
     iframe.setAttribute("context", "contentAreaContextMenu");
     iframe.setAttribute("tooltip", "aHTMLTooltip");
-    iframe.setAttribute("disablehistory", "true");
     iframe.setAttribute("disableglobalhistory", "true");
     iframe.setAttribute("flex", "1");
     iframe.setAttribute("message", "true");
     iframe.setAttribute("messagemanagergroup", "social");
     panel.lastChild.appendChild(iframe);
     let mm = iframe.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.messageManager;
     mm.sendAsyncMessage("Social:SetErrorURL",
                         { template: "about:socialerror?mode=compactInfo&origin=%{origin}&url=%{url}" });
@@ -570,16 +569,17 @@ SocialShare = {
   onShowing: function() {
     (this._currentAnchor || this.anchor).setAttribute("open", "true");
     this.iframe.addEventListener("click", this._onclick, true);
   },
 
   onHidden: function() {
     (this._currentAnchor || this.anchor).removeAttribute("open");
     this._currentAnchor = null;
+    this.iframe.docShellIsActive = false;
     this.iframe.removeEventListener("click", this._onclick, true);
     this.iframe.setAttribute("src", "data:text/plain;charset=utf8,");
     // make sure that the frame is unloaded after it is hidden
     this.iframe.docShell.createAboutBlankContentViewer(null);
     this.currentShare = null;
     // share panel use is over, purge any history
     this.iframe.purgeSessionHistory();
   },
@@ -675,16 +675,19 @@ SocialShare = {
       iframe.addEventListener("load", function panelBrowserOnload(e) {
         iframe.removeEventListener("load", panelBrowserOnload, true);
         iframe.docShellIsActive = true;
         iframe.parentNode.removeAttribute("loading");
         // to support standard share endpoints mimick window.open by setting
         // window.opener, some share endpoints rely on w.opener to know they
         // should close the window when done.
         iframe.contentWindow.opener = iframe.contentWindow;
+        // disable beforeunload dialogs
+        let mm = iframe.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.messageManager;
+        mm.sendAsyncMessage("Social:DisableDialogs", {});
 
         SocialShare._dynamicResizer.start(iframe.parentNode, iframe, size);
 
         let evt = iframe.contentDocument.createEvent("CustomEvent");
         evt.initCustomEvent("OpenGraphData", true, true, JSON.stringify(pageData));
         iframe.contentDocument.documentElement.dispatchEvent(evt);
       }, true);
     }
--- a/browser/base/content/social-content.js
+++ b/browser/base/content/social-content.js
@@ -60,16 +60,17 @@ const SocialErrorListener = {
     addMessageListener("Loop:GetAllWebrtcStats", this);
     addMessageListener("Social:CustomEvent", this);
     addMessageListener("Social:EnsureFocus", this);
     addMessageListener("Social:EnsureFocusElement", this);
     addMessageListener("Social:HookWindowCloseForPanelClose", this);
     addMessageListener("Social:ListenForEvents", this);
     addMessageListener("Social:SetDocumentTitle", this);
     addMessageListener("Social:SetErrorURL", this);
+    addMessageListener("Social:DisableDialogs", this);
     addMessageListener("Social:WaitForDocumentVisible", this);
     addMessageListener("WaitForDOMContentLoaded", this);
     let webProgress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                               .getInterface(Components.interfaces.nsIWebProgress);
     webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
                                           Ci.nsIWebProgress.NOTIFY_LOCATION);
   },
 
@@ -170,16 +171,21 @@ const SocialErrorListener = {
           break;
         }
 
         document.addEventListener("visibilitychange", function onVisibilityChanged() {
           document.removeEventListener("visibilitychange", onVisibilityChanged);
           sendAsyncMessage("Social:DocumentVisible");
         });
         break;
+      case "Social:DisableDialogs":
+        let windowUtils = content.QueryInterface(Ci.nsIInterfaceRequestor).
+                          getInterface(Ci.nsIDOMWindowUtils);
+        windowUtils.disableDialogs();
+        break;
       case "WaitForDOMContentLoaded":
         if (gDOMContentLoaded) {
           sendAsyncMessage("DOMContentLoaded");
         }
         break;
     }
   },
 
--- a/browser/base/content/test/social/browser.ini
+++ b/browser/base/content/test/social/browser.ini
@@ -25,17 +25,16 @@ support-files =
   social_sidebar_empty.html
   unchecked.jpg
   !/browser/base/content/test/plugins/blockNoPlugins.xml
 
 [browser_aboutHome_activation.js]
 [browser_addons.js]
 [browser_blocklist.js]
 [browser_share.js]
-skip-if = true # bug 1115131
 [browser_social_activation.js]
 [browser_social_chatwindow.js]
 [browser_social_chatwindow_resize.js]
 [browser_social_chatwindowfocus.js]
 [browser_social_contextmenu.js]
 skip-if = (os == 'linux' && e10s) # Bug 1072669 context menu relies on target element
 [browser_social_errorPage.js]
 [browser_social_flyout.js]
--- a/browser/base/content/test/social/browser_share.js
+++ b/browser/base/content/test/social/browser_share.js
@@ -16,41 +16,42 @@ function sendActivationEvent(subframe) {
   Social.lastEventReceived = 0;
   let doc = subframe.contentDocument;
   // if our test has a frame, use it
   let button = doc.getElementById("activation");
   ok(!!button, "got the activation button");
   EventUtils.synthesizeMouseAtCenter(button, {}, doc.defaultView);
 }
 
-function promiseShareFrameEvent(iframe, eventName) {
-  let deferred = Promise.defer();
-  iframe.addEventListener(eventName, function load(event) {
-    info("page load is " + iframe.contentDocument.location.href);
-    if (iframe.contentDocument.location.href != "data:text/plain;charset=utf8,") {
-      iframe.removeEventListener(eventName, load, true);
-      deferred.resolve(event);
-    }
-  }, true);
-  return deferred.promise;
-}
-
 function test() {
   waitForExplicitFinish();
   Services.prefs.setCharPref("social.shareDirectory", activationPage);
 
   let frameScript = "data:,(" + function frame_script() {
     addEventListener("OpenGraphData", function (aEvent) {
       sendAsyncMessage("sharedata", aEvent.detail);
     }, true, true);
+    /* bug 1042991, ensure history is available by calling history.back on close */
+    addMessageListener("closeself", function(e) {
+      content.history.back();
+      content.close();
+    }, true);
+    /* if text is entered into field, onbeforeunload will cause a modal dialog
+       unless dialogs have been disabled for the iframe. */
+    content.onbeforeunload = function(e) {
+      return 'FAIL.';
+    };
   }.toString() + ")();";
   let mm = getGroupMessageManager("social");
   mm.loadFrameScript(frameScript, true);
 
+  // Animation on the panel can cause intermittent failures such as bug 1115131.
+  SocialShare.panel.setAttribute("animate", "false");
   registerCleanupFunction(function () {
+    SocialShare.panel.removeAttribute("animate");
     mm.removeDelayedFrameScript(frameScript);
     Services.prefs.clearUserPref("social.directories");
     Services.prefs.clearUserPref("social.shareDirectory");
     Services.prefs.clearUserPref("social.share.activationPanelEnabled");
   });
   runSocialTests(tests, undefined, function(next) {
     let shareButton = SocialShare.shareButton;
     if (shareButton) {
@@ -183,38 +184,58 @@ var tests = {
   },
   testSharePage: function(next) {
     let provider = Social._getProviderFromOrigin(manifest.origin);
 
     let testTab;
     let testIndex = 0;
     let testData = corpus[testIndex++];
 
+    // initialize the button into the navbar
+    CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_NAVBAR);
+    // ensure correct state
+    SocialUI.onCustomizeEnd(window);
+
     let mm = getGroupMessageManager("social");
     mm.addMessageListener("sharedata", function handler(msg) {
       gBrowser.removeTab(testTab);
       hasoptions(testData.options, JSON.parse(msg.data));
       testData = corpus[testIndex++];
-      if (testData) {
-        executeSoon(runOneTest);
-      } else {
-        mm.removeMessageListener("sharedata", handler);
-        SocialService.disableProvider(manifest.origin, next);
-      }
+      BrowserTestUtils.waitForCondition(() => { return SocialShare.currentShare == null; },"share panel closed").then(() => {
+        if (testData) {
+          runOneTest();
+        } else {
+          mm.removeMessageListener("sharedata", handler);
+          SocialService.disableProvider(manifest.origin, next);
+        }
+      });
+      SocialShare.iframe.messageManager.sendAsyncMessage("closeself", {});
     });
 
     function runOneTest() {
       addTab(testData.url, function(tab) {
         testTab = tab;
+
+        let shareButton = SocialShare.shareButton;
+        // verify the attribute for proper css
+        ok(!shareButton.hasAttribute("disabled"), "share button is enabled");
+        // button should be visible
+        is(shareButton.hidden, false, "share button is visible");
+
         SocialShare.sharePage(manifest.origin);
       });
     }
     executeSoon(runOneTest);
   },
   testShareMicroformats: function(next) {
+    // initialize the button into the navbar
+    CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_NAVBAR);
+    // ensure correct state
+    SocialUI.onCustomizeEnd(window);
+
     SocialService.addProvider(manifest, function(provider) {
       let target, testTab;
 
       let expecting = JSON.stringify({
         "url": "https://example.com/browser/browser/base/content/test/social/microformats.html",
         "title": "Raspberry Pi Page",
         "previews": ["https://example.com/someimage.jpg"],
         "microformats": {
@@ -256,59 +277,122 @@ var tests = {
             }
           }
         }
       });
 
       let mm = getGroupMessageManager("social");
       mm.addMessageListener("sharedata", function handler(msg) {
         is(msg.data, expecting, "microformats data ok");
-        gBrowser.removeTab(testTab);
-        mm.removeMessageListener("sharedata", handler);
-        SocialService.disableProvider(manifest.origin, next);
+        BrowserTestUtils.waitForCondition(() => { return SocialShare.currentShare == null; },
+                                          "share panel closed").then(() => {
+          gBrowser.removeTab(testTab);
+          mm.removeMessageListener("sharedata", handler);
+          SocialService.disableProvider(manifest.origin, next);
+        });
+        SocialShare.iframe.messageManager.sendAsyncMessage("closeself", {});
       });
 
       let url = "https://example.com/browser/browser/base/content/test/social/microformats.html"
       addTab(url, function(tab) {
         testTab = tab;
+
+        let shareButton = SocialShare.shareButton;
+        // verify the attribute for proper css
+        ok(!shareButton.hasAttribute("disabled"), "share button is enabled");
+        // button should be visible
+        is(shareButton.hidden, false, "share button is visible");
+
         let doc = tab.linkedBrowser.contentDocument;
         target = doc.getElementById("simple-hcard");
         SocialShare.sharePage(manifest.origin, null, target);
       });
     });
   },
   testSharePanelActivation: function(next) {
     let testTab;
     // cleared in the cleanup function
     Services.prefs.setCharPref("social.directories", "https://example.com");
     Services.prefs.setBoolPref("social.share.activationPanelEnabled", true);
     // make the iframe so we can wait on the load
     SocialShare._createFrame();
     let iframe = SocialShare.iframe;
 
-    promiseShareFrameEvent(iframe, "load").then(() => {
+    // initialize the button into the navbar
+    CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_NAVBAR);
+    // ensure correct state
+    SocialUI.onCustomizeEnd(window);
+
+    ensureEventFired(iframe, "load").then(() => {
       let subframe = iframe.contentDocument.getElementById("activation-frame");
-      waitForCondition(() => {
-          // sometimes the iframe is ready before the panel is open, we need to
-          // wait for both conditions
-          return SocialShare.panel.state == "open"
-                 && subframe.contentDocument
-                 && subframe.contentDocument.readyState == "complete";
-        }, () => {
+      ensureFrameLoaded(subframe, activationPage).then(() => {
         is(subframe.contentDocument.location.href, activationPage, "activation page loaded");
         promiseObserverNotified("social:provider-enabled").then(() => {
           let mm = getGroupMessageManager("social");
           mm.addMessageListener("sharedata", function handler(msg) {
             ok(true, "share completed");
-            gBrowser.removeTab(testTab);
-            mm.removeMessageListener("sharedata", handler);
-            SocialService.uninstallProvider(manifest.origin, next);
+
+            BrowserTestUtils.waitForCondition(() => { return SocialShare.currentShare == null; },
+                                              "share panel closed").then(() => {
+              ensureBrowserTabClosed(testTab).then(() => {
+                mm.removeMessageListener("sharedata", handler);
+                SocialService.uninstallProvider(manifest.origin, next);
+              });
+            });
+            SocialShare.iframe.messageManager.sendAsyncMessage("closeself", {});
           });
         });
         sendActivationEvent(subframe);
-      }, "share panel did not open and load share page");
+      });
     });
     addTab(activationPage, function(tab) {
+      let shareButton = SocialShare.shareButton;
+      // verify the attribute for proper css
+      ok(!shareButton.hasAttribute("disabled"), "share button is enabled");
+      // button should be visible
+      is(shareButton.hidden, false, "share button is visible");
+
       testTab = tab;
       SocialShare.sharePage();
     });
+  },
+  testSharePanelDialog: function(next) {
+    let testTab;
+    // initialize the button into the navbar
+    CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_NAVBAR);
+    // ensure correct state
+    SocialUI.onCustomizeEnd(window);
+    SocialShare._createFrame();
+
+    SocialService.addProvider(manifest, () => {
+      addTab(activationPage, (tab) => {
+        ensureEventFired(SocialShare.iframe, "load").then(() => {
+          // send keys to the input field.  An unexpected failure will happen
+          // if the onbeforeunload handler is fired.
+          EventUtils.sendKey("f");
+          EventUtils.sendKey("a");
+          EventUtils.sendKey("i");
+          EventUtils.sendKey("l");
+  
+          SocialShare.panel.addEventListener("popuphidden", function hidden(evt) {
+            SocialShare.panel.removeEventListener("popuphidden", hidden);
+            let topwin = Services.wm.getMostRecentWindow(null);
+            is(topwin, window, "no dialog is open");
+
+            ensureBrowserTabClosed(testTab).then(() => {
+              SocialService.disableProvider(manifest.origin, next);
+            });
+          });
+          SocialShare.iframe.messageManager.sendAsyncMessage("closeself", {});
+        });
+
+        let shareButton = SocialShare.shareButton;
+        // verify the attribute for proper css
+        ok(!shareButton.hasAttribute("disabled"), "share button is enabled");
+        // button should be visible
+        is(shareButton.hidden, false, "share button is visible");
+
+        testTab = tab;
+        SocialShare.sharePage();
+      });
+    });
   }
 }
--- a/browser/base/content/test/social/head.js
+++ b/browser/base/content/test/social/head.js
@@ -410,26 +410,29 @@ function loadIntoTab(tab, url, callback)
     tab.linkedBrowser.removeEventListener("load", tabLoad, true);
     executeSoon(function() {callback(tab)});
   }, true);
   tab.linkedBrowser.loadURI(url);
 }
 
 function ensureBrowserTabClosed(tab) {
   let promise = ensureEventFired(gBrowser.tabContainer, "TabClose");
-  gBrowser.removeTab(tab, {skipPermitUnload: true});
+  gBrowser.removeTab(tab);
   return promise;
 }
 
-function ensureFrameLoaded(frame) {
+function ensureFrameLoaded(frame, uri) {
   let deferred = Promise.defer();
-  if (frame.contentDocument && frame.contentDocument.readyState == "complete") {
+  if (frame.contentDocument && frame.contentDocument.readyState == "complete" &&
+      (!uri || frame.contentDocument.location.href == uri)) {
     deferred.resolve();
   } else {
     frame.addEventListener("load", function handler() {
+      if (uri && frame.contentDocument.location.href != uri)
+        return;
       frame.removeEventListener("load", handler, true);
       deferred.resolve()
     }, true);
   }
   return deferred.promise;
 }
 
 // chat test help functions
--- a/browser/base/content/test/social/share.html
+++ b/browser/base/content/test/social/share.html
@@ -1,16 +1,9 @@
 <html>
   <head>
     <meta charset="utf-8">
-    <script>
-      addEventListener("OpenGraphData", function(e) {
-        // frame scripts handle test data
-        // share windows self-close
-        history.back(); // bug 1042991, ensure history is available
-        window.close();
-      })
-    </script>
   </head>
-  <body>
+  <body onload="document.getElementById('testclose').focus()">
     <p>This is a test social share window.</p>
+    <input id="testclose"/>
   </body>
 </html>