Update Mar 2014: Whilst this post is 4 years old now, it is still relevant, and still gets a lot of hits. However, I found a great site with really detailed explanations of many types of Selenium Locators – see How to use Locators in Selenium IDE.
I was writing this in an email to a client to I decided to make a post of it. When using Selenium for web testing (see my previous post on Selenium), these are the some tips I have found when creating Selenium Element Locators.
Element Locators are the way of finding the HTML element on the page to perform a Selenium action on. The Selenium reference for Element Locators can be found here and the excellent Selenium documentation here. Element Locators can be a simple as the name of the HTML element or a very complex XPath reference or you even may need to use a combination of different selenium commands on the one locator to perform an action to fire off a javascript event.
In a perfect world every HTML element on the page we are testing with Selenium will have a unique name or ID that we can always reference. Unfortunately, we are usually doing black box testing and have no access to the developer and need to work around the absence of unique names to find the correct elements. Also, some web coding systems like ExtJS recreate the element ID’s each time the application is run – which makes it difficult (see my previous post on working around this).
Below are my tips for the way to use Element Locators from the simplest to the most complex way. The simpler the element locator the less likely the test is to fail in future, and it is easy to read when coming back to the test later. Complex XPath elements may be required, but they may also be very fragile and one small change on the website may break the test in future. Note: This does not cover speed of locating the elements, there are many other blog posts about that – XPath may be slower, but sometimes it is the only way.
1. Direct Reference
Using one of the direct references to the HTML element via the Name or, the ID. This is the most straightforward way of finding the correct element.
Id=MyButton (note in this case, “Id =” is not even required)
Name=Description_Field
Value=ABC XYZ
Link=Contact Us
2. DOM or CSS
This is still very straightforward but can be a little bit harder to read next time you come back to it, and requires some knowledge of HTML and CSS. See the Selenium documentation for locating by DOM or locating by CSS for more information.
dom=document.images[0] (the first image in the page)
css=H1.topic (the first heading with the class name of topic) or css=h1.topic[value=”Topic Index”] (the heading with the specific text)
3. XPath References
I would even divide this into 2 sections – simple and complex XPath References. My favourite XPath resources are the W3Schools reference and the Zvon Tutorials. There is also the great content and links in the Selenium Wiki
3a. Simple XPath
Relatively straightforward to compose and read later down the track.
//td[text()=’My Cell Contents’] (the first table cell with the specified text) or even the very useful //td[normalize-space(text())=’My Cell Contents’] (for finding text that is surrounded by spaces).
//p[contains(text(), ‘My Para Contents’)]
//div(@class=’MyClass’)
//input[contains(@id, ‘myTextField’)]
3b. Complex XPath
These may be necessary if there are no unique ID’s or names in elements nearby the element you need to click on. Try not to use the raw XPath that Selenium records with (See the great post by Browser Mob on this topic), but refine the XPath to be a bit more robust and readable in future.
Remember, when dealing with Xpath’s Firebug is your friend – and for advanced users, try the Xpath $X command in the Console in Firebug (as detailed in the Browser Mob post or here) . There is also XPather to help you find XPath queries.
/html/body/div[1]/div[5]/div/table/tbody/tr/td/p/a[3] (An example bad XPath – it will break as soon as the page layout changes a bit)
//td[contains(text()),’My Label’]/following-sibling::td[2]/input (an un-named input box that has a known label 2 table cells away from it).
There are many more commands I could put here but they will not mean much except to the person who knows the website under test. I have used very complex Xpath expressions for finding even the most obscure of elements that do not have a unique name. Eg a text box on a Pop Up dialog that was actually just a series of Div’s. I found the Pop Up box’s Title, traversed up the DOM using the ../ command to find the Div containing the whole Pop Up box, then use // to search within that div for the specific text box (even using the search for the label trick above). It was the only way as even the label was not unique on the page.
4. Click and Mouse Events
Sometimes to replicate a specific Javascript event that occurs, there are a few tricks that need to be tried. The Javascript may not activate on the selenium Click event. It may actually activated on the Mouse Up Event. There is no way to know this except testing each different scenario (if you don’t have access to the developer, who may be able to help).
Some of the useful commands are:
- Click and ClickAt
- MouseDown and MouseDownAt
- MouseUp and MouseUpAt
- MouseMove and MouseMoveAt
- DragDrop (useful for moving slider bars that calls a JavaScript event to change a value when the slider is moved).
You usually need to use these in combination with each other.
eg doing a ClickAt, MouseDownAt and MouseUpAt in sequence on the same locator, may actually make the Javascript work, whereas a Click will not.
5. Keyboard and Coordinates
If all else fails (and believe me, sometimes it will), you may actually have to resort to using key press events on locators to get the right action (or even just to fill text into a stubborn text field).
Usually the Type command works fine, but there may be cases where the javascript is called after every single key press and you need to replicate that (eg like the Google search box that shows the results after each key stroke).
You can also go to the extreme of KeyDown and KeyUp – rather than the equivalent command of KeyPress as the Javascript may be called on KeyUp. Have a look at the great post by Nathanel Boehm on his efforts to use Selenium for keyboard commands to test a website for keyboard only accessibility – I thought this was a fantastic use for Selenium and shows just how powerful it is.
In the absolute worst case scenario you could use a ClickAt event with X,Y coordinates from the top left hand corner of the page. Fortunately, in all the extremely complex Selenium testing I have done, I have not had to resort to this method. I have found that even if it takes a while, there is usually a way to find the locator and work with it using one of the tricks listed above.