Selenium WebDriver and xpath: a more complicated selection - xpath

So let's say my structure looks like this at some point:
..........
<td>
[...]
<input value="abcabc">
[...]
</td>
[...]
<td></td>
[...]
<td>
<input id="booboobooboo01">
<div></div> <=======I want to click this!
</td>
.........
I need to click that div, but I need to be sure it's on the same line as the td containing the input with value="abcabc". I also know that the div I need to click (which doesn't have id or any other relevant attribute I can use) is in a td at the same level as the first td, right after the input with id CONTAINING "boo" (dynamically generated, I only know the root part of the id). td's contain nothing relevant I can use.
This is what I tried as far as xpath goes:
//input[#value='abcabc']/../td/input[contains(#id,'boo')]/following-sibling::div
//input[#value='abcabc']/..//td/input[contains(#id,'boo')]/following-sibling::div
None of them worked, of course (element cannot be found).
I want to know if there's a way of selecting that div and how.
EDIT: //input[#value='abcabc']/../../td/input[contains(#id,'boo')]/following-sibling::div is the correct way. This was suggested by the person with the accepted answer. Also note that he offered a slightly different way of doing it. See his answer for details.

Try
//input[#value='abcabc']/ancestor::tr[1]/td/input[contains(#id,'boo')]/following-sibling::div[1]
Note that //input[#value='abcabc']/.. only goes up to the parent <td>, that's why your's did not work.

Another XPath that may work, is a bit more simple:
//input[#id='booboobooboo01']/../div[1]

Related

Selenide - found and fill the element

I failed to allocate following element via selenide (i need find and fill it with text (ID) :
<tr>
<th class="col-md-3 basicPropertiesName">Id</th>
<td class="col-md-9">
<input class="form-control ng-pristine ng-valid ng- touched" ng-keypress="keypressHandler($event, 2)" ng-model="newInsight.id" placeholder="ID">
</td>
</tr>
Or maybe this?
$("input[ng-model='newInsight.id']").setValue(value);
Maybe you need something like this?
By(xpath("//input[#ng-model='newInsight.id']))
$(By.xPath("//tr[./th[text()='Id']]")).find("input").setValue("some text)
or without additional find()
$(By.xPath("//tr[./th[text()='Id']]//input")).setValue("some text)
You could use following options using css selectors also.
String str="th[class*='basicPropertiesName']";
SelenideElement element =$(str);
or
String str="th:contains('Id')";
SelenideElement element =$(str);
one important moment.. all from above would fail if your example is placed in iframe (i've faced with such issue last week).
required actions:
a) how to find out if <tr> is (or not) part of iframe >> locate your tr on page, right-click on it, and ensure that you have no View frame source
example of page Inspect with iframe
if No such - try examples from above...
if There is one - see below
b) how to switch into iframe
you have to findout frame name...
--- make r-click on object + Inspert
--- locate your <tr>
--- click on it into Inspect
--- in the bottom of Inspert you'd see whole tree till selected element
--- move to the top of tree and you'd see something like iframe#framenamehere
--- copy it
before seaching your element add line like:
WebDriverRunner.getWebDriver().switchTo().frame(here the value from
prev. steps without #);
and search for your <tr>
I suggest that you use the th text in your query, to better target the input element:
Selenide.$(Selectors.byXpath("//th[text()='Id']/following-sibling::td/input"));
Note: Better to assign a unique id to the input element (and to every element under test) to improve readability and maintenance of your code.

Nokogiri: Finding all tags in a direct path, not including arbitrary levels of nesting

Say I have an html document like:
<div id='findMe'>
<table>
<tr>
<td>
<p>
bad
</p>
</td>
</tr>
</table>
<p>
This is some text and this is a link
</p>
</div>
I want to capture all links instead the div #findMe, inside paragraphs tags, but not inside table or any other tags. So, I want the one labeled "good", but not the one labeled "bad". I'm trying:
Nokogiri::HTML(html).css('#findMe p a')
but that's capturing both links. I also tried a more explicit xpath:
Nokogiri::HTML(html).css('#findMe').xpath('//p/a')
But that's doing the same thing. How can I tell Nokogiri to only search a specific path down the tree?
Use > in CSS to select immediate descendant.
Nokogiri::HTML(html).css('#findMe > p > a')
Or use / in xpath:
Nokogiri::HTML(html).xpath("//div[#id='findMe']/p/a")
Figured out a way to do it, but I'm still not too comfortable with xpaths so if this isn't the best way feel free to post the more canonical way to achieve this.
Nokogiri::HTML(html).css(#findMe').xpath('//div/p/a')

Selenium click() or isSelected() are not executed on RadioButton's input element

I have radio buttons that are located inside a table, such as:
<tr id="radiofield-1080-inputRow">
<td class="x-form-item-body" id="radiofield-1080-bodyEl" colspan="3">
<input type="button" id="radiofield-1080-inputEl" class="x-form-field" autocomplete="off">
<label id="radiofield-1080-boxLabelEl" class="x-form-cb-label">My Label</label>
</td>
</tr>
I do find the input element, by the following code:
xPath = String.format("//tr/td[contains(#id,'%s')][contains(label,'%s')]/label", xType, text);
webElement = webDriver.findElement(By.xpath(xPath));
but isSelected() or click() doesn't seem to work on it.
Do you have any suggestion?
Haven't used selenium in a while but from a quick google it looks like you should try the isChecked and check/uncheck methods.
Here's the Javadoc but for some reason can't get a decent link, obviously check on the Selenium object. If you're using a different version or if I misunderstood something sorry.
http://selenium.googlecode.com/git/docs/api/java/index.html
In your code snippet problem with locator.
Use any of the below below locators
By.cssSelector("input[id*='radiofield-']");
By.id("radiofield-1080-inputEl")
By.xpath("//tr/td[contains(#id,'radiofield-')]/input")
Try clicking on the "input" instead of the "label".
xpath of input:
"//input[#id='radiofield-1080-inputEl']"
If the input id is not always the same, you can try this, the location of input will be based off the label:
//label[text()='My Label']/preceding-sibling::input
Thanks for all your answers.
My finding concluded with the following:
ExtJS implement radiobutton and checkbox as button, therefore the selenium isSelected() is not functioning.
There is a need to implement isSelected(), as suggested at:
How to check if extjs checkbox is selected in selenium?
The click() does the work, as it is a button.
Thanks again, Michal

How can I use Spring MVC "form" tag instead of my "input" tags?

What I have:
I have a generic JSP page that is used throughout my application for displaying certain entities. The code that I am interested in goes like this:
<form:form modelAttribute="object"/>
<core:forEach items="${sections}" var="section" varStatus="itemStat">
<core:forEach items="${section.fields}" var="fieldDef">
<form:input path="${fieldDef.fieldName}"/>
</core:forEach>
</core:forEach>
<form:form>
For each section, and for each field in that section, I have an input having the path fieldName, which is what I want to display from each field.
What I want:
I would like instead of the input to be a simple text, like a label.
What I have tried:
I am most certain that I can do it somehow with <form:label> but I can't really make it work. Making a <form:label path="${fieldDef.fieldName}" /> just tells the browser for which field I need the label, but doesn't get the actual value from it.
I have also tried something like ${object.fieldDef.fieldName}, but in order for this to work I would have to first analyze the value of ${fieldDef.fieldName}, which would give me the name of the column, and then do a ${object.column}, but column being a variable I haven't been able to make this work in any way.
Alternative:
An alternative would be to just make the inputs as disabled and remove the border with CSS, but that would be a dirty way and from what I saw it is also tricky for IE different versions. I am sure that I can handle it directly.
I am a little intrigued by the fact that <form:input path="..."> puts into the input what it finds corresponding to that path (same goes for other form elements), but with label it works different.
So, what I want is basically simple, but I haven't managed to find a way. If someone could shed some light, that would be great. Thanks in advance !
You could look into the spring bind tag. I haven't tried using it before but this may work for you, in place of the input tag
<spring:bind path="fieldDef.fieldName">
${status.value}
</spring:bind>
reference: http://static.springsource.org/spring/docs/1.1.5/taglib/tag/BindTag.html
Instead of
<form:input path="${fieldDef.fieldName}"/>
use
<c:out value="${fieldDef.fieldName}"/>
It would display whatever value is there instead of creating a input field. Hope this helps you. Cheers.
Using the spring form tab, one option would be to use
<form:input disabled="true" path="${fieldDef.fieldName}"/>
To further make it not look like an input you could use CSS to style it to your preference.
Some css styles you could use:
background-color:#EEEEEE;border: 0px solid;
Update:
You could look into the spring bind tag. I haven't tried using it before but this may work for you, in place of the input tag
<spring:bind path="fieldDef.fieldName">
${status.value}
</spring:bind>

Xpath query to find elements which contain a certain descendant

I'm using Html Agility Pack to run xpath queries on a web page. I want to find the rows in a table which contain a certain interesting element. In the example below, I want to fetch the second row.
<table name="important">
<tr>
<td>Stuff I'm NOT interested in</td>
</tr>
<tr>
<td>Stuff I'm interested in</td>
<td><interestingtag/></td>
<td>More stuff I'm interested in</td>
</tr>
<tr>
<td>Stuff I'm NOT interested in</td>
</tr>
<tr>
<td>Stuff I'm NOT interested in</td>
</tr>
</table>
I'm looking to do something like this:
//table[#name='important']/tr[has a descendant named interestingtag]
Except with valid xpath syntax. ;-)
I suppose I could just find the interesting element itself and then work my way up the parent chain from the node that's returned, but it seemed like there ought to be a way to do this in one step and I'm just being dense.
"has a descendant named interestintag" is spelled .//interestintag in XPath, so the expression you are looking for is:
//table[#name='important']/tr[.//interestingtag]
Actually, you need to look for a descendant, not a child:
//table[#name='important']/tr[descendant::interestingtag]
I know this isn't what the OP was asking, but if you wanted to find an element that had a descendant with a particular attribute, you could do something like this:
//table[#name='important']/tr[.//*[#attr='value']]
I know it is a late answer but why not going the other way around. Finding all <interestingtag/> tags and then select the parent <tr> tag.
//interestingtag/ancestor::tr

Resources