Selenium c# - OpenQA.Selenium.StaleElementReferenceException:陈旧元素引用:元素未附加到页面文档

时间:2014-12-09 11:46:41

标签: c# selenium selenium-webdriver

希望有人可以帮助解决这个问题...

在与级联下拉菜单进行交互时,我一直收到上述错误消息(请参阅标题)。 我成功使用的唯一基本修复是" Thread.Sleep" ...请参阅下面的代码摘录:

注意我传递了以下参数:

属性:ID

attrval:例如ID123456(下拉列表的ID)

参数:Car(我们想要选择的下拉值)

IWebElement element = findMyElement(attribute, attrval);
SelectElement selectElement = new SelectElement(element);
selectElement.SelectByText(parameter);
// dirty code - needs to be re-written
Thread.Sleep(500);
if (new SelectElement(findMyElement(attribute, attrval)).SelectedOption.Text.Equals(parameter))
{
    return "pass";
}

注意2:findMyElement是一个自定义方法(这是一个摘录):

public static IWebElement findMyElement(string attribute, string attrval)
        {
            WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
            switch (attribute.ToLower())
            {
                case "id":
                    wait.Until(ExpectedConditions.ElementExists(By.Id(attrval)));
                    wait.Until(ExpectedConditions.ElementIsVisible(By.Id(attrval)));
                    return driver.FindElement(By.Id(attrval));

正如我在代码中所说的那样,无论如何我都可以避免使用 Thread.Sleep ,因为我知道这不是推荐的方法。

提前致谢:)

1 个答案:

答案 0 :(得分:1)

看起来好像第一个下拉元素在回发开始时从DOM中卸载,并在回发完成后重新加载到DOM。

当您的代码在回发期间尝试触摸此元素时,会抛出StaleElementReferenceExceptionSleep()调用的工作方式是暂停代码触摸此元素一段时间,这段时间恰好足以让回发完成。

理想的解决方案是确定回发何时完成。

一旦回发完成,什么谓词才会返回true?将Sleep()替换为等待该谓词返回true。

e.g。如果第二个下拉菜单仅显示在回发上,请将Thread.Sleep(500);替换为:

Func<IWebDriver, bool> predicate = (x) =>
{
    try
    {
        IWebElement elementThatOnlyAppearsOnPostback = findMyElement(attribute, attrval);
        return true;
    }
    catch (NoSuchElementException)
    {
        return false;
    }
};
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30)); // or whatever timeout you want to set
wait.Until(predicate);

如果第二个下拉列表已经存在,但只会在回发中填充选项,请将谓词切换为:

Func<IWebDriver, bool> predicate = (x) =>
{
    SelectElement secondDropDown = new SelectElement(findMyElement(attribute, attrval));
    return (secondDropDown.Options.Count > 0);
}