tags:

views:

1052

answers:

4

Is it possible for Selenium to evaluate all the elements that may match a certain XPath?

For instance, I'd like to evaluate whether all checkboxes are checked with //input[type='checkbox']--problem is I only get one element returned.

+3  A: 

You can use the getXpathCount command to determine the number of matching elements. You can then loop through them using an increment to locate each element individually. The following Java (TestNG/JUnit) example would check that all checkboxes on a page are checked:

int totalCheckboxes = session().getXpathCount("//input[@type='checkbox']").intValue();
for (int i = 1; i < totalCheckboxes+1; i++) {
    assertTrue(session().isChecked("//input[@type='checkbox'][" + i + "]"));
}
Dave Hunt
Thanks Dave, Santi. My problem is that I don't have an option to use the Selenium client within unit tests. Unfortunately, I'm confined to using the Selenium IDE and command tables, but this doesn't mean I wouldn't be able to pinch in some JS to do just the same.
kRON
If you solve it in IDE with JavaScript submit your solution. I'd be interested in seeing it. :)
Dave Hunt
+2  A: 

There's no way selenium could evaluate a list of items returned by a locator. It just grabs the first one and does it's stuff with it.

Dave answer is the best alternative for what you're looking for.

Santi
I think it's still deserving of a go in JS :)
kRON
+1  A: 

I am trying to do the exact same thing in Selenium and tried using @dave-hunt 's example but it is an incorrect method for finding an individual element in a collection.

Consider the following example:

<form>
 <div>
  <input type="text" name="field1" />
 </div>
 <div>
  <input type="text" name="field2" />
 </div>
</form>

If you use an expression like:

//input[@type='text'][1]

this will return all text inputs in the page. Why? Because each input is the first matching element within its own tree.

However, if you use an expression like:

/descendant::input[@type='text'][1]

or

/descendant::input[@type='text'][2]

the first expression will grab the first input and the second expression will grab the second input. It is very important that you use a single "/" and NOT a double "//".

+1  A: 

With

/descendant::input[@type='text'][1]
/descendant::input[@type='text'][2]

you can only search for all input elements in the tree. It won't work if you just want to parse a subtree.

A better way is:

(/form/div/input[@type='text'])[1]
(/form/div/input[@type='text'])[2]

which will return result #1, #2 etc. of the XPath expression within the brackets.

Of course you could also do

(//input[@type='text'])[1]

This is quite handy as Selenium just uses the first match and can't deal with a result set, which is what XPath usually returns.

Sierra