【问题标题】:Selenium Webdriver wait on element click?Selenium Webdriver 等待元素点击?
【发布时间】:2012-03-26 00:11:26
【问题描述】:

我一直在寻找解决方案,但无济于事。我有一个正在单击的按钮,有时需要很长时间才能返回数据,并且驱动程序超时并且我猜只是杀死了应用程序。

我正在尝试使用 WebDriverWait 类来完成此操作,但 Click() 方法在我使用它的方式中不可用。

WebDriverWait wait = new WebDriverWait(browser, new TimeSpan(0, 5, 0));

bool clicked = wait.Until<bool>((elem) =>
{
     elem.Click(); //Doesn't Work
     return true;
});

ImplicitlyWait() 方法只是等待元素加载,但是在 Click() 上超时,所以它甚至无法查找元素。

SetScriptTimeout() 方法只适用于执行 javascript,我没有这样做。

有谁知道这样做的方法吗?

【问题讨论】:

    标签: c# selenium timeout webdriver


    【解决方案1】:

    我使用这个脚本:

      private static void waitUntilScriptFoundAndExecute(String script) {
        int tries = 0;
        boolean found = false;
        do {
          tries++;
          try {
            driver.executeScript(script);
            found = true;
          } catch (NoSuchElementException nse) {
            System.out.println("Wait for script NSE (" + tries + ")");
          } catch (WebDriverException wde) {
            System.out.println("Wait for script WDE (" + tries + ")");
          } catch (Exception e) {
            System.out.println("Wait for script E (" + tries + ")");
          }
    
          // Waiting
          if (!found) {
            System.out.println("Wait for script Not found (" + tries + ")");
            waiting(SCRIPT_WAITING_INTERVAL);
          }
        } while (!found && tries < MAX_SCRIPT_WAIT_TRIES);
    
        if (!found) {
            System.out.println("Script aborted: " + script);
        }
      }
    

    【讨论】:

    • 这不适用于我正在做的事情,但它对于查找脚本很有用。谢谢。我最终找到了一个解决方案,一旦我能够发布它就会发布。新用户无法立即回答他们自己的解决方案。
    • 我在同一块板上,你是如何解决的?你可以分享吗?编辑您的问题并粘贴您的解决方案。
    【解决方案2】:

    您可以尝试使用SendKeys,而不是Click。与Click 不同,SendKeys 在恢复代码执行之前不会等待页面完成加载。所以你可以这样做:

    WebDriverWait wait = new WebDriverWait(browser, new TimeSpan(0, 5, 0));
    
    elem.SendKeys(Keys.Enter);    
    wait.Until<bool>((_driver) =>
    {         
         //Check here if results have loaded yet
         return true;
    });
    

    附带说明一下,我很确定 Until 接受 IWebBrowser 作为输入,而不是元素,这就是为什么你不能点击 elem

    【讨论】:

    • 这是一个很好的解决方案,不幸的是发送回车到这个按钮不起作用。不知道为什么...
    • 我有时也会发生这种情况,尤其是当点击触发 jQuery 事件时。在这种情况下,我使用ExecuteScript 执行点击,类似于:driver.ExecuteScript("$(arguments[0]).click()", elem); 很高兴你现在找到了解决方法。
    【解决方案3】:

    除了 prestomanifesto 的解决方案之外,我还可以提供一个不太理想的解决方案来解决这个问题。事实证明它抛出了一个异常 - 无响应等...... - 所以我只是将它包围在一个 try catch 中,然后等待弹出窗口关闭,这似乎工作正常。

    你可以在你的循环中替换任何你想要的东西,只要确保放一个计数器,这样它就不会永远循环。

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

    【讨论】:

    【解决方案4】:

    试试这个:

    WebDriverWait wait = new WebDriverWait(driver , 1000) ;
    wait.until(ExcepctedConditions.elementToBeClickable(ById("element"));
    

    元素可以是您被重定向到的下一页上存在的任何元素的 ID。 一旦 Page 完全加载,它将开始执行您的代码。

    【讨论】:

    • 问题是当 element.click() 被处理时,它会暂停并等待大约 30 秒让 .click() 方法返回。如果没有,则抛出异常。
    【解决方案5】:

    使用 LINQ Lambda 表达式的RepeatUntil 扩展方法

    将此代码复制到您的项目中:

    public static class SeleniumExtensionMethods
        {
            public static IWebElement RepeatUntil<T>(this T obj, 
                 Func<T, IEnumerable<IWebElement>> func, 
                    Func<IWebElement, bool> compare,
                      int MaxRetry = 20)
            {
                //call function to get elements
                var eles = func(obj);
                IWebElement element = null;
                while (element == null && MaxRetry > 0)
                {
                    MaxRetry-=1;
                    //call the iterator
                    element = IterateCollection(compare, eles);
                    if (element == null)
                    {
                        Thread.Sleep(500);
                        //get new collection of elements
                        eles = func(obj);
                    }
                };
    
                return element;
            }
    
            private static IWebElement IterateCollection(
               Func<IWebElement, bool> compare, 
               IEnumerable<IWebElement> eles){
                IWebElement element = null;
                eles.ToList().ForEach(
                    ele =>
                    {
                        //call the comparator
                        var found = compare(ele);
                        if (found) element = ele;
                    });
                return element;
            }
        }
    

    使用以下语法调用它:

     // You can change PageObjectType to IWebDriver or IWebElement so that 
     // cb is of any type.
     var element = cb.RepeatUntil<MyPageObjectType>(
        //This is the first function to provide the elements
        p => p.FindElements(By.ClassName("TreeNode")), 
        //This is the comparator
        ele => ele.Text == nodeText && ele.Location.Y>YLocation);
    

    注意:在上面的示例中,我们传递了一个 PageObjectType,但您可以将其更改为 IWebDriver 类型或事件 IWebElement。所有类型参数都允许您将其用作您指定类型的扩展方法。

    请注意扩展方法的灵活性,因为调用者可以确定集合以及比较器。

    【讨论】:

      【解决方案6】:

      不要使用线程休眠

      public class(IWebDriver driver)
      {           
      this.driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMinutes(1);
      wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver,TimeSpan.FromMinutes(1));
       }
      
      public void class1()
      {  
      wait.Until(ExpectedConditions.ElementToBeClickable(elem)).Click();
      }
      

      【讨论】:

        猜你喜欢
        • 2018-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-29
        • 2020-02-23
        • 1970-01-01
        • 2016-12-25
        • 2013-08-06
        相关资源
        最近更新 更多