Bug 1408509 - Add web frame, web window, and chrome element support to Marionette client. r?whimboo
MozReview-Commit-ID: 6HFzfYckrB5
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -19,23 +19,29 @@ from six import reraise
from . import errors
from . import transport
from .decorators import do_process_check
from .geckoinstance import GeckoInstance
from .keys import Keys
from .timeout import Timeouts
-WEBELEMENT_KEY = "ELEMENT"
-W3C_WEBELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf"
+CHROME_ELEMENT_KEY = "chromeelement-9fc5-4b51-a3c8-01716eedeb04"
+FRAME_KEY = "frame-075b-4da1-b6ba-e579c2d3230a"
+LEGACY_ELEMENT_KEY = "ELEMENT"
+WEB_ELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf"
+WINDOW_KEY = "window-fcc6-11e5-b4f8-330a88ab9d7f"
class HTMLElement(object):
"""Represents a DOM Element."""
+ identifiers = (CHROME_ELEMENT_KEY, FRAME_KEY, WINDOW_KEY,
+ LEGACY_ELEMENT_KEY, WEB_ELEMENT_KEY)
+
def __init__(self, marionette, id):
self.marionette = marionette
assert(id is not None)
self.id = id
def __str__(self):
return self.id
@@ -171,16 +177,31 @@ class HTMLElement(object):
"""Gets the value of the specified CSS property name.
:param property_name: Property name to get the value of.
"""
body = {"id": self.id, "propertyName": property_name}
return self.marionette._send_message("WebDriver:GetElementCSSValue",
body, key="value")
+ @classmethod
+ def _from_json(cls, json, marionette):
+ if isinstance(json, dict):
+ if WEB_ELEMENT_KEY in json:
+ return cls(marionette, json[WEB_ELEMENT_KEY])
+ elif LEGACY_ELEMENT_KEY in json:
+ return cls(marionette, json[LEGACY_ELEMENT_KEY])
+ elif CHROME_ELEMENT_KEY in json:
+ return cls(marionette, json[CHROME_ELEMENT_KEY])
+ elif FRAME_KEY in json:
+ return cls(marionette, json[FRAME_KEY])
+ elif WINDOW_KEY in json:
+ return cls(marionette, json[WINDOW_KEY])
+ raise ValueError("Unrecognised web element")
+
class MouseButton(object):
"""Enum-like class for mouse button constants."""
LEFT = 0
MIDDLE = 1
RIGHT = 2
@@ -740,22 +761,18 @@ class Marionette(object):
self._handle_error(err)
if key is not None:
return self._unwrap_response(res.get(key))
else:
return self._unwrap_response(res)
def _unwrap_response(self, value):
- if isinstance(value, dict) and (WEBELEMENT_KEY in value or
- W3C_WEBELEMENT_KEY in value):
- if value.get(WEBELEMENT_KEY):
- return HTMLElement(self, value.get(WEBELEMENT_KEY))
- else:
- return HTMLElement(self, value.get(W3C_WEBELEMENT_KEY))
+ if isinstance(value, dict) and any(k in value.keys() for k in HTMLElement.identifiers):
+ return HTMLElement._from_json(value, self)
elif isinstance(value, list):
return list(self._unwrap_response(item) for item in value)
else:
return value
def _handle_error(self, obj):
error = obj["error"]
message = obj["message"]
@@ -1588,42 +1605,39 @@ class Marionette(object):
wrapped = []
for arg in args:
wrapped.append(self._to_json(arg))
elif isinstance(args, dict):
wrapped = {}
for arg in args:
wrapped[arg] = self._to_json(args[arg])
elif type(args) == HTMLElement:
- wrapped = {W3C_WEBELEMENT_KEY: args.id,
- WEBELEMENT_KEY: args.id}
+ wrapped = {WEB_ELEMENT_KEY: args.id,
+ LEGACY_ELEMENT_KEY: args.id}
elif (isinstance(args, bool) or isinstance(args, basestring) or
isinstance(args, int) or isinstance(args, float) or args is None):
wrapped = args
return wrapped
def _from_json(self, value):
if isinstance(value, list):
unwrapped = []
for item in value:
unwrapped.append(self._from_json(item))
+ return unwrapped
elif isinstance(value, dict):
unwrapped = {}
for key in value:
- if key == W3C_WEBELEMENT_KEY:
- unwrapped = HTMLElement(self, value[key])
- break
- elif key == WEBELEMENT_KEY:
- unwrapped = HTMLElement(self, value[key])
- break
+ if key in HTMLElement.identifiers:
+ return HTMLElement._from_json(value[key], self)
else:
unwrapped[key] = self._from_json(value[key])
+ return unwrapped
else:
- unwrapped = value
- return unwrapped
+ return value
def execute_script(self, script, script_args=(), new_sandbox=True,
sandbox="default", script_timeout=None):
"""Executes a synchronous JavaScript script, and returns the
result (or None if the script does return a value).
The script is executed in the context set by the most recent
:func:`set_context` call, or to the CONTEXT_CONTENT context if
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_mouse_action.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_mouse_action.py
@@ -3,17 +3,17 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import absolute_import
import urllib
from marionette_driver import By, errors, Wait
from marionette_driver.keys import Keys
-from marionette_driver.marionette import W3C_WEBELEMENT_KEY
+from marionette_driver.marionette import WEB_ELEMENT_KEY
from marionette_harness import MarionetteTestCase
def inline(doc):
return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc))
@@ -35,19 +35,17 @@ class Actions(object):
"type": "pointer"
}]}
return self.marionette._send_message("performActions", params=params)
def move(self, element, x=0, y=0, duration=250):
self.action_chain.append({
"duration": duration,
- "origin": {
- W3C_WEBELEMENT_KEY: element.id
- },
+ "origin": {WEB_ELEMENT_KEY: element.id},
"type": "pointerMove",
"x": x,
"y": y,
})
return self
def click(self):