【问题标题】:Selenium WaitDriver doesn't wait for element to be clickableSelenium WaitDriver 不等待元素可点击
【发布时间】:2015-08-12 07:17:05
【问题描述】:

当我点击一个按钮时,它会显示一个带有其他按钮的表单,我想点击其中一个。这是一个视频(真的很短),请观看http://screencast.com/t/zyliSemW1s1

所以我就这样点击了“买票”按钮:

button.Click();

然后我等待下一个按钮可以点击。

我使用下一个代码:

WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(15));
IWebElement element = wait.Until(ExpectedConditions.ElementToBeClickable(myButton));

然后我点击我等待的按钮:

element.Click();

我得到错误:此时元素不可点击。

据我所知,ExpectedConditions.ElementToBeClickable() 方法等待两个条件:元素可见且元素已启用。

当我在单击第二个按钮之前使用 Thread.Sleep(3000) 时,代码有效并且按钮是可点击的。

我看到了类似的问题,解决方法是等待这个按钮的处理程序:Selenium Wait doesn't wait for Element to be Clickable

但是如果我不知道如何处理它怎么办?我认为它由 jQuery 处理,我使用下一个代码等到它停止执行:

var ajaxIsComplete = (bool)
    ((IJavaScriptExecutor)Driver).ExecuteScript("return jQuery.active == 0");

如果它返回“false”,我会等待并再次检查。

但还是不行。

所以现在我的流程是这样的:

  1. 我点击“买票”按钮
  2. 我等到 jQuery 停止执行
  3. 我等到元素可以使用 ExpectedConditions.ElementToBeClickable() 方法点击
  4. 我单击该元素,它返回一个错误,指出它不可单击。

请大家告诉我我的流程出了什么问题以及如何正确管理它。

更新: 我正在添加按钮的 HTML 代码:

我点击这个:

<button class="btn btn-warning play-now" name="button" type="submit">Buy Tickets</button>

然后等待这个:

<img alt="Credit Card" class="merchant" src="https://numgames-production.s3.amazonaws.com/uploads/merchant/image/21/CC_Offline.png?AWSAccessKeyId=AKIAJ2Q64HPERGHAJJUA&amp;Expires=1470984765&amp;Signature=Qj%2BFSQ3ElctkY6KTMfzp%2FedPjPo%3D">

【问题讨论】:

  • 你能把这个增加到 30 吗? WebDriverWait(Driver, TimeSpan.FromSeconds(15)); 然后试试看。
  • 当然我试过了。它不起作用。事实上,我需要 1-2 秒才能完成。但它不会等待它......
  • 我知道你不应该使用这种方法:ElementToBeClickable
  • denis,我将添加一些扩展方法,用于在类似于您自己的场景中导航这些波涛汹涌的水域。请注意,这些可能无法形成答案,只是帮助您克服障碍的跳板
  • 你能分享按钮的 html 吗?

标签: c# ajax selenium-webdriver


【解决方案1】:

丹尼斯,

正如 cmets to OP 中提到的,这里有一些小扩展方法可能对您的任务有所帮助:

public static void WaitForAjax(this IWebDriver driver, int timeoutSecs = 10, bool throwException = false)
{
    for (var i = 0; i < (timeoutSecs*10); i++)
    {
        var javaScriptExecutor = driver as IJavaScriptExecutor;
        var ajaxIsComplete = javaScriptExecutor != null && (bool)javaScriptExecutor.ExecuteScript("return jQuery.active == 0");
        if (ajaxIsComplete) return;
        Thread.Sleep(100);
    }
    if (throwException)
    {
        throw new Exception("WebDriver timed out waiting for AJAX call to complete");
    }
}

public static bool ElementExists(this IWebDriver driver, By condition)
{
    return ElementExists(driver, condition, new TimeSpan());
}

public static bool ElementExists(this IWebDriver driver, By condition, TimeSpan timeSpan)
{
    bool isElementPresent = false;

    if (timeSpan == default(TimeSpan))
    {
        timeSpan = TimeSpan.FromMilliseconds(15000);
    }

    var driverWait = new WebDriverWait(driver, (TimeSpan)timeSpan);
    driverWait.IgnoreExceptionTypes(typeof(WebDriverTimeoutException));
    isElementPresent = driverWait.Until(x => x.FindElements(condition).Any());

    return isElementPresent;
}

public static IWebElement FindElementAfterWait(this IWebDriver driver, By condition, int fromSeconds = 90)
{
    bool isElementPresent = false;
    IWebElement singleElement = null;

    var driverWait = new WebDriverWait(driver, TimeSpan.FromSeconds(fromSeconds));
    driverWait.IgnoreExceptionTypes(typeof(WebDriverTimeoutException));

    try
    {
        isElementPresent = driverWait.Until(ExpectedConditions.ElementExists(condition)) != null;

        if (isElementPresent)
        {
            singleElement = driver.FindElement(condition);
        }
    }
    catch
    {
        // log any errors
    }

    return singleElement;
}

用法:

bool elementExists = _driver.ElementExists(By.Id("submitButton"));

var submitButton = _driver.FindElementAfterWait(By.Id("submitButton"));
submitButton.Click();
_driver.WaitForAjax();

// then do other code stuff...

希望这些组合可以让您摆脱困境。

【讨论】:

  • 所以你真正改变的是你用来等待元素的方法。您使用“ExpectedConditions.ElementExists”。我会尝试,但我怀疑这会奏效。感谢您的尝试)
  • Deni - PLUS,WaitForAjax 方法循环直到 ajax 代码完成,或者在任意时间后超时
  • 是的..我有相同的代码)我想我们是从同一个来源复制的)
【解决方案2】:

这是处理任何异步 (AJAX) 页面的典型问题。

您不需要使用任何“魔法”方法,例如 sleep、jquery.active 和预期条件。

网页通常以用户在操作结束时看到的方式构建 - 例如出现一些消息,或启用一些按钮。我相信在您的情况下,您单击“购买门票”后也会发生类似的情况 - 您需要注意这一点并在您的代码中等待这一点。

需要针对您的具体情况使用显式等待来执行该等待。这是管理异步页面(包括尚未可点击的元素)的唯一可靠方法。

您可以在我的博文中看到更详细的概述 - Approaches to handling AJAX in Web Automation (Selenium)

【讨论】:

    【解决方案3】:

    尝试使用 presentOfElementLocated,而不是使用 ElementToBeClickable。我认为您的预期元素在 DOM 上不存在,因此请先尝试使用 presentOfElementLocated。一旦它出现在 DOM 上,然后使用 ElementToBeClickable。

    【讨论】:

    • 我一起尝试了下一个方法:ExpectedConditions.PresenceOfAllElementsLocatedBy(); ExpectedConditions.ElementExists(); ExpectedConditions.ElementToBeSelected(); ExpectedConditions.ElementToBeClickable();
    • 我也有同样的问题,这些都没有帮助:(
    • 这些条件(或它们的组合)都不适合我
    【解决方案4】:
     //   public void test() 
       {
            IWebDriver driver = new ChromeDriver();
            ClickSaveButton(driver,"MyButton",10); //Wait for 10 seconds
        }
    
     //Customized wait block 
    public void ClickSaveButton(IWebDriver driver,String ElementID = "" int TimeOut)
        {
            Console.Error.WriteLine("Waiting....");
            try
            {
               driver.FindElement(By.Id(ElementID)).Click();
            }
            catch (Exception exception)
            {
                Thread.Sleep(1000);
                if (TimeOut > 0) ClickSaveButton(driver, TimeOut - 1);
            }
        }
    

    【讨论】:

      【解决方案5】:

      我遇到了这个问题,并且检查元素是否可点击、可见、定位(或它们的组合)等是不够的。 Selenium 仍然没有等待并尝试点击该元素。

      我为我的案例找到的唯一解决方案是一种不好的做法,但可以作为一种解决方法。我尝试在 Falgun Cont 响应中使用 Try/Catch 获取循环内的元素:

      StackExchange - How to wait for element to be clickable in WebDriver with C#

      【讨论】:

        猜你喜欢
        • 2020-02-23
        • 2016-12-29
        • 2018-02-19
        • 2012-03-26
        • 2019-10-16
        • 1970-01-01
        • 2020-02-23
        • 2022-11-28
        • 2015-10-11
        相关资源
        最近更新 更多