Bug 1357878 - Maximize window synchronously and restore when maximized; r?maja_zf draft
authorAndreas Tolfsen <ato@mozilla.com>
Thu, 20 Apr 2017 17:04:58 +0100
changeset 569445 efe58458d9c782264a07a2e21183d090cc6b6500
parent 569444 9d1226683c8bb3d3fd6e84ea1b2fa6dfb16ac246
child 626221 d6a6c0f92046971bc90190f1ed6c10988c9d3267
push id56187
push userbmo:ato@mozilla.com
push dateThu, 27 Apr 2017 14:41:11 +0000
reviewersmaja_zf
bugs1357878
milestone55.0a1
Bug 1357878 - Maximize window synchronously and restore when maximized; r?maja_zf When refactoring the tests for the Set Window Rect command, it was discovered that the Maximize Window command was not synchronous. This patch makes GeckoDriver#maximizeWindow synchronous by waiting for the DOM resize event to fire before returning the window rect to the user. It also aligns the command with the WebDriver standard by making it restore the window to its original size when calling the command a second time. MozReview-Commit-ID: Ft3tn2A4m7u
testing/marionette/driver.js
testing/marionette/harness/marionette_harness/tests/unit/test_window_maximize.py
testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -2853,32 +2853,52 @@ GeckoDriver.prototype.setScreenOrientati
   }
 
   if (!win.screen.mozLockOrientation(mozOr)) {
     throw new WebDriverError(`Unable to set screen orientation: ${or}`);
   }
 };
 
 /**
- * Maximizes the user agent window as if the user pressed the maximise
- * button.
+ * Synchronously maximizes the user agent window as if the user pressed
+ * the maximize button, or restores it if it is already maximized.
+ *
+ * Not supported on Fennec.
+ *
+ * @return {Map.<string, number>}
+ *     Window rect.
  *
  * @throws {UnsupportedOperationError}
  *     Not available for current application.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
-GeckoDriver.prototype.maximizeWindow = function (cmd, resp) {
+GeckoDriver.prototype.maximizeWindow = function* (cmd, resp) {
   assert.firefox();
   const win = assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
-  win.maximize()
+  yield new Promise(resolve => {
+    win.addEventListener("resize", resolve, {once: true});
+
+    if (win.windowState == win.STATE_MAXIMIZED) {
+      win.restore();
+    } else {
+      win.maximize();
+    }
+  });
+
+  return {
+    x: win.screenX,
+    y: win.screenY,
+    width: win.outerWidth,
+    height: win.outerHeight,
+  };
 };
 
 /**
  * Dismisses a currently displayed tab modal, or returns no such alert if
  * no modal is displayed.
  */
 GeckoDriver.prototype.dismissDialog = function (cmd, resp) {
   assert.window(this.getCurrentWindow());
new file mode 100644
--- /dev/null
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_window_maximize.py
@@ -0,0 +1,90 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_driver.errors import InvalidArgumentException
+
+from marionette_harness import MarionetteTestCase
+
+
+class TestWindowMaximize(MarionetteTestCase):
+
+    def setUp(self):
+        MarionetteTestCase.setUp(self)
+        self.max = self.marionette.execute_script("""
+            return {
+              width: window.screen.availWidth,
+              height: window.screen.availHeight,
+            }""", sandbox=None)
+
+        # ensure window is not maximized
+        self.marionette.set_window_size(
+            self.max["width"] - 100, self.max["height"] - 100)
+        actual = self.marionette.window_size
+        self.assertNotEqual(actual["width"], self.max["width"])
+        self.assertNotEqual(actual["height"], self.max["height"])
+
+        self.original_size = actual
+
+    def tearDown(self):
+        self.marionette.set_window_size(
+            self.original_size["width"], self.original_size["height"])
+
+    def assert_window_maximized(self, actual, delta=None):
+        if self.marionette.session_capabilities["platformName"] == "windows_nt":
+            delta = 16
+        else:
+            delta = 8
+
+        self.assertAlmostEqual(
+            actual["width"], self.max["width"],
+            delta=delta,
+            msg="Window width is not within {} px of availWidth: "
+                "current width {} and max width {}"
+                .format(delta, actual["width"], self.max["width"]))
+        self.assertAlmostEqual(
+            actual["height"], self.max["height"],
+            delta=delta,
+            msg="Window height is not within {} px of availHeight, "
+                "current height {} and max height {}"
+                .format(delta, actual["height"], self.max["height"]))
+
+    def assert_window_restored(self, actual):
+        self.assertEqual(self.original_size["width"], actual["width"])
+        self.assertEqual(self.original_size["height"], actual["height"])
+
+    def assert_window_rect(self, rect):
+        self.assertIn("width", rect)
+        self.assertIn("height", rect)
+        self.assertIn("x", rect)
+        self.assertIn("y", rect)
+        self.assertIsInstance(rect["width"], int)
+        self.assertIsInstance(rect["height"], int)
+        self.assertIsInstance(rect["x"], int)
+        self.assertIsInstance(rect["y"], int)
+
+    def test_maximize(self):
+        rect = self.marionette.maximize_window()
+        self.assert_window_rect(rect)
+        size = self.marionette.window_size
+        self.assertEqual(size, rect)
+        self.assert_window_maximized(size)
+
+    def test_maximize_twice_restores(self):
+        maximized = self.marionette.maximize_window()
+        self.assert_window_maximized(maximized)
+
+        restored = self.marionette.maximize_window()
+        self.assert_window_restored(restored)
+
+    def test_stress(self):
+        maximized = False
+
+        for i in range(1, 25):
+            expect_maximized = bool(i % 2)
+
+            rect = self.marionette.maximize_window()
+            if expect_maximized:
+                self.assert_window_maximized(rect)
+            else:
+                self.assert_window_restored(rect)
--- a/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
+++ b/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
@@ -69,16 +69,18 @@ skip-if = appname == 'fennec'
 [test_window_handles_chrome.py]
 skip-if = appname == 'fennec'
 [test_window_handles_content.py]
 [test_window_close_chrome.py]
 skip-if = appname == 'fennec'
 [test_window_close_content.py]
 [test_window_rect.py]
 skip-if = appname == 'fennec'
+[test_window_maximize.py]
+skip-if = appname == 'fennec'
 [test_window_status_content.py]
 [test_window_status_chrome.py]
 
 [test_screenshot.py]
 [test_cookies.py]
 [test_title.py]
 [test_title_chrome.py]
 skip-if = appname == 'fennec'