When I click on a button it displays me a form with another buttons and I want to click on one of them. Here is a video with this (really short one), please watch http://screencast.com/t/zyliSemW1s1
So I click on button "Buy Tickets" simply like that:
button.Click();
And then I wait for the next button to be clickable.
I use the next code:
WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(15));
IWebElement element = wait.Until(ExpectedConditions.ElementToBeClickable(myButton));
After that I click on button that I waited for:
element.Click();
And I get error: Element is not clickable at that point.
As I know, the method ExpectedConditions.ElementToBeClickable() waits for 2 conditions: element is visible and element is enabled.
When I use Thread.Sleep(3000) before clicking on the second button the code works and button is clickable.
I saw similar issue and the solution was to wait for handlers of this button:Selenium Wait doesn't wait for Element to be Clickable
But what to do if I don't know what handles it? I think it handles by jQuery and I use the next code to wait till it stops executing:
var ajaxIsComplete = (bool)
((IJavaScriptExecutor)Driver).ExecuteScript("return jQuery.active == 0");
If it returns "false" I wait and check again.
But it still doesn't work.
So for now my flow goes like that:
Please guys tell me what is wrong in my flow and how to manage it correct.
Update: I'm adding HTML code of buttons:
I click to this one:
<button class="btn btn-warning play-now" name="button" type="submit">Buy Tickets</button>
And wait for this one:
<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">
#1) elementToBeClickable() – The expected condition waits for an element to be clickable i.e. it should be present/displayed/visible on the screen as well as enabled. wait. until(ExpectedConditions.
This is because the element is present in DOM, but its position is not fixed on the page. Adding the explicit wait. The webdriver can wait till the expected condition - visibilityOf(webdriver shall wait for an element in DOM to be visible). Adding the explicit wait.
var wait = new WebDriverWait(driver, TimeSpan. FromMinutes(1)); var clickableElement = wait. Until(ExpectedConditions.
We can wait until an element is present in Selenium webdriver. This can be done with the help of synchronization concept. We have an explicit wait condition where we can pause or wait for an element before proceeding to the next step. The explicit wait waits for a specific amount of time before throwing an exception.
Denis,
As mentioned in comments to OP, here are a few little extension methods that may help your quest:
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;
}
usages:
bool elementExists = _driver.ElementExists(By.Id("submitButton"));
var submitButton = _driver.FindElementAfterWait(By.Id("submitButton"));
submitButton.Click();
_driver.WaitForAjax();
// then do other code stuff...
Hopefully, a combo of these may get you out of the fix.
This is a typical problem of working with any asynchronous (AJAX) page.
You don't need to use any "magic" methods like sleeps, jquery.active and expected conditions.
Web pages are usually built that way that user would see when operation ends - like some message appears, or some button become enabled. I believe in your case something like this also happens after you click "Buy Tickets" - you need to notice this and wait for this in your code.
That wait needs to be performed using Explicit wait for your specific case. This is the only reliable way to manage asynchronous pages (including elements not yet clickable).
You can see more detailed overview in my blog post - Approaches to handling AJAX in Web Automation (Selenium)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With