зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
c8c1a3c5f2
Коммит
0ae2105fde
|
@ -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]
|
||||
|
|
Загрузка…
Ссылка в новой задаче