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.
Jodie Miners says
I’m sorry, I haven’t used Selenium in quite a while now. I suggest you get onto the Selenium help forums.
Dwarika Dhish Mishra says
Could you please help me in writing case insensitive search through Xpath Text
This is my query
Xapth is //span[text()=’Google Search’] and this xpath find the Google Search button but
I want to replace Google Search with google search or Google search or google Search but still i want that my xpath hit the same Google Search Button on Google Home page.
Here I have taken one example of google you may take any example to make me understand this query.
Jodie Miners says
I’m sorry, I haven’t used Selenium in quite a while now. I suggest you get onto the Selenium help forums.
raj3sh@gmail.com says
Hi Jodie
I am using Selenium IDe for the first time and I am getting the following error
[error] Element css=td[title=”Marianna Bertucci Ernst & Young Becket House 1 Lambeth Palace Road LONDON SE1 7EU”] not found
I am not sure how to get round this error.
The command for the above is a clicking on a returned set of search results.
Any help with this would be much appreciated
Bill says
Wow, this article is fastidious, my sister is analyzing these kinds of things,
therefore I am going to inform her.
Julie says
hello,
I’m currently using the Firefox plugin, Selenium IDE, I’m a complete newbie and I’m having trouble with a few test cases. There is one test case which requires me to select a folder from a list of folders that is produced dynamically, when I record the test with Selenium it saves the xpath (specifically:xpath=(//input[@type=’checkbox’])[3]) that is position dependent, so then when I test again it selects whatever folder is in the 3 checkbox, which is not what I want it to do. Any ideas with how to fix this?
Joris van de Ven says
Thanks for the info in this post Jodie, will be very helpfull I’m sure.
Ash says
hi Jodie,
Thanks for the post. I am new to selenium. Has anyone written right click code in selenium?
I am trying to do it with getSelenium().contextMenu(getLocator(dor)), but its throwing nullPointerException. Can anyone guide me please?
Thanks in advance,
Ash
rachitranjan says
Hi Jodie, i just stuck up to the situation that you have mentioned here,there is a flash object in my site,i want to hit to specific object(inside that flash),but i couldn’t able to…please help me !!
thanks again..:)
Krishnam1234 says
@Jodie
I could finally succeed in getting this working (y). Below is a sample working code for your reference.
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverBackedSelenium;
import com.thoughtworks.selenium.Selenium;
/**
* User Story: BI-32 – Write automated (selenium) test scripts for all the TG events
@Test
public void testApproveWorkflow() {
selenium.open(“http://localhost:8080/BizzForce/#”);
selenium.type(LoginForm.USERNAME_INPUT_FIELD, “admin”);
selenium.type(LoginForm.PASSWORD_INPUT_FIELD, “admin”);
selenium.click(LoginForm.LOGIN_BUTTON);
selenium.click(“id=render-grid”);
selenium.click(“//table[@id=’bf-grid’]/tbody/tr/td[1]/div[@class=’GMHeadLeft’]/table[@class=’GMSectionFF3′]/tbody/tr[2]/td[3]”);
selenium.click(“//table[@id=’bf-grid’]/tbody/tr/td[1]/div[@class=’GMHeadLeft’]/table[@class=’GMSectionFF3′]/tbody/tr[2]/td[3]”);
}
@After
public void finish() {
System.out.println(“Finished ” + testName + “…”);
System.out.println(“—–“);
nl.myapp.selenium.core.AssertHelper.checkForVerificationErrors();
}
}
Krishnam Raju says
This is one of the hardest exercises that I see many people have given up.. Aka TreeGrid testing. We either see very little help or see many people saying not possible to automate TreeGrid (including TreeeGrid developers).
Just want to give it a try if QA Folks can do some magic here 😉
Krishnam Raju says
Thanks for your reply Jodie. I found out from one of the blog posts that we can use SeleniumBackedWebDriver to do a trick. I tried the same with some reference and it indeed worked on the COQSoft webiste. However, the same does not work with our application. I guess, you can add some suggestions / tricks to get this working.
This could be a very good brain sharpening exercise to try selenium expertise. hehe
Thanks in advance 🙂
Reference Link: http://www.sencha.com/forum/showthread.php?142755-TreeGrid&p=681092
joe says
Thank you very much for taking the time to create this very useful post. I really appreciate it.
Jodie Miners says
The whole point of Selenium is that you should not need to use x,y coordinates. If you can’t find the item by a locator, it must mean you are using Flash or some other embedded object?
Amol says
Hi Jodie,
Please let me know how to click at specific xy coordinate without using locator ?
Jodie Miners says
@Krishnam
Without spending many hours remembering how I did the extremely complicated selenium testing I did a few years back, I’m sorry I can’t help you specifically.
I can say that Xpath is your friend. Use Xpath at all times instead of mouse events. You will need to learn how to traverse the DOM using Xpath and using the children or siblings to find the exact element ID to click on relative to a known element.
eg //td[contains(text()),’My Label’]/following-sibling::td[2]/input
You know the Div of the overall grid, you know the fixed labels or even fixed image names for the add button, so find those, then find the table or other element nearby this element that you know how to find.
Or use CSS selectors. This is one that I did not investigate fully, but could be very useful to you.
Whatever you do, it is going to be hard, and very time consuming. I know that Selenium can do it, as I have done it before, but I’m not convinced it was worth the effort, as the Selenium code ends up being very fragile as it is based on the Xpath references – as soon as a new version of the grid control is released – all your tests may need to be written again.
Krishnam Raju says
Hi Jodie, Nice Article.
I am however stuckup with mouseAt,MouseDown and MouseUp events while testing TreeGrid component. We have the below reply from TreeGrid when asked for info:
TreeGrid uses low
level DOM and JavaScript to be as fast as possible, especially it uses
innerHTML attribute as the fastest way of changing DOM, so the automated
testing tools usually fail on it. (We test TreeGrid always manually.)
This is an event log of pressing Add icon in Toolbar:
OnMouseDown: Cell [Toolbar,Add] at [11,7].
OnMouseUp: Cell [Toolbar,Add] at [11,7].
OnClick: User clicked cell [Toolbar,Add] at [11,7]. Cell value is ”.
OnCanRowAdd: Test if is possible add row to root as the last row
OnGenerateId: The identity attribute (id) of the row ” was set to ‘__’
OnSetRowId: The id attribute of the row ‘__’ was set to ‘__’
OnRowAdd: User ADDED new row ‘__’ to root as the last row
OnScroll: Grid was scrolled from position [0,15] to new position [0,16];
OnCalculate: row ‘__’ children are calculated
OnCalculate: TreeGrid is calculated
OnRowAdded: Row ‘__’ was sucessfully added
OnScroll: Grid was scrolled from position [0,16] to new position [0,30];
OnFocus: User focused cell [__,null]. Original focused cell was [none,none].
You can watch these events in TreeGrid “Extended JavaScript API example”
in “Universal local HTML and JavaScript API examples” section of our
downloadable TreeGridEval versions.
Ref URL:http://www.treegrid.com/treegrid/www/
Can you please help us with automating this?
Hugo says
Thank you very much for your post.The section you talked about 4. Click and Mouse Events solved my questions I have been dealing with for the past hours.
Jodie Miners says
Not at the moment, as I’m not working with Selenium right now…
Zain Mecklai says
Great post, are you planning any further posts on Selenium?
krish says
HI JODIE,
An Excellent article !!
I got a small trouble while using selenium in IDE 1.0.5 .I need to capture a value and retrieve back for example in google page , after results are displayed i need to capture value of time it took.Iam enclosing the code used by me to do it.when i run this i got a NULL value .Please help me out.
import com.thoughtworks.selenium.Selenium;
import org.openqa.selenium.*;
import org.openqa.selenium.htmlunit.*;
import org.openqa.selenium.firefox.*;
import org.openqa.selenium.chrome.*;
import org.openqa.selenium.ie.*;
import org.testng.Reporter;
import org.testng.annotations.*;
import static org.testng.Assert.*;
@SuppressWarnings(“unused”)
public class test {
WebDriver driver;
Selenium selenium;
@BeforeMethod
public void startSelenium() {
driver = new FirefoxDriver();
selenium = new WebDriverBackedSelenium(driver, “http://www.google.com/”);
}
@AfterMethod
public void stopSelenium() {
driver.close();
}
@Test
public void testtest() {
selenium.open(“/firefox?client=firefox-a&rls=org.mozilla:en-US:official”);
selenium.type(“sf”, “SACHIN”);
selenium.click(“btnG”);
selenium.waitForPageToLoad(“30000”);
String i = selenium.getValue(“//div[@id=”resultStats”]”);
Reporter.log(i);
}
}
Jodie Miners says
Hi Jared
It looks entirely possible.
The WAVE Toolbar adds extra html to the page to describe the errors and markup. So you should be able to use that additional html in your locators to find specific wave errors or assert that specific text has the correct WAVE icon next to it to say that it is accessible.
It looks quite promising.
Let me know how you go with it 🙂
Jodie
Jared says
Hey Jodie,
Great post. I’m just curious if you’ve had any luck tying Firefox plug-ins like WAVE or Qompliance to Selenium tests for testing accessibility? If not, do you know if that would be possible? We’re trying to make sure our apps are accessible and following 508 guidelines, but it’s too much work to test each page manually. Any pointers would be greatly appreciated.
Cheers,
Jared