Selenium get dynamic ID XPath - dynamic

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

Related

Xpath following the for the next thumbnail - optimized solution? (for selenium automated solution)

At demo store we have a list of thumbnail as given below :
<ul class="product_list grid row">
<li class="ajax_block_product....">
<div class="product-container">
<!-- at this level ist the thumbnail number 1 -->
</div>
</li>
<li class="ajax_block_product....">
<div class="product-container">
<!-- at this level ist the thumbnail number 2 -->
</div>
</li>
<li class="ajax_block_product....">
<div class="product-container">
<!-- at this level ist the thumbnail number 3 -->
</div>
</li>
</ul>
I can navigate through thumbnails using the xpath mentioned below:
thumbnail number 1 = //div[#class="product-container"]
thumbnail number 2 = //div[#class="product-container"]/following::div[#class="product-container"][1]
thumbnail number 3 = //div[#class="product-container"]/following::div[#class="product-container"][1]/following::div[#class="product-container"][1]
Through, above xpath are working fine for me but not an optimized solution.
Update 1: The objective is leave the xpath in a closed "form" at web page object library, for using by automated tests.
Get all the thumbnails in a list and then navigate through. Use below CSS selector for the same. Not sure which language you are using. I write this using Java.
List<WebElement> products = driver.findElements(By.cssSelector("div.product-container"));
for(WebElement product : products){
String productName = product.findElement(By.cssSelector(".product-name")).getText();
String productPrice = product.findElement(By.cssSelector(".right-block .price")).getText();
...
}
OR using the xpath mentioned by you.
List<WebElement> allThumbnails = driver.findElements(By.xpath("//div[#class='product-container']"));
for(WebElement thumbnails:allThumbnails){
String productName = product.findElement(By.xpath(".//a[#class='product-name']")).getText();
String productPrice = product.findElement(By.xpath("//div[#class='right-block']//span[#class='price product-price']")).getText();
...
}
UPDATED
As per your comment if it is require to mentioned fix element in your xpath then using indexes would be the right approach.
there are total 7 product present on the page you shared the URL and xpath so you can write it like-
thumbnail number 1 = //ul[#class='product_list grid row']/li[1]
thumbnail number 2 = //ul[#class='product_list grid row']/li[2]
...
thumbnail number 7 = //ul[#class='product_list grid row']/li[7]
If all the products share the same class you can just have Selenium pick up all matching elements, as opposed to explicitly stating one after the other like you're currently trying.
You've not said what language you're using, but here's what it'd look like in C#:
// Setup your web driver...
var thumbnails = driver.FindElements(By.XPath("//div[#class=\"product-container\"]"));
foreach (var thumbnail in thumbnails)
{
// Do work
}
Or
for(int i = 0; i < thumbnails.Count; i++)
{
// Do work by index
}
Note the plural FindElements, it returns a collection of all matching elements. Selenium does a fairly good job of matching methods across languages so that should point you in the right direction at least.

xpath selenium multi/and operators

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.

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');