Browser tools (reahl-browsertools)¶
Reahl browser tools provides an interface to Selenium WebDriver that simplifies tests that deal with ajax. It also includes programmatically composable XPaths that are easy to read in code.
See also
Composing XPaths programmatically¶
XPath
can be used to compose complicated XPath expressions in a readable, consistent way.
Creating an XPath¶
To create an XPath
, call a class method for a simple element:
>>> from reahl.browsertools.browsertools import XPath
>>> XPath.div()
XPath('//div')
To obtain the raw xpath expression, cast an XPath
to a string:
>>> str(XPath.div())
'//div'
Composing expressions¶
Call methods on an XPath
instance to compose a larger expression:
>>> XPath.div().including_class('myclass')
XPath('//div[contains(concat(" ", @class, " "), " myclass ")]')
These methods can be chained, since each one returns an XPath
:
>>> XPath.div().including_class('myclass').including_text('hello')
XPath('//div[contains(concat(" ", @class, " "), " myclass ")][contains(normalize-space(), normalize-space("hello"))]')
Since methods like including_text()
can be called on any XPath
, you get
standardised behaviour such as that spaces are always normalised: if you pass text with a single space in it, but
the HTML is laid out with more than one space, the resulting expression will still match.
Less simple starting elements¶
Some XPath
class methods can find elements that are not so easily composable, such as
input_labelled()
,
button_labelled()
,
fieldset_with_legend()
or
table_cell_aligned_to()
.
XPath
s inside other XPath
s¶
An XPath
can also be located inside of another:
XPath.button_labelled('Save').inside_of(XPath.div().including_class('myclass'))
Smart browser interfaces¶
Websites with embedded JavaScript add more fluff to test code: you often have to first wait for an element to appear before you can click on it, for example.
DriverBrowser
contains a number of methods to simulate a human interacting with the browser, such
as click()
:
browser.click(XPath.button_labelled('Save'))
These methods always automatically wait for the operated-on element to appear, so you don’t have to write that in
your tests. Where sensible, they also wait for possible ajax action to complete before returning, as in the case
with type()
:
browser.type(XPath.input_labelled('Percentage'), '99')
Why wait? Because typing a value and tabbing out to the next field might trigger changes to the page. You want to wait for the page to change before performing another action.
For consistency when not using webdriver, Browser
provides a similar interface to WebTest. This makes for faster tests
where an actual browser and JavaScript are not required.