Java Web元素列表中的Selenium Web驱动程序过时引用异常

Java Web元素列表中的Selenium Web驱动程序过时引用异常,java,c#,selenium,selenium-webdriver,Java,C#,Selenium,Selenium Webdriver,我在selenium页面上有一个属性列表,例如: public IEnumerable<MyItem> MyList => webDriverInstance.FindListElementsWithWait<MyItem>(By.ClassName("my-item")); 这是可行的,但问题是我是否在MyItem上有其他属性,而这些属性最初并不在元素上。例如,如果我更改了某些状态,现在会出现“取消”按钮。如果在构造函数中有cancel按钮初始化

我在selenium页面上有一个属性列表,例如:

public IEnumerable<MyItem> MyList =>
        webDriverInstance.FindListElementsWithWait<MyItem>(By.ClassName("my-item"));
这是可行的,但问题是我是否在MyItem上有其他属性,而这些属性最初并不在元素上。例如,如果我更改了某些状态,现在会出现“取消”按钮。如果在构造函数中有cancel按钮初始化,那么它将抛出NoTouchElementException并在页面加载时失败。我可以通过为新的Cancel按钮属性提供一个getter主体来解决这个问题。但这正在产生/促进脆弱的测试


是否有人找到了一种干净的方法来更新/刷新列表中没有唯一定位器的过时WebElement?

在我看来,您设计的问题太多了。我喜欢把事情简单化

By MyItemsBeforeLocator = By.TagName("h4"); // locator for the element BEFORE the page state change
By MyItemsAfterLocator = By.CssSelector("h4.my-item"); // locator for the element AFTER the page state change
WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(10));
ReadOnlyCollection<IWebElement> Items = wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(MyItemsBeforeLocator));
// do stuff with Items

// do stuff that changes the state of the page

Items = wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(MyItemsAfterLocator));
// do stuff with Items
By MyItemsBeforeLocator=By.TagName(“h4”);//页面状态更改前元素的定位器
By MyItemsAfterLocator=By.CssSelector(“h4.my item”);//页面状态更改后元素的定位器
WebDriverWait wait=新的WebDriverWait(驱动程序,TimeSpan.FromSeconds(10));
ReadOnlyCollection Items=wait.Until(预期条件。由(MyItemsBeforeLocator)指定的Allelements的可见性);
//处理物品
//执行更改页面状态的操作
Items=等待.直到(MyItemsAfterLocator指定的Allelements的预期条件.可见性);
//处理物品

我建议您也研究一下页面对象模型。在页面对象中定义给定页面的所有定位器,然后提供使用这些定位器在页面上执行操作的方法。

好的,因此这是javascript中的竞争条件,在AJAX请求完成之前,webdriver正在执行操作@JeffC提出了一个很好的观点,即在处理web元素之前使用驱动程序来提取这些元素,尤其是列表

在我的特殊情况下,我从列表中删除了一个元素。因此,如果您正在获取StaleElementReferenceException并正在从视图中删除一个元素,那么这可能对您有用:

  • 确保使用webdriver在页面上获取最新的元素。因此,如果要更改页面的状态,请确保使用webdriver再次定位元素,以刷新元素
  • 如果仍然得到异常,那么javascript中可能存在竞争条件。因此,请确保在对webelement引用执行操作之前,您正在等待任何动画/ajax请求完成

我发现以下文章在解决此问题时非常有用:

感谢您的回复,为了避免StaleElementReferenceException,前后定位器必须不同吗?我尝试了一种与您的答案类似的方法,但仍然遇到了异常:
Driver.Instance.FindElementsWithWait(By.CssSelector(“.my item h4”)).Select(we=>we.Text).ToList()这仍然会引发异常。FindElementsWithWait将等待代码封装在您的应答器中。否,定位器应特定于您需要抓取它们时它们所处的状态。如果它们总是相同的,那么你应该只需要一个定位器,你只需要返回并再次刮取它。是的,你的自定义函数在我的答案中封装了等待代码,但这就是重点。。。您必须编写和调试15行代码,这些代码的功能与开箱即用的单行方法相同。依我看,这是更多的工作,它更有可能有错误,你必须维护它。。。为什么不使用开箱即用的方法呢?函数是:
public static IEnumerable FindElementsWithWait(此IWebDriver驱动程序,按定位器,int-timeoutmillizes=10000){var wait=new-WebDriverWait(驱动程序,TimeSpan.frommillises(timeoutmillizes));返回wait.untill(ExpectedConditions.VisibilityOfAllElementsLocatedBy(locator));}
它不是15行代码,可以在任何我想使用FindElements并等待的地方重用。我猜javascript和webdriver等待都有竞争条件。
public class MyItem
{
    public string Name { get; private set; }

    public MyItem(IWebElement webElement)
    {
        Name = webElement.FindElement(By.TagName("H4")).Text;
    }
}
By MyItemsBeforeLocator = By.TagName("h4"); // locator for the element BEFORE the page state change
By MyItemsAfterLocator = By.CssSelector("h4.my-item"); // locator for the element AFTER the page state change
WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(10));
ReadOnlyCollection<IWebElement> Items = wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(MyItemsBeforeLocator));
// do stuff with Items

// do stuff that changes the state of the page

Items = wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(MyItemsAfterLocator));
// do stuff with Items