For the past few years myself and colleagues have used Selenium extensively to test-drive (and continuously test) all the web-apps which we’ve collectively been responsible for. In that time our massed experience meant we got pretty slick at writing these tests. Then when I started on a new project with a new team, I realised those tips/best practices hadn’t been documented and consequently saw developers new to Selenium introducing brittle tests through no fault of their own.
Here’s a quick rundown of the most useful things we learnt about Selenium Test Xpaths. Please feel free to comment and add your own tips too!
- Assuming you are following best practices for CSS styling you ought to already be using IDs and CLASS attributes in markup. If not, why not!?
- Write XPaths which focus on the ‘pivots’ in a deeply nested XPath; where possible use ID and CLASS (and/or other relevant attributes) to filter down to your target element(s).So where previously you might have had:
xpath=/div[0]/div[3]/div[6]/span[2]
You could instead use:
xpath=//div[@class="foo"]//span[@id="pageTitle"]
- Test that attributes exist or have the right value, rather than testing text content in pages (especially where that content is dynamic)
So for example, test that button ID x is in page, and click by the xpath of the button ID, rather than using the Selenium IDE recorded click ‘{text button visual name}’ method.
Another example might be locating that a A HREF link is going to the right place
Assert
xpath=//div[@id="profile"]//a[@class="modifyProfile"]/@href
is ‘/someLink’
- For links (or src URL locations) employ regex or globs rather than test FQNs
Assert that
xpath=//div[@id="profile"]//a[@class="modifyProfile"]/@href
is ‘glob:*/deepNestedContext/mofiyProfile.action’
- A corollary from my opening point; make sure all markup is W3C valid. Helps to avoid shooting yourself in the foot using xpaths (ie: duplicate IDs)
- Employ selenium extensions to compress repetitious, multi step / test activities into a single test action
- When iterating over listed content, avoid index based xpaths – dynamic changes could cause failures. Try where possible to specify a search form of xpath
eg: instead of asserting that
xpath=//div[0]/span[1]/ul/li[3] is 'bob'
its far less brittle to write
xpath=//div[@id="mainContent"]//ul[@id="userList"]/li[text() == 'bob']
In cases where list order is important then using the list index is of value, but often it can cause more trouble than it’s worth to use indexes.
- Use storeExpression to store and re-use Xpaths which are repeated often in a test (the benefit being when you do have to change the Xpath you change one place not 15)
- Use the Selenium IDE in record mode more as a guide than as an absolute way to build up tests; IDE xpaths are inflexible and can’t handle changes as well as xpaths defined with resilience in mind
- Lastly, but not least, remember IE compatibility for your Selenium RC tests
