当我点击一个按钮时,它会显示一个带有另一个按钮的表单,我想点击其中一个按钮。这是一个视频(真的很短),请观看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”,我等待并再次检查。
但它仍然无效。
所以现在我的流程是这样的:
请大家告诉我我的流程有什么问题,以及如何正确管理它。
更新:我正在添加按钮的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&Expires=1470984765&Signature=Qj%2BFSQ3ElctkY6KTMfzp%2FedPjPo%3D">
这是使用任何异步(AJAX)页面的典型问题。
您不需要使用任何“神奇”方法,如sleeps,jquery.active和预期条件。
网页通常以用户在操作结束时看到的方式构建 - 例如某些消息出现,或某些按钮变为启用状态。我相信你的情况也会发生这样的事情,你点击“购买门票”后 - 你需要注意这一点,并在你的代码中等待这一点。
需要使用显式等待您的特定情况执行该等待。这是管理异步页面(包括尚未可点击的元素)的唯一可靠方法。
您可以在我的博客文章中找到更详细的概述 - Approaches to handling AJAX in Web Automation (Selenium)
而不是使用ElementToBeClickable,尝试使用presenceOfElementLocated。我认为你的预期元素不存在于DOM中,所以首先尝试使用presenceOfElementLocated。一旦它出现在DOM上,然后使用ElementToBeClickable。
丹尼斯,
正如对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...
希望这些组合可能会让你摆脱困境。
// 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);
}
}
我正面临这个问题,并检查元素是否可点击,可见,定位(或其组合)等是不够的。 Selenium仍未等待,并试图点击该元素。
我为我的案例找到的唯一解决方案是一个不好的做法,但作为一种解决方法的功能。我尝试将这个元素放在一个带有Try / Catch的循环中,如Falgun Cont响应中所示:
StackExchange - How to wait for element to be clickable in WebDriver with C#