Bug 1739369 - [marionette] Move wait for initial page load logic into shared navigate module. r=webdriver-reviewers,jdescottes

Differential Revision: https://phabricator.services.mozilla.com/D134541
This commit is contained in:
Henrik Skupin 2022-01-07 21:28:33 +00:00
Родитель c8c1a3c5f2
Коммит 0ae2105fde
6 изменённых файлов: 191 добавлений и 48 удалений

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

@ -15,6 +15,7 @@ remote.jar:
# shared modules (all protocols)
content/shared/Format.jsm (shared/Format.jsm)
content/shared/Log.jsm (shared/Log.jsm)
content/shared/Navigate.jsm (shared/Navigate.jsm)
content/shared/RecommendedPreferences.jsm (shared/RecommendedPreferences.jsm)
content/shared/Stack.jsm (shared/Stack.jsm)
content/shared/Sync.jsm (shared/Sync.jsm)

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

@ -54,6 +54,8 @@ XPCOMUtils.defineLazyModuleGetters(this, {
"chrome://remote/content/shared/webdriver/Capabilities.jsm",
unregisterCommandsActor:
"chrome://remote/content/marionette/actors/MarionetteCommandsParent.jsm",
waitForInitialNavigationCompleted:
"chrome://remote/content/shared/Navigate.jsm",
waitForLoadEvent: "chrome://remote/content/marionette/sync.js",
waitForObserverTopic: "chrome://remote/content/marionette/sync.js",
WebDriverSession: "chrome://remote/content/shared/webdriver/Session.jsm",
@ -462,46 +464,7 @@ GeckoDriver.prototype.newSession = async function(cmd) {
const browsingContext = this.curBrowser.contentBrowser.browsingContext;
this.currentSession.contentBrowsingContext = browsingContext;
let resolveNavigation;
// Prepare a promise that will resolve upon a navigation.
const onProgressListenerNavigation = new Promise(
resolve => (resolveNavigation = resolve)
);
// Create a basic webprogress listener which will check if the browsing
// context is ready for the new session on every state change.
const navigationListener = {
onStateChange: (progress, request, flag, status) => {
const isStop = flag & Ci.nsIWebProgressListener.STATE_STOP;
if (isStop) {
resolveNavigation();
}
},
QueryInterface: ChromeUtils.generateQI([
"nsIWebProgressListener",
"nsISupportsWeakReference",
]),
};
// Monitor the webprogress listener before checking isLoadingDocument to
// avoid race conditions.
browsingContext.webProgress.addProgressListener(
navigationListener,
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT
);
if (browsingContext.webProgress.isLoadingDocument) {
await onProgressListenerNavigation;
}
browsingContext.webProgress.removeProgressListener(
navigationListener,
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT
);
await waitForInitialNavigationCompleted(browsingContext);
this.curBrowser.contentBrowser.focus();
}

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

@ -11,17 +11,20 @@ const { navigate } = ChromeUtils.import(
"chrome://remote/content/marionette/navigate.js"
);
const topContext = {
const mockTopContext = {
get children() {
return [mockNestedContext];
},
id: 7,
get top() {
return this;
},
};
const nestedContext = {
const mockNestedContext = {
id: 8,
parent: topContext,
top: topContext,
parent: mockTopContext,
top: mockTopContext,
};
add_test(function test_isLoadEventExpectedForCurrent() {
@ -66,11 +69,21 @@ add_test(function test_isLoadEventExpectedForTarget() {
const data = [
{ cur: "http://a/", target: "", expected: true },
{ cur: "http://a/", target: "_blank", expected: false },
{ cur: "http://a/", target: "_parent", bc: topContext, expected: true },
{ cur: "http://a/", target: "_parent", bc: nestedContext, expected: false },
{ cur: "http://a/", target: "_parent", bc: mockTopContext, expected: true },
{
cur: "http://a/",
target: "_parent",
bc: mockNestedContext,
expected: false,
},
{ cur: "http://a/", target: "_self", expected: true },
{ cur: "http://a/", target: "_top", bc: topContext, expected: true },
{ cur: "http://a/", target: "_top", bc: nestedContext, expected: false },
{ cur: "http://a/", target: "_top", bc: mockTopContext, expected: true },
{
cur: "http://a/",
target: "_top",
bc: mockNestedContext,
expected: false,
},
];
for (const entry of data) {

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

@ -0,0 +1,78 @@
/* 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/. */
"use strict";
const EXPORTED_SYMBOLS = ["waitForInitialNavigationCompleted"];
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
Log: "chrome://remote/content/shared/Log.jsm",
});
XPCOMUtils.defineLazyGetter(this, "logger", () =>
Log.get(Log.TYPES.REMOTE_AGENT)
);
// Used to keep weak references of webProgressListeners alive.
const webProgressListeners = new Set();
/**
* Wait until the initial load of the given browsing context is done.
*
* @param {BrowsingContext} browsingContext
* The browsing context to check.
*/
function waitForInitialNavigationCompleted(browsingContext) {
let listener;
return new Promise(resolve => {
listener = new ProgressListener(resolve);
// Keep a reference to the weak listener so it's not getting gc'ed.
webProgressListeners.add(listener);
// Monitor the webprogress listener before checking isLoadingDocument to
// avoid race conditions.
browsingContext.webProgress.addProgressListener(
listener,
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT
);
if (!browsingContext.webProgress.isLoadingDocument) {
logger.trace("Initial navigation already completed");
resolve();
}
}).finally(() => {
browsingContext.webProgress.removeProgressListener(
listener,
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT
);
webProgressListeners.delete(listener);
});
}
class ProgressListener {
constructor(resolve) {
this.resolve = resolve;
}
onStateChange(progress, request, flag, status) {
const isStop = flag & Ci.nsIWebProgressListener.STATE_STOP;
if (isStop) {
this.resolve();
}
}
get QueryInterface() {
return ChromeUtils.generateQI([
"nsIWebProgressListener",
"nsISupportsWeakReference",
]);
}
}

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

@ -0,0 +1,87 @@
/* 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/. */
const { waitForInitialNavigationCompleted } = ChromeUtils.import(
"chrome://remote/content/shared/Navigate.jsm"
);
const mockWebProgress = {
onStateChangeCalled: false,
isLoadingDocument: false,
addProgressListener(listener) {
if (!this.isLoadingDocument) {
return;
}
listener.onStateChange(
null,
null,
Ci.nsIWebProgressListener.STATE_STOP,
null
);
this.onStateChangeCalled = true;
},
removeProgressListener(listener) {},
};
const mockTopContext = {
get children() {
return [mockNestedContext];
},
id: 7,
get top() {
return this;
},
webProgress: mockWebProgress,
};
const mockNestedContext = {
id: 8,
parent: mockTopContext,
top: mockTopContext,
webProgress: mockWebProgress,
};
add_test(async function test_waitForInitialNavigationCompleted_isNotLoading() {
const browsingContext = Object.assign({}, mockTopContext);
await waitForInitialNavigationCompleted(browsingContext);
ok(
!browsingContext.webProgress.onStateChangeCalled,
"WebProgress' onStateChange hasn't been fired"
);
run_next_test();
});
add_test(async function test_waitForInitialNavigationCompleted_topIsLoading() {
const browsingContext = Object.assign({}, mockTopContext);
browsingContext.webProgress.isLoadingDocument = true;
await waitForInitialNavigationCompleted(browsingContext);
ok(
browsingContext.webProgress.onStateChangeCalled,
"WebProgress' onStateChange has been fired"
);
run_next_test();
});
add_test(
async function test_waitForInitialNavigationCompleted_nestedIsLoading() {
const browsingContext = Object.assign({}, mockNestedContext);
const topContext = browsingContext.top;
browsingContext.webProgress.isLoadingDocument = true;
await waitForInitialNavigationCompleted(topContext);
ok(
browsingContext.webProgress.onStateChangeCalled,
"WebProgress' onStateChange has been fired on the nested browsing context"
);
ok(
topContext.webProgress.onStateChangeCalled,
"WebProgress' onStateChange has been fired on the top browsing context"
);
run_next_test();
}
);

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

@ -3,6 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[test_Format.js]
[test_Navigate.js]
[test_RecommendedPreferences.js]
[test_Stack.js]
[test_Sync.js]