views:

1576

answers:

2

I'm trying to select an element given by:

/html/body[@id='someid']/form[@id='formid']/div[@id='someid2']/div[@id='']/div[@id='']/div[@id='']/table/tbody[@id='tableid']/tr[7]/td[2]

Now the html of that row I'm trying to select looks like this:

<tr>
<td class="someClass">some text</td>
<td class="someClass2">my required text for verifying</td>
</tr>

I need to check whether my required text for verifying exists in the page.

1)I used selenium.isTextPresent("my required text for verifying"); and it doesnt work

2)So now I tried with selenium.isElementPresent("//td[contains(text(),'my required text for verifying')]")
This works sometimes but occassionally gives random failures.
3)Tried with selenium.isElementPresent(//*[contains(text(),'my required text for verifying')]) too..

How do I verify this text on the page using selenium?

The problem is not with the page taking time to load. I took screenshots before the failure occurs and found that the page was fully loaded so that shouldnt be the problem.

Could someone please suggest any way to select this element or any way to validate this text on the screen?

Thanks,
Mugen

A: 

I've never heard of selenium; but your initial XPath is unnecessarily fragile and verbose.

If an element has an id, it's unique; using such a long XPath just to select a particular element is unnecessary; just select the last element with the id. Further, I see that you're occasionally selecting xyz[@id=''] - if you're trying to select elements without id attributes, you can do `xyz[not(@id)] instead.

Assuming your initial XPath is basically correct, it would suffice to do something like this:

//tbody[@id='tableid']/tr[7]/td[2]

However, using a specific row and column number like that is asking for trouble if ever anyhow changes details of the html. Also, it's atypical to have id's on tbody elements, perhaps the table element has the id?

Finally, you may be running into space-normalization issues. In xml, multiple consecutive spaces are often considered equivalent to a single space, and you're not accounting for that. In particular, if the xhtml is pretty-printed and contains a line-break in the middle of your sought-after text, it won't work.

//td[contains(normalize-space(text()),'my required text for verifying')]

Finally, text() explicitly selects child text nodes - so the above xpath won't select elements where the text isn't the immediate child of td (e.g. <td><b>my required text for verifying</b></td>) won't match. Perhaps you mean to look up the concatenated text vale of all descendents:

//td[contains(normalize-space(string(.)),'my required text for verifying')]

Finally, type conversion can be implicit in XPath, so string(.) can be replaced by . in the above, leading to the version:

//td[contains(normalize-space(.),'my required text for verifying')]

This may be slow on large documents since it needs to normalize the spaces and perform a string search for each td element. If you run into perf problems, try to be more specific about which td elements need to be inspected, or, if you don't care where the text occurs, try to reduce the number of "calls" to normalize-space by normalizing the entire doc in one go (e.g. via /*[contains(normalize-space(.),'my required text for verifying')]).

Eamon Nerbonne
He's not using that XPath, it's just to illustrate the HTML in use.
Dave Hunt
Then why tag it with "xpath"??
Pavel Minaev
Thanks for replying, but I'm not having the space-normalization issues.
Mugen
It was tagged with xpath because that's the locator strategy being used within Selenium. The XPath at the top of the question was an illustration of the HTML, so comments of its fragility are redundant. The remaining XPaths in the question were examples of attempts to locate the element.
Dave Hunt
Regardless of the framework implementing xpath writing robust xpath is probably a good idea. Certainly sounds to me like he was actually using that XPath, but apparently not.
Eamon Nerbonne
I'm sorry if my post gave the appearance that I was using that XPath I mentioned in the first line. Dave is right in his comment above as to what I meant. From my side, I'll try to make it more clear next time so that people dont have this confusion. However, thanks for pointing it out and for taking the time to reply to my question. :-)
Mugen
+2  A: 

Try locating it by CSS:

assertText(selenium.getText("css=.someClass2"), "my required text for verifying");

The above should give a better failure message than isElementPresent, but you can still use that with CSS locators:

assertTrue(selenium.isElementPresent("css=.someClass2"));

If there is an issue with the load times you could try waiting for the element to be present:

selenium.waitForCondition("var value = selenium.isElementPresent('css=.someClass2'); value == true", "60000");

Some other XPath locators that might work for you, if you prefer not to use CSS locators:

  • //td[contains(@class, 'someClass2')
  • xpath=id('tableid')/tr[7]/td[2]
  • xpath=id('tableid')/descendant::td[contains(@class, 'someClass2')][7]
Dave Hunt
Thats a big help, Dave! It finally works now!
Mugen