107

我正在研究 Java Selenium-WebDriver。我添加了

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

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

因为我的应用程序需要几秒钟来加载用户界面。所以我设置了 2 秒的隐式等待。但我无法找到元素文本框

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

现在它工作正常。哪个是更好的方法?

4

14 回答 14

127

好吧,有两种类型的等待:显式等待和隐式等待。显式等待的想法是

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

隐式等待的概念是

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

您可以在此处了解详细信息。

在这种情况下,我更喜欢使用显式等待(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 元素。来自文档fluentWaitWait 接口的实现,它可以动态配置其超时和轮询间隔。每个 FluentWait 实例定义等待条件的最长时间,以及检查条件的频率。此外,用户可以将等待配置为在等待时忽略特定类型的异常,例如在页面上搜索元素时的 NoSuchElementExceptions。 您可以在这里获得详细信息

在您的情况下,用法fluentWait如下:

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

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

于 2012-10-12T13:02:26.330 回答
16

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

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

这是一个接受 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
    );

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

于 2014-11-08T00:39:05.657 回答
14

如果使用 webdriverJs (node.js),

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

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

于 2013-09-17T19:46:48.973 回答
10

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

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

于 2012-10-12T12:49:49.440 回答
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返回列表 - 是否为空,您只需检查即可。

于 2014-02-20T11:20:20.203 回答
2

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

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

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

于 2014-02-28T02:03:57.830 回答
1

隐式等待和 Thread.sleep 两者都仅用于同步..但不同之处在于我们可以使用隐式等待整个程序,但 Thread.sleep 仅适用于该单个代码..这里我的建议是在程序中使用隐式等待一次当您的网页每次刷新时意味着在那个时候使用 Thread.sleep ..它会更好:)

这是我的代码:

package beckyOwnProjects;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;

public class Flip {

    public static void main(String[] args) throws InterruptedException {
        WebDriver driver=new FirefoxDriver();
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(2, TimeUnit.MINUTES);
        driver.get("https://www.flipkart.com");
    WebElement ele=driver.findElement(By.cssSelector(".menu-text.fk-inline-block"));
    Actions act=new Actions(driver);
    Thread.sleep(5000);
    act.moveToElement(ele).perform();
    }

}
于 2015-12-19T12:38:45.383 回答
1

使用动作 -

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

请参阅 Actions#pause方法。

于 2019-12-24T07:55:57.400 回答
0

有时隐式等待似乎会被覆盖,等待时间会缩短。[@eugene.polschikov] 有很好的文档说明原因。我在使用 Selenium 2 进行测试和编码时发现,隐式等待很好,但有时您必须显式等待。

最好避免直接调用线程休眠,但有时也没有很好的解决方法。但是,还有其他 Selenium 提供的等待选项可以提供帮助。waitForPageToLoadwaitForFrameToLoad被证明特别有用。

于 2013-02-05T19:37:39.913 回答
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;
}

除了零星的、偶然的失败之外,还有其他原因可以避免隐式等待(请参阅此链接)。

您可以像 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();
    }
}
于 2017-06-29T19:17:33.643 回答
0

:等待几秒钟,然后使用 Selenium WebDriver 的元素可见性通过以下方法。

implicitlyWait():WebDriver 实例等到整个页面加载。您可以使用 30 到 60 秒来等待整个页面加载。

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

ExplicitlyWait WebDriverWait():WebDriver 实例等到整个页面加载。

WebDriverWait wait = new WebDriverWait(driver, 60);

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

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

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

于 2018-04-05T08:36:22.157 回答
-1

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

for(int i=0; i<2 && driver.findElements(By.id("textbox")).size()==0 ; i++){
   Thread.sleep(1000);
}
于 2013-11-26T08:44:13.090 回答
-1

隐式等待:在隐式等待期间,如果 Web Driver 由于其可用性而无法立即找到它,则 WebDriver 将等待提到的时间,并且在指定的时间段内不会再次尝试查找元素。一旦指定的时间结束,它将在抛出异常之前的最后一次尝试再次搜索元素。默认设置为零。一旦我们设置了一个时间,Web Driver 就会等待 WebDriver 对象实例的时间。

显式等待:可能存在特定元素需要超过一分钟才能加载的情况。在这种情况下,您绝对不喜欢为隐式等待设置很长的时间,因为如果您这样做,您的浏览器将为每个元素等待相同的时间。为避免这种情况,您只需在所需元素上单独设置时间即可。通过遵循这一点,您的浏览器隐式等待时间对于每个元素都会很短,而对于特定元素会很长。

于 2015-12-27T07:49:03.920 回答
-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();
  • 也是动态等待
  • 在这等待将只在几秒钟内
  • 我们必须使用显式等待我们想要使用的特定 Web 元素。
于 2018-02-16T17:32:46.130 回答