为什么我在 Driver.FindElementsByCssSelector(); 刚刚检索到的元素上得到 StaleElementReferenceException;

Why I'm getting StaleElementReferenceException on just retrieved elements by Driver.FindElementsByCssSelector();

我使用edge webdriver在页面(SPA)上查找元素,并立即模拟点击。

但是,我收到 OpenQA.Selenium.StaleElementReferenceException:过时的元素参考:元素未附加到页面文档。

如果元素在查找元素和单击之间被 SPA 框架重新呈现,我添加了一些重试逻辑,但我仍然收到错误。

IWebElement FirstCell => Driver.FindElementsByCssSelector(".simple-grid .sg-row>.sg-cell").FirstOrDefault();


void Test()
{
  try 
  {
    FirstCell.Click();
  }
  catch (StaleElementReferenceException)
  {
    FirstCell.Click(); //retry - this should find element againand return new instance
  }
}

注意,在重试块中我得到了新的元素引用

here 和许多其他教程和问题所述 StaleElementReferenceException 通过 Driver.FindElementsByCssSelector(".simple-grid .sg-row>.sg-cell") 命令,您实际上捕获了与传递的定位器匹配的 Web 元素并将对它的引用存储在IWebElement FirstCell.
但是由于网页仍在动态变化,尚未最终构建,因此您存储的引用很快就会变得陈旧、陈旧、无效,因为 web 元素已更改。
这就是为什么通过在 try 块中包含 FirstCell.Click() 你会得到 StaleElementReferenceException.
尝试在 catch 块中涉及完全相同的操作将再次抛出 StaleElementReferenceException,因为您仍在使用已知的无效(陈旧)FirstCell 引用。
要使代码正常工作,您可以做的是在 catch 块中获取该元素引用 Again 并尝试单击它。
像这样:

IWebElement FirstCell => Driver.FindElementsByCssSelector(".simple-grid .sg-row>.sg-cell").FirstOrDefault();


void Test()
{
  try 
  {
    FirstCell.Click();
  }
  catch (StaleElementReferenceException)
  {
    FirstCell = Driver.FindElementsByCssSelector(".simple-grid .sg-row>.sg-cell").FirstOrDefault();
    FirstCell.Click(); //retry - Now this indeed should find element again and return new instance
  }
}

然而,这也不一定有效,因为页面可能仍未完全稳定。
要完成这项工作,您可以循环执行此操作,如下所示:

void Test()
{
  IWebElement FirstCell;
  for(int i=0;i<10;i++){
    try 
    {
      FirstCell = Driver.FindElementsByCssSelector(".simple-grid .sg-row>.sg-cell").FirstOrDefault();
      FirstCell.Click();
    }
    catch (StaleElementReferenceException)
    {
      System.Threading.Thread.Sleep(200);
    }
  }
}