Bug 1381459 - Allow closing of browserless tabs. draft
authorNathaniel Nebel <me@nathanielnebel.com>
Fri, 24 Nov 2017 03:11:18 -0800
changeset 703152 615efcc9967d
parent 703142 e91a098e6e99
child 703653 5ab75881cf90
push id90723
push userbmo:me@nathanielnebel.com
push dateFri, 24 Nov 2017 11:12:05 +0000
bugs1381459
milestone59.0a1
Bug 1381459 - Allow closing of browserless tabs. 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)