xpath selenium multi/and operators - selenium

Could anybody help how to solve this dilemma
I have this code:
<div>
Link
<span class="make">Chevrolet</span><br>
<span class="year">1956</span><br>
<span class="price">$20,000</span><br>
</div>
<div>
Link
<span class="make">Ford</span><br>
<span class="year">1958</span><br>
<span class="price">$21,000</span><br>
</div>
I need get the link for example Fords with the year greater then 1950.
Presently, I am using following xpath:
//*[text()='Ford' and .//text()>'1950']//parent::a
And this doesn't work! Have you any idea ?

This is one possible XPath :
//div[span/text()='Ford' and span/text()>1950]/a
Basically the XPath check if div has child span with text equals 'Ford' and another child span with value greater than 1950. Then from such div that match the two criteria above, return child a element.
demo
Better yet, only check span with class 'make' for manufacturer and span with class 'year' for manufacturing year :
//div[span[#class='make']='Ford' and span[#class='year']>1950]/a

You can write a generic method to get the required links, as shown below:
public static List<WebElement> getLinks(String linkText, int year) {
List<WebElement> links = driver.findElements(By.xpath("//a[text()='" + linkText + "']/following-sibling::span[1]"));
List<WebElement> linksGreaterThanRequiredYear = new ArrayList<WebElement>();
for (WebElement link : links) {
if (Integer.parseInt(link.getText()) > year)
linksGreaterThanRequiredYear.add(link);
}
return linksGreaterThanRequiredYear;
}
Hence, if you want to get the Fords with year greater than 1950, you can call above method in following way:
List<WebElement> fordsWithYearGreaterThan1950 = getLinks("Ford", 1950);
Above method can be further enhanced to include less than criteria as well. Let me know, if you have any further queries.

Related

Finding a parent element in webdriver.io

I've seen a couple of solutions in the original webdriver that use getAttribute('xpath') and append to that '/..' but webdriver.io doesn't have an xpath attribute so I haven't been able to use that. Any ideas on how to grab the parent element?
The case I am trying to test is inside of a bootstrap layout and the element that is actually getting the class I am trying to check is one above. It looks like this:
<div class="form-group">
<input class="form-control" type="text" name="username">
<other stuff>
</div>
I am selecting by driver.element("input[name='username'"] but the error class actually hits the div
<div class="form-group error">
<input class="form-control" type="text" name="username">
<other stuff>
</div>
So I need to check if the div itself has an error class, not the input I can find (there are no uniques on the div)
Any help would be greatly appreciated.
Just searched the same and found this by inspecting Webdriver.IO source code - you can use el.$('..') to get the parent element, like this:
$('input[name="username"]').$('..') // returns the parent element
Voila! It's a part of their XPath selectors support.
I ended up solving this by using execute to get the xpath from jQuery, here is the code I used (albeit for a different test I was writing - if every label that has a * is a required field). Hopefully this is helpful to somebody in the future:
var requiredXPaths = browser.execute(function () {
var returner = [];
var $elements = $('.modal.fade.in').find("label:contains('*')");
_.each($elements, el => {
var xpath = '';
var element = el.parentElement;
for (; element && element.nodeType == 1; element = element.parentNode) {
var id = $(element.parentNode).children(element.tagName).index(element) + 1;
id > 1 ? (id = '[' + id + ']') : (id = '');
xpath = '/' + element.tagName.toLowerCase() + id + xpath;
}
returner.push(xpath);
});
return returner;
});
I got the xPath function from another stackoverflow page (How to calculate the XPath position of an element using Javascript?)
WebdriverIO actually lets you use XPath in your selectors, so any valid Xpath selector should work to find the element you want.
Alternatively, you could just use isExisting to check if the element exists on the page using the error class parent:
driver.isExisting('.error input[name="username"]');
If the element doesn't exist, then your error class didn't get added.
I've been talking about this in gitter, when the parent can be selected input[name="username"]
The parent of this element can be selected as //div[input[name="username"]]

Selenium - locating multiple elements with the same class name

Hello there I am trying to locate multiple elements with the same className. The className and the body structure of the elements are the same but the texts, links and pictures are different.
<div class="dc-content-right clearfix"> (parent)
<div class="dc-item clearfix"> (child nodes)
<div class="dc-item clearfix">
<div class="dc-item clearfix">
Each of these child elements looks something like this:
<div class="dc-item clearfix">
<div class="dc-icon">
<div class="dc-info">
<h2>
AVG AntiVirusFree 2015
</h2>
Each child element has different text in the H2 tag. So once it is AVG AntiVirus Free 2015, then it is Internet Security .... and so on. So what I want to do is save all elements into a list and then work with them.
At first I save these elements intto a list of WebElements :
List <"WebElement"> list = driver.findElements(By.xpath("//div[#class='dc-item clearfix']"));
Afterwards I want to iterate through the list and write the h2 text for each element on the screen:
for(WebElement i:superDiv)
{
System.out.println(i.findElement(By.xpath("//h2/a")).getText());
}
So the outcome should be a list of 3 different headings extracted from divs. The problem: the outcome is the list of 3 headings which are the same!
AVG AntiVirus Free 2015
AVG AntiVirus Free 2015
AVG AntiVirus Free 2015
It looks like I located the same element 3 times. Does anyone have an idea what could be the problem? Thank you
List<WebElement> list = driver.findElements(By.xpath(".//*[#class='dc-item clearfix']//h2/a"));
for(WebElement el : list) {
System.out.println(el.getText());
}
You can also try:-
List<WebElement> list = driver.findElements(By.xpath(".//*[#class='dc-info']//a"));
for(WebElement element : list) {
System.out.println(element.getText());
}
If div tag does not contains id or class, then use like this
List<WebElement> elements = driver.findElements(By.xpath("//div[contains(#style,'height:50px')]"));
for(WebElement element : elements) {
System.out.println(element.getText());
}

Identifying the Web element with same class name in Selenium

I have tried to get the number of tweets(tweet count) through selenium
Here is the page source:
<li class="DashboardProfileCard-stat Arrange-sizeFit">
<a class="DashboardProfileCard-statLink u-textUserColor u-linkClean u-block"
title="1 Tweet"
href="/saisiva14"
data-element-term="tweet_stats">
<span class="DashboardProfileCard-statLabel u-block">Tweets</span>
<span class="DashboardProfileCard-statValue" data-is-compact="false">1</span>
</a>
</li>
<li class="DashboardProfileCard-stat Arrange-sizeFit">
<a class="DashboardProfileCard-statLink u-textUserColor u-linkClean u-block"
title="38 Following"
href="/following"
data-element-term="follower_stats">
<span class="DashboardProfileCard-statLabel u-block">Following</span>
<span class="DashboardProfileCard-statValue" data-is-compact="false">38</span>
</a>
</li>
<li class="DashboardProfileCard-stat Arrange-sizeFit">
<a class="DashboardProfileCard-statLink u-textUserColor u-linkClean u-block"
title="4 Followers"
href="/followers"
data-element-term="following_stats">
<span class="DashboardProfileCard-statLabel u-block">Followers</span>
<span class="DashboardProfileCard-statValue" data-is-compact="false">4</span>
</a>
</li>
I could not able to locate the web element for getting Tweets,Followers & following. The reason is span class names are common for all these elements.Please help me .
To get number of Tweets/ Following/ Followers, You can try the below statements:
System.out.println(driver.findElement(By.xpath("//a[contains(#title, 'Tweet')]/span[2]")).getText());
System.out.println(driver.findElement(By.xpath("//a[contains(#title, 'Following')]/span[2]")).getText());
System.out.println(driver.findElement(By.xpath("//a[contains(#title, 'Followers')]/span[2]")).getText());
To click on the Tweets/ Following/ Followers links, You can try the below statements:
driver.findElement(By.xpath("//a[contains(#title, 'Tweet')]")).click();
driver.findElement(By.xpath("//a[contains(#title, 'Following')]")).click();
driver.findElement(By.xpath("//a[contains(#title, 'Followers')]")).click();
or
driver.findElement(By.xpath("//a[./span[text()='Tweets']]")).click();
driver.findElement(By.xpath("//a[./span[text()='Following']]")).click();
driver.findElement(By.xpath("//a[./span[text()='Followers']]")).click();
The above statements are working fine for me.
try this
IList<IWebElement> elements = driver.FindElements(By.ClassName("DashboardProfileCard-stat"));
foreach (IWebElement element in elements)
{
IWebElement ele = element.FindElement(By.ClassName("DashboardProfileCard-statLabel"));
if (ele.Text == "Tweets")
{
return element.FindElement(By.ClassName("DashboardProfileCard-statValue")).Text;
}
}
this is using C#, you can modify accordingly if anyother language is used.
The selector .DashboardProfileCard-stat span:nth-child(2) should give you the collection of web elements pointing to the count. For example in Java:
ArrayList<WebElement> elements = driver.findElements(By.cssSelector(".DashboardProfileCard-stat span:nth-child(2)"))
Then you can use elements.get(0).getText() for tweets. elements.get(1).getText() for following. elements.get(2).getText() for followers. So:
ArrayList<WebElement> elements = driver.findElements(By.cssSelector(".DashboardProfileCard-stat span:nth-child(2)"));
int tweets = elements.get(0).getText();
int following = elements.get(1).getText();
int followers = elements.get(2).getText();
Of course, do your appropriate safety checks, etc. Check the length of the array before access.
This code is in Java :)
capture all the parents of the "SPAN" into a collection item.
Iterate on the collection to find the span elements (which are child of <a> tag) and capture text based on the class name variation statLabel / statValue".
List<WebElement> webElement = driver.findElements(By.xpath("//li[#class='DashboardProfileCard-stat Arrange-sizeFit']//a"));
for (WebElement element : webElement) {
System.out.println(element.findElement(By.xpath("//span[contains(#class,'statLabel')]")).getText());
System.out.println(element.findElement(By.xpath("//span[contains(#class,'statValue')]")).getText());
}

Finding all "A" tags with specific strings in the attribute href?

driver.FindElement(By.Name("zipcode")).Clear();
driver.FindElement(By.Name("zipcode")).SendKeys(zipcode);
driver.FindElement(By.Name("Go")).Click();
driver.FindElements(By.TagName("A"). //<---- ?????????
I have some Selenium API code that I started. I aim to get all the "A" tags with the string "alertsepy" and the sting "sevendwarves" in the attribute href and return all those elements into an array so I can do some further processing. I started the code but I am really not quite sure how to get all the way there yet. Does anyone know how to do this type of query with Selenium.
Kind Regards!
You should use css selector:
IList<IWebElement> elements = driver.findElements(By.cssSelector("a[href*=alertsepy],a[href*=sevendwarves]")
This query will return a nodes with href attribute that contains alertsepy or sevendwarves or both strings:
<a href="alertsepy.html" > </a>
<a href="sevendwarves.html" > </a>
<a href="http://sevendwarves.org/alertsepy.html" > </a>
Or you can use:
IList<IWebElement> elements = driver.findElements(By.cssSelector("a[href*=alertsepy][href*=sevendwarves]")
This query will return a nodes with href attribute that contains alertsepy and sevendwarves strings:
<a href="http://sevendwarves.org/alertsepy.html" > </a>
For a list of generally available css selectors refer to w3c css selectors. For the list of available in Selenium query types refer to Locating UI Elements.
List<WebElement> anchortaglist = driver.find Elements(By.Tag Name('a');

Selenium get dynamic ID XPath

I'm new on Selenium, new here and my english is not the best.
I'm using selenium with .NET ...
I have a HTML page like this but the number of the events are different:
<div id="eventContent" style="text-align: center;">
<div class="event" id="event-8971062">
<ul>
<li ...></li>
<li ...></li>
<li ...></li>
</ul>
</div>
<div class="event odd" id="event-9224880">
<ul>
<li ...></li>
<li ...></li>
<li ...></li>
</ul>
</div>
</div>
I need to check all datas in the different divs but the count is dynamic and the (event)id is dynamic too. I'm trying to find out the count of the divs at first but this does'nt work. For that I try this:
DefaultSelenium selenium = new DefaultSelenium(...);
decimal count = selenium.GetXpathCount("//div[#id='eventContent']");
but this brings only 1 as result and not two for this example.
when I try:
Console.WriteLine(selenium.GetText("//div[#id='eventContent'][1]"));
it prints all divs, but when I do:
Console.WriteLine(selenium.GetText("//div[#id='eventContent'][1]/div"));
it prints only the first div and I do not understand why.
Could someone be so kind and give me an explaination of whats going on here and where I'm wrong?
Thanks in advance
elur
decimal count = selenium.GetXpathCount("//div[#id='eventContent']");
This will return the count of divs that have an id of eventContent - there is only one div like this, which is why you get a count of 1 (count variables are typically ints rather than decimals, incidentally).
If you want the count of the contained divs, use
int count = selenium.GetXpathCount("//div[#id='eventContent']/div");
This will count the number of div children of the div with an id of eventContent. This should return 2, as desired.
As for your GetText examples, I think GetText will only return the text of the first node that the xpath argument selects. So with
selenium.GetText("//div[#id='eventContent'][1]")
you get the entire text of the parent div, which naturally contains all the child divs, but with
selenium.GetText("//div[#id='eventContent'][1]/div")
you get the text of only the first child div. This xpath selects all the child divs, but GetText operates on a single element only, I believe. If you want to examine the text of each child div in turn, you'll need to first get a count of the child divs, then use for loop to get each one in turn:
for(int i = 1; i <= count; ++i)
{
string childXpath = "//div[#id='eventContent']/div[" + i + "]";
string eventText = selenium.GetText(childXpath);
// Processing of eventText
}
A for loop and manual xpath processing are needed here (rather than the neater foreach), as I believe Selenium doesn't have a way of taking an xpath and returning a collection of elements.
tryed this but returns with 0. I solved this with a while expression where I check with isElementPresent like this:
int a = 1;
while (selenium.IsElementPresent("//div[#id='eventContent'][1]/div[" + a + "]"))
{
// check data here
a++;
}
seems to work so. thanks a lot for your help,
best regards elur