WebDriver Wait'.until(ExpectedConditions.elementToBeClickable'仅在我将Thread.sleep(500)添加到代码时才有效?

时间:2016-07-22 14:25:49

标签: java selenium selenium-webdriver webdriver wait

  1. 我正在尝试使用webdriver等单击页面上可见的按钮,但只有在我向代码添加Thread.sleep后,webdriver才能单击按钮。

  2. 在执行代码之前,我还检查了按钮以查看其是否可见(True),然后依次returns = true

  3. // Button Visiblity check:

    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

5 个答案:

答案 0 :(得分:2)

您希望尽可能避免在测试中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

答案 1 :(得分:0)

页面上仍然可能正在执行活动的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");
            }
        }
    );

答案 2 :(得分:0)

以下方法似乎正常工作:

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

答案 3 :(得分:0)

尝试使用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创建一个自定义谓词,在发布之前检查后点击条件是否为真。如果不是这样,那么让谓词重新执行点击!

  

由于时区问题,我无法查找   成功发布点击内容,因此缺少参考   片段。它被标记为 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;
        }
    });        
}

答案 4 :(得分:0)

您是否尝试过使用urlContains?我遇到了您所问的相同问题,因此线程睡眠正常进行了

详细信息如下

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