Bug 937659 - Implement page load strategy. r=ato

By using the page load strategy each navigation request has to return
when the page load has reached the expected document ready state, or
immediately if a strategy of "none" is set.

This also removes the page load checks when switching frames because
this is not part of the webdriver spec.

MozReview-Commit-ID: 3KbsDvzEG6c

--HG--
extra : rebase_source : 68170235424e181c083febd44fca6bb0c5dfec63
This commit is contained in:
Henrik Skupin 2017-04-19 13:22:13 +02:00
parent cfdbf9979c
commit 2a458fb433
3 changed files with 74 additions and 29 deletions

View File

@ -30,6 +30,7 @@ class BaseNavigationTestCase(WindowManagerMixin, MarionetteTestCase):
self.test_page_insecure = self.fixtures.where_is("test.html", on="https")
self.test_page_not_remote = "about:robots"
self.test_page_remote = self.marionette.absolute_url("test.html")
self.test_page_slow_resource = self.marionette.absolute_url("slow_resource.html")
if self.marionette.session_capabilities["platformName"] == "darwin":
self.mod_key = Keys.META
@ -94,6 +95,11 @@ class BaseNavigationTestCase(WindowManagerMixin, MarionetteTestCase):
return tabBrowser.isRemoteBrowser;
""")
@property
def ready_state(self):
return self.marionette.execute_script("return window.document.readyState;",
sandbox=None)
class TestNavigate(BaseNavigationTestCase):
@ -148,9 +154,7 @@ class TestNavigate(BaseNavigationTestCase):
def test_find_element_state_complete(self):
self.marionette.navigate(self.test_page_remote)
state = self.marionette.execute_script(
"return window.document.readyState", sandbox=None)
self.assertEqual("complete", state)
self.assertEqual("complete", self.ready_state)
self.assertTrue(self.marionette.find_element(By.ID, "mozLink"))
def test_navigate_timeout_error_no_remoteness_change(self):
@ -606,3 +610,35 @@ class TestTLSNavigation(MarionetteTestCase):
with self.safe_session() as session:
with self.assertRaises(errors.InsecureCertificateException):
session.navigate(invalid_cert_url)
class TestPageLoadStrategy(BaseNavigationTestCase):
def setUp(self):
super(TestPageLoadStrategy, self).setUp()
if self.marionette.session is not None:
self.marionette.delete_session()
def test_none(self):
self.marionette.start_session({"desiredCapabilities": {"pageLoadStrategy": "none"}})
# With a strategy of "none" there should be no wait for the page load, and the
# current load state is unknown. So only test that the command executes successfully.
self.marionette.navigate(self.test_page_slow_resource)
def test_eager(self):
self.marionette.start_session({"desiredCapabilities": {"pageLoadStrategy": "eager"}})
self.marionette.navigate(self.test_page_slow_resource)
self.assertEqual(self.test_page_slow_resource, self.marionette.get_url())
self.assertEqual("interactive", self.ready_state)
self.marionette.find_element(By.ID, "slow")
def test_normal(self):
self.marionette.start_session({"desiredCapabilities": {"pageLoadStrategy": "normal"}})
self.marionette.navigate(self.test_page_slow_resource)
self.assertEqual(self.test_page_slow_resource, self.marionette.get_url())
self.assertEqual("complete", self.ready_state)
self.marionette.find_element(By.ID, "slow")

View File

@ -0,0 +1,13 @@
<!-- 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/. -->
<!DOCTYPE html>
<html>
<head>
<title>Slow loading resource</title>
</head>
<body>
<img src="/slow?delay=1" id="slow" />
</body>
</html>

View File

@ -72,8 +72,6 @@ var asyncTestTimeoutId;
var inactivityTimeoutId = null;
var originalOnError;
//timer for doc changes
var checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
// Send move events about this often
var EVENT_INTERVAL = 30; // milliseconds
// last touch for each fingerId
@ -248,9 +246,11 @@ var loadListener = {
sendError(new UnknownError("Reached error page: " +
event.target.baseURI), this.command_id);
// Special-case about:blocked pages which should be treated as non-error
// pages but do not raise a pageshow event.
} else if (/about:blocked\?/.exec(event.target.baseURI)) {
// Return early with a page load strategy of eager, and also special-case
// about:blocked pages which should be treated as non-error pages but do
// not raise a pageshow event.
} else if (capabilities.get("pageLoadStrategy") === session.PageLoadStrategy.Eager ||
/about:blocked\?/.exec(event.target.baseURI)) {
this.stop();
sendOk(this.command_id);
}
@ -351,6 +351,11 @@ var loadListener = {
*/
navigate: function (trigger, command_id, timeout, loadEventExpected = true,
useUnloadTimer = false) {
// Only wait if the page load strategy is not `none`
loadEventExpected = loadEventExpected &&
capabilities.get("pageLoadStrategy") !== session.PageLoadStrategy.None;
if (loadEventExpected) {
let startTime = new Date().getTime();
this.start(command_id, timeout, startTime, true);
@ -1046,7 +1051,8 @@ function setDispatch(batches, touches, batchIndex=0) {
}
if (maxTime != 0) {
checkTimer.initWithCallback(function() {
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.initWithCallback(function() {
setDispatch(batches, touches, batchIndex);
}, maxTime, Ci.nsITimer.TYPE_ONE_SHOT);
} else {
@ -1530,21 +1536,10 @@ function switchToShadowRoot(id) {
*/
function switchToFrame(msg) {
let command_id = msg.json.command_id;
function checkLoad() {
let errorRegex = /about:.+(error)|(blocked)\?/;
if (curContainer.frame.document.readyState == "complete") {
sendOk(command_id);
return;
} else if (curContainer.frame.document.readyState == "interactive" &&
errorRegex.exec(curContainer.frame.document.baseURI)) {
sendError(new UnknownError("Error loading page"), command_id);
return;
}
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
}
let foundFrame = null;
let frames = [];
let parWindow = null;
// Check of the curContainer.frame reference is dead
try {
frames = curContainer.frame.frames;
@ -1569,7 +1564,7 @@ function switchToFrame(msg) {
curContainer.frame.focus();
}
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
sendOk(command_id);
return;
}
@ -1619,11 +1614,12 @@ function switchToFrame(msg) {
// context so should treat it accordingly.
sendSyncMessage("Marionette:switchedToFrame", { frameValue: null});
curContainer.frame = content;
if(msg.json.focus == true) {
curContainer.frame.focus();
}
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
sendOk(command_id);
return;
}
} catch (e) {
@ -1650,22 +1646,22 @@ function switchToFrame(msg) {
curContainer.frame.wrappedJSObject, seenEls)[element.Key];
sendSyncMessage("Marionette:switchedToFrame", {frameValue: frameValue});
let rv = null;
if (curContainer.frame.contentWindow === null) {
// The frame we want to switch to is a remote/OOP frame;
// notify our parent to handle the switch
curContainer.frame = content;
rv = {win: parWindow, frame: foundFrame};
let rv = {win: parWindow, frame: foundFrame};
sendResponse(rv, command_id);
} else {
curContainer.frame = curContainer.frame.contentWindow;
if (msg.json.focus) {
curContainer.frame.focus();
}
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
return;
}
sendResponse(rv, command_id);
sendOk(command_id);
}
}
function addCookie(cookie) {