Bug 1114623 - Implement closeChromeWindow endpoint for marionette.;r=automatedtester
authorChris Manchester <cmanchester@mozilla.com>
Thu, 08 Jan 2015 19:13:30 -0500
changeset 248658 f1b76a42c9105853ee54c8f99b88c08affda6708
parent 248657 f359670a036d96c4339ab88748a2e133823b6251
child 248659 5da7240111cc742b5af6ac22d8eddfda754e24e5
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersautomatedtester
bugs1114623
milestone37.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 1114623 - Implement closeChromeWindow endpoint for marionette.;r=automatedtester
testing/marionette/client/marionette/marionette.py
testing/marionette/client/marionette/tests/unit/test_window_handles.py
testing/marionette/client/marionette/www/newTab.html
testing/marionette/client/marionette/www/windowHandles.html
testing/marionette/marionette-server.js
--- a/testing/marionette/client/marionette/marionette.py
+++ b/testing/marionette/client/marionette/marionette.py
@@ -985,16 +985,27 @@ class Marionette(object):
 
         On B2G this method is a noop and will return immediately.
 
         """
 
         response = self._send_message("close", "ok")
         return response
 
+    def close_chrome_window(self):
+        """Close the currently selected chrome window, ending the session
+        if it's the last window open.
+
+        On B2G this method is a noop and will return immediately.
+
+        """
+
+        response = self._send_message("closeChromeWindow", "ok")
+        return response
+
     def set_context(self, context):
         '''
         Sets the context that Marionette commands are running in.
 
         :param context: Context, may be one of the class properties
          `CONTEXT_CHROME` or `CONTEXT_CONTENT`.
 
         Usage example::
--- a/testing/marionette/client/marionette/tests/unit/test_window_handles.py
+++ b/testing/marionette/client/marionette/tests/unit/test_window_handles.py
@@ -34,44 +34,72 @@ class TestWindowHandles(MarionetteTestCa
         self.marionette.switch_to_window(addons_page)
         self.assertEqual(self.marionette.get_url(), "about:addons")
         self.marionette.close()
 
         self.marionette.switch_to_window(origin_win)
         self.assertEqual(self.marionette.get_url(), "about:blank")
 
     def test_link_opened_tab_window_handles(self):
-        tab_testpage = self.marionette.absolute_url("newTab.html")
+        tab_testpage = self.marionette.absolute_url("windowHandles.html")
         self.marionette.navigate(tab_testpage)
         start_win = self.marionette.current_window_handle
         link = self.marionette.find_element("id", "new-tab")
         link.click()
         self.wait_for_condition(lambda mn: len(mn.window_handles) == 2)
 
         handles = self.marionette.window_handles
         handles.remove(start_win)
         dest_win = handles.pop()
 
         self.marionette.switch_to_window(dest_win)
         self.assertEqual(self.marionette.get_url(), "about:blank")
         self.assertEqual(self.marionette.title, "")
 
         self.marionette.switch_to_window(start_win)
 
-        self.assertIn('newTab.html', self.marionette.get_url())
+        self.assertIn('windowHandles.html', self.marionette.get_url())
         self.assertEqual(self.marionette.title, "Marionette New Tab Link")
 
         self.marionette.close()
         self.marionette.switch_to_window(dest_win)
         self.assertEqual(self.marionette.get_url(), "about:blank")
 
+    def test_chrome_windows(self):
+        start_tab = self.marionette.current_window_handle
+        opener_page = self.marionette.absolute_url("windowHandles.html")
+
+        self.marionette.navigate(opener_page)
+        self.marionette.find_element("id", "new-window").click()
+
+        self.assertEqual(len(self.marionette.window_handles), 2)
+        self.assertEqual(len(self.marionette.chrome_window_handles), 2)
+        windows = self.marionette.window_handles
+        windows.remove(start_tab)
+        dest_tab = windows.pop()
+        self.marionette.switch_to_window(dest_tab)
+
+        self.marionette.navigate(opener_page)
+        new_tab_link = self.marionette.find_element("id", "new-tab")
+
+        for i in range(3):
+            new_tab_link.click()
+            self.marionette.switch_to_window(dest_tab)
+            self.wait_for_condition(lambda mn: len(mn.window_handles) == i + 3)
+            self.assertEqual(len(self.marionette.chrome_window_handles), 2)
+
+        self.marionette.close_chrome_window()
+        self.assertEqual(len(self.marionette.chrome_window_handles), 1)
+        self.assertEqual(len(self.marionette.window_handles), 1)
+        self.marionette.switch_to_window(start_tab)
+
     def test_tab_and_window_handles(self):
         start_tab = self.marionette.current_window_handle
         start_chrome_window = self.marionette.chrome_window_handle
-        tab_open_page = self.marionette.absolute_url("newTab.html")
+        tab_open_page = self.marionette.absolute_url("windowHandles.html")
         window_open_page = self.marionette.absolute_url("test_windows.html")
 
         # Open a new tab and switch to it.
         self.marionette.navigate(tab_open_page)
         link = self.marionette.find_element("id", "new-tab")
         link.click()
 
         self.wait_for_condition(lambda mn: len(mn.window_handles) == 2)
rename from testing/marionette/client/marionette/www/newTab.html
rename to testing/marionette/client/marionette/www/windowHandles.html
--- a/testing/marionette/client/marionette/www/newTab.html
+++ b/testing/marionette/client/marionette/www/windowHandles.html
@@ -3,11 +3,12 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <!DOCTYPE html>
 <html>
 <head>
 <title>Marionette New Tab Link</title>
 </head>
 <body>
-  <a href="about:blank" id="new-tab" target="_blank" class="linkClass">Click me!</a>
+  <a href="about:blank" id="new-tab" target="_blank">Click me!</a>
+  <a href="about:blank" id="new-window" onClick='javascript:window.open("about:blank", null, "location=1,toolbar=1");'>Click me!</a>
 </body>
 </html>
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -2407,16 +2407,63 @@ MarionetteServerConnection.prototype = {
       catch (e) {
         this.sendError("Could not close window: " + e.message, 13, e.stack,
                        command_id);
       }
     }
   },
 
   /**
+   * Close the currently selected chrome window, ending the session if it's the last
+   * window currently open.
+   *
+   * On B2G this method is a noop and will return immediately.
+   */
+  closeChromeWindow: function MDA_closeChromeWindow() {
+    let command_id = this.command_id = this.getCommandId();
+    if (appName == "B2G") {
+      // We can't close windows so just return
+      this.sendOk(command_id);
+    }
+    else {
+      // Get the total number of windows
+      let numOpenWindows = 0;
+      let winEnum = this.getWinEnumerator();
+      while (winEnum.hasMoreElements()) {
+        numOpenWindows += 1;
+        winEnum.getNext();
+      }
+
+      // if there is only 1 window left, delete the session
+      if (numOpenWindows === 1) {
+        try {
+          this.sessionTearDown();
+        }
+        catch (e) {
+          this.sendError("Could not clear session", 500,
+                         e.name + ": " + e.message, command_id);
+          return;
+        }
+        this.sendOk(command_id);
+        return;
+      }
+
+      try {
+        this.messageManager.removeDelayedFrameScript(FRAME_SCRIPT);
+        this.getCurrentWindow().close();
+        this.sendOk(command_id);
+      }
+      catch (e) {
+        this.sendError("Could not close window: " + e.message, 13, e.stack,
+                       command_id);
+      }
+    }
+  },
+
+  /**
    * Deletes the session.
    *
    * If it is a desktop environment, it will close all listeners
    *
    * If it is a B2G environment, it will make the main content listener sleep, and close
    * all other listeners. The main content listener persists after disconnect (it's the homescreen),
    * and can safely be reused.
    */
@@ -3023,16 +3070,17 @@ MarionetteServerConnection.prototype.req
   "switchToWindow": MarionetteServerConnection.prototype.switchToWindow,
   "deleteSession": MarionetteServerConnection.prototype.deleteSession,
   "emulatorCmdResult": MarionetteServerConnection.prototype.emulatorCmdResult,
   "importScript": MarionetteServerConnection.prototype.importScript,
   "clearImportedScripts": MarionetteServerConnection.prototype.clearImportedScripts,
   "getAppCacheStatus": MarionetteServerConnection.prototype.getAppCacheStatus,
   "close": MarionetteServerConnection.prototype.close,
   "closeWindow": MarionetteServerConnection.prototype.close,  // deprecated
+  "closeChromeWindow": MarionetteServerConnection.prototype.closeChromeWindow,
   "setTestName": MarionetteServerConnection.prototype.setTestName,
   "takeScreenshot": MarionetteServerConnection.prototype.takeScreenshot,
   "screenShot": MarionetteServerConnection.prototype.takeScreenshot,  // deprecated
   "screenshot": MarionetteServerConnection.prototype.takeScreenshot,  // Selenium 2 compat
   "addCookie": MarionetteServerConnection.prototype.addCookie,
   "getCookies": MarionetteServerConnection.prototype.getCookies,
   "getAllCookies": MarionetteServerConnection.prototype.getCookies,  // deprecated
   "deleteAllCookies": MarionetteServerConnection.prototype.deleteAllCookies,