【问题标题】:WebDriver Wait '.until(ExpectedConditions.elementToBeClickable' only works when i add Thread.sleep(500) to the Code?WebDriver Wait '.until(ExpectedConditions.elementToBeClickable' 仅在我将 Thread.sleep(500) 添加到代码时才有效?
【发布时间】:2016-11-26 12:05:00
【问题描述】:
  1. 我正在尝试使用 webdriver wait 单击页面上可见的按钮,但 webdriver 只有在我将 Thread.sleep 添加到代码后才能单击该按钮。

  2. 在执行我的代码之前,我还检查了按钮是否可见 (True),而它又是 returns = true

//按钮可见性检查:

List<WebElement> signOutList = driver.findElements(.xpath(".//*[starts-with(@id,'fulfillment-time-type-section-')]/div[2]//button"));
Assert.assertTrue(signOutList.size() > 0);

//下面的代码没有点击按钮

By timeDropdownButton = By.xpath(".//*[starts-with(@id,'fulfillment-time-type-section-')]/div[2]//button");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
              .until(ExpectedConditions.elementToBeClickable(timeDropdownButton));
myDynamicElement.click();

//下面的代码是否点击了按钮:

Thread.sleep(500);
By timeDropdownButton = By.xpath(".//*[starts-with(@id,'fulfillment-time-type-section-')]/div[2]//button");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
              .until(ExpectedConditions.elementToBeClickable(timeDropdownButton));
myDynamicElement.click();


请注意,我还尝试使用 JS 代码和 WebDriver 操作等单击按钮

我不知道为什么“Wait Clickable”只有在与“Thread.sleep”结合使用时才有效?

The button I'm trying to click

【问题讨论】:

  • 您是否尝试过将时间从 10 秒增加到更多..???
  • 嗨 Saurabh,我尝试了以下代码,但仍然无法正常工作(从 10 更改为 1000):WebElement myDynamicElement = (new WebDriverWait(driver, 1000))
  • 尝试使用ExpectedConditions.visibilityOfElementLocated..告诉我..
  • 感谢您帮助 Saurabh,恐怕即使尝试 ExpectedConditions.visibilityOfElementLocated 它仍然不起作用
  • 你能分享一下发生了什么异常吗??

标签: java selenium selenium-webdriver webdriver wait


【解决方案1】:

您希望在测试中尽可能避免Thread.sleep。仅仅通过几个测试它可能看起来并不那么重要,但它们的使用存在很多固有的问题。首先,如果你有一堆测试,测试套件的运行时间可能会变得难以管理。其次,它们有时还不够。例如,对于一般的生产机器,等待 500 毫秒可能就足够了,但如果 Web 服务器处于高负载或测试环境中,则可能需要 750 毫秒才能准备好。然后,您正在处理非确定性故障。最好使用WebDriverWait 之类的构造,并给它们一个合理(但过于慷慨)的最大值,这样您就不必等待比必要的时间更长,但如果它失败了,则意味着下面的环境存在严重问题测试。

这里的必胜客网站也大量使用异步 java 脚本和浮动面板等。所有这些都需要在使用 Selenium 时更加小心,因为元素需要在与它们交互之前准备好,但它们通常是已经在 DOM 中了。这意味着默认情况下,Selenium 可能会在 JavaScript 完成之前快速找到它们,并且它们实际上并未处于准备使用状态。您将希望像您已经尝试做的那样使用 ExpectedConditions。您遇到问题的按钮需要等待 JavaScript 完成,这是已经建议的,但它不需要在页面加载时,而是在单击按钮之前。在我的机器上运行的示例:

@Test
public void foo() {
    WebDriver driver = new FirefoxDriver();
    driver.manage()
          .window()
          .maximize();
    // Move through the page to the point you are interested in
    driver.get("https://www.pizzahut.co.uk/");
    waitForElement(driver, By.cssSelector(".hidden-xs [title='Pizza']")).click();
    waitForElement(driver, By.cssSelector("form[action='/menu/startyourorder']")).submit();
    WebElement postElement = waitForElement(driver, By.id("ajax-postcode-txt"));
    postElement.sendKeys("TS1 4AG" + Keys.ENTER);
    // Wait for the java script to finish executing
    waitForJavaScript(driver);
    // Finally you should be able to click on the link
    waitForElement(driver, By.partialLinkText("Start Your Order")).click();
    // continue on ... then quit the driver
    driver.quit();
}

private WebElement waitForElement(WebDriver driver, By locator) {
    return new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(locator));
}

private void waitForJavaScript(WebDriver driver) {
    new WebDriverWait(driver, 10).until(new Predicate<WebDriver>() {
                                            public boolean apply(WebDriver driver) {
                                                return ((JavascriptExecutor) driver).executeScript("return document.readyState")
                                                                                    .equals("complete");
                                            }
                                        }
    );
}

在 WebDriverWait 中,给定的 int 参数是它将继续尝试给定检查的秒数。如果达到设定的数量(上例中为10 秒),它将抛出TimeoutException

【讨论】:

    【解决方案2】:

    页面上可能仍在执行活动的 Javascript。在第一瞬间,它可能会以ExpectedCondition 无法分辨的方式对其进行修改。当我遇到意外行为问题时,我发现等待页面加载(包括 JavaScript 脚本)通常可以解决大部分问题。

    要等待页面加载,您可以调用您的一些 Javascript 来检查文档的readyState。尝试等待页面加载,然后等待元素可点击。

    快速搜索返回此 (code taken from here):

    wait.until( new Predicate<WebDriver>() {
                public boolean apply(WebDriver driver) {
                    return ((JavascriptExecutor)driver).executeScript("return document.readyState").equals("complete");
                }
            }
        );
    

    【讨论】:

    • 感谢@Parker 的帮助,我在上面的代码中试过了,但还是不行
    【解决方案3】:

    以下方法似乎可以正常工作:

    public void waitForPageLoad() {
        ExpectedCondition<Boolean> expectation = new
                ExpectedCondition<Boolean>() {
                    public Boolean apply(WebDriver driver) {
                        return ((JavascriptExecutor) driver).executeScript("return document.readyState").toString().equals("complete");
                    }
                };
        try {
            Thread.sleep(1000);
            WebDriverWait wait = new WebDriverWait(driver, 30);
            wait.until(expectation);
        } catch (Throwable error) {
            Assert.fail("Timeout waiting for Page Load Request to complete.");
        }
    }
    

    【讨论】:

      【解决方案4】:

      尝试使用 PageFactory 实现,看看 selenium API 是否为您解决了问题。

      public class OrderMyPizzaPage {
              @FindBy(css="form[action='/menu/startyourorder']")
              WebElement startMyOrder;
      
              public void startOrder() {
                  startMyOrder.click();
              }
          }
      

      太好了,现在如果我们假设其他所有事情都已成功完成,并且我们可以点击“开始您的订单”

       public void myExecutingMethod(WebDriver driver) {
              //previous steps occur and we've just performed interactions which should cause the 'start your order' button to be on the dom
      
              OrderMyPizzaPage orderPage = PageFactory.initElements(driver, OrderMyPizzaPage.class);
              orderPage.startOrder();
      
              //And now maybe it worked?
          }
      

      如果这不起作用,请尝试更强力的方法。为您的 WebDriverWait 创建一个自定义谓词,在发布前检查点击后条件是否为真。如果不正确,则让谓词重新执行点击!

      由于时区问题,我无法查找 成功的点击后内容,因此在 sn-p。它被标记为 FIXME

      public void startOrder(WebDriver driver) {
          WebDriverWait wait = new WebDriverWait(driver, 30);
          //Throttle the polling!
          wait.pollingEvery(1500, TimeUnit.MILLISECONDS);
          wait.until(new Predicate<WebDriver>() {
              public boolean apply(WebDriver input) {
                  boolean successfulClick = false;
                  //FIXME:  Need to check for something that should occur after the click happens successfully
                  By lookupAfterClick = By.cssSelector("");
                  WebElement nextElement = ExpectedConditions.visibilityOfElementLocated(lookupAfterClick).apply(input);
                  if (nextElement == null) {
                      System.out.println("Not there yet, Keep trying!");
                      By startOrderLookup = By.cssSelector("form[action='/menu/startyourorder']");
                      WebElement startOrder =ExpectedConditions.visibilityOfElementLocated(startOrderLookup).apply(input);
                      if (startOrder != null) {
                          System.out.println("Clicking Start Order!");
                          startOrder.click();                        
                      } else {
                          System.out.println("Start Order isn't visible!");
                      }
                  } else {
                      System.out.println("Hey, That worked!");
                      successfulClick = true;
                  }
                  return successfulClick;
              }
          });        
      }
      

      【讨论】:

        【解决方案5】:

        您是否尝试过使用 urlContains ?我遇到了你问的同样的问题,不知何故线程睡眠正常

        详情如下

        (new WebDriverWait(driver, 50)).until(ExpectedConditions.urlContains("/completing-profile?step=skin_type"));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-05-22
          • 1970-01-01
          • 2018-01-05
          • 1970-01-01
          • 2021-11-24
          • 2022-11-16
          • 2010-09-29
          • 1970-01-01
          相关资源
          最近更新 更多