--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -63,100 +63,109 @@ class HTMLElement(object):
"""
return self.marionette.find_elements(method, target, self.id)
def get_attribute(self, name):
"""Returns the requested attribute, or None if no attribute
is set.
"""
body = {"id": self.id, "name": name}
- return self.marionette._send_message("getElementAttribute", body, key="value")
+ return self.marionette._send_message("WebDriver:GetElementAttribute",
+ body, key="value")
def get_property(self, name):
"""Returns the requested property, or None if the property is
not set.
"""
try:
body = {"id": self.id, "name": name}
- return self.marionette._send_message("getElementProperty", body, key="value")
+ return self.marionette._send_message("WebDriver:GetElementProperty",
+ body, key="value")
except errors.UnknownCommandException:
# Keep backward compatibility for code which uses get_attribute() to
# also retrieve element properties.
# Remove when Firefox 55 is stable.
return self.get_attribute(name)
def click(self):
"""Simulates a click on the element."""
- self.marionette._send_message("clickElement", {"id": self.id})
+ self.marionette._send_message("WebDriver:ElementClick",
+ {"id": self.id})
def tap(self, x=None, y=None):
"""Simulates a set of tap events on the element.
:param x: X coordinate of tap event. If not given, default to
the centre of the element.
:param y: Y coordinate of tap event. If not given, default to
the centre of the element.
"""
body = {"id": self.id, "x": x, "y": y}
self.marionette._send_message("singleTap", body)
@property
def text(self):
"""Returns the visible text of the element, and its child elements."""
body = {"id": self.id}
- return self.marionette._send_message("getElementText", body, key="value")
+ return self.marionette._send_message("WebDriver:GetElementText",
+ body, key="value")
def send_keys(self, *strings):
"""Sends the string via synthesized keypresses to the element.
If an array is passed in like `marionette.send_keys(Keys.SHIFT, "a")` it
will be joined into a string.
If an integer is passed in like `marionette.send_keys(1234)` it will be
coerced into a string.
"""
keys = Marionette.convert_keys(*strings)
- body = {"id": self.id, "text": keys}
- self.marionette._send_message("sendKeysToElement", body)
+ self.marionette._send_message("WebDriver:ElementSendKeys",
+ {"id": self.id, "text": keys})
def clear(self):
"""Clears the input of the element."""
- self.marionette._send_message("clearElement", {"id": self.id})
+ self.marionette._send_message("WebDriver:ElementClear",
+ {"id": self.id})
def is_selected(self):
"""Returns True if the element is selected."""
body = {"id": self.id}
- return self.marionette._send_message("isElementSelected", body, key="value")
+ return self.marionette._send_message("WebDriver:IsElementSelected",
+ body, key="value")
def is_enabled(self):
"""This command will return False if all the following criteria
are met otherwise return True:
* A form control is disabled.
* A ``HTMLElement`` has a disabled boolean attribute.
"""
body = {"id": self.id}
- return self.marionette._send_message("isElementEnabled", body, key="value")
+ return self.marionette._send_message("WebDriver:IsElementEnabled",
+ body, key="value")
def is_displayed(self):
"""Returns True if the element is displayed, False otherwise."""
body = {"id": self.id}
- return self.marionette._send_message("isElementDisplayed", body, key="value")
+ return self.marionette._send_message("WebDriver:IsElementDisplayed",
+ body, key="value")
@property
def size(self):
"""A dictionary with the size of the element."""
warnings.warn("The size property has been deprecated and will be removed in a future version. \
Please use HTMLElement#rect", DeprecationWarning)
rect = self.rect
return {"width": rect["width"], "height": rect["height"]}
@property
def tag_name(self):
"""The tag name of the element."""
body = {"id": self.id}
- return self.marionette._send_message("getElementTagName", body, key="value")
+ return self.marionette._send_message("WebDriver:GetElementTagName",
+ body, key="value")
@property
def location(self):
"""Get an element's location on the page.
The returned point will contain the x and y coordinates of the
top left-hand corner of the given element. The point (0,0)
refers to the upper-left corner of the document.
@@ -174,27 +183,27 @@ class HTMLElement(object):
This will return a dictionary with the following:
* x and y represent the top left coordinates of the ``HTMLElement``
relative to top left corner of the document.
* height and the width will contain the height and the width
of the DOMRect of the ``HTMLElement``.
"""
- body = {"id": self.id}
- return self.marionette._send_message("getElementRect", body)
+ return self.marionette._send_message("WebDriver:GetElementRect",
+ {"id": self.id})
def value_of_css_property(self, property_name):
"""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(
- "getElementValueOfCssProperty", body, key="value")
+ return self.marionette._send_message("WebDriver:GetElementCSSValue",
+ body, key="value")
class MouseButton(object):
"""Enum-like class for mouse button constants."""
LEFT = 0
MIDDLE = 1
RIGHT = 2
@@ -527,32 +536,34 @@ class Alert(object):
Alert(marionette).dismiss()
"""
def __init__(self, marionette):
self.marionette = marionette
def accept(self):
"""Accept a currently displayed modal dialog."""
- self.marionette._send_message("acceptDialog")
+ # TODO: Switch to "WebDriver:AcceptAlert" in Firefox 62
+ self.marionette._send_message("WebDriver:AcceptDialog")
def dismiss(self):
"""Dismiss a currently displayed modal dialog."""
- self.marionette._send_message("dismissDialog")
+ self.marionette._send_message("WebDriver:DismissAlert")
@property
def text(self):
"""Return the currently displayed text in a tab modal."""
- return self.marionette._send_message("getTextFromDialog", key="value")
+ return self.marionette._send_message("WebDriver:GetAlertText",
+ key="value")
def send_keys(self, *string):
"""Send keys to the currently displayed text input area in an open
tab modal dialog."""
- body = {"text": Marionette.convert_keys(*string)}
- self.marionette._send_message("sendKeysToDialog", body)
+ self.marionette._send_message("WebDriver:SendAlertText",
+ {"text": Marionette.convert_keys(*string)})
class Marionette(object):
"""Represents a Marionette connection to a browser or device."""
CONTEXT_CHROME = "chrome" # non-browser content: windows, dialogs, etc.
CONTEXT_CONTENT = "content" # browser content: iframes, divs, etc.
DEFAULT_STARTUP_TIMEOUT = 120
@@ -725,17 +736,17 @@ class Marionette(object):
:param name: Requested command key.
:param params: Optional dictionary of key/value arguments.
:param key: Optional key to extract from response.
:returns: Full response from the server, or if `key` is given,
the value of said key in the response.
"""
- if not self.session_id and name != "newSession":
+ if not self.session_id and name != "WebDriver:NewSession":
raise errors.MarionetteException("Please start a session")
try:
msg = self.client.request(name, params)
except IOError:
self.delete_session(send_request=False)
raise
@@ -991,17 +1002,18 @@ class Marionette(object):
case prefInterface.PREF_INVALID:
return false;
}}
""".format(pref, value))
if not pref_exists:
break
if not pref_exists:
- context = self._send_message("getContext", key="value")
+ context = self._send_message("Marionette:GetContext",
+ key="value")
self.delete_session()
self.instance.restart(prefs)
self.raise_for_port()
self.start_session()
# Restore the context as used before the restart
self.set_context(context)
@@ -1052,17 +1064,18 @@ class Marionette(object):
if canceled:
raise errors.MarionetteException(
"Something cancelled the quit application request")
body = None
if len(flags) > 0:
body = {"flags": list(flags)}
- return self._send_message("quitApplication", body, key="cause")
+ return self._send_message("Marionette:Quit",
+ body, key="cause")
@do_process_check
def quit(self, clean=False, in_app=False, callback=None):
"""Terminate the currently running instance.
This command will delete the active marionette session. It also allows
manipulation of eg. the profile data while the application is not running.
To start the application again, :func:`start_session` has to be called.
@@ -1081,17 +1094,18 @@ class Marionette(object):
"on Gecko instances launched by Marionette")
cause = None
if in_app:
if callback is not None:
if not callable(callback):
raise ValueError("Specified callback '{}' is not callable".format(callback))
- self._send_message("acceptConnections", {"value": False})
+ self._send_message("Marionette:AcceptConnections",
+ {"value": False})
callback()
else:
cause = self._request_in_app_shutdown()
self.delete_session(send_request=False)
# Give the application some time to shutdown
returncode = self.instance.runner.wait(timeout=self.DEFAULT_SHUTDOWN_TIMEOUT)
@@ -1124,28 +1138,30 @@ class Marionette(object):
browser. Otherwise the browser will be restarted immediately
by killing the process.
:param callback: If provided and `in_app` is True, the callback will be
used to trigger the restart.
"""
if not self.instance:
raise errors.MarionetteException("restart() can only be called "
"on Gecko instances launched by Marionette")
- context = self._send_message("getContext", key="value")
+ context = self._send_message("Marionette:GetContext",
+ key="value")
cause = None
if in_app:
if clean:
raise ValueError("An in_app restart cannot be triggered with the clean flag set")
if callback is not None:
if not callable(callback):
raise ValueError("Specified callback '{}' is not callable".format(callback))
- self._send_message("acceptConnections", {"value": False})
+ self._send_message("Marionette:AcceptConnections",
+ {"value": False})
callback()
else:
cause = self._request_in_app_shutdown("eRestart")
self.delete_session(send_request=False)
try:
timeout = self.DEFAULT_SHUTDOWN_TIMEOUT + self.DEFAULT_STARTUP_TIMEOUT
@@ -1233,17 +1249,18 @@ class Marionette(object):
# top-level, and after bug 1388424 removed support for overriding
# the session ID, we also do this with this client. However,
# because this client is used with older Firefoxen (through upgrade
# tests et al.) we need to preserve backwards compatibility until
# Firefox 60.
if "capabilities" not in body and capabilities is not None:
body["capabilities"] = dict(capabilities)
- resp = self._send_message("newSession", body)
+ resp = self._send_message("WebDriver:NewSession",
+ body)
self.session_id = resp["sessionId"]
self.session = resp["capabilities"]
# fallback to processId can be removed in Firefox 55
self.process_id = self.session.get("moz:processID", self.session.get("processId"))
self.profile = self.session.get("moz:profile")
return self.session
@@ -1259,17 +1276,17 @@ class Marionette(object):
"""Close the current session and disconnect from the server.
:param send_request: Optional, if `True` a request to close the session on
the server side will be sent. Use `False` in case of eg. in_app restart()
or quit(), which trigger a deletion themselves. Defaults to `True`.
"""
try:
if send_request:
- self._send_message("deleteSession")
+ self._send_message("WebDriver:DeleteSession")
finally:
self.process_id = None
self.profile = None
self.session = None
self.session_id = None
self.window = None
if self.client is not None:
@@ -1348,17 +1365,18 @@ class Marionette(object):
Returns an opaque server-assigned identifier to this window
that uniquely identifies it within this Marionette instance.
This can be used to switch to this window at a later point.
:returns: unique window handle
:rtype: string
"""
- self.window = self._send_message("getWindowHandle", key="value")
+ self.window = self._send_message("WebDriver:GetWindowHandle",
+ key="value")
return self.window
@property
def current_chrome_window_handle(self):
"""Get the current chrome window's handle. Corresponds to
a chrome window that may itself contain tabs identified by
window_handles.
@@ -1404,68 +1422,70 @@ class Marionette(object):
:param x: x coordinate for the top left of the window
:param y: y coordinate for the top left of the window
:param width: The width to resize the window to.
:param height: The height to resize the window to.
"""
if (x is None and y is None) and (height is None and width is None):
raise errors.InvalidArgumentException("x and y or height and width need values")
- return self._send_message("setWindowRect", {"x": x, "y": y,
- "height": height,
- "width": width})
+ body = {"x": x, "y": y, "height": height, "width": width}
+ return self._send_message("WebDriver:SetWindowRect",
+ body)
@property
def window_rect(self):
- return self._send_message("getWindowRect")
+ return self._send_message("WebDriver:GetWindowRect")
@property
def title(self):
"""Current title of the active window."""
- return self._send_message("getTitle", key="value")
+ return self._send_message("WebDriver:GetTitle",
+ key="value")
@property
def window_handles(self):
"""Get list of windows in the current context.
If called in the content context it will return a list of
references to all available browser windows. Called in the
chrome context, it will list all available windows, not just
browser windows (e.g. not just navigator.browser).
Each window handle is assigned by the server, and the list of
strings returned does not have a guaranteed ordering.
:returns: Unordered list of unique window handles as strings
"""
- return self._send_message("getWindowHandles")
+ return self._send_message("WebDriver:GetWindowHandles")
@property
def chrome_window_handles(self):
"""Get a list of currently open chrome windows.
Each window handle is assigned by the server, and the list of
strings returned does not have a guaranteed ordering.
:returns: Unordered list of unique chrome window handles as strings
"""
return self._send_message("getChromeWindowHandles")
@property
def page_source(self):
"""A string representation of the DOM."""
- return self._send_message("getPageSource", key="value")
+ return self._send_message("WebDriver:GetPageSource",
+ key="value")
def close(self):
"""Close the current window, ending the session if it's the last
window currently open.
:returns: Unordered list of remaining unique window handles as strings
"""
- return self._send_message("close")
+ return self._send_message("WebDriver:CloseWindow")
def close_chrome_window(self):
"""Close the currently selected chrome window, ending the session
if it's the last window open.
:returns: Unordered list of remaining unique chrome window handles as strings
"""
return self._send_message("closeChromeWindow")
@@ -1477,34 +1497,37 @@ class Marionette(object):
`CONTEXT_CHROME` or `CONTEXT_CONTENT`.
Usage example::
marionette.set_context(marionette.CONTEXT_CHROME)
"""
if context not in [self.CONTEXT_CHROME, self.CONTEXT_CONTENT]:
raise ValueError("Unknown context: {}".format(context))
- self._send_message("setContext", {"value": context})
+
+ self._send_message("Marionette:SetContext",
+ {"value": context})
@contextmanager
def using_context(self, context):
"""Sets the context that Marionette commands are running in using
a `with` statement. The state of the context on the server is
saved before entering the block, and restored upon exiting it.
:param context: Context, may be one of the class properties
`CONTEXT_CHROME` or `CONTEXT_CONTENT`.
Usage example::
with marionette.using_context(marionette.CONTEXT_CHROME):
# chrome scope
... do stuff ...
"""
- scope = self._send_message("getContext", key="value")
+ scope = self._send_message("Marionette:GetContext",
+ key="value")
self.set_context(context)
try:
yield
finally:
self.set_context(scope)
def switch_to_alert(self):
"""Returns an :class:`~marionette_driver.marionette.Alert` object for
@@ -1522,34 +1545,35 @@ class Marionette(object):
"""Switch to the specified window; subsequent commands will be
directed at the new window.
:param window_id: The id or name of the window to switch to.
:param focus: A boolean value which determins whether to focus
the window that we just switched to.
"""
- body = {"focus": focus, "name": window_id}
- self._send_message("switchToWindow", body)
+ self._send_message("WebDriver:SwitchToWindow",
+ {"focus": focus, "name": window_id})
self.window = window_id
def get_active_frame(self):
"""Returns an :class:`~marionette_driver.marionette.HTMLElement`
representing the frame Marionette is currently acting on."""
- return self._send_message("getActiveFrame", key="value")
+ return self._send_message("WebDriver:GetActiveFrame",
+ key="value")
def switch_to_default_content(self):
"""Switch the current context to page's default content."""
return self.switch_to_frame()
def switch_to_parent_frame(self):
"""
Switch to the Parent Frame
"""
- self._send_message("switchToParentFrame")
+ self._send_message("WebDriver:SwitchToParentFrame")
def switch_to_frame(self, frame=None, focus=True):
"""Switch the current context to the specified frame. Subsequent
commands will operate in the context of the specified frame,
if applicable.
:param frame: A reference to the frame to switch to. This can
be an :class:`~marionette_driver.marionette.HTMLElement`,
@@ -1560,46 +1584,51 @@ class Marionette(object):
:param focus: A boolean value which determins whether to focus
the frame that we just switched to.
"""
body = {"focus": focus}
if isinstance(frame, HTMLElement):
body["element"] = frame.id
elif frame is not None:
body["id"] = frame
- self._send_message("switchToFrame", body)
+
+ self._send_message("WebDriver:SwitchToFrame",
+ body)
def switch_to_shadow_root(self, host=None):
"""Switch the current context to the specified host's Shadow DOM.
Subsequent commands will operate in the context of the specified Shadow
DOM, if applicable.
:param host: A reference to the host element containing Shadow DOM.
This can be an :class:`~marionette_driver.marionette.HTMLElement`.
If you call ``switch_to_shadow_root`` without an argument, it will
switch to the parent Shadow DOM or the top-level frame.
"""
body = {}
if isinstance(host, HTMLElement):
body["id"] = host.id
- return self._send_message("switchToShadowRoot", body)
+
+ return self._send_message("WebDriver:SwitchToShadowRoot",
+ body)
def get_url(self):
"""Get a string representing the current URL.
On Desktop this returns a string representation of the URL of
the current top level browsing context. This is equivalent to
document.location.href.
When in the context of the chrome, this returns the canonical
URL of the current resource.
:returns: string representation of URL
"""
- return self._send_message("getCurrentUrl", key="value")
+ return self._send_message("WebDriver:GetCurrentURL",
+ key="value")
def get_window_type(self):
"""Gets the windowtype attribute of the window Marionette is
currently acting on.
This command only makes sense in a chrome context. You might use this
method to distinguish a browser window from an editor window.
"""
@@ -1623,29 +1652,30 @@ class Marionette(object):
`window` triggers and `document.readyState` is "complete".
In chrome context it will change the current `window`'s location
to the supplied URL and wait until `document.readyState` equals
"complete" or the page timeout duration has elapsed.
:param url: The URL to navigate to.
"""
- self._send_message("get", {"url": url})
+ self._send_message("WebDriver:Navigate",
+ {"url": url})
def go_back(self):
"""Causes the browser to perform a back navigation."""
- self._send_message("goBack")
+ self._send_message("WebDriver:Back")
def go_forward(self):
"""Causes the browser to perform a forward navigation."""
- self._send_message("goForward")
+ self._send_message("WebDriver:Forward")
def refresh(self):
"""Causes the browser to perform to refresh the current page."""
- self._send_message("refresh")
+ self._send_message("WebDriver:Refresh")
def _to_json(self, args):
if isinstance(args, list) or isinstance(args, tuple):
wrapped = []
for arg in args:
wrapped.append(self._to_json(arg))
elif isinstance(args, dict):
wrapped = {}
@@ -1763,17 +1793,19 @@ class Marionette(object):
frame = stack[-2:-1][0] # grab the second-to-last frame
body = {"script": script,
"args": args,
"newSandbox": new_sandbox,
"sandbox": sandbox,
"scriptTimeout": script_timeout,
"line": int(frame[1]),
"filename": os.path.basename(frame[0])}
- rv = self._send_message("executeScript", body, key="value")
+
+ rv = self._send_message("WebDriver:ExecuteScript",
+ body, key="value")
return self._from_json(rv)
def execute_async_script(self, script, script_args=(), new_sandbox=True,
sandbox="default", script_timeout=None,
debug_script=False):
"""Executes an asynchronous JavaScript script, and returns the
result (or None if the script does return a value).
@@ -1812,17 +1844,19 @@ class Marionette(object):
body = {"script": script,
"args": args,
"newSandbox": new_sandbox,
"sandbox": sandbox,
"scriptTimeout": script_timeout,
"line": int(frame[1]),
"filename": os.path.basename(frame[0]),
"debug_script": debug_script}
- rv = self._send_message("executeAsyncScript", body, key="value")
+
+ rv = self._send_message("WebDriver:ExecuteAsyncScript",
+ body, key="value")
return self._from_json(rv)
def find_element(self, method, target, id=None):
"""Returns an :class:`~marionette_driver.marionette.HTMLElement`
instance that matches the specified method and target in the current
context.
An :class:`~marionette_driver.marionette.HTMLElement` instance may be
@@ -1843,17 +1877,19 @@ class Marionette(object):
"tag", target might equal "div". If method = "id", target would
be an element id.
:param id: If specified, search for elements only inside the element
with the specified id.
"""
body = {"value": target, "using": method}
if id:
body["element"] = id
- return self._send_message("findElement", body, key="value")
+
+ return self._send_message("WebDriver:FindElement",
+ body, key="value")
def find_elements(self, method, target, id=None):
"""Returns a list of all
:class:`~marionette_driver.marionette.HTMLElement` instances that match
the specified method and target in the current context.
An :class:`~marionette_driver.marionette.HTMLElement` instance may be
used to call other methods on the element, such as
@@ -1871,20 +1907,23 @@ class Marionette(object):
"tag", target might equal "div". If method = "id", target would be
an element id.
:param id: If specified, search for elements only inside the element
with the specified id.
"""
body = {"value": target, "using": method}
if id:
body["element"] = id
- return self._send_message("findElements", body)
+
+ return self._send_message("WebDriver:FindElements",
+ body)
def get_active_element(self):
- el_or_ref = self._send_message("getActiveElement", key="value")
+ el_or_ref = self._send_message("WebDriver:GetActiveElement",
+ key="value")
return el_or_ref
def add_cookie(self, cookie):
"""Adds a cookie to your current session.
:param cookie: A dictionary object, with required keys - "name"
and "value"; optional keys - "path", "domain", "secure",
"expiry".
@@ -1893,42 +1932,43 @@ class Marionette(object):
::
driver.add_cookie({"name": "foo", "value": "bar"})
driver.add_cookie({"name": "foo", "value": "bar", "path": "/"})
driver.add_cookie({"name": "foo", "value": "bar", "path": "/",
"secure": True})
"""
- body = {"cookie": cookie}
- self._send_message("addCookie", body)
+ self._send_message("WebDriver:AddCookie",
+ {"cookie": cookie})
def delete_all_cookies(self):
"""Delete all cookies in the scope of the current session.
Usage example:
::
driver.delete_all_cookies()
"""
- self._send_message("deleteAllCookies")
+ self._send_message("WebDriver:DeleteAllCookies")
def delete_cookie(self, name):
"""Delete a cookie by its name.
:param name: Name of cookie to delete.
Usage example:
::
driver.delete_cookie("foo")
"""
- self._send_message("deleteCookie", {"name": name})
+ self._send_message("WebDriver:DeleteCookie",
+ {"name": name})
def get_cookie(self, name):
"""Get a single cookie by name. Returns the cookie if found,
None if not.
:param name: Name of cookie to get.
"""
cookies = self.get_cookies()
@@ -1940,17 +1980,17 @@ class Marionette(object):
def get_cookies(self):
"""Get all the cookies for the current domain.
This is the equivalent of calling `document.cookie` and
parsing the result.
:returns: A list of cookies for the current domain.
"""
- return self._send_message("getCookies")
+ return self._send_message("WebDriver:GetCookies")
def screenshot(self, element=None, highlights=None, format="base64",
full=True, scroll=True):
"""Takes a screenshot of a web element or the current frame.
The screen capture is returned as a lossless PNG image encoded
as a base 64 string by default. If the `element` argument is defined the
capture area will be limited to the bounding box of that
@@ -1986,17 +2026,19 @@ class Marionette(object):
body = {"id": element,
"highlights": lights,
"full": full,
"hash": False,
"scroll": scroll}
if format == "hash":
body["hash"] = True
- data = self._send_message("takeScreenshot", body, key="value")
+
+ data = self._send_message("WebDriver:TakeScreenshot",
+ body, key="value")
if format == "base64" or format == "hash":
return data
elif format == "binary":
return base64.b64decode(data.encode("ascii"))
else:
raise ValueError("format parameter must be either 'base64'"
" or 'binary', not {0}".format(repr(format)))
@@ -2079,18 +2121,18 @@ class Marionette(object):
button in the OS window.
Note that this command is not available on Fennec. It may also
not be available in certain window managers.
:returns: Window rect.
"""
- return self._send_message("maximizeWindow")
+ return self._send_message("WebDriver:MaximizeWindow")
def fullscreen(self):
"""Synchronously sets the user agent window to full screen as
if the user had done "View > Enter Full Screen", or restores
it if it is already in full screen.
:returns: Window rect.
"""
- return self._send_message("fullscreen")
+ return self._send_message("WebDriver:FullscreenWindow")