Getting ALL attributes from an IWebElement with Selenium WebDriver - c#

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

Related

How to get innertext of all li elements in an list with puppeteer-sharp and XPath in C#

I am trying to get all the innertext from a list of "li"-elements. It seems I am hitting something, there are 19 elements in the variable has, but I don't know how to pick out the actual innertext values:
string xpath = "//h1[#title='UL']//li";
IElementHandle[] has = await ((IPage)pageTabel).XPathAsync(xp);
IJSHandle ha = has[0].GetPropertiesAsync("value");
I think e.g.
foreach (var listItem in has)
{
Console.WriteLine((await listItem.GetPropertyAsync("textContent")).RemoteObject.Value.ToString());
}
would work. I don't know whether browser's also implement the (originally IE only) innerText property, if they do then of course above doing GetPropertyAsync("innerText") instead should also work.
If you'd prefer a strongly typed experience then PuppeteerSharp.Dom provides a set of extensions to PuppeteerSharp.
Install PuppeteerSharp.Dom from Nuget.org then you can use the strongly typed extensions.
// Add using PuppeteerSharp.Dom; to access XPathAsync<T>
string xpath = "//h1[#title='UL']//li";
var has = await ((IPage)pageTabel).XPathAsync<HtmlListItemElement>(xpath);
foreach (var listItem in has)
{
var textContent = await listItem.GetTextContentAsync();
}

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;

How to get all options in a drop-down list by Selenium WebDriver using C#?

I'm new to both C# and Selenium WebDriver.
I know how to select/click on an option in a drop-down list, but I've a problem before that. Since the drop-down list is dynamically generated, I have to get all options/values from the list before running each case.
Is there anyone kindly tell me how to get all values/options from a drop-down list. I'm using IE and I didn't find any class which supports method to get values/options in Selenium.IE namespace for C#.
My example:
A list contains several time zones:
<TD>
<select name = "time_zone">
<option value "-09:00"><script>timezone.Alaska</script></option>
<option value "+00:00"><script>timezone.England</script></option>
<option value "+02:00"><script>timezone.Greece</script></option>
<option value "+05:30"><script>timezone.India</script></option>
</select>
<TD>
This is a drop-down list in an IE page and how to get the dynamically generated time zone list?
My code:
IWebElement elem = driver.FindElement(By.XPath("//select[#name='time_zone']"));
List<IWebElement> options = elem.FindElements(By.TagName("option"));
C# just pops an Error:
Cannot implicitly covert type 'OpenQA.Selenium.IWebElement' to 'System.Collections.Generic.List'. An explicit conversion exists (are you missing a cast?).
thanks.
You can try using the WebDriver.Support SelectElement found in OpenQA.Selenium.Support.UI.Selected namespace to access the option list of a select list:
IWebElement elem = driver.FindElement(By.XPath("//select[#name='time_zone']"));
SelectElement selectList = new SelectElement(elem);
IList<IWebElement> options = selectList.Options;
You can then access each option as an IWebElement, such as:
IWebElement firstOption = options[0];
Assert.AreEqual(firstOption.GetAttribute("value"), "-09:00");
Select select = new Select(driver.findElement(By.id("searchDropdownBox")));
select.getOptions();//will get all options as List<WebElement>
Make sure you reference the WebDriver.Support.dll assembly to gain access to the OpenQA.Selenium.Support.UI.SelectElement dropdown helper class. See this thread for additional details.
Edit: In this screenshot, you can see that I can get the options just fine. Is IE opening up when you create a new InternetExplorerDriver?
Here is code in Java to get all options in dropdown list.
WebElement sel = myD.findElement(By.name("dropdown_name"));
List<WebElement> lists = sel.findElements(By.tagName("option"));
for(WebElement element: lists)
{
String var2 = tdElement.getText();
System.out.println(var2);
}
Hope it may helpful to someone.
You can use selenium.Support to use the SelectElement class, this class have a property "Options" that is what you are looking for, I created an extension method to convert your web element to a select element
public static SelectElement AsDropDown(this IWebElement webElement)
{
return new SelectElement(webElement);
}
then you could use it like this
var elem = driver.FindElement(By.XPath("//select[#name='time_zone']"));
var options = elem.AsDropDown().Options
Use IList<IWebElement> instead of List<IWebElement>.
For instance:
IList<IWebElement> options = elem.FindElements(By.TagName("option"));
foreach (IWebElement option in options)
{
Console.WriteLine(option.Text);
}
To get all the dropdown values you can use List.
List<string> lstDropDownValues = new List<string>();
int iValuescount = driver.FindElement(By.Xpath("\html\....\select\option"))
for(int ivalue = 1;ivalue<=iValuescount;ivalue++)
{
string strValue = driver.FindElement(By.Xpath("\html\....\select\option["+ ivalue +"]"));
lstDropDownValues.Add(strValue);
}
WebElement drop_down =driver.findElement(By.id("Category"));
Select se = new Select(drop_down);
for(int i=0 ;i<se.getOptions().size(); i++)
System.out.println(se.getOptions().get(i).getAttribute("value"));
WebElement element = driver.findElement(By.id("inst_state"));
Select s = new Select(element);
List <WebElement> elementcount = s.getOptions();
System.out.println(elementcount.size());
for(int i=0 ;i<elementcount.size();i++)
{
String value = elementcount.get(i).getText();
System.out.println(value);
}
To get all options in a drop-down list by Selenium WebDriver C#:
SelectElement TimeZoneSelect = new SelectElement(driver.FindElement(By.Name("time_zone")));
IList<IWebElement> ElementCount = TimeZoneSelect.Options;
int ItemSize = ElementCount.Count;
for (int i = 0; i < ItemSize; i++)
{
String ItemValue = ElementCount.ElementAt(i).Text;
Console.WriteLine(ItemValue);
}
It seems to be a cast exception. Can you try converting your result to a list
i.e. elem.findElements(xx).toList ?
You need to pass the desired select webelement here and you can use getOptions() that helps you to get all the options of the drop-down.
Now you can get all the elements one-by-one using loop and you can print it on the console.
Select s = new Select(driver.findElement(By.xpath("<xpath>")));
// getting the list of options in the dropdown with getOptions()
List <WebElement> op = s.getOptions();
int size = op.size();
for(int i =0; i<size ; i++)
{
String options = op.get(i).getText();
System.out.println(options);
}

Categories