Selenium how to determine if element has child? - c#

I am using Selenium via c#. I use this XPath to get all the children elements
element.FindElements(By.XPath("./child::*"));
Although if there is no child, it throws an error after a timeout. I am looking for a simple way to determine if it has a child or not to avoid the exception.

As per your question to get all the Child Nodes of a Parent Node you can use FindElements() method with following-sibling::* attribute within xpath as follows :
Sample Code Block :
List<IWebElement> textfields = new List<IWebElement>();
textfields = driver.FindElements(By.XPath("//desired_parent_element//following-sibling::*"));
Note : When FindElements() is used inconjunction with implicitly or explicitly waits, FindElements() method will return as soon as there are more than 0 items in the found collection, or will return an empty list if the timeout is reached.
XPath Details :
Description : This xpath technique is used to locate the sibling elements of a particular node.
Explanation : The xpath expression gets the all the sibling elements of the parent element located using desired_parent_element.

FindElements returns a list, so you can check the size of the list, if it is zero, it means there are no child elements
Java
List<WebElement> childs = rootWebElement.findElements(By.xpath(".//*"));
int numofChildren = childs.size();
C#
IReadOnlyList<IWebElement> childs = rootWebElement.FindElements(By.XPath(".//*"));
Int32 numofChildren = childs.Count;

bool HasChild(IWebElement element)
{
//Save implicit timeout to reset it later
var temp = driver.Manage().Timeouts().ImplicitWait;
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(0);
bool exists = element.FindElements(By.XPath(".//*")).Count > 0;
driver.Manage().Timeouts().ImplicitWait = temp;
return exists;
}

The simplest way is:
boolean hasChildren(WebElement node) {
return node.findElements(By.xpath("./descendant-or-self::*")).size() > 1;
}

To do in Javascript:
var childElements = await element.findElements(By.xpath('.//*'));
for (i = 0; i <= childElements.length; i++) {
var elementId = await childElements[i].getAttribute("id");
await console.log(elementId);
}

Related

Verify the data from the last element of xpath with dynamic list c#

From the above image the new data that I add gets added to the last page but there can be similar name and I need to verify the data using the ID as shown. So I am trying to figure out the way to store text values from the id and when the new data is added it should verify the last newly added ID. Any ideas?
int i = 1;
bool found = false;
string ID;
try
{
IWebElement LastPage = Driver.driver.FindElement(By.XPath("html/body/div[4]/div/div/div[2]/table/tbody/tr[8]/td[1]"));
LastPage.Click();
for (i = 1; i <= 10; i++) ;
{
ID= Driver.driver.FindElement(By.XPath("html/body/div[4]/div/div/div[2]/table/tbody/tr[" + i + "]/td[1]")).Text;
if (??)
}
As #viet-pham said, using last is a good idea, you can also use a relative xpath like:
//table/tbody/tr[last()-1]/td
and you don't need to use [1] since you are using FindElement and not FindElements and is returning the first element found.
You don't need to use for loop to get the last item, just put last() to select the final tr element
In your case:
IWebElement lastElement = Driver.driver.FindElement(By.XPath("(html/body/div[4]/div/div/div[2]/table/tbody/tr)[last()]/td[1]"));
ID = lastElement.Text;
In additional: because the last row is the total, so you must change to the row before it => [last()-1]

Get all elements in IWebElement using XPATH

I've tried using webelement(and IWebElement) and string lists, but i keep getting errors. How I do get a list or strings of all the elements text by XPath? I have all Selenium references. Do i need some java.util dll? Should I implement a foreach loop?
I don't know what exactly you want to do but you can get element text using following code.
public List<String> policy1Details = new List<String>();
public void PolicySummary1(int i)
{
//var driver = new FirefoxDriver();
policy1Details.Clear();
var psummary = driver.FindElements(By.XPath("//text()"));//give your xPath.
//var psummary = driver.FindElement(By.XPath("//div[#id='PolicyDetails_" + i + "']/div/table"));
foreach (IWebElement d in psummary)
{
//resultText.Add(d.Text);
policy1Details.Add(d.Text);
}
}
if any issue the let me know.
Here is the topic with a similar question! - XPath to get all child nodes (elements, comments, and text) without parent
And here is the quote from there!
child::* selects all element children of the context node
So you can do the:
var childs = parent.findElements(By.xpath("./child::*"));
Also here is the documentation of XPath, you can read more here!

How to find multiple elements on a page in selenium?

I have multiple input HTML tags on same page having same id and name or class,
Now How should I find 2nd or 3rd.. etc input. I can work with arrays so Do we have some function which will return all the textBox(input tag) from that page.
First you create a list with FindElements, then you can iterate through that list. For example:
var allTextBoxes = driver.FindElements(By.TagName("input"));
foreach(var textBox in allTextBoxes)
{
textBox.DoSomething();
}
You can use a for-loop as well:
for(int i = 0; i < allTextBoxes.Count; i++)
{
allTextBoxes[i].DoSomething();
}
Or if you want a specific Element, in example the 3rd:
allTextBoxes[2].DoSomething();
Expanding on Anaxi's answer,
If you are using the PageObject framework you can do it like this and set the FindsBy attribute on a property:
[FindsBy(How = How.Id, Using = "YourId")]
public IList<IWebElement> ListOfWebElements { get; set; }
i dont know about selenium... but to select element of html page you can use HtmlAgilityPack..
HtmlWeb hw = new HtmlWeb();
HtmlDocument doc = hw.Load(#"http://example.com");
HtmlNode node = doc.DocumentNode.SelectNodes("//div[#class='your_class_name']");
it will return a list of node that contains your_class_name.. then find and use the one you want.
to select all the input tags from that page you can use
foreach (var input in doc.DocumentNode.SelectNodes("//input"))
{
//your logic here
}
hope it helps..
In C# I use FindElements then ElementAt():
var foo= Driver.FindElements(By.XPath("//div[#class='your_class_name']"));
var foo2= foo.ElementAt(1);
If it's 10 elements with the same ID (which is HORRIBLE) and I'd like to grab the 8th element, I just use ElementAt(8); (or index 7 or however you're set up).
It's a tough call. I'd much rather have them fix the code but in some cases that's just not going to happen... at least not in the near future.
Hope this helps.

Selenium: How to find element by partial href?

Working code 1:
Driver.Instance.FindElement( By.XPath("//a[contains(#href,'" + PartialLinkHref + "')]" ));
Working code 2:
ReadOnlyCollection<IWebElement> linkList = Driver.Instance.FindElements(By.TagName("a"));
for (int i = 0; i < linkList.Count ; i++)
{
if (linkList[1].GetAttribute("href").Contains(PartialLinkHref))
{
element.SetElement(linkList[i]);
return element;
break;
}
}
The problem with your initial selector is that you're missing the // in front of the selector. the // tells XPath to search the whole html tree.
This should do the trick:
Driver.Instance.FindElement(By.XPath("//a[contains(#href, 'long')]"))
If you want to find children of an element, use .// instead, e.g.
var element = Driver.Instance.FindElement("..some selector..")
var link = element.FindElement(".//a[contains(#href, 'long')]"))
If you want to find a link that contains text and not by the href attribute, you can use
Driver.Instance.FindElement(By.XPath("//a[contains(text(), 'long')]"))
I don't think the problem is your selector, I think it's the object you're trying to return the results of FindElements to.
In c#, FindElements returns a ReadOnlyCollection<IWebElement> object, not a List object. If you change your linkList definition, it should work:
ReadOnlyCollection<IWebElement> linkList = Driver.Instance.FindElements(By.TagName("a"));
You may also need to add this using:
using System.Collections.ObjectModel;

Xdocument,Descendants in C#

I have the below code to get alexa page rank.
private int GetAlexaRank(string domain)
{
var alexaRank = 0;
try
{
var url = string.Format("http://data.alexa.com/data?cli=10&dat=snbamz&url={0}", domain);
var doc = XDocument.Load(url);
var rank = doc.Descendants("POPULARITY").Select(node => node.Attribute("TEXT").Value).FirstOrDefault();
if (!int.TryParse(rank, out alexaRank))
alexaRank = -1;
}
catch (Exception e)
{
return -1;
}
return alexaRank;
}
But I truly don't understand how does that code work???
Would you tell me exactly, what is the "POPULARITY" and "TEXT"? and where are they stored?
I don't understand this syntax: doc.Descendants("POPULARITY").Select(node => node.Attribute("TEXT").Value).FirstOrDefault();
Please!!!!
I would recommend you navigating to the url you have in your code and take a look at the XML file structure. You should see tags with POPULARITY and TEXT, by the look of your code these are the nodes/attributes/values that you are selecting.
.Descendants returns a collection, and since you provide POPULARITY it will bring back the elements within the <POPULARITY> tag in your XML file.
You are then looking at each node in the Collection whose Descendants are Popularity and selecting an item with attribute TEXT. Your return the first value found, or null if the collection does not contain a node with attribute TEXT.

Categories