Webdriver How to Wait Until the Element Is Clickable in Webdriver C#

Webdriver How to wait until the element is clickable in webdriver C#

Well taking a look into the Java source, tells me it is basically doing two things to determine if it's 'clickable':

https://code.google.com/p/selenium/source/browse/java/client/src/org/openqa/selenium/support/ui/ExpectedConditions.java

Firstly, it'll check if it's 'visible' by using the standard ExpectedConditions.visibilityOfElementLocated, it'll then simply check if the element.isEnabled() is true or not.

This can be condensed slightly, this basically means (simplified, in C#):

  1. Wait until the element is returned from the DOM
  2. Wait until the element's .Displayed property is true (which is essentially what visibilityOfElementLocated is checking for).
  3. Wait until the element's .Enabled property is true (which is essentially what the elementToBeClickable is checking for).

I would implement this like so (adding onto the current set of ExpectedConditions, but there are multiple ways of doing it:

/// <summary>
/// An expectation for checking whether an element is visible.
/// </summary>
/// <param name="locator">The locator used to find the element.</param>
/// <returns>The <see cref="IWebElement"/> once it is located, visible and clickable.</returns>
public static Func<IWebDriver, IWebElement> ElementIsClickable(By locator)
{
return driver =>
{
var element = driver.FindElement(locator);
return (element != null && element.Displayed && element.Enabled) ? element : null;
};
}

Usable in something like:

var wait = new WebDriverWait(driver, TimeSpan.FromMinutes(1));
var clickableElement = wait.Until(ExpectedConditions.ElementIsClickable(By.Id("id")));

However, you might have a different idea of what clickable might mean, in which case, this solution may not work - but it is a direct translation of what the Java code is doing.

Selenium C# WebDriver: Wait until element is present

Alternatively you can use an implicit wait:

driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);

An implicit wait is to tell WebDriver to poll the DOM for a certain
amount of time when trying to find an element or elements if they are
not immediately available. The default setting is 0. Once set, the
implicit wait is set for the life of the WebDriver object instance.

Random errors using wait for element clickable method in Selenium

This is what I use in a framework I've created. It eats ElementClickInterceptedException and StaleElementReferenceException and keeps trying until the timeout or success. It got rid of a lot of issues like what you are talking about. There are other ways to do it specific to each page but I found that this works really well in a large number of scenarios.

/// <summary>
/// Clicks on an element
/// </summary>
/// <param name="locator">The locator used to find the element.</param>
/// <param name="timeOut">[Optional] How long to wait for the element (in seconds). The default timeOut is 10s.</param>
public void Click(By locator, int timeOut = 10)
{
DateTime now = DateTime.Now;
while (DateTime.Now < now.AddSeconds(timeOut))
{
try
{
new WebDriverWait(Driver, TimeSpan.FromSeconds(timeOut)).Until(ExpectedConditions.ElementToBeClickable(locator)).Click();

return;
}

catch (ElementClickInterceptedException)
{
// do nothing, loop again
}
catch (StaleElementReferenceException)
{
// do nothing, loop again
}
}

throw new Exception($"Unable to click element <{locator}> within {timeOut}s.");
}

WaitForElementClickable/ Visible - Selenium C#

As I understood your element is visible and clickable when loading element on the screen but overlaying you element, also maybe you need to wait javascript to complete to click successfully.

You need get "loading circles" locator. For that open chrome devtools trigger "loading circles" to appear and press F8(pause) then you can find html of loading element.

Wait until loading element is disappeared:

var wait = new WebDriverWait(Driver.Instance, TimeSpan.FromSeconds(8));
wait.until(ExpectedConditions.invisibilityOfElementLocated(loadingElementLocator);

Also you can check if javascript is complete :

IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
bool jsLoaded = (bool)js.ExecuteScript("return (document.readyState == \"complete\" || document.readyState == \"interactive\")");

Here Java example:

new WebDriverWait(driver, timeoutSec).until(d ->
{
boolean ajaxComplete;
boolean jsReady;
boolean loaderHidden = false;

JavascriptExecutor js = (JavascriptExecutor) d;
jsReady = (boolean) js.executeScript("return (document.readyState == \"complete\" || document.readyState == \"interactive\")");;

try {
ajaxComplete = (boolean) js.executeScript("var result = true; try { result = (typeof jQuery != 'undefined') ? jQuery.active == 0 : true } catch (e) {}; return result;");
} catch (Exception ignored) {
ajaxComplete = true;
}

try {
loaderHidden = !d.findElement(loadElementLocator).isDisplayed();
} catch (Exception ignored) {}

return ajaxComplete && jsReady && loaderHidden;
});

Here your updated code:

public static void WaitForLoading(IWebDriver driver, int timeoutInSeconds)
{
new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds)).Until(d =>
{
Boolean ajaxComplete;
Boolean jsReady;
Boolean loaderHidden = false;

IJavaScriptExecutor js = (IJavaScriptExecutor)d;
jsReady = (Boolean)js.ExecuteScript("return (document.readyState == \"complete\" || document.readyState == \"interactive\")"); ;

try
{
ajaxComplete = (Boolean)js.ExecuteScript("var result = true; try { result = (typeof jQuery != 'undefined') ? jQuery.active == 0 : true } catch (e) {}; return result;");
}
catch (Exception)
{
ajaxComplete = true;
}
try
{
loaderHidden = !d.FindElement(By.ClassName("Loader__background")).Displayed;
}
catch (Exception) { }

return ajaxComplete && jsReady && loaderHidden;
});
}

How to use:

WaitForLoading(driver, 10);
myButton.Click();

How to use Selenium elements to wait, check, click on without finding the elements again?

There is an expected condition for visibility that accepts a WebElement:
https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html#visibilityOf-org.openqa.selenium.WebElement-

Until also returns the element being waited for, so you can combine this into one line:

internal void ClickUpdateButton(TimeSpan timeout)
{
WebDriverWait wait = new WebDriverWait(_driver, timeout);
wait.Until(ExpectedConditions.visibilityOf(UpdateButton)).click();
}

However, in my frameworks I usually add a helper function that does this, as it get's used so much. You can also do similar things with wait until clickable, etc. and have methods that accept a WebElement or a By:

public WebElement waitThenClick(WebElement element) 
{
WebDriverWait wait = new WebDriverWait(_driver, timeout);
return wait.Until(ExpectedConditions.visibilityOf(UpdateButton)).click();
}

Python Selenium: Wait until element is clickable - Element is found using find_elements

You need to take care of a couple of things here as follows:

  • As the searchBar element is a clickable element ideally you need you need to induce WebDriverWait for the element_to_be_clickable() as follows:

    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, "react-select-3-input"))).send_keys(address)
  • Again as the searchButton element is a clickable element you need you need to induce WebDriverWait for the element_to_be_clickable() as follows (in the worst case scenario assuming the searchButton gets enabled when search text is populated):

    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CLASS_NAME, "sc-1mx0n6y-0"))).click()
  • Ideal dropdowns are html-select tags and ideally you should be using the Select class inducing WebDriverWait as follows:

    Select(WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "cssSelector_select_element")))).select_by_visible_text("visible_text")
  • Finally, the ID and CLASS_NAME values which you have used e.g. react-select-3-input, sc-1mx0n6y-0, css-19bqh2r, etc looks dynamic and may change when you would access the application afresh or in short intervals. So you may opt to lookout for some other static attributes.

  • Note: You have to add the following imports :

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC

Selenium Webdriver wait on element click?

In addition to prestomanifesto's solution I can offer a less than ideal solution to that I implemented to solve this issue. It turns out it is throwing an exception - No Response etc... - so I just surrounded it in a try catch then waited for the popup to close, which seems to work fine.

You can substitute whatever you want in your loop, just make sure to put a counter in so it won't loop forever.

try
{
element.Click();
}
catch
{
cnt++;
do
{
//wait for whatever
cnt++;
Thread.Sleep(1000);
// Wait for 30 seconds for popup to close
} while (!string.IsNullOrEmpty(browser.CurrentWindowHandle) && cnt < 30);
}


Related Topics



Leave a reply



Submit