Bug 1363053 - Return JSON representation of return value
According to a recent change in the WebDriver specification, we need to
return an object's JSON representation iff it exists.
The relevant specification prose change was made in
https://github.com/w3c/webdriver/commit/1ee4c61c11004f38bb3db0fb6a1d740e185a2196.
This patch causes return values that have a toJSON property that is a
function, to return the value of calling said function.
MozReview-Commit-ID: GpQNE9GpjCH
--- a/testing/marionette/evaluate.js
+++ b/testing/marionette/evaluate.js
@@ -242,17 +242,17 @@ evaluate.fromJSON = function (obj, seenE
* @param {element.Store} seenEls
* Element store to use for lookup of web element references.
*
* @return {?}
* Same object as provided by |obj| with the elements replaced by
* web elements.
*/
evaluate.toJSON = function (obj, seenEls) {
- let t = Object.prototype.toString.call(obj);
+ const t = Object.prototype.toString.call(obj);
// null
if (t == "[object Undefined]" || t == "[object Null]") {
return null;
}
// literals
else if (t == "[object Boolean]" || t == "[object Number]" || t == "[object String]") {
@@ -265,16 +265,22 @@ evaluate.toJSON = function (obj, seenEls
}
// HTMLElement
else if ("nodeType" in obj && obj.nodeType == 1) {
let uuid = seenEls.add(obj);
return element.makeWebElement(uuid);
}
+ // custom JSON representation
+ else if (typeof obj["toJSON"] == "function") {
+ let unsafeJSON = obj.toJSON();
+ return evaluate.toJSON(unsafeJSON, seenEls);
+ }
+
// arbitrary objects + files
else {
let rv = {};
for (let prop in obj) {
try {
rv[prop] = evaluate.toJSON(obj[prop], seenEls);
} catch (e if (e.result == Cr.NS_ERROR_NOT_IMPLEMENTED)) {
logger.debug(`Skipping ${prop}: ${e.message}`);
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py
@@ -44,16 +44,19 @@ class TestExecuteSimpleTestContent(Mario
class TestExecuteContent(MarionetteTestCase):
def assert_is_defined(self, property, sandbox="default"):
self.assertTrue(self.marionette.execute_script(
"return typeof arguments[0] != 'undefined'", [property], sandbox=sandbox),
"property {} is undefined".format(property))
+ def assert_is_web_element(self, element):
+ self.assertIsInstance(element, HTMLElement)
+
def test_return_number(self):
self.assertEqual(1, self.marionette.execute_script("return 1"))
self.assertEqual(1.5, self.marionette.execute_script("return 1.5"))
def test_return_boolean(self):
self.assertTrue(self.marionette.execute_script("return true"))
def test_return_string(self):
@@ -325,16 +328,35 @@ class TestExecuteContent(MarionetteTestC
</script>
"""))
self.marionette.execute_script("", sandbox=None)
def test_access_global_objects_from_chrome(self):
# test inspection of arguments
self.marionette.execute_script("__webDriverArguments.toString()")
+ def test_toJSON(self):
+ foo = self.marionette.execute_script("""
+ return {
+ toJSON () {
+ return "foo";
+ }
+ }""",
+ sandbox=None)
+ self.assertEqual("foo", foo)
+
+ def test_unsafe_toJSON(self):
+ el = self.marionette.execute_script("""
+ return {
+ toJSON () {
+ return document.documentElement;
+ }
+ }""",
+ sandbox=None)
+ self.assert_is_web_element(el)
class TestExecuteChrome(WindowManagerMixin, TestExecuteContent):
def setUp(self):
super(TestExecuteChrome, self).setUp()
self.marionette.set_context("chrome")