Reputation: 930
I working on automating a website and I'm trying to find a way to reduce the use of xpaths in my code. My code looks something like this
driver.findElement(By.xpath("//html/body/center/div/div/center/table/tbody/tr/td/form/table/tbody/tr[3]/td/input")).click();
driver.findElement(By.xpath("//html/body/div/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr/td")).getText();
driver.findElement(By.xpath("//html/body/div/table/tbody/tr/td/div[2]/div/div/div[4]/div/div/div")).click();
driver.findElement(By.xpath("//html/body/div[3]/div/div/div/div[2]/div/span/ul[2]/li[6]/a")).click();
/*driver.findElement(By.xpath("//html/body/div/div/div/div[3]/div/div[2]/div[2]/table/tbody/tr/td[3]/table/tbody/tr/td[2]/em/button")).click();
WebElement editUserForm = driver.findElement(By.cssSelector("iframe[src*='editUserForm']"));
Is there any way I can reduce these xpaths so that my codes don't look shabby ? One of the member here suggested me "Please don't use absolute xpath". What does it mean ? Please help. Also let me know if there any link that will help me on this.
Is it possible to create a file that will make a string to xpath pointer and then we can just use the string in the code ?
Upvotes: 0
Views: 5271
Reputation: 350
Here again Y XPath Y Not to go with CSS
css=.uploadDetails > .docSpan -- .doc
css=.uploadDetails > .excelSpan -- .xls
css=.uploadDetails > .txtSpan -- .txt
Simple
Upvotes: 0
Reputation: 25076
You should invest in Page Objects, it's a very useful pattern:
https://code.google.com/p/selenium/wiki/PageObjects
It will help seperate the test from the implementation. By that I mean, the test should be left detailing what steps are taken, the implementation (the 'page object') should detail how those steps are taken.
As for the XPath's themselves, yes, they are pretty bad & unreliable. I would assume you've had them automatically generated for you by some tool, maybe the IDE or Firebug. Please throw these away now, don't ever use it again and read some XPath tutorials - even the XPath spec is a great learning place.
Firstly, drop the //html/body
bit, it's unneeded, and makes it look worse. It will work fine without it.
Secondly, yes, having absolute XPaths (i.e, those that are based upon position) are bad. In your first XPath:
//html/body/center/div/div/center/table/tbody/tr/td/form/table/tbody/tr[3]/td/input
See that final tr[3]
? What if I was to stick another row (tr
) before that one? It means now your XPath should be:
//html/body/center/div/div/center/table/tbody/tr/td/form/table/tbody/tr[4]/td/input
So it means the test will break. However, the test will break not because the functionality it's testing is broken, it's broken because the test implementation is broken. Your tests should not be that flaky. If a developer wants to stick a tr
above that one you want, fine, unless it breaks the actual thing you are testing, then your test should still pass.
You should think about it differently. Think about other ways of getting to that element. Let's say I have this:
<div id="divUpload">
<span class="uploadDetails">We only support the following files:
<span class="docSpan">.doc</span>
<span class="txtSpan">.txt</span>
</span>
<button type="submit">Upload the file<submit>
<div>
I want to get the span with docSpan
as it's class name.
I could either:
//div/span/span[1]
Which would work, but what if it's changed to:
<div id="divUpload">
<span class="uploadDetails">We only support the following files:
<span class="excelSpan">.xls</span>
<span class="docSpan">.doc</span>
<span class="txtSpan">.txt</span>
</span>
<button type="submit">Upload the file<submit>
<div>
It means the [1]
bit is no longer valid.
So I could:
//div/span[@class='uploadDetails']/span[text()='.doc']
Which means, it's only going to fail if the span
I want is taken out of being a child of the span with a class uploadDetails
or the uploadDetails
class is taken off the span altogether.
Or I could:
//div/descendant::span[text()='.doc']
This means it's only going to fail if the span is moved altogether, and is no longer a child of that 'parent' div.
Bottom line is don't rely on positions. Think about what's near that element. Is there something with a class? Is there something with text inside it? Is there something with an ID near it?
Upvotes: 11