Java WebDriver等待';。直到(ExpectedConditions.ElementTobelickable';仅在向代码中添加Thread.sleep(500)时有效?

Java WebDriver等待';。直到(ExpectedConditions.ElementTobelickable';仅在向代码中添加Thread.sleep(500)时有效?,java,selenium,selenium-webdriver,webdriver,wait,Java,Selenium,Selenium Webdriver,Webdriver,Wait,我试图使用webdriver wait单击页面上可见的按钮,但webdriver只能在我向代码添加线程.sleep后单击该按钮 在我执行代码之前,我还检查了按钮,查看它是否可见(True),然后它返回=True //按钮可视性检查: List<WebElement> signOutList = driver.findElements(.xpath(".//*[starts-with(@id,'fulfillment-time-type-section-')]/div[2]//butt

我试图使用webdriver wait单击页面上可见的按钮,但webdriver只能在我向代码添加
线程.sleep
后单击该按钮

  • 在我执行代码之前,我还检查了按钮,查看它是否可见(True),然后它返回=True

  • //按钮可视性检查:

    List<WebElement> signOutList = driver.findElements(.xpath(".//*[starts-with(@id,'fulfillment-time-type-section-')]/div[2]//button"));
    Assert.assertTrue(signOutList.size() > 0);
    
    //下面的代码确实单击了按钮:

    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操作等单击按钮

    我不知道为什么“等待可点击”只在我与“Thread.sleep”结合使用时才起作用


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

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

    快速搜索将返回以下内容():

    wait.until(新谓词(){
    公共布尔应用(WebDriver驱动程序){
    return((JavascriptExecutor)driver.executeScript(“return document.readyState”).equals(“complete”);
    }
    }
    );
    
    以下方法似乎工作正常:

    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.");
        }
    }
    
    public void waitForPageLoad(){
    预期条件预期=新
    期望条件(){
    公共布尔应用(WebDriver驱动程序){
    return((JavascriptExecutor)driver.executeScript(“return document.readyState”).toString().equals(“complete”);
    }
    };
    试一试{
    睡眠(1000);
    WebDriverWait wait=新的WebDriverWait(驱动程序,30);
    等待,直到(期望);
    }捕获(可丢弃错误){
    Assert.fail(“等待页面加载请求完成的超时”);
    }
    }
    
    通常,您希望尽量避免在测试中执行线程。通常情况下,在测试中睡眠。仅使用几个测试可能看起来不太重要,但它们的使用中存在许多固有的问题。首先,如果您有一组测试,测试套件的运行时间可能会变得不可管理。其次,它们有时还不够。例如,等待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");
                                                }
                                            }
        );
    }
    
    @测试
    公共图书馆{
    WebDriver=newfirefoxdriver();
    driver.manage()
    .window()
    .最大化();
    //将页面移动到您感兴趣的点
    驱动程序。获取(“https://www.pizzahut.co.uk/");
    waitForElement(驱动程序,由.cssSelector(“.hidden xs[title='Pizza']”)创建)。单击();
    waitForElement(driver,By.cssSelector(“form[action='/menu/startyourorder'])).submit();
    WebElement postElement=waitForElement(驱动程序,By.id(“ajax邮编txt”);
    postElement.sendKeys(“TS1 4AG”+Keys.ENTER);
    //等待java脚本完成执行
    waitForJavaScript(驱动程序);
    //最后,你应该能够点击链接
    waitForElement(驱动程序,By.partialLinkText(“启动订单”))。单击();
    //继续…然后退出驱动程序
    driver.quit();
    }
    私有WebElement waitForElement(WebDriver驱动程序,按定位器){
    返回新的WebDriverWait(驱动程序,10).until(ExpectedConditions.ElementToBickable(定位器));
    }
    私有void waitForJavaScript(WebDriver驱动程序){
    新WebDriverWait(驱动程序,10).until(新谓词(){
    公共布尔应用(WebDriver驱动程序){
    return((JavascriptExecutor)driver.executeScript(“return document.readyState”)
    .等于(“完全”);
    }
    }
    );
    }
    

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

    尝试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?
        }
    

    如果这不起作用,可以尝试一些更暴力的方法
    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?
        }
    
    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;
            }
        });        
    }
    
    (new WebDriverWait(driver, 50)).until(ExpectedConditions.urlContains("/completing-profile?step=skin_type"));