WaitForElementClickable/ Visible - Selenium C#

我的未来我决定 提交于 2019-12-11 00:50:23

问题


I need to implement & modify my current method to do both matters:

  • Waiting for element of being visible - (which is currently implemented but it still uses ExpectedCondition which is obsolete and might be changed)
  • Waiting for element of being clickable - (When my test are running, it's face a problems with "loading circles", I'm pressing the button and before window is loaded there is loader which takes for 1 to 4 seconds and then it disappears. My goal is to force Selenium to wait "XXX" time and when loading will finish then continue with process.

Current code:

public static IWebElement WaitForElementVisible(this IWebDriver driver, By by, int timeoutInSeconds = 6)
    {
        IWebElement element;
        driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(0);
        try
        {
            WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            element = wait.Until(ExpectedConditions.ElementIsVisible(by));
            driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(Configuration.ElementTimeout);
            return element;

        }
        catch (WebDriverTimeoutException e)
        {
            Console.WriteLine(e.ToString());
        }
        driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(Configuration.ElementTimeout);
        return null;
    }

Based on different topics I've started writing something but unfortunately it's just copy...

I would prefer to do one valuable method which goal would be to check both things. Could you please give me any advice's/ hints what could be added to that specific method?

//Edit

I'm adding how that loader code looks like:

    <div class="Loader__background" style="display: block; position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 10;">
   <div class="Loader__foreground" style="display: table; width: 100%; height: 100%; text-align: center; z-index: 20; color: white;">
      <div class="Loader__message" style="display: table-cell; vertical-align: middle;">
         <div mode="indeterminate" value="0" min="0" max="100" style="position: relative; display: inline-block; width: 280px; height: 280px;">
            <div style="width: 280px; height: 280px; display: inline-block; transition: transform 10s linear 0ms; transform: rotate(1800deg);">
               <svg viewBox="0 0 280 280" style="width: 280px; height: 280px; position: relative;">
                  <circle cx="140" cy="140" r="137.5" fill="none" stroke-width="5" stroke-miterlimit="20" style="stroke: rgb(0, 188, 212); stroke-linecap: round; transition: all 750ms ease-in-out 0ms; stroke-dasharray: 604.757, 863.938; stroke-dashoffset: -259.181;"></circle>
               </svg>
            </div>
         </div>
      </div>
   </div>
</div>

I've also transferred @sers Java advice into C#:

public static IWebElement WaitForElementClickable(this IWebDriver driver, By by, 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).Displayed;
            }
            catch (Exception) { }

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

回答1:


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();



回答2:


The ExpectedConditions in .NET binding is obsolete, however it was moved to DotNetSeleniumExtras

'ExpectedConditions' is obsolete: 'The ExpectedConditions implementation in the .NET bindings is deprecated and will be removed in a future release. This portion of the code has been migrated to the DotNetSeleniumExtras repository on GitHub (https://github.com/DotNetSeleniumTools/DotNetSeleniumExtras)'

Use ExpectedConditions from there, it will dismiss the warning

using WaitHelpers = SeleniumExtras.WaitHelpers;

wait.Until(WaitHelpers.ExpectedConditions.ElementIsVisible(by));

You can also use ExpectedConditions to wait for the element to be clickable

IWebElement webElement = wait.Until(WaitHelpers.ExpectedConditions.ElementToBeClickable(by));
webElement.Click();

Another option is to wait for the loader to appear and then disappear and then continue

wait.Until(WaitHelpers.ExpectedConditions.ElementIsVisible(by));   
wait.Until(WaitHelpers.ExpectedConditions.InvisibilityOfElementLocated(by));


来源:https://stackoverflow.com/questions/51981329/waitforelementclickable-visible-selenium-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!