Selenium: How to find element by partial href? - c#

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;

Related

Selenium how to determine if element has child?

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

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.

Getting ALL attributes from an IWebElement with Selenium WebDriver

I want to extract some information from the DOM with Selenium. I'm using the C# WebDriver.
Looking at the IWebElement interface you can easily extract a given attribute. However, I would like to extract all the attributes of an element without knowing their names in before hand.
There must be some simple way of doing this since there is a method for getting an attribute value if you know its name.
An example:
<button id="myButton" ng-click="blabla()" ng-show="showMyButton"
some-other-attribute="foo.bar" />
IWebElement element = driver.FindElement(By.Id("myButton"));
Dictionary<string, string> attributes = new Dictionary<string, string>();
// ???????
// Profit.
Hopefully I'm missing something obvious.
Thanks in advance!
The .attributes property in JavaScript will return an array of all the attributes a given element has and it's value.
So what you'll need to do is first get a driver that has the capability to run JavaScript:
IJavascriptExecutor javascriptDriver = (IJavaScriptExecutor)driver;
Now, execute it by:
Dictionary<string, object> attributes = javascriptDriver.ExecuteScript("var items = {}; for (index = 0; index < arguments[0].attributes.length; ++index) { items[arguments[0].attributes[index].name] = arguments[0].attributes[index].value }; return items;", element) as Dictionary<string, object>;
The idea behind the JavaScript is to use the JavaScript attributes property within the element itself and then pull out the information we need - the name and value of the attribute. The attributes property, in reality, pulls a lot of information about each individual property but we want only two fields. So we get those two fields, put them into a dictionary and WebDriver will then parse it back to us. (It could probably be cleaned up a bit)
It's now a Dictionary and thus you can loop through however you like. The key of each pair will be the name of the attribute, and the value of each pair will be the value of the attribute.
Only tested this with a few elements dotted around the web (here, Google, and a few small web pages) and it seems to work well.
You can try this:
IWebElement element = driver.FindElement(By.Id("myButton"));
string elementHtml = element.GetAttribute("outerHTML");
This will give you the html of the element. From here, you can parse it, as Arran suggested
List<IWebElement> el = new List<IWebElement>(); el.AddRange(driver.FindElements(By.CssSelector("*")));
List<string> ag= new List<string>();
for (int b = 0; b < el.Count; b++)
{
ag.Add(el[b].GetAttribute("outerHTML"));
}
you can do a FindElement(By.tag("body")) to return a list of WebElements and then parse the results as you suggest.
You can try this:
Actions newTab = new Actions(web driver);
newTab.ContextClick(element).SendKeys(Keys.ArrowDown).SendKeys(Keys.ArrowDown).SendKeys(Keys.Return).Build().Perform();
I have created WebDriver Extension based on the first answer
public static List<string> GetElementAttributes(this RemoteWebDriver driver, IWebElement element)
{
IJavaScriptExecutor ex = driver;
var attributesAndValues = (Dictionary<string, object>)ex.ExecuteScript("var items = { }; for (index = 0; index < arguments[0].attributes.length; ++index) { items[arguments[0].attributes[index].name] = arguments[0].attributes[index].value }; return items;", element);
var attributes = attributesAndValues.Keys.ToList();
return attributes;
}

Categories