Bug 1381459 - Allow closing of browserless tabs. r=whimboo
authorNathaniel Nebel <me@nathanielnebel.com>
Fri, 24 Nov 2017 03:11:18 -0800
changeset 393590 705facc285e5
parent 393589 118d1c52c6b8
child 393591 833a6bc4eb72
push id55969
push userhskupin@mozilla.com
push dateFri, 24 Nov 2017 11:18:32 +0000
treeherderautoland@705facc285e5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswhimboo
bugs1381459
milestone59.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 1381459 - Allow closing of browserless tabs. r=whimboo Closing a tab should always be allowed, even if the current content browser doesn't exist. This can be the case when a tab gets moved to a different process. MozReview-Commit-ID: LaU9MgEyCOx
testing/marionette/driver.js
testing/marionette/harness/marionette_harness/tests/unit/test_window_close_content.py
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -236,16 +236,22 @@ Object.defineProperty(GeckoDriver.protot
 });
 
 Object.defineProperty(GeckoDriver.prototype, "windows", {
   get() {
     return enumeratorIterator(Services.wm.getEnumerator(null));
   },
 });
 
+Object.defineProperty(GeckoDriver.prototype, "windowType", {
+  get() {
+    return this.curBrowser.window.document.documentElement.getAttribute("windowtype");
+  },
+});
+
 Object.defineProperty(GeckoDriver.prototype, "windowHandles", {
   get() {
     let hs = [];
 
     for (let win of this.windows) {
       let tabBrowser = browser.getTabBrowser(win);
 
       // Only return handles for browser windows
@@ -1160,19 +1166,19 @@ GeckoDriver.prototype.getTitle = functio
   assert.window(this.getCurrentWindow());
   this._assertAndDismissModal();
 
   return this.title;
 };
 
 /** Gets the current type of the window. */
 GeckoDriver.prototype.getWindowType = function(cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
-
-  resp.body.value = win.document.documentElement.getAttribute("windowtype");
+  assert.window(this.getCurrentWindow());
+
+  resp.body.value = this.windowType;
 };
 
 /**
  * Gets the page source of the content document.
  *
  * @return {string}
  *     String serialisation of the DOM of the current browsing context's
  *     active document.
@@ -2795,17 +2801,17 @@ GeckoDriver.prototype.deleteCookie = fun
  *     Unique window handles of remaining windows.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
 GeckoDriver.prototype.close = async function() {
-  assert.contentBrowser(this.curBrowser);
+  assert.window(this.getCurrentWindow(Context.Content));
   this._assertAndDismissModal();
 
   let nwins = 0;
 
   for (let win of this.windows) {
     // For browser windows count the tabs. Otherwise take the window itself.
     let tabbrowser = browser.getTabBrowser(win);
     if (tabbrowser && tabbrowser.tabs) {
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_close_content.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_window_close_content.py
@@ -75,8 +75,36 @@ class TestCloseWindow(WindowManagerMixin
 
     def test_close_window_for_last_open_tab(self):
         self.close_all_tabs()
 
         self.assertListEqual([], self.marionette.close())
         self.assertListEqual([self.start_tab], self.marionette.window_handles)
         self.assertListEqual([self.start_window], self.marionette.chrome_window_handles)
         self.assertIsNotNone(self.marionette.session)
+
+    @skip_if_mobile("discardBrowser is only available in Firefox")
+    def test_close_browserless_tab(self):
+        self.close_all_tabs()
+
+        test_page = self.marionette.absolute_url("windowHandles.html")
+        tab = self.open_tab()
+        self.marionette.switch_to_window(tab)
+        self.marionette.navigate(test_page)
+        self.marionette.switch_to_window(self.start_tab)
+
+        with self.marionette.using_context("chrome"):
+            self.marionette.execute_async_script("""
+              Components.utils.import("resource:///modules/RecentWindow.jsm");
+
+              let win = RecentWindow.getMostRecentBrowserWindow();
+              win.addEventListener("TabBrowserDiscarded", ev => {
+                marionetteScriptFinished(true);
+              }, { once: true});
+              win.gBrowser.discardBrowser(win.gBrowser.tabs[1].linkedBrowser);
+            """)
+
+        window_handles = self.marionette.window_handles
+        window_handles.remove(self.start_tab)
+        self.assertEqual(1, len(window_handles))
+        self.marionette.switch_to_window(window_handles[0], focus=False)
+        self.marionette.close()
+        self.assertListEqual([self.start_tab], self.marionette.window_handles)