mirror of
https://github.com/classilla/tenfourfox.git
synced 2025-01-15 09:30:20 +00:00
186 lines
6.8 KiB
ReStructuredText
186 lines
6.8 KiB
ReStructuredText
.. py:currentmodule:: marionette_driver.marionette
|
|
|
|
Marionette Python Client
|
|
========================
|
|
|
|
The Marionette python client library allows you to remotely control a
|
|
Gecko-based browser or device which is running a Marionette_
|
|
server. This includes desktop Firefox and FirefoxOS (support for
|
|
Firefox for Android is planned, but not yet fully implemented).
|
|
|
|
The Marionette server is built directly into Gecko and can be started by
|
|
passing in a command line option to Gecko, or by using a Marionette-enabled
|
|
build. The server listens for connections from various clients. Clients can
|
|
then control Gecko by sending commands to the server.
|
|
|
|
This is the official python client for Marionette. There also exists a
|
|
`NodeJS client`_ maintained by the Firefox OS automation team.
|
|
|
|
.. _Marionette: https://developer.mozilla.org/en-US/docs/Marionette
|
|
.. _NodeJS client: https://github.com/mozilla-b2g/marionette-js-client
|
|
|
|
Getting the Client
|
|
------------------
|
|
|
|
The python client is officially supported. To install it, first make sure you
|
|
have `pip installed`_ then run:
|
|
|
|
.. parsed-literal::
|
|
pip install marionette_client
|
|
|
|
It's highly recommended to use virtualenv_ when installing Marionette to avoid
|
|
package conflicts and other general nastiness.
|
|
|
|
You should now be ready to start using Marionette. The best way to learn is to
|
|
play around with it. Start a `Marionette-enabled instance of Firefox`_, fire up
|
|
a python shell and follow along with the
|
|
:doc:`interactive tutorial <interactive>`!
|
|
|
|
.. _pip installed: https://pip.pypa.io/en/latest/installing.html
|
|
.. _virtualenv: http://virtualenv.readthedocs.org/en/latest/
|
|
.. _Marionette-enabled instance of Firefox: https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/Builds
|
|
|
|
Using the Client for Testing
|
|
----------------------------
|
|
|
|
Please visit the `Marionette Tests`_ section on MDN for information regarding
|
|
testing with Marionette.
|
|
|
|
.. _Marionette Tests: https://developer.mozilla.org/en/Marionette/Tests
|
|
|
|
Session Management
|
|
------------------
|
|
A session is a single instance of a Marionette client connected to a Marionette
|
|
server. Before you can start executing commands, you need to start a session
|
|
with :func:`start_session() <Marionette.start_session>`:
|
|
|
|
.. parsed-literal::
|
|
client = Marionette('localhost', port=2828)
|
|
client.start_session()
|
|
|
|
This returns a session id and an object listing the capabilities of the
|
|
Marionette server. For example, a server running on a Firefox OS device will
|
|
have the ability to rotate the window, while a server running from Firefox
|
|
won't. It's also possible to access the capabilities using the
|
|
:attr:`~Marionette.session_capabilities` attribute. After finishing with a
|
|
session, you can delete it with :func:`~Marionette.delete_session()`. Note that
|
|
this will also happen automatically when the Marionette object is garbage
|
|
collected.
|
|
|
|
Context Management
|
|
------------------
|
|
Commands can only be executed in a single window, frame and scope at a time. In
|
|
order to run commands elsewhere, it's necessary to explicitly switch to the
|
|
appropriate context.
|
|
|
|
Use :func:`~Marionette.switch_to_window` to execute commands in the context of a
|
|
new window:
|
|
|
|
.. parsed-literal::
|
|
original_window = client.current_window_handle
|
|
for handle in client.window_handles:
|
|
if handle != original_window:
|
|
client.switch_to_window(handle)
|
|
print("Switched to window with '{}' loaded.".format(client.get_url()))
|
|
client.switch_to_window(original_window)
|
|
|
|
Similarly, use :func:`~Marionette.switch_to_frame` to execute commands in the
|
|
context of a new frame (e.g an <iframe> element):
|
|
|
|
.. parsed-literal::
|
|
iframe = client.find_element(By.TAG_NAME, 'iframe')
|
|
client.switch_to_frame(iframe)
|
|
assert iframe == client.get_active_frame()
|
|
|
|
Finally Marionette can switch between `chrome` and `content` scope. Chrome is a
|
|
privileged scope where you can access things like the Firefox UI itself or the
|
|
system app in Firefox OS. Content scope is where things like webpages or normal
|
|
Firefox OS apps live. You can switch between `chrome` and `content` using the
|
|
:func:`~Marionette.set_context` and :func:`~Marionette.using_context` functions:
|
|
|
|
.. parsed-literal::
|
|
client.set_context(client.CONTEXT_CONTENT)
|
|
# content scope
|
|
with client.using_context(client.CONTEXT_CHROME):
|
|
#chrome scope
|
|
... do stuff ...
|
|
# content scope restored
|
|
|
|
|
|
Navigation
|
|
----------
|
|
|
|
Use :func:`~Marionette.navigate` to open a new website. It's also possible to
|
|
move through the back/forward cache using :func:`~Marionette.go_forward` and
|
|
:func:`~Marionette.go_back` respectively. To retrieve the currently
|
|
open website, use :func:`~Marionette.get_url`:
|
|
|
|
.. parsed-literal::
|
|
url = 'http://mozilla.org'
|
|
client.navigate(url)
|
|
client.go_back()
|
|
client.go_forward()
|
|
assert client.get_url() == url
|
|
|
|
|
|
DOM Elements
|
|
------------
|
|
|
|
In order to inspect or manipulate actual DOM elements, they must first be found
|
|
using the :func:`~Marionette.find_element` or :func:`~Marionette.find_elements`
|
|
methods:
|
|
|
|
.. parsed-literal::
|
|
from marionette import HTMLElement
|
|
element = client.find_element(By.ID, 'my-id')
|
|
assert type(element) == HTMLElement
|
|
elements = client.find_elements(By.TAG_NAME, 'a')
|
|
assert type(elements) == list
|
|
|
|
For a full list of valid search strategies, see :doc:`advanced/findelement`.
|
|
|
|
Now that an element has been found, it's possible to manipulate it:
|
|
|
|
.. parsed-literal::
|
|
element.click()
|
|
element.send_keys('hello!')
|
|
print(element.get_attribute('style'))
|
|
|
|
For the full list of possible commands, see the :class:`HTMLElement`
|
|
reference.
|
|
|
|
Be warned that a reference to an element object can become stale if it was
|
|
modified or removed from the document. See :doc:`advanced/stale` for tips
|
|
on working around this limitation.
|
|
|
|
Script Execution
|
|
----------------
|
|
|
|
Sometimes Marionette's provided APIs just aren't enough and it is necessary to
|
|
run arbitrary javascript. This is accomplished with the
|
|
:func:`~Marionette.execute_script` and :func:`~Marionette.execute_async_script`
|
|
functions. They accomplish what their names suggest, the former executes some
|
|
synchronous JavaScript, while the latter provides a callback mechanism for
|
|
running asynchronous JavaScript:
|
|
|
|
.. parsed-literal::
|
|
result = client.execute_script("return arguments[0] + arguments[1];",
|
|
script_args=[2, 3])
|
|
assert result == 5
|
|
|
|
The async method works the same way, except it won't return until a special
|
|
`marionetteScriptFinished()` function is called:
|
|
|
|
.. parsed-literal::
|
|
result = client.execute_async_script("""
|
|
setTimeout(function() {
|
|
marionetteScriptFinished("all done");
|
|
}, arguments[0]);
|
|
""", script_args=[1000])
|
|
assert result == "all done"
|
|
|
|
Beware that running asynchronous scripts can potentially hang the program
|
|
indefinitely if they are not written properly. It is generally a good idea to
|
|
set a script timeout using :func:`~Marionette.set_script_timeout` and handling
|
|
`ScriptTimeoutException`.
|