Selenium2 Webdriver C# .Click() List - Stale Reference Exception - c#

I need some help because I keep getting a StaleElementReference when I try to parse a list of a tags to click.
What I have done is on page land I iterate through the page and generate an object List<> with with all the a tags
private List<IWebElement> _pageLinks;
public List<IWebElement> pageLinks
{
get
{
if (_pageLinks == null)
{
_pageLinks = InfoDriver.FindElements(By.TagName("a")).ToList();
}
return _pageLinks;
}
}
Then I want to parse this list, and click each one and then go back to the page it was referenced from.
private static SeleniumInformation si = new SeleniumInformation(ffDriver);
si.pageLinks.ForEach(i =>
{
i.Click();
System.Threading.Thread.Sleep(1000);
ffDriver.Navigate().Back();
});
What happens is that after the first click it goes to the new page and then goes back to the starting page but it can't get the next link. I've tried setting it to a static element, setting a backing field so that it checks to see if there is data there already however it appears that on click the IwebElement looses the list and it doesn't rebuild the list either so I get a StaleElementReference exception not handled and element not found in cache.
Is this a bug in Selenium with the IWebElement class or am I doing something wrong? Any help would be greatly appreciated.

This is the expected behavior. You left the page the element was on. When you navigated back, it is a new page and that element is no longer on it.
To work around this I would suggest passing around Bys instead, if you can. Assuming your anchorlinks all have unique hrefs, you could instead generate a list as follows (java code, but should translate to c#):
private static List<By> getLinks(WebDriver driver)
{
List<By> anchorLinkBys = new ArrayList<By>();
List<WebElement> elements = driver.findElements(By.tagName("a"));
for(WebElement e : elements)
{
anchorLinkBys.add(By.cssSelector("a[href=\"" + e.getAttribute("href") + "\"]"));
//could also use another attribute such as id.
}
return anchorLinkBys;
}
I don't know the makeup of your page so I don't know if it is possible to generate By's dynamically that uniquely identify the elements you want. For example if all the elements have the same parent, you could use the css level 3 selector nth-child(n). Hopefully you get some ideas from the above code.

private void YourTest()
{
IWebDriver browserDriver = new FirefoxDriver();
browserDriver.Navigate().GoToUrl(pageUrl);
int linkCount= browserDriver.FindElements(By.TagName("a")).Count;
for (int i = 0; i <= linkCount-1; i++ )
{
List<IWebElement> linksToClick = browserDriver.FindElements(By.TagName("a")).ToList();
linksToClick[i].Click();
System.Threading.Thread.Sleep(4000);
if(some boolean check)
{
//Do something here for validation
}
browserDriver.Navigate().Back();
}
broswerDriver.Quit();
}

Related

Selenium C# ImplicitWait won't wait for element to load

I have created a custom method to implicitly wait for an element to load, then I use this in a custom click method as so:
public static void WeElementToBeClickable(this IWebElement element, int sec = 10)
{
var wait = new WebDriverWait(Driver.Browser(), TimeSpan.FromSeconds(sec));
wait.Until(ExpectedConditions.ElementToBeClickable(element));
}
public static void WeClick(this IWebElement element, int sec = 10)
{
element.WeElementToBeClickable();
element.Click();
}
I then attach this to any element I click on to make sure it always polls the DOM to make sure the element has been loaded, but it doesn't seem to wait for some specific elements to load.
I'm searching for this element as so:
<span class="button add fr" onclick="GoToHash('/ContractorCommon/Contractor/ContractorAdd', null, 'Contractor'); "><span class="icon-add"></span> Contractor</span>
public IWebElement AddContractorIcon => Driver.FindElement(By.XPath("//span[#class='button add fr']"));
But it always gives off the following exception straight away:
OpenQA.Selenium.NoSuchElementException : no such element: Unable to locate element: {"method":"xpath","selector":"//span[#class='button add fr']"}
I've tried everything to get it to wait for this element to load but I can't seem to figure it out. Weirdly enough if I debug it...it finds the element.
Any help would be greatly appreciated!

Webbrowser C# How to put a changing value in a textbox?

I cant seem to figure out how to put the value text into a texbox.Text on Webbrowser C# because with this website the value changes and there are duplicates of the input code and cant pinpoint Webbrowser to put the changing value username in a textbox.Text as seen in screenshot below.
I hope someone knows how to do this with the Webbrowser in C#
Thanks in advance.
Problem Screenshot
This is the website I am trying to get the username from: fakepersongenerator
You'd need to manually scan through the DOM and find the element based on it's xpath. Like this:
webBrowser.DocumentCompleted += (o, e) =>
{
var frame1 = webBrowser.Document.Body.GetElementsByClassName("frame-1");
if (frame1.Count > 0)
{
var rows = frame1[0].GetElementsByClassName("row no-margin");
if (rows.Count > 4)
{
var usernameForm = rows[4].GetElementsByClassName("form-control");
if (rows.Count > 0)
{
// Do something with value here
Console.WriteLine(usernameForm[0].GetAttribute("value"));
}
}
}
};
webBrowser.Navigate("http://www.fakepersongenerator.com/Index/generate");
Extension class to :
internal static class Utils
{
internal static List<HtmlElement> GetElementsByClassName(this HtmlElement doc, string className = "")
{
var list = new List<HtmlElement>();
foreach (HtmlElement e in doc.All)
if (e.GetAttribute("className") == className)
list.Add(e);
return list;
}
}
There isn't really a way in the default web browser to detect changes after a page load, so if you wanted to monitor for changes, you'd have to set up a BackgroundWorker or Timer to poll the browser and manually look for a value change.

Selenium Web Driver Stale Reference Exception

I have to click a certain button on a page. However, when I retrieve all of the elements that have a particular class name. All of the retrieved elements throw a stale reference exception when I try to perform each one or click. I can not double click on any of them. It find's the right elements but throws the exception for all of them. The commented out code is where I actually am trying to select and click the appropriate button. I attached a picture of the form. Note that the pages are changed each time a button is clicked or performed. The Select Upload BOM button is what you need to pay particular attention to.
Website
// Switch to correct frame
IWebElement editorFrame = driver.FindElement(By.ClassName("frame-banner"));
driver.SwitchTo().Frame(editorFrame);
var action = new OpenQA.Selenium.Interactions.Actions(driver);
// Select Project File
IList<IWebElement> projectFileButtonList= driver.FindElements(By.ClassName("data-cell"));
foreach (var button in projectFileButtonList)
{
if (button.Text == "BOM_scrub")
{
// Found Project File now select it
action.DoubleClick(button);
action.Perform();
break;
}
}
// Select Upload BOM Button
IList<IWebElement> uploadBomBtn = driver.FindElements(By.ClassName("se-custom-main-button"));
foreach (var element in uploadBomBtn )
{
try
{
action.DoubleClick(element);
action.Perform();
}
catch
{
}
/*
if (element.Text == "Upload BOM")
{
int i = 0;
while (i == 0)
{
try
{
action.DoubleClick(element);
action.Perform();
break;
}
catch
{
}
}
}
*/
}
Don't use driver.findElement(-s) with dynamic components.
StaleElementReferenceException occurs, as you're trying to perform an action against element, which has already been detached from DOM.
You have to use explicit waits mechanism (a combination of WebDriverWait + ExpectedConditions), which automatically refreshes element's state, and returns its valid representation, when specified condition is met.

Clicking on element fails if page is scrolled down/up and element is outside current view

I want to click on specific element, but this element is not displayed in current view, clicking on that element fails.
I tried to set focus on needed element before clicking using the following code
Actions actions = new Actions(driver);
actions.MoveToElement(element);
actions.Perform();
But it fails. Can anyone please help?
One of two things. Is this on a popup by chance? If so you need to switch to the iframe.
public static void switchToIframe(string name)
{
_webDriver.SwitchTo().Frame(name);
}
If the element is off the page and it is a scrolling issue you can try this:
You can pass in a value of 100 to move down 100px.
public static void ScrollDownByAmount(string value)
{
var windowScroll = string.Format("window.scrollBy(0,{0})", value);
IJavaScriptExecutor javascript = (IJavaScriptExecutor)_webDriver;
javascript.ExecuteScript(windowScroll , "");
Thread.Sleep(500);
}

I want to select dropdown element

I want to click a dropdown element. I have mentioned element's xpath/css both. But it is constantly giving error "no element found". I am working on C# on selenium . I have also given dropdown ID first then wait for the dropdown element and then get it clicked but it gives same error always. Any idea ???
It depend of available iFrame or maybe you should switch to default content. It's complicated, without your code.
Any way try this code. It's working for me:
private static void ChooseZipCode(IWebDriver wd)
{
if (!wd.FindElement(By.XPath("//td[#id='divShipStateCombo']/select//option[3]")).Selected)
{
wd.FindElement(By.XPath("//td[#id='divShipStateCombo']/select//option[3]")).Click();
}
}
// where is "[3]" the position your element(ID) in drop down menu
// or
private static void SelectElement(IWebDriver wd, string CardType)
{
SelectElement cardSelect = newSelectElement(wd.FindElement(By.Name("CardType")));
cardSelect.SelectByText("Visa Card");
}

Categories