Bluejuice Bluejuice - 1 year ago 105
HTML Question

Protractor/XPath - Find element that contains a descendant that contains text

I am seeking some help with XPath selectors. I've learned the basics of XPath but am having trouble combining them to solve this one problem.

So I have a grid in HTML that contains about 30 rows, each row (from left to right) has a checkbox and employee name. Here is a snippet of the composition of the rows:

<div class="ui-grid-row ng-scope" data-row-num="21"> //Whole row
<div role="row" ui-grid-row="row" class="ng-isolate-scope">
<div role="rowheader" id="1746254927-13-urGrid-005-cell"> //This is checkbox
<div role="gridcell" id="17443224958-13-urGrid-005-cell">
<div class="ui-grid-cell-contents ng-binding text-left"> Appleseed, Jonny</div>

My goal here is to find: div class="ui-grid-row ng-scope" data-row-num="21"> based on its descendant containing 'Appleseed, Jonny'. From here, I will extract the data-row-num with getAttribute so I can then navigate to the right checkbox.

What I have so far is:

element(by.xpath("//div[@class='ui-grid-row ng-scope') and contains(.//div, 'Appleseed, Jonny')]"));

Could someone help point me in the right direction here? I'm not looking for the element that contains this text, but its parent element so I can extract its data-row-num.

Or if I can find the div element that contains 'Appleseed, Jonny' how could I then find its parent element (in this case it isn't the direct parent but 2 elements up)?

Answer Source

This XPath should work given the HTML provided

//div[@class='ui-grid-row ng-scope'][.//div[contains(.,'Appleseed, Jonny')]]

It's looking for a DIV that contains the classes specified, [@class='ui-grid-row ng-scope'], and also has a child DIV that contains the desired text, [.//div[contains(.,'Appleseed, Jonny')]].

I prefer to be as specific as (reasonably) possible, e.g. use the tagname instead of * and so on.

Since you mentioned you are looking for the checkbox associated with that row, another way to do this is to look for the checkbox directly, relative to the element that contains the desired text.

//div[@role='rowheader'][.//div[contains(.,'Appleseed, Jonny')]]

Since I'm assuming you will be using this XPath numerous times, I would put it into a function and pass in the desired text, e.g. "Appleseed, Jonny", as a string and build that into the XPath.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download