![]() |
version seven.   http://demongin.org |
Using xpaths to Write Better Selenium Test Scripts in Python
Two example of how to use xpaths in test scripts written in python: first, how to count input boxes in a fieldset; second, how to find the text value for a th tag.
Monday, 2010-01-11 | Careerism, Programming, Testing
| XPath uses path expressions to select nodes or node-sets in an XML document. These path expressions look very much like the expressions you see when you work with a traditional computer file system. |
| w3schools.com |
One of the advantages of writing test scripts for web applications with Selenium is that you can use xpaths to find elements of your HTML source. In this way, Selenium can make test-writing a task that is not totally unlike using BeautifulSoup to scrape or interact with an HTML document.
Obviously, if you're working on commercial code, your source code will include a lot of a id and value tags. You'll often see things like this:
<div style="margin-top: 10px;"> <label for="j_password">Password:</label> <input id="j_password" name="j_password" size="18" type="password" /> </div>
sel.type("j_password", "my password")
<form target=""> <fieldset class="basic"> <label>Name:</label><input id="_id75:_id77" name="_id75:_id77" value="" size="15" type="text" /> <label>Handle:</label><input id="_id75:_id79" name="_id75:_id79" value="" size="10" type="text" /> </fieldset></form>
At first glance, the name and id values on the input tag are temping, but using what are very obviously randomly generated values in your tests is, as I've mentioned before, weak-sauce test-writing.
Those label tags won't help you either and the size and type attributes of theinput tag are subject to change and too vague (respectively).
The smart thing to do here is write an xpath statement using the fieldset class and the number of the input box you're looking for. This is a sort of "counting method" that is pretty safe to use in contexts where the form isn't subject to change. Check it out:
sel.type("//form[@target='']/fieldset[@class='basic']/input[1]", client_handle)
Now, suppose you were trying to automate the submission of a form that had UI code that had even fewer identifiers and could change dynamically (rendering the counting method used above out of the question). Imagine that you were working with a table that was generated on the fly, and produced code that looked like the following:
<tbody> <tr> <th>Primary Contact:</th> <td><input id="" name="editorForm:_id86" value="" type="text"></td> <th>Contact Phone:</th> <td><input id="" name="editorForm:_id88" value="" type="text"></td> </tr> </tbody>
At first glance, it looks like your engineers (or, more likely, their framework) have left you high and dry on this one: the tbody has neither an id nor a class, ditto the tr, the th, the td and the input.
Code like this is, without a doubt, tough to work with, when you're trying to write effective, scalable and durable tests.
Once again, however, knowing how to write xpaths saves the day, however, as you can find the input using the text within the th's. For the above code, you could fill that input thus:
sel.type("//tbody/tr/th[text()='Primary Contact:']/../td/input[1]", "Timothy O'Connell") sel.type("//tbody/tr/th[text()='Contact Phone:']/../td/input[1]", "123 456 7890")
