Bug 1696878 - [marionette] Call to "waitForWindow()` has to wait until window is ready. r=marionette-reviewers,jgraham

This method is asynchronous but misses the "await" statement.
As such it can cause race conditions in the "WebDriver:NewSession"
command.

Differential Revision: https://phabricator.services.mozilla.com/D107430
This commit is contained in:
Henrik Skupin 2021-03-09 13:04:30 +00:00
Родитель 645675cdd8
Коммит 5bcd2dee6b
1 изменённых файлов: 59 добавлений и 53 удалений

Просмотреть файл

@ -596,62 +596,68 @@ GeckoDriver.prototype.newSession = async function(cmd) {
logger.info("Preemptively starting accessibility service in Chrome");
}
let waitForWindow = function() {
let windowTypes;
switch (this.appId) {
case APP_ID_THUNDERBIRD:
windowTypes = ["mail:3pane"];
break;
default:
// We assume that an app either has GeckoView windows, or
// Firefox/Fennec windows, but not both.
windowTypes = ["navigator:browser", "navigator:geckoview"];
break;
}
let win;
for (let windowType of windowTypes) {
win = Services.wm.getMostRecentWindow(windowType);
if (win) {
break;
}
}
if (!win) {
// if the window isn't even created, just poll wait for it
let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
checkTimer.initWithCallback(
waitForWindow.bind(this),
100,
Ci.nsITimer.TYPE_ONE_SHOT
);
} else if (win.document.readyState != "complete") {
// otherwise, wait for it to be fully loaded before proceeding
let listener = ev => {
// ensure that we proceed, on the top level document load event
// (not an iframe one...)
if (ev.target != win.document) {
return;
}
win.removeEventListener("load", listener);
waitForWindow.call(this);
};
win.addEventListener("load", listener, true);
} else {
if (MarionettePrefs.clickToStart) {
Services.prompt.alert(
win,
"",
"Click to start execution of marionette tests"
);
}
this.addBrowser(win);
this.mainFrame = win;
}
};
registerCommandsActor();
registerEventsActor();
waitForWindow.call(this);
// Wait until the initial application window has been loaded
await new Promise(resolve => {
const waitForWindow = () => {
let windowTypes;
switch (this.appId) {
case APP_ID_THUNDERBIRD:
windowTypes = ["mail:3pane"];
break;
default:
// We assume that an app either has GeckoView windows, or
// Firefox/Fennec windows, but not both.
windowTypes = ["navigator:browser", "navigator:geckoview"];
break;
}
let win;
for (const windowType of windowTypes) {
win = Services.wm.getMostRecentWindow(windowType);
if (win) {
break;
}
}
if (!win) {
// if the window isn't even created, just poll wait for it
let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
checkTimer.initWithCallback(
waitForWindow,
100,
Ci.nsITimer.TYPE_ONE_SHOT
);
} else if (win.document.readyState != "complete") {
// otherwise, wait for it to be fully loaded before proceeding
let listener = ev => {
// ensure that we proceed, on the top level document load event
// (not an iframe one...)
if (ev.target != win.document) {
return;
}
win.removeEventListener("load", listener);
waitForWindow();
};
win.addEventListener("load", listener, true);
} else {
if (MarionettePrefs.clickToStart) {
Services.prompt.alert(
win,
"",
"Click to start execution of marionette tests"
);
}
this.addBrowser(win);
this.mainFrame = win;
resolve();
}
};
waitForWindow();
});
for (let win of this.windows) {
const tabBrowser = browser.getTabBrowser(win);