Bug 1381876 - Ensure Maximize Window is synchronous. r?automatedtester
Because the sizemodechange event is not synchronous on all platforms,
we additionally need to await the window's dimensions to change.
However, if the window manager does not have a notion of a maximised
state, this operation too could time out. However, it is believed
that the additional wait will allow for the window to transition to the
required state in this scenario.
MozReview-Commit-ID: KeHJMKSJfjQ
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -14,17 +14,20 @@ Cu.import("resource://gre/modules/Log.js
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("chrome://marionette/content/accessibility.js");
Cu.import("chrome://marionette/content/addon.js");
Cu.import("chrome://marionette/content/assert.js");
Cu.import("chrome://marionette/content/atom.js");
-Cu.import("chrome://marionette/content/browser.js");
+const {
+ browser,
+ WindowState,
+} = Cu.import("chrome://marionette/content/browser.js", {});
Cu.import("chrome://marionette/content/capture.js");
Cu.import("chrome://marionette/content/cert.js");
Cu.import("chrome://marionette/content/cookie.js");
Cu.import("chrome://marionette/content/element.js");
const {
ElementNotInteractableError,
error,
InsecureCertificateError,
@@ -43,17 +46,17 @@ Cu.import("chrome://marionette/content/e
Cu.import("chrome://marionette/content/event.js");
Cu.import("chrome://marionette/content/interaction.js");
Cu.import("chrome://marionette/content/l10n.js");
Cu.import("chrome://marionette/content/legacyaction.js");
Cu.import("chrome://marionette/content/modal.js");
Cu.import("chrome://marionette/content/proxy.js");
Cu.import("chrome://marionette/content/reftest.js");
Cu.import("chrome://marionette/content/session.js");
-Cu.import("chrome://marionette/content/wait.js");
+const {wait, TimedPromise} = Cu.import("chrome://marionette/content/wait.js", {});
Cu.importGlobalProperties(["URL"]);
this.EXPORTED_SYMBOLS = ["GeckoDriver", "Context"];
var FRAME_SCRIPT = "chrome://marionette/content/listener.js";
const CLICK_TO_START_PREF = "marionette.debugging.clicktostart";
@@ -2925,40 +2928,86 @@ GeckoDriver.prototype.minimizeWindow = f
};
/**
* 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>}
+ * @return {Object.<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 = async function(cmd, resp) {
assert.firefox();
const win = assert.window(this.getCurrentWindow());
assert.noUserPrompt(this.dialog);
- yield new Promise(resolve => {
- win.addEventListener("resize", resolve, {once: true});
+ const origSize = {
+ outerWidth: win.outerWidth,
+ outerHeight: win.outerHeight,
+ };
+
+ // Wait for the window size to change.
+ async function windowSizeChange(from) {
+ return wait.until((resolve, reject) => {
+ let curSize = {
+ outerWidth: win.outerWidth,
+ outerHeight: win.outerHeight,
+ };
+ if (curSize.outerWidth != origSize.outerWidth ||
+ 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 {
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();
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.