diff options
Diffstat (limited to 'testing/marionette/client/docs/advanced/findelement.rst')
-rw-r--r-- | testing/marionette/client/docs/advanced/findelement.rst | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/testing/marionette/client/docs/advanced/findelement.rst b/testing/marionette/client/docs/advanced/findelement.rst new file mode 100644 index 000000000..abcbc8e89 --- /dev/null +++ b/testing/marionette/client/docs/advanced/findelement.rst @@ -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 |