Xpath: robust path for a locator of an element with 1 sibling and one...cousin? - xpath

This is the code:
<li>
<a>
<h1>Quorn StukĀ­jes</h1>
<p class="price">
</a>
<form>
<button type="submit">+</button>
</form>
</li>
I want to create a locator that finds the first <h1> that has an sibling element <p> with an attribute "price". Easy so far. But now I also want that <h1> to share its grandparent with a <button> class with the attribute type "submit".
What I created was the following:
//a/p[#class="price"]/preceding-sibling::p/preceding-sibling::h1
I'm wondering if this is the most sensible solution (it does work), or if there is something more elegant and robust.

(//*[form/button[#type = 'submit']]/*[p[#class = 'price']]/h1)[1] should do (assuming a submit button only makes sense in a form parent element).

Related

Click on a element with specific text

Alright, I have a item which has this class class="country" and there are 12 elements with the same class. Now I want to get a element on its value. For example Italy. And now I want to click on a link in this item. The class of the link is class="link". So basically I want to click the link of the item with the name Italy
My code at the moment:
cy.get('.country').should('have.text', 'Italy').click();
HTML
<div class="countries">
<div class="text">
<h3></h3>
<div class="country">Italy</div>
<h4>Yala</h4>
<p>test</p>
<a class="link" href="/mysite">Show details</a>
</div>
</div>
Should() is an assertion and won't select the element you want.
you probably want the contains() function.
cy.get('.country').contains('Italy').click()
Best

xpath - axes methods return wrong nodes

I have noticed that using xpath axes methods sometimes return wrong nodes. I have two examples:
url: "http://demo.guru99.com/v1/"
<tr>
<td align="center">
<img src="../images/1.gif">
<img src="../images/3.gif">
<img src="../images/2.gif">
</td>
</tr>
I can select three img elements by axes methods "//td//child::img". However when I use "//td//following-sibling::img", it can still return the second and third img elements. As far as I know, child and sibling are two different thing, so why this happens?
url: http://demo.guru99.com/selenium/guru99home/
<div class="rt-grid-12 rt-alpha rt-omega" id="rt-feature">
<div class="rt-grid-6 ">
<div class="rt-block">
<h3>
Desktop, mobile, and tablet access</h3>
<ul>
<li>
<p>
Free android App</p>
</li>
<li>
<p>
Download any tutorial for free</p>
</li>
<li>
<p>
Watch video tutorials from anywhere </p>
</li>
</ul>
<p>
<img alt="" src="images/app_google_play(1).png"></p>
</div>
</div>
<div class="rt-grid-5 ">
<div class="rt-block">
<img src="images/logo_respnsivsite.png"><br>
</div>
</div>
</div>
Here, if I use "//div[#id='rt-feature' and (#class='rt-grid-12 rt-alpha rt-omega')]//following-sibling::div", those div elements which should be child elements are still be counted as siblings
Use "//div[#id='rt-feature' and (#class='rt-grid-12 rt-alpha rt-omega')]//parent::div", the self element and its child div elements are all counted as parent.
This cause me a lot of confusion, please help me.
Suggesting that the XPath parser returns the wrong nodes, rather than that you don't understand why it is returning what it does, is starting from the wrong mindset. Unless you know the XPath parser is unreliable, start with the assumption that it is right and your expectations are wrong. Then go to the spec and study the semantics of the expression you have written.
You will find that
//td//following-sibling::img
is an abbreviation for
/descendant-or-self::node()/td/descendant-or-self::node()/following-sibling::img
so you have asked for all the following siblings of all the descendants of all the td nodes, which is exactly what you are getting.
I've come across people who habitually write "//" in place of "/" as a sort of magic fairy dust without having the faintest idea what it means. Don't do it: read the spec.

Xpath: locate a node by multiple attributes of a parent node

Here is the code:
<li class="abc">
<div class="abc">
<input type="checkbox">
</div>
<div class="xyz">
<div class="headline">Mongo like candy</div>
<div>
</li>
<li class="abc">
<div class="abc">
<input type="checkbox">
</div>
<div class="xyz">
<div class="headline">Candygram for mongo</div>
<div>
</li>
Xpath challenge. I want locate the checkbox of the li which contains the headline "Mongo like candy" so I can select it using Selenium. In other words, how do you locate the checkbox from here:
li//div[#class='abc']//input[#type='checkbox']
but qualifying it with a different attribute within the same parent node:
li//div[#headline][contains(text(),"Mongo like candy")]
The basic idea is to qualify the final path with a predicate, i.e.
li[/*predicate here*/]//div[#class='abc']//input[#type='checkbox']
The predicate expresses the condition on the li that you want:
.//div[#class='headline' and contains(text(), "Mongo like candy")]
Putting them together yields:
li[.//div[#class='headline' and contains(text(), "Mongo like candy")]]//div[#class='abc']//input[#type='checkbox']
something like
li[div[#class='xyz']//div[#class='headline' and contains(text(),"Mongo like candy"))]]//input[#type='checkbox']
unless I messed up parentheses. (that is, you select not just li, but the proper li).
Even this works:
//li[1]/div[1]/input[#type='checkbox']
It may fail if more div tags are introduced in the page.

Selecting cousin element with XPATH

Given following markup
<div>
<a>Username1</a>
</div>
<div>
<button>Unblock</button>
</div>
<div>
<a>Username2</a>
</div>
<div>
<button>Unblock</button>
</div>
<div>
<a>Username3</a>
</div>
<div>
<button>Unblock</button>
</div>
How do I select button element which is a cousin of a element with text Username2?
I can select the a element with //a[contains(., 'Username2')], so I thought that //a[contains(., 'Username2')]/following-sibling::/div/button would select the correct button, but that does not work. I think that it's not even valid XPATH.
You were close:
//a[contains(., 'Username2')]/../following-sibling::div[1]/button
To navigate to the cousin you first have to go to the parent (..) and then to its sibling.
Note that the following-sibling:: axis selects all following siblings, not only the first one. This means you must use [1] if you just want the first.
This would also work:
//a[. = 'Username2']/../following-sibling::div[1]/button
So would this:
//div[a = 'Username2']/following-sibling::div[1]/button

xPath strange behaviour - selecting ALL elements even if [1] set

today I stumbled upon a very interesting case (at least for me). I am messing around with Selenium and xPath and tried to get some elements, but got a strange behaviour:
<div class="resultcontainer">
<div class="info">
<div class="title">
<a>
some text
</a>
</div>
</div>
</div>
<div class="resultcontainer">
<div class="info">
<div class="title">
<a>
some other text
</a>
</div>
</div>
</div>
<div class="resultcontainer">
<div class="info">
<div class="title">
<a>
some even unrelated text
</a>
</div>
</div>
</div>
This is my data.
When i run the following xPath query:
//div[#class="title"][1]/a
I get as a result ALL instead of only the first one. But if I query:
//div[#class="resultcontainer"][1]/div[#class="info"]/div[#class="title"]/a
I get only the first , not all.
Is there some divine reason behind that?
Best regards,
bisko
I think you want
(//div[#class="title"])[1]/a
This:
//div[#class="title"][1]/a
selects all (<a> elements that are children of) <div> elements that have a #class of 'title', that are the first children of their parents (in this context). Which means: it selects all of them.
The working XPath selects all <div> elements that have a #class of 'title' - and of those it takes the first one.
The predicates (the expressions in square brackets []) are applied to each element that matched the preceding location step (i.e. "//div") individually. To apply a predicate to a filtered set of nodes, you need to make the grouping clear with parentheses.
Consequently, this:
//div[1][#class="title"]/a
would select all <div> elements, take the first one, and then filter it down futher by checking the #class value. Also not what you want. ;-)

Resources