Bug 1391691 - Make WebDriver:MaximizeWindow idempotent. r=automatedtester
MozReview-Commit-ID: EJ0VQOTWysg
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -3047,17 +3047,19 @@ GeckoDriver.prototype.minimizeWindow = a
});
}
return this.curBrowser.rect;
};
/**
* Synchronously maximizes the user agent window as if the user pressed
- * the maximize button, or restores it if it is already maximized.
+ * the maximize button.
+ *
+ * No action is taken if the window is already maximized.
*
* Not supported on Fennec.
*
* @return {Object.<string, number>}
* Window rect.
*
* @throws {UnsupportedOperationError}
* Not available for current application.
@@ -3087,58 +3089,54 @@ GeckoDriver.prototype.maximizeWindow = a
curSize.outerHeight != origSize.outerHeight) {
resolve();
} else {
reject();
}
});
}
- let modeChangeEv;
- await new TimedPromise(resolve => {
- modeChangeEv = resolve;
- win.addEventListener("sizemodechange", modeChangeEv, {once: true});
-
- if (win.windowState == win.STATE_MAXIMIZED) {
- win.restore();
- } else {
+ let state = WindowState.from(win.windowState);
+ if (state != WindowState.Maximized) {
+ await new TimedPromise(resolve => {
+ win.addEventListener("sizemodechange", resolve, {once: true});
win.maximize();
- }
- }, {throws: null});
- win.removeEventListener("sizemodechange", modeChangeEv);
-
- // Transitioning into a window state is asynchronous on Linux, and we
- // cannot rely on sizemodechange to accurately tell us when the
- // transition has completed.
- //
- // To counter for this we wait for the window size to change, which
- // it usually will. On platforms where the transition is synchronous,
- // the wait will have the cost of one iteration because the size will
- // have changed as part of the transition. Where the platform
- // is asynchronous, the cost may be greater as we have to poll
- // continuously until we see a change, but it ensures conformity in
- // behaviour.
- //
- // Certain window managers, however, do not have a concept of maximised
- // windows and here sizemodechange may never fire. Indeed, if the
- // window covers the maximum available screen real estate, the window
- // size may also not change. In this circumstance, which admittedly
- // is a somewhat bizarre edge case, we assume that the timeout of
- // waiting for sizemodechange to fire is sufficient to give the window
- // enough time to transition itself into whatever form or shape the
- // WM is programmed to give it.
- await windowSizeChange();
+ }, {throws: null});
+
+ // Transitioning into a window state is asynchronous on Linux,
+ // and we cannot rely on sizemodechange to accurately tell us when
+ // the transition has completed.
+ //
+ // To counter for this we wait for the window size to change, which
+ // it usually will. On platforms where the transition is synchronous,
+ // the wait will have the cost of one iteration because the size
+ // will have changed as part of the transition. Where the platform is
+ // asynchronous, the cost may be greater as we have to poll
+ // continuously until we see a change, but it ensures conformity in
+ // behaviour.
+ //
+ // Certain window managers, however, do not have a concept of
+ // maximised windows and here sizemodechange may never fire. Indeed,
+ // if the window covers the maximum available screen real estate,
+ // the window size may also not change. In this circumstance,
+ // which admittedly is a somewhat bizarre edge case, we assume that
+ // the timeout of waiting for sizemodechange to fire is sufficient
+ // to give the window enough time to transition itself into whatever
+ // form or shape the WM is programmed to give it.
+ await windowSizeChange();
+ }
return this.curBrowser.rect;
};
/**
* Synchronously sets the user agent window to full screen as if the user
- * had done "View > Enter Full Screen", or restores it if it is already
- * in full screen.
+ * had done "View > Enter Full Screen".
+ *
+ * No action is taken if the window is already in full screen mode.
*
* Not supported on Fennec.
*
* @return {Map.<string, number>}
* Window rect.
*
* @throws {UnsupportedOperationError}
* Not available for current application.
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_maximize.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_window_maximize.py
@@ -40,20 +40,16 @@ class TestWindowMaximize(MarionetteTestC
"current width {current} should be greater than or equal to max width {max}"
.format(delta=delta, current=actual["width"], max=self.max["width"] - delta))
self.assertGreaterEqual(
actual["height"], self.max["height"] - delta,
msg="Window height is not within {delta} px of availHeight: "
"current height {current} should be greater than or equal to max height {max}"
.format(delta=delta, current=actual["height"], max=self.max["height"] - delta))
- 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)
@@ -61,24 +57,26 @@ class TestWindowMaximize(MarionetteTestC
def test_maximize(self):
maximize_resp = self.marionette.maximize_window()
self.assert_window_rect(maximize_resp)
window_rect_resp = self.marionette.window_rect
self.assertEqual(maximize_resp, window_rect_resp)
self.assert_window_maximized(maximize_resp)
- def test_maximize_twice_restores(self):
+ def test_maximize_twice_is_idempotent(self):
maximized = self.marionette.maximize_window()
self.assert_window_maximized(maximized)
- restored = self.marionette.maximize_window()
- self.assert_window_restored(restored)
+ still_maximized = self.marionette.maximize_window()
+ self.assert_window_maximized(still_maximized)
def test_stress(self):
for i in range(1, 25):
expect_maximized = bool(i % 2)
- rect = self.marionette.maximize_window()
if expect_maximized:
+ rect = self.marionette.maximize_window()
self.assert_window_maximized(rect)
else:
- self.assert_window_restored(rect)
+ rect = self.marionette.set_window_rect(width=800, height=600)
+ self.assertEqual(800, rect["width"])
+ self.assertEqual(600, rect["height"])
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -626288,17 +626288,17 @@
"94b6f474bb4417cf2c06cb5fc6042c01bde98aa2",
"support"
],
"webdriver/tests/conftest.py": [
"ab95734024a8e152ed84128eb804344740be91d4",
"support"
],
"webdriver/tests/contexts/maximize_window.py": [
- "de49d5d8cc03e863dfe7e29ca8c10678d9b45e83",
+ "905e748f0ab795a66ab41d70aebb22dbc6adbe7e",
"wdspec"
],
"webdriver/tests/contexts/resizing_and_positioning.py": [
"479379109115668183643e8a050396219332887d",
"wdspec"
],
"webdriver/tests/cookies/cookies.py": [
"e31177e638269864031e44808945fa1e7c46031c",
--- a/testing/web-platform/tests/webdriver/tests/contexts/maximize_window.py
+++ b/testing/web-platform/tests/webdriver/tests/contexts/maximize_window.py
@@ -1,67 +1,87 @@
from tests.support.inline import inline
from tests.support.asserts import assert_error, assert_success
+
alert_doc = inline("<script>window.alert()</script>")
+
+def maximize(session):
+ return session.transport.send("POST", "session/%s/window/maximize" % session.session_id)
+
+
# 10.7.3 Maximize Window
-def test_maximize_no_browsing_context(session, create_window):
- # Step 1
+
+
+def test_no_browsing_context(session, create_window):
+ # step 1
session.window_handle = create_window()
session.close()
- result = session.transport.send("POST", "session/%s/window/maximize" % session.session_id)
- assert_error(result, "no such window")
+ response = maximize(session)
+ assert_error(response, "no such window")
def test_handle_user_prompt(session):
- # Step 2
+ # step 2
session.url = alert_doc
- result = session.transport.send("POST", "session/%s/window/maximize" % session.session_id)
- assert_error(result, "unexpected alert open")
+ response = maximize(session)
+ assert_error(response, "unexpected alert open")
def test_maximize(session):
before_size = session.window.size
assert session.window.state == "normal"
# step 4
- result = session.transport.send("POST", "session/%s/window/maximize" % session.session_id)
- assert_success(result)
+ response = maximize(session)
+ assert_success(response)
assert before_size != session.window.size
assert session.window.state == "maximized"
def test_payload(session):
before_size = session.window.size
assert session.window.state == "normal"
- result = session.transport.send("POST", "session/%s/window/maximize" % session.session_id)
+ response = maximize(session)
# step 5
- assert result.status == 200
- assert isinstance(result.body["value"], dict)
+ assert response.status == 200
+ assert isinstance(response.body["value"], dict)
- rect = result.body["value"]
- assert "width" in rect
- assert "height" in rect
- assert "x" in rect
- assert "y" in rect
- assert "state" in rect
- assert isinstance(rect["width"], (int, float))
- assert isinstance(rect["height"], (int, float))
- assert isinstance(rect["x"], (int, float))
- assert isinstance(rect["y"], (int, float))
- assert isinstance(rect["state"], basestring)
+ value = response.body["value"]
+ assert "width" in value
+ assert "height" in value
+ assert "x" in value
+ assert "y" in value
+ assert "state" in value
+ assert isinstance(value["width"], (int, float))
+ assert isinstance(value["height"], (int, float))
+ assert isinstance(value["x"], (int, float))
+ assert isinstance(value["y"], (int, float))
+ assert isinstance(value["state"], basestring)
assert before_size != session.window.size
assert session.window.state == "maximized"
+def test_maximize_twice_is_idempotent(session):
+ assert session.window.state == "normal"
+
+ first_response = maximize(session)
+ assert_success(first_response)
+ assert session.window.state == "maximized"
+
+ second_response = maximize(session)
+ assert_success(second_response)
+ assert session.window.state == "maximized"
+
+
def test_maximize_when_resized_to_max_size(session):
# Determine the largest available window size by first maximising
# the window and getting the window rect dimensions.
#
# Then resize the window to the maximum available size.
session.end()
assert session.window.state == "normal"
available = session.window.maximize()
--- a/testing/web-platform/tests/webdriver/tests/set_window_rect.py
+++ b/testing/web-platform/tests/webdriver/tests/set_window_rect.py
@@ -82,37 +82,89 @@ def test_handle_prompt_missing_value(ses
{"height": None, "width": None, "x": {}, "y": {}},
])
def test_invalid_params(session, data):
# step 8-9
response = set_window_rect(session, data)
assert_error(response, "invalid argument")
-def test_fullscreened(session):
- # step 10
+def test_fully_exit_fullscreen(session):
+ """
+ 10. Fully exit fullscreen.
+
+ [...]
+
+ To fully exit fullscreen a document document, run these steps:
+
+ 1. If document's fullscreen element is null, terminate these steps.
+
+ 2. Unfullscreen elements whose fullscreen flag is set, within
+ document's top layer, except for document's fullscreen element.
+
+ 3. Exit fullscreen document.
+
+ """
+
session.window.fullscreen()
- assert session.window.state == "fullscreen"
+ assert session.execute_script("return window.fullScreen") is True
+
response = set_window_rect(session, {"width": 400, "height": 400})
- assert_success(response)
- assert rect["width"] == 400
- assert rect["height"] == 400
- assert rect["state"] == "normal"
+ value = assert_success(response)
+ assert value["width"] == 400
+ assert value["height"] == 400
+ assert value["state"] == "normal"
-def test_minimized(session):
- # step 11
+def test_restore_window_from_minimized(session):
+ """
+ 11. Restore the window.
+
+ [...]
+
+ To restore the window, given an operating system level window with an
+ associated top-level browsing context, run implementation-specific
+ steps to restore or unhide the window to the visible screen. Do not
+ return from this operation until the visibility state of the top-level
+ browsing context's active document has reached the visible state,
+ or until the operation times out.
+ """
+
session.window.minimize()
- assert session.window.state == "minimized"
+ assert session.execute_script("return document.hidden") is True
+
+ response = set_window_rect(session, {"width": 450, "height": 450})
+ value = assert_success(response)
+ assert value["width"] == 450
+ assert value["height"] == 450
+ assert value["state"] == "normal"
- response = set_window_rect(session, {"width": 400, "height": 400})
- rect = assert_success(response)
- assert rect["width"] == 400
- assert rect["height"] == 400
- assert rect["state"] == "normal"
+
+def test_restore_window_from_maximized(session):
+ """
+ 11. Restore the window.
+
+ [...]
+
+ To restore the window, given an operating system level window with an
+ associated top-level browsing context, run implementation-specific
+ steps to restore or unhide the window to the visible screen. Do not
+ return from this operation until the visibility state of the top-level
+ browsing context’s active document has reached the visible state,
+ or until the operation times out.
+ """
+
+ session.window.maximize()
+ assert session.window.state == "maximized"
+
+ response = set_window_rect(session, {"width": 500, "height": 500})
+ value = assert_success(response)
+ assert value["width"] == 500
+ assert value["height"] == 500
+ assert value["state"] == "normal"
def test_height_width(session):
original = session.window.rect
max = session.execute_script("""
return {
width: window.screen.availWidth,
height: window.screen.availHeight,