C# Selenium Driver - get all elements by text - c#

private IWebDriver webDriver;
[SetUp]
public void Setup()
{
webDriver = new FirefoxDriver();
webDriver.Navigate().GoToUrl("https://localhost:44311/");
}
[Test]
public void ButtonsCount_IsCorrect_IsTrue()
{
var buttons = webDriver.FindElement(...));
...
}
Simple scenario - website contains dynamically created buttons. I want to ensure count of buttons is the same as expected.
Catching it by XPath would be easy, except XPath leads to certain element, here we want to catch multiple dynamically created elements, but each one looks like this:
<a><i></i>Details</a>
The only difference is where href leads, and I have skipped classes because they are not important here.
Conclusions are, it wouls be wise to search for all <a> which contain string Details. Now question is, how to do it in C# driver.

You can use findElements with xpath to find List of elements:
List<WebElement> elementName = driver.FindElements(By.XPath("//a[contains(text(),'Details')]"));

Related

Unable to click web element by xpath via selenium chrome driver

Hellow, i have pop-up window with 'select' element in chrome browser, i need to click this 'select' element in my ui-test scenario. It is on image: my web page
I am using c# and TechTalk.SpecFlow. I am trying to click it like this:
Browser.ClickWebElementNew("/html/body/div[1]/div/select", FoundBy.XPath);
here is realisation of Browser.ClickWebElementNew(), it from selenium chrome driver:
//
public void ClickWebElementNew(
string findElement, FoundBy f
)
{
if (f == FoundBy.XPath)
{
var element = _chromeDriver.FindElement(By.XPath(findElement));
element.Click();
}
else if (f == FoundBy.CssSelector)
{
var element = _chromeDriver.FindElement(By.CssSelector(findElement));
element.Click();
}
}
//
public IWebElement FindElement(By by) => !(by == (By) null) ? by.FindElement((ISearchContext) this) : throw new ArgumentNullException(nameof (by), "by cannot be null");
but i allways get this error:
OpenQA.Selenium.NoSuchElementException : no such element: Unable to locate element: {"method":"xpath","selector":"/html/body/div[1]/div/select
xPath to 'select' is totally correct, i check it many times. i have a enought delay in test scenario before this pop-up window emerge so what i am doing wrong? what i must do to suссessfully click this 'select'?
A couple of suggestions. I would try suggestion 1 first. If that doesn't work, try suggestion 2 as well:
Don't Use Exact XPaths — I see this frequently. Use a combination of tag names, attributes and parent elements to make your locators more robust. In fact, the <select> tag has an Id. Use that. Id attributes must be unique in the HTML document (if they aren't, it is a bug that should be fixed):
Browser.ClickWebElementNew("//select[#id = 'state']", FoundBy.XPath);
This can help keep your tests passing when minor HTML changes are made in the future.
Use An Explicit Wait — You will likely need this as well. You will need to wait for the element to be clickable. If using Selenium 3 or if you have the DotNetSeleniumExtras NuGet package installed, use ExpectedConditions in the ClickWebElementNew method:
public void ClickWebElementNew(string findElement, FoundBy f)
{
var wait = new WebDriverWait(_chromeDriver, TimeSpan.FromSeconds(30));
By locator = null;
if (f == FoundBy.XPath)
{
locator = By.XPath(findElement)
}
else if (f == FoundBy.CssSelector)
{
locator = By.CssSelector(findElement);
}
else
{
throw new InvalidOperationException("Unsupported FoundBy");
}
var element = wait.Until(ExpectedConditions.ElementToBeClickable(locator));
element.Click();
}
If using Selenium 4 and you don't have the DotNetSeleniumExtras package installed, this should work:
var element = wait.Until(d => { d.FindElement(locator).Click(); return true; });
element.Click();
The main reason for "waiting for the element to be clickable" is because certain user interface animations prevent Selenium from interacting with elements. These can be subtle, but important. Any movement, or fade-in can cause issues with interacting with the page.
If ideas 1 and 2 do not work, look to see if the element is inside a frame or iframe. You need to switch to the frame before interacting with its elements. Also look for elements that overlap that same region of the page. This can cause problems too, especially if running in headless mode and you are not setting a window size.

selenium unable to find element button

i am trying to get this button with selenium in c#
<a id="1|0AqnCSdkjQ0|none" href="" target="_self" rel="nofollow" class="download_link 1">Download</a>
i tried with id and class but it didn't work.
Here is the web page:
http://www.mp3juices.cc/ - > on the next page
Your code is failing with that "Compound class" error because you are, basically, asking for two class names.
The button has the class download_link.
If you do something like driver.findElements(By.className("download_link")) you'll get a List of all the buttons, and get whichever you wanted.
(The above snippet is Java, so you may have to adapt it to C#)
you can use this as a solution
driver.findElement(By.xpath("//a[#class='download_link 1'] and contains(text(),'Download')"));
Did you try
driver.FindElement(By.CssSelector("a.download_link.2")
When you tried to use "download_link 2" you were requesting two class names. You can specify two class names (or more) in a CSS Selector and put a period between them. The CSS selector above is read as find an A tag with class download_link and class 2.
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
try
{
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
{
try
{
return d.FindElement(By.ClassName("dl_link 1"));
}
catch
{
return null;
}
});
}
catch(Exception e)
{
}
ReadOnlyCollection<IWebElement> lists = driver.FindElements(By.ClassName("download_link"));
lists[0].Click();
*The code is not optimized, but it works great. (First part i am using to wait for the button to be loaded).

How to scroll up using Protractor.NET?

My web page is little lengthy and the SAVE button is at the top right-hand corner. As I input the data through Protractor.NET, the webpage scrolls down which hides the SAVE button, thereby throwing a Element is not clickable at a point error. Now inorder to save the webpage, I need to scroll up and then find the SAVE button and click it.
I have an example in Protractor which uses window.scrollTo(0,0), but how do I implement the same in Protractor.NET
EDIT: Included code
public void Test()
{
var saveBtn = NgWebDriver
.FindElement(By.ClassName("btnSave"))
.FindElement(By.ClassName("Save"));
var btnSv = Scroller(saveBtn);
btnSv.Click();
}
public IWebElement Scroller(IWebElement element)
{
((IJavaScriptExecutor)NgWebDriver).ExecuteScript("arguments[0].scrollIntoView();", element);
return element;
}
So the exception occurs in Scroller method while casting the NgWebDriver to IJavaScriptExecutor type
How can I accomplish this?
Finally got the solution to scrolling up to the top in Protractor.NET
Had referred the link and was able to solve my problem.
The below code worked for me.
IWebDriver driver = MyWebDriver.WrappedDriver;
IJavaScriptExecutor jse = (IJavaScriptExecutor)driver;
jse.ExecuteScript("scroll(0, -250);");
Why do you want to make it complicated?
If you want to scroll to an element you can use this simple method:
public IWebElement ScrollToElement(IWebElement webElement)
{
((IJavaScriptExecutor)Driver).ExecuteScript("arguments[0].scrollIntoView();", webElement);
return webElement;
}
The below code helped me to achieve the same.
IJavaScriptExecutor jse = (IJavaScriptExecutor)NgDriver;
jse.ExecuteScript("arguments[0].scrollIntoView()", webElement);

Selenium webdriver: IE 11 element.Click() doesnt work

I tried to find any solution but nothing is not helped me.
I have this element
<span data-lkd="GUI-411396" data-lkta="tc" data-lkda="title" class="panelbar_item" title="Hledat">Form</span>
In Selenium I find it with
IWebElement form = GetElementAndWaitForEnabled(By.CssSelector("span[data-lkd=\'GUI-411396\']"));
It's not problem to this part. But if try click on this element in IE11 nothing happend
find.Click()
I tried some solution like:
driver.SwitchTo().Window(driver.CurrentWindowHandle);
find.SendKeys(Keys.Enter);
find.Click();
But nothing happend. In Chrome and Firefox is normaly click on element.
If I clik in other elements for example button it works on IE 11. But I need click on this element.
I'm using Selenium v2.46.0, IE 11 (x86, x64).
With IE, it's always something extra you should do. Try this "special" trick:
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
js.ExecuteScript("arguments[0].click();", find)
It looks like you are trying to click on a span element. Instead of using a work around to click on the span element and trying to get the desired effect, try checking to see if it is wrapped in an anchor element or input / button element.
As an aside a good practice is to remember to always scroll the element into view, an example wrapper function would be:
public static void clickElementAsUser(WebDriver driver, By by)
{
WebElement element;
try
{
element = driver.findElement(by);
scrollElementIntoView(driver, element);
Thread.sleep(100); //Wait a moment for the element to be scrolled into view
element.click();
}
catch(Exception e) //Could be broken into multicatch
{
//Do Something
}
}
public static void scrollElementIntoView(WebDriver driver, WebElement element)
{
try
{
((JavascriptExecutor)driver).executeScript("arguments[0].scrollIntoView(true);", element);
}
catch(Exception e)
{
//Do Something
}
}
If you post a small code sample of what is aroudn the span I may be able to help further. Goodluck!

C# System.Windows.Automation get element text

I am trying to get text/labels from application controls with Automation in C#.
So far I am able to obtain AutomationElement tree of application (for example Notepad) with this function:
private void WalkControlElements(AutomationElement rootElement, TreeNode treeNode)
{
AutomationElement elementNode = TreeWalker.ContentViewWalker.GetFirstChild(rootElement);;
while (elementNode != null)
{
TreeNode childTreeNode = treeNode.Nodes.Add(elementNode.Current.ControlType.LocalizedControlType);
// here I want to get text from 'elementNode'
WalkControlElements(elementNode, childTreeNode);
elementNode = TreeWalker.ControlViewWalker.GetNextSibling(elementNode);
}
}
I tried to follow this article http://msdn.microsoft.com/en-us/library/ms788751(v=vs.110).aspx but it only can get text attributes as font name, font weight and so on.
Could anybody point me to the right procedure how to get element text with Automation?
That sample is showing you how to get text attributes, i.e. information about the display of the text in the UI, not the actual displayed text. Getting all the actual displayed text for a general application is more difficult that it might first appear.
It is made difficult by the fact that there are several ways get text and there is inconsistent support by applications and controls. There are two patterns that are of some use, ValuePattern and TextPattern. By convention the Name property contains text displayed to the user however adherence to this is inconsistent. Below is a helper method that I've used in UI automation for testing. It basically goes through those patterns checking the control for support and falls back to the Name.
public static class AutomationExtensions
{
public static string GetText(this AutomationElement element)
{
object patternObj;
if (element.TryGetCurrentPattern(ValuePattern.Pattern, out patternObj))
{
var valuePattern = (ValuePattern)patternObj;
return valuePattern.Current.Value;
}
else if (element.TryGetCurrentPattern(TextPattern.Pattern, out patternObj))
{
var textPattern = (TextPattern)patternObj;
return textPattern.DocumentRange.GetText(-1).TrimEnd('\r'); // often there is an extra '\r' hanging off the end.
}
else
{
return element.Current.Name;
}
}
}
This takes care of getting the text out of simple controls like labels, textboxes (both vanilla textbox and richtextbox), and buttons. Controls like listboxes and comboboxes (esp. in WPF) can be tricker because their items can be virtualized so they may not exist in the automation tree until the user interacts with them. You may want to filter and call this method only on certain UI Automation control types like Edit, Text, and Document which you know contain text.
Mike Zboray answer works fine. In case you have access to pattern-Matching, here is the same (condensed) code :
public static class AutomationExtensions
{
public static string GetText(this AutomationElement element)
=> element.TryGetCurrentPattern(ValuePattern.Pattern, out object patternValue) ? ((ValuePattern)patternValue).Current.Value
: element.TryGetCurrentPattern(TextPattern.Pattern, out object patternText) ? ((TextPattern)patternText).DocumentRange.GetText(-1).TrimEnd('\r') // often there is an extra '\r' hanging off the end.
: element.Current.Name;
}

Categories

Resources