Selenium WaitDriver不等待元素可点击

时间:2015-08-12 07:17:05

标签: c# ajax selenium-webdriver

当我点击一个按钮时,它会显示一个带有其他按钮的表单,我想点击其中一个按钮。这是一个带有此视频的视频(非常简短),请观看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()等待2个条件:元素可见,元素已启用。

当我在点击第二个按钮之前使用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. 我点击该元素,它返回一个不可点击的错误。
  5. 请大家告诉我我的流程有什么问题,以及如何正确管理。

    更新: 我正在添加按钮的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">
    

5 个答案:

答案 0 :(得分:1)

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

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

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

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

您可以在我的博客文章-Approaches to handling AJAX in Web Automation (Selenium)

中看到更多详细的概述。

答案 1 :(得分:0)

尝试使用presenceOfElementLocated,而不是使用ElementToBeClickable。我认为你的预期元素不存在于DOM中,所以首先尝试使用presenceOfElementLocated。一旦它出现在DOM上,那么使用ElementToBeClickable。

答案 2 :(得分:0)

尼,

正如对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...

希望这些组合可能会让你摆脱修复。

答案 3 :(得分:0)

 //   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);
        }
    }

答案 4 :(得分:0)

我遇到了这个问题并检查该元素是否可点击,可见,定位(或其组合)等是不够的。 Selenium仍未等待,并试图点击该元素。

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

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