Unjustified stale element-exception (with repro)

51 views
Skip to first unread message

Michael Baas

unread,
Jun 22, 2020, 6:20:06 AM6/22/20
to Selenium Users
I finally found the reason for the exception that's been bugging me for a while. I had accidentally called the test twice - and doing it again caused problems (in my environment). I now succeeded in building a repro (albeit using 2 URLs). Wonder if I am missing any Selenium-mysteries or if I should post it as a bug to the recommended places.

The following C# needs webdriver4 alpha (WebDriver3 has the same problem, but can't read logs, so I can't make the point as clear there)

I have a simple ol or ul and try to move to the first link in the list:
using System;
using System.Diagnostics;
using System.IO;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using static OpenQA.Selenium.By;
using static OpenQA.Selenium.LogType;
using OpenQA.Selenium.Interactions;
using System.Linq;


namespace Stale
{
   
class Program
   
{


       
static void Main()
       
{
           
ChromeOptions options = new ChromeOptions();
            options
.SetLoggingPreference("driver", LogLevel.All);
            options
.AddArgument("--allow-file-access-from-files");
           
ChromeDriverService BSVC = ChromeDriverService.CreateDefaultService("./", "chromedriver.exe");
           
ChromeDriver driver = new ChromeDriver(BSVC, options);
           
var ACTIONS = new OpenQA.Selenium.Interactions.Actions(driver);


            driver
.Navigate().GoToUrl("http://mbaas.de/stale/ol.html");
           
CheckLogs(driver); /* call once to get rid of irrelevant entries */
           
IWebElement link1 = driver.FindElementByCssSelector("#links > li > a");
            ACTIONS
.MoveToElement(link1).Perform();


            driver
.Navigate().GoToUrl("http://mbaas.de/stale/ul.html");
           
System.Threading.Thread.Sleep(5000); /* just to make the point that giving it time to process changes does not help */
           
           
IWebElement link2 = driver.FindElementByCssSelector("#links > li > a");
           
try
           
{
                ACTIONS
.MoveToElement(link2).Perform();
           
}
           
catch (OpenQA.Selenium.StaleElementReferenceException)
           
{
               
Console.WriteLine("Exception! See log for details...");
           
}


           
CheckLogs(driver);
         
//   driver.Dispose(); // Commented this line so that we keep seeing the conle (with the msg about logging the exception)
         
}


       
private static void CheckLogs(ChromeDriver Driver)
       
{
           
File.Delete("./driver.log");
           
System.Collections.Generic.List<LogEntry> logs = Driver.Manage().Logs.GetLog(LogType.Driver).ToList();
           
using StreamWriter sw = File.CreateText("./driver.log");
           
foreach (var entry in logs)
           
{
                sw
.WriteLine(entry.Message);
           
}


       
}


     
   
}
}



I am quite a n00b with C# and also with these driver logs, so some of may conclusions may be wrong - but if I try to apply the scheme seen in the first Find/Move-operation (lines 135 and 143) to the second run (525/533), it looks like the internal ids from the first run are re-used in the 2nd MoveTo. But clearly I'm passing a different value from my code.

Did I so something wrong or could it be a "real" bug?

(BTW, it's not related to ChromeDriver, I can repro with Firefox or Edge as well)


driver.log

Josh Abrahamsen

unread,
Jun 22, 2020, 6:51:20 AM6/22/20
to seleniu...@googlegroups.com
When you called the test twice, were they ran in parallel? If so, then this may explain the issue. Hard to say without seeing true sample code. When running in parallel, you need to have a static field for driver with a [ThreadStatic] attribute. This is the simplest way to achieve multi-threaded capability using NUnit with C#.

My guess is that one instance of your driver crossed with the other if you're not handling threads safely.

--
You received this message because you are subscribed to the Google Groups "Selenium Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to selenium-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/selenium-users/5d3aea54-98c6-4850-8a0c-dab13afb5e08o%40googlegroups.com.

Michael Baas

unread,
Jun 22, 2020, 6:57:21 AM6/22/20
to Selenium Users
Hmm, I'm not sure what you mean with "true sample code". I ran the code above just once - it calls two pages and executes the same code against those pages. The 2nd run fails. Nothing runs parallel.

To unsubscribe from this group and stop receiving emails from it, send an email to seleniu...@googlegroups.com.

Jim Evans

unread,
Jun 23, 2020, 8:00:59 PM6/23/20
to Selenium Users
The StaleElementException is completely justified. You see, Actions instances are cumulative. When you call .Perform(), the Actions class does not clear out the queues actions, so it’s attempting to move to `link1` twice, once during the first move, and again after the navigation to the second page. And after the second navigation, the link to the first element is stale. You should either (1) create a new instance of the (very lightweight, so you shouldn’t be worried about construction time or memory) Actions class, or (2) clear the queued actions list by calling the (Selenium 4-only) .Reset() method.

Michael Baas

unread,
Jun 24, 2020, 5:21:57 AM6/24/20
to Selenium Users
Hurray! Indeed - that Reset finally solves the problem - THANK YOU so much, Jim! :)

Now...how could I have found that? My usual point of reference if https://www.selenium.dev/selenium/docs/api/dotnet/ - but that does not mention Reset. So is it v3 only, is there a different URL for v4? Am I looking at the wrong places?
Reply all
Reply to author
Forward
0 new messages