Bug 1162860 - Ensure closing tabs really don't get closed twice. r=ttaubert, a=lizzard
☠☠ backed out by 10093acd851e ☠ ☠
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Mon, 11 May 2015 14:13:08 +0100
changeset 267509 590fbb8b449eb9cdd44052f396ed8a8fe81e03fe
parent 267508 3cc15b5aa2cd30ab8e0d4ff256488f917b8f8240
child 267510 549b8e7903f5dc03a97740aae4afb1ce63f6cb75
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersttaubert, lizzard
bugs1162860
milestone39.0
Bug 1162860 - Ensure closing tabs really don't get closed twice. r=ttaubert, a=lizzard
browser/base/content/tabbrowser.xml
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_tabs_close_beforeunload.js
browser/base/content/test/general/close_beforeunload.html
browser/base/content/test/general/close_beforeunload_opens_second_tab.html
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -5519,17 +5519,23 @@
         </getter>
         <setter>
           this._lastAccessed = val;
         </setter>
       </property>
 
       <field name="mOverCloseButton">false</field>
       <field name="mCorrespondingMenuitem">null</field>
+
+      <!--
+      While it would make sense to track this in a field, the field will get nuked
+      once the node is gone from the DOM, which causes us to think the tab is not
+      closed, which causes us to make wrong decisions. So we use an expando instead.
       <field name="closing">false</field>
+      -->
 
       <method name="_mouseenter">
         <body><![CDATA[
           if (this.hidden || this.closing)
             return;
 
           let tabContainer = this.parentNode;
           let visibleTabs = tabContainer.tabbrowser.visibleTabs;
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -427,16 +427,20 @@ skip-if = buildapp == 'mulet'
 skip-if = buildapp == 'mulet'
 [browser_tabbar_big_widgets.js]
 skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
                                        # Disabled on OS X because of bug 967917
 [browser_tabfocus.js]
 [browser_tabkeynavigation.js]
 skip-if = e10s
 [browser_tabopen_reflows.js]
+[browser_tabs_close_beforeunload.js]
+support-files =
+  close_beforeunload_opens_second_tab.html
+  close_beforeunload.html
 [browser_tabs_isActive.js]
 skip-if = e10s # Bug 1100664 - test relies on linkedBrowser.docShell
 [browser_tabs_owner.js]
 [browser_testOpenNewRemoteTabsFromNonRemoteBrowsers.js]
 run-if = e10s
 [browser_trackingUI.js]
 support-files =
   trackingPage.html
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_tabs_close_beforeunload.js
@@ -0,0 +1,43 @@
+"use strict";
+
+const FIRST_TAB = getRootDirectory(gTestPath) + "close_beforeunload_opens_second_tab.html";
+const SECOND_TAB = getRootDirectory(gTestPath) + "close_beforeunload.html";
+
+add_task(function*() {
+  let firstTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, FIRST_TAB);
+  let newTabPromise = waitForNewTabEvent(gBrowser);
+  ContentTask.spawn(firstTab.linkedBrowser, "", function*() {
+    content.document.getElementsByTagName("a")[0].click();
+  });
+  let tabOpenEvent = yield newTabPromise;
+  let secondTab = tabOpenEvent.target;
+  yield ContentTask.spawn(secondTab.linkedBrowser, SECOND_TAB, function*(expectedURL) {
+    if (content.window.location.href == expectedURL &&
+        content.document.readyState === "complete") {
+      return Promise.resolve();
+    }
+    return new Promise(function(resolve, reject) {
+      content.window.addEventListener("load", function() {
+        if (content.window.location.href == expectedURL) {
+          resolve();
+        }
+      }, false);
+    });
+  });
+
+  let closeBtn = document.getAnonymousElementByAttribute(secondTab, "anonid", "close-button");
+  let closePromise = BrowserTestUtils.removeTab(secondTab, {dontRemove: true});
+  info("closing second tab (which will self-close in beforeunload)");
+  closeBtn.click();
+  ok(secondTab.closing, "Second tab should be marked as closing synchronously.");
+  yield closePromise;
+  ok(secondTab.closing, "Second tab should still be marked as closing");
+  ok(!secondTab.linkedBrowser, "Second tab's browser should be dead");
+  ok(!firstTab.closing, "First tab should not be closing");
+  ok(firstTab.linkedBrowser, "First tab's browser should be alive");
+  info("closing first tab");
+  yield BrowserTestUtils.removeTab(firstTab);
+
+  ok(firstTab.closing, "First tab should be marked as closing");
+  ok(!firstTab.linkedBrowser, "First tab's browser should be dead");
+});
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/close_beforeunload.html
@@ -0,0 +1,8 @@
+<body>
+  <p>I will close myself if you close me.</p>
+  <script>
+    window.onbeforeunload = function() {
+      window.close();
+    };
+  </script>
+</body>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/close_beforeunload_opens_second_tab.html
@@ -0,0 +1,3 @@
+<body>
+  <a href="#" onclick="window.open('close_beforeunload.html', '_blank')">Open second tab</a>
+</body>