I am using Selenium 2 to test an asp.net web forms page using the InternetExplorerDriver and am encountering a StaleElementReferenceException. The page contains a (auto-postback) drop down list, which I am selecting different values from.
Example code:
Page:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication.WebForm1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DropDownList ID="ddl" runat="server" AutoPostBack="true">
<asp:ListItem Text="one"></asp:ListItem>
<asp:ListItem Text="two"></asp:ListItem>
</asp:DropDownList>
</div>
</form>
</body>
</html>
(The code-behind file contains nothing more than the Visual Studio auto-created stuff.)
Test fixture code:
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.IE;
namespace IntegrationTests
{
[TestFixture]
public class WebForm1TestFixture
{
[Test]
public void ShouldSelectItemOneThenItemTwo()
{
IWebDriver driver = new InternetExplorerDriver(); // Using ChromeDriver causes test to pass...
driver.Navigate().GoToUrl("http://localhost/<my-virtual-directory-name>/WebForm1.aspx");
IWebElement list = driver.FindElement(By.Id("ddl"));
IWebElement itemOne = list.FindElement(By.XPath("option[1]"));
itemOne.Select();
list = driver.FindElement(By.Id("ddl"));
IWebElement itemTwo = list.FindElement(By.XPath("option[2]"));
itemTwo.Select();
list = driver.FindElement(By.Id("ddl"));
itemOne = list.FindElement(By.XPath("option[1]"));// This line causes the StaleElementReferenceException to occur
itemOne.Select();
// Some assertion would go here
}
}
}
When I run the test I get the following error:
OpenQA.Selenium.StaleElementReferenceException: Element is no longer valid
at OpenQA.Selenium.Remote.RemoteWebDriver.UnpackAndThrowOnError(Response errorResponse) in e:\Projects\WebDriver\trunk\remote\client\src\csharp\webdriver-remote-client\RemoteWebDriver.cs: line 883
at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(DriverCommand driverCommandToExecute, Dictionary`2 parameters) in e:\Projects\WebDriver\trunk\remote\client\src\csharp\webdriver-remote-client\RemoteWebDriver.cs: line 727
at OpenQA.Selenium.Remote.RemoteWebElement.FindElement(String mechanism, String value) in e:\Projects\WebDriver\trunk\remote\client\src\csharp\webdriver-remote-client\RemoteWebElement.cs: line 570
at OpenQA.Selenium.Remote.RemoteWebElement.FindElementByXPath(String xpath) in e:\Projects\WebDriver\trunk\remote\client\src\csharp\webdriver-remote-client\RemoteWebElement.cs: line 458
at OpenQA.Selenium.By.<>c__DisplayClasse.<XPath>b__c(ISearchContext context) in e:\Projects\WebDriver\trunk\common\src\csharp\webdriver-common\By.cs: line 119
at OpenQA.Selenium.By.FindElement(ISearchContext context) in e:\Projects\WebDriver\trunk\common\src\csharp\webdriver-common\By.cs: line 227
at OpenQA.Selenium.Remote.RemoteWebElement.FindElement(By by) in e:\Projects\WebDriver\trunk\remote\client\src\csharp\webdriver-remote-client\RemoteWebElement.cs: line 267
at IntegrationTests.WebForm1TestFixture.ShouldSelectItemOneThenItemTwo() in WebForm1TestFixture.cs: line 25
If I change the test to use a ChromeDriver then the test passes. It seems to me like this means it is either a problem with the InternetExplorerDriver or the Internet Explorer browser itself. Does anybody know which and if there's anything I can do to get round this (the site will be used in IE by the end users, so changing browsers isn't possible, unfortunately)?
EDIT: The current work-around that I am using is to put a Thread.Sleep()
after the list has been selected; this works but obviously isn't an ideal solution.
I found calling
driver.refresh()
after going to the page that it worked fine, my code is:The list element could be changing in the DOM due to the autopostback. Try refinding the list element each time you select an option. E.g.
Below is the pattern I ended up implementing.
After each
item*.Select()
I've implemented a wait:Where <some-condition-to-wait-for> is a way of determining that the item selection has finished (for example, by checking that another control on the page has been updated, e.g.
MyCustomWebDriverWait
is a class that implementsIWait<IWebDriver>
and is almost identical to the WebDriverWait class, only it catchesStaleElementReferenceException
as well asNotFoundException
(which meant changing the type oflastException
fromNotFoundException
toWebDriverException
.You can read how I was pointed in this direction by Daniel Wagner-Hall on the Selenium-users google group here.