Selenium在调用FindElements后停止工作

时间:2015-07-15 17:47:15

标签: c# visual-studio selenium selenium-webdriver automated-tests

有时当我调用Selenium FindElements(By)时,它会抛出异常并且我的驱动程序停止工作。参数" BY"也许可能是问题:当我使用不同的搜索相同的元素时,它的工作原理。

此外,我可以看到,即使我的元素存在,或者之前调用了相同参数的相同方法,也不会阻止该方法抛出异常。

我的方法是:

    public IWebElement SafeFindElement(By by)
    {
        try
        {
            IWebElement element;
            if (_driver.FindElements(by).Any())
            {
                element = _driver.FindElements(by).First();
                return element;
            }

            return null;
        }
        catch (NoSuchElementException)
        {
            return null;
        }
        catch (Exception)
        {
            return null;
        }
    }

BY值的一个例子,它不会一直有效(即使它存在于页面中):

By.CssSelector("input[data-id-selenium='entrar']")

例外:

  

WebDriverException

     

对远程WebDriver服务器的URL请求   http://localhost:46432/session/ef6cd2f1bf3ed5c924fe29d0f2c677cf/elements   60秒后超时。

我不知道它是什么或导致这种不稳定的原因。有人有任何消化吗?

@EDIT

我找到了一个临时解决方案。

早期,我试图使用以下方法找到元素:

var element = browser
    .FindElements(By.CssSelector("input[data-id-selenium='entrar']")
    .FirstOrDefault();

或者

var element = browser
    .FindElements(By.XPath("//input[@data-id-selenium='entrar']");
    .FirstOrDefault();

现在,我正在使用:

var element = browser
    .FindElements(By.TagName("input"))
    .FirstOrDefault(x => x.GetAttribute("data-id-selenium") == "entrar");

他们做同样的事情,但第一次抛出一个没有理由的例外。此外,这是一个临时解决方案,我正在尝试解决问题,只使用选择器搜索元素。

2 个答案:

答案 0 :(得分:0)

这是selenium的一个已知问题,webdriver服务器对每个请求的最大超时限制为60秒,并且我没有意识到要改变它,我建议你考虑一下在使用FindElement()之前使用显式等待,虽然可能会出现此问题,但是这个问题的解决方法对我有用,使用我已经实现的扩展方法,想法是等待特定条件,以便如果webdriver抛出一个异常,表示它等待了60秒的最大限制,您可以通过尝试在特定时间段内重复等待特定条件来处理,每次循环时,新请求都会发送到webdriver服务器

    public static void WaitUntil(this IWebDriver webDriver, Func<IWebDriver, bool> predicate, TimeSpan timeout)
    {
        var dtStart = DateTime.Now;

        while (true)
        {
            try
            {
                if (!predicate(webDriver))
                    throw new Exception();

                break;
            }
            catch (Exception ex)
            {
                if (DateTime.Now.Subtract(dtStart) >= timeout)
                    throw ex;
            }

            Thread.Sleep(30000);
        }
    }
    public static void WaitUntil(this IWebDriver webDriver, Func<IWebDriver, IWebElement> predicate, TimeSpan timeout)
    {
        var dtStart = DateTime.Now;

        while (true)
        {
            try
            {
                predicate(webDriver);
                break;
            }
            catch (Exception ex)
            {
                if (DateTime.Now.Subtract(dtStart) >= timeout)
                    throw ex;
            }

            Thread.Sleep(30000);
        }
    }
例如,您可以使用类似

的扩展方法
webDriver.WaitUntil(w => w.Title == "title", TimeSpan.FromMinutes(2));

webDriver.WaitUntil(ExpectedConditions.TitleIs("title"), TimeSpan.FromMinutes(2));

webDriver.WaitUntil(ExpectedConditions.ElementIsVisible(By.Id("elementId")), TimeSpan.FromMinutes(2));

<强>更新

在查看了你的上一条评论后,你说当你使用了FindElements(By.TagName(&#34;输入&#34;))时你得到了一些元素;这意味着你正在使用的选择器导致问题,你可以按标签名称查找元素,然后按属性值过滤结果,或者如果您确定您使用的选择器是正确的并且行为不正确,请尝试调试问题,如果有任何javascript,负责设置属性值,在调用FindElement()之前确保它首先使用隐式或显式等待运行。

答案 1 :(得分:0)

我发现了问题。我在我的所有测试套件中都使用了一种方法来等待加载消息的解除。但它尝试使用jquery,而不是我的应用程序中的所有页面都使用它。

所以,selenium放弃尝试在60秒后执行jquery并返回超时错误,但是这个错误没有破坏Selenium驱动程序,只有FindElements然后它返回一个空列表。当它试图返回空列表时,所有驱动器都坏了。

原始方法:

public void WaitLoadingMessage(int timeout)
{
    while (timeout > 0)
    {
        try
        {
            var loadingIsVisible = _js.ExecuteScript("return $('#loading-geral').is(':visible');").ToString();

            if (loadingIsVisible.ToLower() == "false")
                break;

            Thread.Sleep(1000);
            timeout -= 1000;
        }
        catch (Exception ex)
        {
            if (!ex.Message.ToLower().Contains("$ is not defined"))
                throw;
        }
    }
}

更正:

public void WaitLoadingMessage(int timeout)
{
    while (timeout > 0)
    {
        try
        {
            var loadingIsVisible = _js.ExecuteScript("return $('#loading-geral').is(':visible');").ToString();

            if (loadingIsVisible.ToLower() == "false")
                break;

            Thread.Sleep(1000);
            timeout -= 1000;
        }
        catch (Exception ex)
        {
            if (!ex.Message.ToLower().Contains("$ is not defined"))
                throw;

            break;
        }
    }
}