Java Webdriver FluentWait 不忽略异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20468865/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 02:10:07  来源:igfitidea点击:

Webdriver FluentWait not ignoring exceptions

javaselenium-webdriver

提问by Ilyas Patel

I have automated some user flows which go via this page http://www.efinancialcareers.co.uk/search. When I narrow a search using the left hand-side refine rail, an overlay appears where a user has to wait until the search results are returned. The method waits for the overlay to appear and then waits for it to disappear.

我已经自动化了一些通过此页面http://www.efinancialcareers.co.uk/search 进行的用户流程。当我使用左侧的细化栏缩小搜索范围时,会出现一个叠加层,用户必须等待搜索结果返回。该方法等待覆盖出现,然后等待它消失。

public void waitForSRPOverlayToComplete() {

    Wait<WebDriver> wait = new FluentWait<WebDriver>(getDriver())
            .withTimeout(5, TimeUnit.SECONDS)
            .pollingEvery(1, TimeUnit.NANOSECONDS)
            .ignoring(NoSuchElementException.class)
            .ignoring(TimeoutException.class);

    **// Error occurs here**
    WebElement blockedOverlay = wait.until(new Function<WebDriver, WebElement>() {
        public WebElement apply(WebDriver driver) {
            return driver.findElement(By.className("blockOverlay"));
        }
    });

    Wait<WebDriver> wait2 = new FluentWait<WebDriver>(getDriver())
            .withTimeout(5, TimeUnit.SECONDS)
            .pollingEvery(1, TimeUnit.NANOSECONDS)
            .ignoring(NoSuchElementException.class)
            .ignoring(TimeoutException.class);

    wait2.until(ExpectedConditions.stalenessOf(blockedOverlay));
}

On occasion I get a Timeout exception as the element (blockOverlay) is not found. I have observed the page when this occurs and the overlay does appear but I think sometimes when the search is very fast the above method misses it. I don't understand why I get a technical error as I have told the fluent wait to ignore them.

有时我会收到超时异常,因为找不到元素 (blockOverlay)。当发生这种情况时,我已经观察到页面并且确实出现了叠加层,但我认为有时当搜索速度非常快时,上述方法会错过它。我不明白为什么会出现技术错误,因为我已经告诉流畅的等待忽略它们。

This is the code to make the overlay appear:

这是使叠加层出现的代码:

$('body').block({
            message: $('#loaderEl'),
            css: {
                backgroundColor: 'transparent',
                border: "none",
                color: '#333333',
                fontWeight: 'bolder',
                top: ($(window).height() - $('#loaderEl').height()) / 2 + $(window).scrollTop() + "px"
            },
            overlayCSS: {
                backgroundColor: '#f8f8f8'
            },
            centerY: false
        });

And to remove it

并删除它

$('body').unblock();

This is the error I receive:

这是我收到的错误:

Caused by: org.openqa.selenium.TimeoutException: Timed out after 5 seconds waiting for     com.efinancialcareers.myefc.desktop.BasePage@548238e0
Build info: version: '2.35.0', revision: '8df0c6bedf70ff9f22c647788f9fe9c8d22210e2',     time: '2013-08-17 12:46:41'
System info: os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.6.0_26'
Driver info: driver.version: unknown
    ... 33 more
Caused by: org.openqa.selenium.NoSuchElementException: Unable to locate element: {"method":"class name","selector":"blockOverlay"}

Any help or suggestions would be appreciated.

任何帮助或建议将不胜感激。

采纳答案by JimEvans

You can't suppress TimeoutExceptionwhen the FluentWaitactually times out. That's simply the nature of the API. If this is an exception you truly want to ignore, you need to catch the TimeoutException.

TimeoutExceptionFluentWait实际超时时,您无法抑制。这就是 API 的本质。如果这是您真正想忽略的异常,则需要捕获TimeoutException.

Also, as a side note, attempting to poll for the condition every nanosecond is likely counterproductive. You should probably extend your polling interval to something like every 200 or 250 milliseconds.

此外,作为旁注,尝试每纳秒轮询一次条件可能会适得其反。您可能应该将轮询间隔延长到每 200 或 250 毫秒一次。

回答by MasterJoe2

A big thank you to Jim Evans for giving me the critical clue I needed to know why this problem occurs.

非常感谢吉姆·埃文斯 (Jim Evans) 为我提供了了解为什么会出现此问题所需的关键线索。

I decided to go further by digging into the FluentWait code (Java 1.8 or higher) to see why the TimeoutException is thrown even if you request it to not be thrown.

我决定通过深入研究 FluentWait 代码(Java 1.8 或更高版本)来了解为什么即使您请求不抛出 TimeoutException 也会抛出 TimeoutException。

Typical example of FluentWait:

FluentWait 的典型例子:

        WebDriver driver = new ChromeDriver();

        FluentWait wait = new FluentWait(driver)
                .withTimeout(30, TimeUnit.SECONDS)
                .pollingEvery(5, TimeUnit.SECONDS)
                .ignoring(NoSuchElementException.class);

        WebElement foo = (WebElement) wait.until(new Function() {
            @Override
            public WebElement apply(Object input) {
                return null;
            }
        });

We look at the untilmethod of FluentWait because that is the method which actually starts the waiting process. Its likely that all the exception handling/throwing logic might be there. All other method calls of FluentWait, such as withTimeout, ignoringetc. actually create "settings" for a FluentWait object. They do not perform any actions like waiting or running some code etc.

我们看一下untilFluentWait的方法,因为它是实际启动等待过程的方法。很可能所有的异常处理/抛出逻辑都在那里。FluentWait的所有其他方法调用,如withTimeoutignoring等实际上是一个FluentWait对象创建“设置”。它们不执行任何操作,例如等待或运行某些代码等。

Let's look at the documentation for "until". The last line tells us that the method throws a TimeoutException. So, the until method is NOT supposed to ignore TimeoutException even if you requested for it.

让我们看看“直到”文档。最后一行告诉我们该方法抛出 TimeoutException。因此,即使您要求,until 方法也不应该忽略 TimeoutException。

Throws:
TimeoutException - If the timeout expires.

We now quickly look at the code of FluentWait to understand why "until" does not ignore TimeoutException.

我们现在快速查看 FluentWait 的代码,以了解为什么“直到”不会忽略 TimeoutException。

  public <V> V until(Function<? super T, V> isTrue) {
    long end = clock.laterBy(timeout.in(MILLISECONDS));
    Throwable lastException = null;
    while (true) {
      try {
        V value = isTrue.apply(input);
        if (value != null && Boolean.class.equals(value.getClass())) {
          if (Boolean.TRUE.equals(value)) {
            return value;
          }
        } else if (value != null) {
          return value;
        }
      } catch (Throwable e) {
        lastException = propagateIfNotIgnored(e);
      }

      // Check the timeout after evaluating the function to ensure conditions
      // with a zero timeout can succeed.
      if (!clock.isNowBefore(end)) {
        String message = messageSupplier != null ?
            messageSupplier.get() : null;

        String toAppend = message == null ?
            " waiting for " + isTrue.toString() : ": " + message;

        String timeoutMessage = String.format("Timed out after %d seconds%s",
            timeout.in(SECONDS), toAppend);
        throw timeoutException(timeoutMessage, lastException);
      }

      try {
        sleeper.sleep(interval);
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new WebDriverException(e);
      }
    }
  }

The while block will:

while 块将:

  1. return the "value" variable, OR
  2. propagate any exception which you did not request to be ignored. (refer to the propagateIfNotIgnored method call. The name makes it obvious and you can see the code as well to confirm.)
  1. 返回“值”变量,或
  2. 传播您未要求忽略的任何异常。(请参阅propagateIfNotIgnored 方法调用。名称使其显而易见,您也可以查看代码以进行确认。)

The if block will run when an exception is not propagated. It will throw a TimeoutException if timeout occurs. So, that is the bit of code responsible for the timeout exception.

if 块将在异常未传播时运行。如果发生超时,它将抛出 TimeoutException。所以,这是负责超时异常的代码。