我如何要求Selenium-WebDriver在Java中等待几秒钟?

时间:2012-10-12 12:21:23

标签: java selenium selenium-webdriver webdriver

我正在开发Java Selenium-WebDriver。我添加了

driver.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);

WebElement textbox = driver.findElement(By.id("textbox"));

因为我的应用程序需要几秒钟才能加载用户界面。所以我设置2秒implicitwait。但我无法找到元素文本框

然后我添加Thread.sleep(2000);

现在它运作正常。哪一种更好?

14 个答案:

答案 0 :(得分:111)

嗯,有两种类型的等待:显式和隐式等待。 明确等待的想法是

WebDriverWait.until(condition-that-finds-the-element);

隐式等待的概念是

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

您可以获得详细信息here

在这种情况下,我更喜欢使用显式等待(特别是fluentWait):

public WebElement fluentWait(final By locator) {
    Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(30, TimeUnit.SECONDS)
            .pollingEvery(5, TimeUnit.SECONDS)
            .ignoring(NoSuchElementException.class);

    WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
        public WebElement apply(WebDriver driver) {
            return driver.findElement(locator);
        }
    });

    return  foo;
};

fluentWait函数返回找到的web元素。 来自fluentWait的文档: Wait接口的实现,可以动态配置其超时和轮询间隔。 每个FluentWait实例定义等待条件的最大时间量,以及检查条件的频率。此外,用户可以将等待配置为在等待时忽略特定类型的异常,例如在页面上搜索元素时的NoSuchElementExceptions。 您可以获得详细信息here

在您的案例中使用fluentWait如下:

WebElement textbox = fluentWait(By.id("textbox"));

这种方法恕我直言更好,因为您不知道确切等待多长时间,并且在轮询间隔中您可以设置任意时间值,哪些元素存在将通过验证。 问候。

答案 1 :(得分:16)

如果使用webdriverJs(node.js),

driver.findElement(webdriver.By.name('btnCalculate')).click().then(function() {
    driver.sleep(5000);
});

上面的代码使浏览器在点击按钮后等待5秒钟。

答案 2 :(得分:12)

这个帖子有点老了,但我想我会发布我目前正在做的事情(正在进行中)。

虽然我仍然遇到系统负载过重的情况,但当我点击提交按钮(例如,login.jsp)时,所有三个条件(见下文)都会返回true但下一页(例如,home.jsp)尚未开始加载。

这是一个通用的等待方法,它采用了ExpectedConditions列表。

public boolean waitForPageLoad(int waitTimeInSec, ExpectedCondition<Boolean>... conditions) {
    boolean isLoaded = false;
    Wait<WebDriver> wait = new FluentWait<>(driver)
            .withTimeout(waitTimeInSec, TimeUnit.SECONDS)
            .ignoring(StaleElementReferenceException.class)
            .pollingEvery(2, TimeUnit.SECONDS);
    for (ExpectedCondition<Boolean> condition : conditions) {
        isLoaded = wait.until(condition);
        if (isLoaded == false) {
            //Stop checking on first condition returning false.
            break;
        }
    }
    return isLoaded;
}

我定义了各种可重复使用的ExpectedConditions(下面三个)。在此示例中,三个预期条件包括document.readyState ='complete',没有“wait_dialog”,并且没有'spinners'(表示正在请求异步数据的元素)。

只有第一个可以通用地应用于所有网页。

/**
 * Returns 'true' if the value of the 'window.document.readyState' via
 * JavaScript is 'complete'
 */
public static final ExpectedCondition<Boolean> EXPECT_DOC_READY_STATE = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        String script = "if (typeof window != 'undefined' && window.document) { return window.document.readyState; } else { return 'notready'; }";
        Boolean result;
        try {
            result = ((JavascriptExecutor) driver).executeScript(script).equals("complete");
        } catch (Exception ex) {
            result = Boolean.FALSE;
        }
        return result;
    }
};
/**
 * Returns 'true' if there is no 'wait_dialog' element present on the page.
 */
public static final ExpectedCondition<Boolean> EXPECT_NOT_WAITING = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
            WebElement wait = driver.findElement(By.id("F"));
            if (wait.isDisplayed()) {
                loaded = false;
            }
        } catch (StaleElementReferenceException serex) {
            loaded = false;
        } catch (NoSuchElementException nseex) {
            loaded = true;
        } catch (Exception ex) {
            loaded = false;
            System.out.println("EXPECTED_NOT_WAITING: UNEXPECTED EXCEPTION: " + ex.getMessage());
        }
        return loaded;
    }
};
/**
 * Returns true if there are no elements with the 'spinner' class name.
 */
public static final ExpectedCondition<Boolean> EXPECT_NO_SPINNERS = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
        List<WebElement> spinners = driver.findElements(By.className("spinner"));
        for (WebElement spinner : spinners) {
            if (spinner.isDisplayed()) {
                loaded = false;
                break;
            }
        }
        }catch (Exception ex) {
            loaded = false;
        }
        return loaded;
    }
};

根据页面的不同,我可能会使用其中一个或全部:

waitForPageLoad(timeoutInSec,
            EXPECT_DOC_READY_STATE,
            EXPECT_NOT_WAITING,
            EXPECT_NO_SPINNERS
    );

以下类中还预定义了ExpectedCondition:org.openqa.selenium.support.ui.ExpectedConditions

答案 3 :(得分:9)

使用Thread.sleep(2000);是无条件等待。如果你的测试加载速度更快,你仍然需要等待。所以原则上使用implicitlyWait是更好的解决方案。

但是,我不明白为什么implicitlyWait在您的情况下不起作用。您是否在测量异常之前测量findElement是否实际需要两秒钟。如果是这样,您是否可以尝试使用WebDriver的条件等待,如this回答中所述?

答案 4 :(得分:3)

我喜欢使用自定义条件。这是Python中的一些代码:

def conditions(driver):
    flag = True
    ticker = driver.find_elements_by_id("textbox")
    if not ticker:
        flag = False
    return flag

... click something to load ...
self.wait = WebDriverWait(driver, timeout)
self.wait.until(conditions)

每当您需要等待时,您可以通过检查某个元素的存在来明确地执行此操作(此元素可能因页面而异)。 find_elements_by_id返回列表 - 是否为空,您只需要检查。

答案 5 :(得分:2)

点击似乎是阻止? - 如果你正在使用WebDriverJS,这是另一种等待方式:

driver.findElement(webdriver.By.name('mybutton')).click().then(function(){
  driver.getPageSource().then(function(source) {
    console.log(source);
  });
});

上面的代码在单击按钮以下载页面后等待,然后抓取下一页的来源。

答案 6 :(得分:0)

有时隐式等待似乎被覆盖,等待时间缩短。 [@ eugene.polschikov]有关于为什么的好文档。我在Selenium 2的测试和编码中发现,隐式等待是好的,但偶尔你必须明确等待。

最好避免直接调用线程进入睡眠状态,但有时候没有好办法解决问题。但是,还有其他Selenium提供的等待选项可以提供帮助。事实证明 waitForPageToLoad waitForFrameToLoad 特别有用。

答案 7 :(得分:0)

隐式等待:在隐式等待期间,如果Web驱动程序因其可用性而无法立即找到它,则WebDriver将等待上述时间,并且不会尝试在指定时间段内再次找到该元素。一旦指定的时间结束,它将尝试在抛出异常之前最后一次搜索该元素。默认设置为零。设置时间后,Web驱动程序将等待WebDriver对象实例的句点。

显式等待:可能存在特定元素加载超过一分钟的实例。在这种情况下,你绝对不喜欢为Implicit wait设置一个巨大的时间,就好像你这样做,你的浏览器将等待每个元素的同一时间。 为避免这种情况,您只需在所需元素上单独设置一个时间即可。通过遵循这一点,您的浏览器隐含的等待时间对于每个元素都是短的,并且对于特定元素它将是大的。

答案 8 :(得分:0)

有时隐式等待失败,说一个元素存在但实际上并不存在。

解决方案是避免使用driver.findElement并将其替换为隐式使用显式等待的自定义方法。例如:

import org.openqa.selenium.NoSuchElementException;


public WebElement element(By locator){
    Integer timeoutLimitSeconds = 20;
    WebDriverWait wait = new WebDriverWait(driver, timeoutLimitSeconds);
    try {
        wait.until(ExpectedConditions.presenceOfElementLocated(locator));
    }
    catch(TimeoutException e){
        throw new NoSuchElementException(locator.toString());
    }
    WebElement element = driver.findElement(locator);
    return element;
}

除了零星的,偶然的失败之外,还有其他理由可以避免隐性等待(见link)。

您可以像driver.findElement一样使用此“元素”方法。 例如:

    driver.get("http://yoursite.html");
    element(By.cssSelector("h1.logo")).click();

如果你真的想等待几秒钟进行故障排除或其他一些罕见的场合,你可以创建一个类似于selenium IDE提供的暂停方法:

    public void pause(Integer milliseconds){
    try {
        TimeUnit.MILLISECONDS.sleep(milliseconds);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

答案 9 :(得分:0)

回答:在使用Selenium WebDriver查看元素可见性之前,请等待几秒钟。

implicitlyWait():WebDriver实例等到整页加载。你冥想使用30至60秒等待整页加载。

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

显式地等待WebDriverWait():WebDriver实例等到整页加载。

WebDriverWait wait = new WebDriverWait(driver, 60);

wait.until(ExpectedConditions.visibilityOf(textbox));

driver.findElement(By.id("Year")).sendKeys(allKeys);

注意:请使用ExplicitlyWait WebDriverWait()来处理任何特定的WebElement。

答案 10 :(得分:0)

使用操作-

  

面向用户的API,用于模拟复杂的用户手势。

请参见Actions#pause方法。

答案 11 :(得分:-1)

我更喜欢以下代码等待2秒。

for(int i=0; i<2 && driver.findElements(By.id("textbox")).size()==0 ; i++){
   Thread.sleep(1000);
}

答案 12 :(得分:-1)

Thread.sleep(1000);

更糟糕的是:作为静态等待,它会使测试脚本变慢。

driver.manage().timeouts.implicitlyWait(10,TimeUnit.SECONDS);

这是一次动态等待

  • 直到webdriver存在才有效或者有一个范围直到驱动程序有效期
  • 我们也可以隐含等待。

最后,我的建议是

WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.<different canned or predefined conditions are there>);

有一些预定义的条件:

isAlertPresent();
elementToBeSelected();
visibilityOfElementLocated();
visibilityOfAllElementLocatedBy();
frameToBeAvailableAndSwitchToIt();
  • 这也是动态等待
  • 在此等待将只有几秒钟
  • 我们必须使用显式等待我们想要使用的特定网络元素。

答案 13 :(得分:-1)

Thread.Sleep(5000);

这对我有帮助,但需要处理InterruptedException异常。 所以用try和catch更好地包围它:

try {
    Thread.Sleep(5000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

OR

添加投掷声明:

public class myClass {
    public static void main(String[] args) throws InterruptedException
    { ... }

我更喜欢第二个,因为人们可以根据需要多次使用sleep(),并且每次try时都避免重复catchsleep()阻止已被使用。