зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1370850 - Serialise undefined script evaluation return value to null; r=maja_zf
When a call through the content frame proxy is interrupted by the dialogueObserver, the synchronous promise that is meant to wait for a response from the frame script is resolved immediately with an undefined return value. When an undefined value is assigned to the response body, it gets dropped during JSON serialisation. To ensure the "value" field expected from the Execute Script and Execute Async Script commands is populated, we need to assign a null value to resp.body.value. We can treat undefined as null by calling evaluate.toJSON again on the return value from the proxied frame script call. This effectively means we serialise it twice, since it first needs to be serialised to cross the IPC border, though the second computation only looks at primitives and no known web element store is required. It would be nicer if the content frame script itself would be able to return early with null by installing a user prompt notification event, but this is not possible because the tabmodal dialogue that appears blocks script execution. This means we need to rely on the dialogueObserver in testing/marionette/proxy.js to take care of the dialogue for us. MozReview-Commit-ID: D14TA2TYYXI --HG-- extra : rebase_source : 5fc17a1f0786e2fc9a2d054ef7c1f8b0e3336906
This commit is contained in:
Родитель
8ad4ba015d
Коммит
fec9a028f3
|
@ -871,11 +871,13 @@ GeckoDriver.prototype.execute_ = function (script, args, timeout, opts = {}) {
|
|||
case Context.CONTENT:
|
||||
// evaluate in content with lasting side-effects
|
||||
if (!opts.sandboxName) {
|
||||
return this.listener.execute(script, args, timeout, opts);
|
||||
return this.listener.execute(script, args, timeout, opts)
|
||||
.then(evaluate.toJSON);
|
||||
|
||||
// evaluate in content with sandbox
|
||||
} else {
|
||||
return this.listener.executeInSandbox(script, args, timeout, opts);
|
||||
return this.listener.executeInSandbox(script, args, timeout, opts)
|
||||
.then(evaluate.toJSON);
|
||||
}
|
||||
|
||||
case Context.CHROME:
|
||||
|
@ -887,8 +889,8 @@ GeckoDriver.prototype.execute_ = function (script, args, timeout, opts = {}) {
|
|||
|
||||
opts.timeout = timeout;
|
||||
let wargs = evaluate.fromJSON(args, this.curBrowser.seenEls, sb.window);
|
||||
let evaluatePromise = evaluate.sandbox(sb, script, wargs, opts);
|
||||
return evaluatePromise.then(res => evaluate.toJSON(res, this.curBrowser.seenEls));
|
||||
return evaluate.sandbox(sb, script, wargs, opts)
|
||||
.then(res => evaluate.toJSON(res, this.curBrowser.seenEls));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import os
|
|||
import urllib
|
||||
|
||||
from marionette_driver import By, errors
|
||||
from marionette_driver.marionette import HTMLElement
|
||||
from marionette_driver.marionette import Alert, HTMLElement
|
||||
from marionette_driver.wait import Wait
|
||||
|
||||
from marionette_harness import MarionetteTestCase, skip_if_mobile, WindowManagerMixin
|
||||
|
@ -31,6 +31,23 @@ globals = set([
|
|||
|
||||
class TestExecuteContent(MarionetteTestCase):
|
||||
|
||||
def alert_present(self):
|
||||
try:
|
||||
Alert(self.marionette).text
|
||||
return True
|
||||
except errors.NoAlertPresentException:
|
||||
return False
|
||||
|
||||
def wait_for_alert_closed(self, timeout=None):
|
||||
Wait(self.marionette, timeout=timeout).until(
|
||||
lambda _: not self.alert_present())
|
||||
|
||||
def tearDown(self):
|
||||
if self.alert_present():
|
||||
alert = self.marionette.switch_to_alert()
|
||||
alert.dismiss()
|
||||
self.wait_for_alert_closed()
|
||||
|
||||
def assert_is_defined(self, property, sandbox="default"):
|
||||
self.assertTrue(self.marionette.execute_script(
|
||||
"return typeof arguments[0] != 'undefined'", [property], sandbox=sandbox),
|
||||
|
@ -340,6 +357,11 @@ class TestExecuteContent(MarionetteTestCase):
|
|||
sandbox=None)
|
||||
self.assert_is_web_element(el)
|
||||
|
||||
def test_return_value_on_alert(self):
|
||||
res = self.marionette._send_message("executeScript", {"script": "alert()"})
|
||||
self.assertIn("value", res)
|
||||
self.assertIsNone(res["value"])
|
||||
|
||||
|
||||
class TestExecuteChrome(WindowManagerMixin, TestExecuteContent):
|
||||
|
||||
|
@ -408,6 +430,9 @@ class TestExecuteChrome(WindowManagerMixin, TestExecuteContent):
|
|||
def test_access_chrome_objects_in_event_listeners(self):
|
||||
pass
|
||||
|
||||
def test_return_value_on_alert(self):
|
||||
pass
|
||||
|
||||
|
||||
class TestElementCollections(MarionetteTestCase):
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче