mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-21 01:37:16 +00:00
Bug 1088666 - Re-organize marionette client's documentation into basic, advanced and api reference sections, r=AutomatedTester, DONTBUILD because NPOTB
--HG-- extra : rebase_source : 4dc97864c6944d1b102ab7ab98287b480fe51ad7
This commit is contained in:
parent
0e7807d54c
commit
e2f5e08b80
46
testing/marionette/client/docs/advanced/actions.rst
Normal file
46
testing/marionette/client/docs/advanced/actions.rst
Normal file
@ -0,0 +1,46 @@
|
||||
Actions
|
||||
=======
|
||||
|
||||
.. py:currentmodule:: marionette
|
||||
|
||||
Action Sequences
|
||||
----------------
|
||||
|
||||
:class:`Actions` are designed as a way to simulate user input as closely as possible
|
||||
on a touch device like a smart phone. A common operation is to tap the screen
|
||||
and drag your finger to another part of the screen and lift it off.
|
||||
|
||||
This can be simulated using an Action::
|
||||
|
||||
from marionette import Actions
|
||||
|
||||
start_element = marionette.find_element('id', 'start')
|
||||
end_element = marionette.find_element('id', 'end')
|
||||
|
||||
action = Actions(marionette)
|
||||
action.press(start_element).wait(1).move(end_element).release()
|
||||
action.perform()
|
||||
|
||||
This will simulate pressing an element, waiting for one second, moving the
|
||||
finger over to another element and then lifting the finger off the screen. The
|
||||
wait is optional in this case, but can be useful for simulating delays typical
|
||||
to a users behaviour.
|
||||
|
||||
Multi-Action Sequences
|
||||
----------------------
|
||||
|
||||
Sometimes it may be necessary to simulate multiple actions at the same time.
|
||||
For example a user may be dragging one finger while tapping another. This is
|
||||
where :class:`MultiActions` come in. MultiActions are simply a way of combining
|
||||
two or more actions together and performing them all at the same time::
|
||||
|
||||
action1 = Actions(marionette)
|
||||
action1.press(start_element).move(end_element).release()
|
||||
|
||||
action2 = Actions(marionette)
|
||||
action2.press(another_element).wait(1).release()
|
||||
|
||||
multi = MultiActions(marionette)
|
||||
multi.add(action1)
|
||||
multi.add(action2)
|
||||
multi.perform()
|
54
testing/marionette/client/docs/advanced/debug.rst
Normal file
54
testing/marionette/client/docs/advanced/debug.rst
Normal file
@ -0,0 +1,54 @@
|
||||
Debugging
|
||||
=========
|
||||
|
||||
.. py:currentmodule:: marionette
|
||||
|
||||
Sometimes when working with Marionette you'll run into unexpected behaviour and
|
||||
need to do some debugging. This page outlines some of the Marionette methods
|
||||
that can be useful to you.
|
||||
|
||||
Please note that the best tools for debugging are the `ones that ship with
|
||||
Gecko`_. This page doesn't describe how to use those with Marionette. Also see
|
||||
a related topic about `using the debugger with Marionette`_ on MDN.
|
||||
|
||||
.. _ones that ship with Gecko: https://developer.mozilla.org/en-US/docs/Tools
|
||||
.. _using the debugger with Marionette: https://developer.mozilla.org/en-US/docs/Marionette/Debugging
|
||||
|
||||
|
||||
Storing Logs on the Server
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
By calling `~Marionette.log` it is possible to store a message on the server.
|
||||
Logs can later be retrieved using `~Marionette.get_logs`. For example::
|
||||
|
||||
try:
|
||||
marionette.log("Sending a click event") # logged at INFO level
|
||||
elem.click()
|
||||
except:
|
||||
marionette.log("Something went wrong!", "ERROR")
|
||||
|
||||
print(marionette.get_logs())
|
||||
|
||||
Disclaimer: Example for illustrative purposes only, don't actually hide
|
||||
tracebacks like that!
|
||||
|
||||
|
||||
Seeing What's on the Page
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sometimes it's difficult to tell what is actually on the page that is being
|
||||
manipulated. Either because it happens too fast, the window isn't big enough or
|
||||
you are manipulating a remote server! There are two methods that can help you
|
||||
out. The first is `~Marionette.screenshot`::
|
||||
|
||||
marionette.screenshot() # takes screenshot of entire frame
|
||||
elem = marionette.find_element(By.ID, 'some-div')
|
||||
marionette.screenshot(elem) # takes a screenshot of only the given element
|
||||
|
||||
Sometimes you just want to see the DOM layout. You can do this with the
|
||||
`~Marionette.page_source` property. Note that the page source depends on the
|
||||
context you are in::
|
||||
|
||||
print(marionette.page_source)
|
||||
marionette.set_context('chrome')
|
||||
print(marionette.page_source)
|
126
testing/marionette/client/docs/advanced/findelement.rst
Normal file
126
testing/marionette/client/docs/advanced/findelement.rst
Normal file
@ -0,0 +1,126 @@
|
||||
Finding Elements
|
||||
================
|
||||
.. py:currentmodule:: marionette
|
||||
|
||||
One of the most common and yet often most difficult tasks in Marionette is
|
||||
finding a DOM element on a webpage or in the chrome UI. Marionette provides
|
||||
several different search strategies to use when finding elements. All search
|
||||
strategies work with both :func:`~Marionette.find_element` and
|
||||
:func:`~Marionette.find_elements`, though some strategies are not implemented
|
||||
in chrome scope.
|
||||
|
||||
In the event that more than one element is matched by the query,
|
||||
:func:`~Marionette.find_element` will only return the first element found. In
|
||||
the event that no elements are matched by the query,
|
||||
:func:`~Marionette.find_element` will raise `NoSuchElementException` while
|
||||
:func:`~Marionette.find_elements` will return an empty list.
|
||||
|
||||
Search Strategies
|
||||
-----------------
|
||||
|
||||
Search strategies are defined in the :class:`By` class::
|
||||
|
||||
from marionette import By
|
||||
print(By.ID)
|
||||
|
||||
The strategies are:
|
||||
|
||||
* `id` - The easiest way to find an element is to refer to its id directly::
|
||||
|
||||
container = client.find_element(By.ID, 'container')
|
||||
|
||||
* `class name` - To find elements belonging to a certain class, use `class name`::
|
||||
|
||||
buttons = client.find_elements(By.CLASS_NAME, 'button')
|
||||
|
||||
* `css selector` - It's also possible to find elements using a `css selector`_::
|
||||
|
||||
container_buttons = client.find_elements(By.CSS_SELECTOR, '#container .buttons')
|
||||
|
||||
* `name` - Find elements by their name attribute (not implemented in chrome
|
||||
scope)::
|
||||
|
||||
form = client.find_element(By.NAME, 'signup')
|
||||
|
||||
* `tag name` - To find all the elements with a given tag, use `tag name`::
|
||||
|
||||
paragraphs = client.find_elements(By.TAG_NAME, 'p')
|
||||
|
||||
* `link text` - A convenience strategy for finding link elements by their
|
||||
innerHTML (not implemented in chrome scope)::
|
||||
|
||||
link = client.find_element(By.LINK_TEXT, 'Click me!')
|
||||
|
||||
* `partial link text` - Same as `link text` except substrings of the innerHTML
|
||||
are matched (not implemented in chrome scope)::
|
||||
|
||||
link = client.find_element(By.PARTIAL_LINK_TEXT, 'Clic')
|
||||
|
||||
* `xpath` - Find elements using an xpath_ query::
|
||||
|
||||
elem = client.find_element(By.XPATH, './/*[@id="foobar"')
|
||||
|
||||
.. _css selector: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors
|
||||
.. _xpath: https://developer.mozilla.org/en-US/docs/Web/XPath
|
||||
|
||||
|
||||
|
||||
Chaining Searches
|
||||
-----------------
|
||||
|
||||
In addition to the methods on the Marionette object, HTMLElement objects also
|
||||
provide :func:`~HTMLElement.find_element` and :func:`~HTMLElement.find_elements`
|
||||
methods. The difference is that only child nodes of the element will be searched.
|
||||
Consider the following html snippet::
|
||||
|
||||
<div id="content">
|
||||
<span id="main"></span>
|
||||
</div>
|
||||
<div id="footer"></div>
|
||||
|
||||
Doing the following will work::
|
||||
|
||||
client.find_element(By.ID, 'container').find_element(By.ID, 'main')
|
||||
|
||||
But this will raise a `NoSuchElementException`::
|
||||
|
||||
client.find_element(By.ID, 'container').find_element(By.ID, 'footer')
|
||||
|
||||
|
||||
Finding Anonymous Nodes
|
||||
-----------------------
|
||||
|
||||
When working in chrome scope, for example manipulating the Firefox user
|
||||
interface, you may run into something called an anonymous node.
|
||||
|
||||
Firefox uses a markup language called XUL_ for its interface. XUL is similar
|
||||
to HTML in that it has a DOM and tags that render controls on the display. One
|
||||
ability of XUL is to create re-useable widgets that are made up out of several
|
||||
smaller XUL elements. These widgets can be bound to the DOM using something
|
||||
called the `XML binding language (XBL)`_.
|
||||
|
||||
The end result is that the DOM sees the widget as a single entity. It doesn't
|
||||
know anything about how that widget is made up. All of the smaller XUL elements
|
||||
that make up the widget are called `anonymous content`_. It is not possible to
|
||||
query such elements using traditional DOM methods like `getElementById`.
|
||||
|
||||
Marionette provides two special strategies used for finding anonymous content.
|
||||
Unlike normal elements, anonymous nodes can only be seen by their parent. So
|
||||
it's necessary to first find the parent element and then search for the
|
||||
anonymous children from there.
|
||||
|
||||
* `anon` - Finds all anonymous children of the element, there is no search term
|
||||
so `None` must be passed in::
|
||||
|
||||
anon_children = client.find_element('id', 'parent').find_elements('anon', None)
|
||||
|
||||
* `anon attribute` - Find an anonymous child based on an attribute. An
|
||||
unofficial convention is for anonymous nodes to have an
|
||||
`anonid` attribute::
|
||||
|
||||
anon_child = client.find_element('id', 'parent').find_element('anon attribute', {'anonid': 'container'})
|
||||
|
||||
|
||||
.. _XUL: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL
|
||||
.. _XML binding language (XBL): https://developer.mozilla.org/en-US/docs/XBL
|
||||
.. _anonymous content: https://developer.mozilla.org/en-US/docs/XBL/XBL_1.0_Reference/Anonymous_Content
|
13
testing/marionette/client/docs/advanced/landing.rst
Normal file
13
testing/marionette/client/docs/advanced/landing.rst
Normal file
@ -0,0 +1,13 @@
|
||||
Advanced Topics
|
||||
===============
|
||||
|
||||
Here are a collection of articles explaining some of the more complicated
|
||||
aspects of Marionette.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
findelement
|
||||
stale
|
||||
actions
|
||||
debug
|
71
testing/marionette/client/docs/advanced/stale.rst
Normal file
71
testing/marionette/client/docs/advanced/stale.rst
Normal file
@ -0,0 +1,71 @@
|
||||
Dealing with Stale Elements
|
||||
===========================
|
||||
.. py:currentmodule:: marionette
|
||||
|
||||
Marionette does not keep a live representation of the DOM saved. All it can do
|
||||
is send commands to the Marionette server which queries the DOM on the client's
|
||||
behalf. References to elements are also not passed from server to client. A
|
||||
unique id is generated for each element that gets referenced and a mapping of
|
||||
id to element object is stored on the server. When commands such as
|
||||
:func:`~HTMLElement.click()` are run, the client sends the element's id along
|
||||
with the command. The server looks up the proper DOM element in its reference
|
||||
table and executes the command on it.
|
||||
|
||||
In practice this means that the DOM can change state and Marionette will never
|
||||
know until it sends another query. For example, look at the following HTML::
|
||||
|
||||
<head>
|
||||
<script type=text/javascript>
|
||||
function addDiv() {
|
||||
var div = document.createElement("div");
|
||||
document.getElementById("container").appendChild(div);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
</div>
|
||||
<input id="button" type=button onclick="addDiv();">
|
||||
</body>
|
||||
|
||||
Care needs to be taken as the DOM is being modified after the page has loaded.
|
||||
The following code has a race condition::
|
||||
|
||||
button = client.find_element('id', 'button')
|
||||
button.click()
|
||||
assert len(client.find_elements('css selector', '#container div')) > 0
|
||||
|
||||
|
||||
Explicit Waiting and Expected Conditions
|
||||
----------------------------------------
|
||||
|
||||
To avoid the above scenario, manual synchronisation is needed. Waits are used
|
||||
to pause program execution until a given condition is true. This is a useful
|
||||
technique to employ when documents load new content or change after
|
||||
``Document.readyState``'s value changes to "complete".
|
||||
|
||||
The :class:`Wait` helper class provided by Marionette avoids some of the
|
||||
caveats of ``time.sleep(n)``. It will return immediately once the provided
|
||||
condition evaluates to true.
|
||||
|
||||
To avoid the race condition in the above example, one could do::
|
||||
|
||||
button = client.find_element('id', 'button')
|
||||
button.click()
|
||||
|
||||
def find_divs():
|
||||
return client.find_elements('css selector', '#container div')
|
||||
|
||||
divs = Wait(client).until(find_divs)
|
||||
assert len(divs) > 0
|
||||
|
||||
This avoids the race condition. Because finding elements is a common condition
|
||||
to wait for, it is built in to Marionette. Instead of the above, you could
|
||||
write::
|
||||
|
||||
button = client.find_element('id', 'button')
|
||||
button.click()
|
||||
assert len(Wait(client).until(expected.elements_present('css selector', '#container div'))) > 0
|
||||
|
||||
For a full list of built-in conditions, see :mod:`~marionette.expected`.
|
185
testing/marionette/client/docs/basics.rst
Normal file
185
testing/marionette/client/docs/basics.rst
Normal file
@ -0,0 +1,185 @@
|
||||
.. py:currentmodule:: 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`.
|
@ -95,8 +95,20 @@ pygments_style = 'sphinx'
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
|
||||
html_theme = 'default'
|
||||
|
||||
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||
|
||||
if not on_rtd:
|
||||
try:
|
||||
import sphinx_rtd_theme
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
|
@ -1,220 +1,16 @@
|
||||
.. Marionette Python Client documentation master file, created by
|
||||
sphinx-quickstart on Tue Aug 6 13:54:46 2013.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
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).
|
||||
|
||||
.. _Marionette: https://developer.mozilla.org/en-US/docs/Marionette
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
Getting the Client
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
We officially support a python client. The latest supported version of
|
||||
the client is available on pypi_, so you can download it via pip.
|
||||
This client should be used within a virtual environment to ensure that
|
||||
your environment is pristine:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
virtualenv venv
|
||||
source venv/bin/activate
|
||||
pip install marionette_client
|
||||
|
||||
.. _pypi: https://pypi.python.org/pypi/marionette_client/
|
||||
|
||||
Using the Client Interactively
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Once you installed the client and have Marionette running, you can fire
|
||||
up your favourite interactive python environment and start playing with
|
||||
Marionette. Let's use a typical python shell:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
python
|
||||
|
||||
First, import Marionette:
|
||||
|
||||
.. parsed-literal::
|
||||
from marionette import Marionette
|
||||
|
||||
Now create the client for this session. Assuming you're using the default
|
||||
port on a Marionette instance running locally:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
client = Marionette(host='localhost', port=2828)
|
||||
client.start_session()
|
||||
|
||||
This will return some id representing your session id. Now that you've
|
||||
established a connection, let's start doing interesting things:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
client.execute_script("alert('o hai there!');")
|
||||
|
||||
You should now see this alert pop up! How exciting! Okay, let's do
|
||||
something practical. Close the dialog and try this:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
client.navigate("http://www.mozilla.org")
|
||||
|
||||
Now you're at mozilla.org! You can even verify it using the following:
|
||||
|
||||
.. parsed-literal::
|
||||
client.get_url()
|
||||
|
||||
You can even find an element and click on it. Let's say you want to get
|
||||
the first link:
|
||||
|
||||
.. parsed-literal::
|
||||
first_link = client.find_element("tag name", "a")
|
||||
|
||||
first_link now holds a reference to the first link on the page. You can click it:
|
||||
|
||||
.. parsed-literal::
|
||||
first_link.click()
|
||||
|
||||
Using the Client for Testing
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Please visit, our `Marionette Tests`_ section for information regarding testing.
|
||||
|
||||
.. _Marionette Tests: https://developer.mozilla.org/en/Marionette/Tests
|
||||
|
||||
.. automodule:: marionette
|
||||
|
||||
Marionette Objects
|
||||
------------------
|
||||
.. autoclass:: Marionette
|
||||
|
||||
Session Management
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
.. automethod:: Marionette.start_session
|
||||
.. automethod:: Marionette.delete_session
|
||||
.. autoattribute:: Marionette.session_capabilities
|
||||
.. automethod:: Marionette.get_cookie
|
||||
.. automethod:: Marionette.get_cookies
|
||||
.. automethod:: Marionette.add_cookie
|
||||
.. automethod:: Marionette.delete_all_cookies
|
||||
|
||||
Context Management
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
.. autoattribute:: Marionette.current_window_handle
|
||||
.. autoattribute:: Marionette.window_handles
|
||||
.. automethod:: Marionette.set_context
|
||||
.. automethod:: Marionette.switch_to_frame
|
||||
.. automethod:: Marionette.switch_to_window
|
||||
.. automethod:: Marionette.get_active_frame
|
||||
.. automethod:: Marionette.close
|
||||
|
||||
Navigation Methods
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
.. autoattribute:: Marionette.title
|
||||
.. automethod:: Marionette.navigate
|
||||
.. automethod:: Marionette.get_url
|
||||
.. automethod:: Marionette.go_back
|
||||
.. automethod:: Marionette.go_forward
|
||||
.. automethod:: Marionette.refresh
|
||||
.. automethod:: Marionette.absolute_url
|
||||
.. automethod:: Marionette.get_window_type
|
||||
|
||||
DOM Element Methods
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
.. automethod:: Marionette.set_search_timeout
|
||||
.. automethod:: Marionette.find_element
|
||||
.. automethod:: Marionette.find_elements
|
||||
|
||||
Script Execution
|
||||
^^^^^^^^^^^^^^^^
|
||||
.. automethod:: Marionette.execute_script
|
||||
.. automethod:: Marionette.execute_async_script
|
||||
.. automethod:: Marionette.set_script_timeout
|
||||
|
||||
Debugging
|
||||
^^^^^^^^^
|
||||
.. autoattribute:: Marionette.page_source
|
||||
.. automethod:: Marionette.log
|
||||
.. automethod:: Marionette.get_logs
|
||||
.. automethod:: Marionette.screenshot
|
||||
|
||||
Querying and Modifying Document Content
|
||||
---------------------------------------
|
||||
.. autoclass:: HTMLElement
|
||||
:members:
|
||||
|
||||
.. autoclass:: DateTimeValue
|
||||
:members:
|
||||
|
||||
Action Objects
|
||||
--------------
|
||||
|
||||
Action Sequences
|
||||
^^^^^^^^^^^^^^^^
|
||||
.. autoclass:: Actions
|
||||
:members:
|
||||
|
||||
Multi-action Sequences
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
.. autoclass:: MultiActions
|
||||
:members:
|
||||
|
||||
Explicit Waiting and Expected Conditions
|
||||
----------------------------------------
|
||||
|
||||
Waits are used to pause program execution
|
||||
until a given condition is true.
|
||||
This is a useful technique to employ
|
||||
when documents load new content or change
|
||||
after ``Document.readyState``'s value changes to "complete".
|
||||
|
||||
Because Marionette returns control to the user
|
||||
when the document is completely loaded,
|
||||
any subsequent interaction with elements
|
||||
are subject to manual synchronisation.
|
||||
The reason for this is that Marionette
|
||||
does not keep a direct representation of the DOM,
|
||||
but instead exposes a way for the user to
|
||||
query the browser's DOM state.
|
||||
|
||||
The `Wait` helper class provided by Marionette
|
||||
avoids some of the caveats of ``time.sleep(n)``,
|
||||
which sets the condition to an exact time period to wait.
|
||||
It will return immediately
|
||||
once the provided condition evaluates to true.
|
||||
|
||||
In addition to writing your own custom conditions
|
||||
you can combine `Wait`
|
||||
with a number of ready-made expected conditions
|
||||
that are listed below.
|
||||
|
||||
Waits
|
||||
^^^^^
|
||||
.. autoclass:: marionette.wait.Wait
|
||||
:members:
|
||||
:special-members:
|
||||
.. autoattribute marionette.wait.DEFAULT_TIMEOUT
|
||||
.. autoattribute marionette.wait.DEFAULT_INTERVAL
|
||||
|
||||
Expected Conditions
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
.. automodule:: marionette.expected
|
||||
:members:
|
||||
.. include:: basics.rst
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
------------------
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
Getting Started <basics>
|
||||
Interactive Tutorial <interactive>
|
||||
advanced/landing
|
||||
reference
|
||||
|
55
testing/marionette/client/docs/interactive.rst
Normal file
55
testing/marionette/client/docs/interactive.rst
Normal file
@ -0,0 +1,55 @@
|
||||
Using the Client Interactively
|
||||
==============================
|
||||
|
||||
Once you installed the client and have Marionette running, you can fire
|
||||
up your favourite interactive python environment and start playing with
|
||||
Marionette. Let's use a typical python shell:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
python
|
||||
|
||||
First, import Marionette:
|
||||
|
||||
.. parsed-literal::
|
||||
from marionette import Marionette
|
||||
|
||||
Now create the client for this session. Assuming you're using the default
|
||||
port on a Marionette instance running locally:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
client = Marionette(host='localhost', port=2828)
|
||||
client.start_session()
|
||||
|
||||
This will return some id representing your session id. Now that you've
|
||||
established a connection, let's start doing interesting things:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
client.execute_script("alert('o hai there!');")
|
||||
|
||||
You should now see this alert pop up! How exciting! Okay, let's do
|
||||
something practical. Close the dialog and try this:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
client.navigate("http://www.mozilla.org")
|
||||
|
||||
Now you're at mozilla.org! You can even verify it using the following:
|
||||
|
||||
.. parsed-literal::
|
||||
client.get_url()
|
||||
|
||||
You can even find an element and click on it. Let's say you want to get
|
||||
the first link:
|
||||
|
||||
.. parsed-literal::
|
||||
from marionette import By
|
||||
first_link = client.find_element(By.TAG_NAME, "a")
|
||||
|
||||
first_link now holds a reference to the first link on the page. You can click it:
|
||||
|
||||
.. parsed-literal::
|
||||
first_link.click()
|
||||
|
43
testing/marionette/client/docs/reference.rst
Normal file
43
testing/marionette/client/docs/reference.rst
Normal file
@ -0,0 +1,43 @@
|
||||
=============
|
||||
API Reference
|
||||
=============
|
||||
.. py:currentmodule:: marionette
|
||||
|
||||
Marionette
|
||||
----------
|
||||
.. autoclass:: Marionette
|
||||
:members:
|
||||
|
||||
HTMLElement
|
||||
-----------
|
||||
.. autoclass:: HTMLElement
|
||||
:members:
|
||||
|
||||
DateTimeValue
|
||||
-------------
|
||||
.. autoclass:: DateTimeValue
|
||||
:members:
|
||||
|
||||
Actions
|
||||
-------
|
||||
.. autoclass:: Actions
|
||||
:members:
|
||||
|
||||
MultiActions
|
||||
------------
|
||||
.. autoclass:: MultiActions
|
||||
:members:
|
||||
|
||||
Wait
|
||||
----
|
||||
|
||||
.. autoclass:: Wait
|
||||
:members:
|
||||
:special-members:
|
||||
.. autoattribute marionette.wait.DEFAULT_TIMEOUT
|
||||
.. autoattribute marionette.wait.DEFAULT_INTERVAL
|
||||
|
||||
Built-in Conditions
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
.. automodule:: marionette.expected
|
||||
:members:
|
Loading…
x
Reference in New Issue
Block a user