Skip to content

[🐛 Bug]: Java Wait/FluentWait.until missing non-null return type #16970

@TWiStErRob

Description

@TWiStErRob

Description

Recent nullability changes made ExpectedConditions.* return a @Nullable WebElement:

public static ExpectedCondition<@Nullable WebElement> presenceOfElementLocated(final By locator) {

WebDriverWait extends FluentWait which declares until:

public <V> V until(Function<? super T, V> isTrue) {

When the two are combined, the until function now implicitly "declares" to return null and that breaks compilation of existing working Kotlin code:

> Task :test-integration:compileKotlin FAILED
e: .../wait.kt [ARGUMENT_TYPE_MISMATCH] Argument type mismatch: actual type is 'WebElement?', but 'WebElement' was expected.

For completeness:

public interface ExpectedCondition<T extends @Nullable Object>
extends Function<WebDriver, T>, java.util.function.Function<WebDriver, T> {}

Solution?

until has the following structure (relevant parts only), where you can clearly see there's no code path which would return a V? instance.

  public <V> V until(Function<? super T, V> isTrue) {
    while (true) {
      try {
        V value = isTrue.apply(input);
        if (value != null) {
          return value;
        }
      } catch (Throwable e) {
      }
      if (...) {
        throw;
      }
      try {
      } catch (InterruptedException e) {
        throw;
      }
    }
  }

Currently:

  public <V> V until(Function<? super T, V> isTrue) {

becomes

  public <V = @Nullable WebElement> @Nullable WebElement until(Function<WebDriver, @Nullable WebElement> isTrue) {

I hope it's possible to declare it like this:

  public <V> @NonNull V until(Function<? super T, V> isTrue) {

which hopefully becomes:

  public <V = @Nullable WebElement> @NonNull WebElement until(Function<WebDriver, @Nullable WebElement> isTrue) {

The Wait<?> interface might complicate things, hope that its design allows it to be non-null return type too (as it is documented!).

Reproducible Code

import org.openqa.selenium.By
import org.openqa.selenium.WebDriver
import org.openqa.selenium.support.ui.ExpectedConditions
import org.openqa.selenium.support.ui.WebDriverWait
import kotlin.time.Duration.Companion.minutes
import kotlin.time.toJavaDuration
fun WebDriver.waitForExistenceAndVisibility(locator: By) {
	val wait = WebDriverWait(this, 1.minutes.toJavaDuration())
	val element = wait.until(ExpectedConditions.presenceOfElementLocated(locator))
	wait.until(ExpectedConditions.visibilityOf(element))
}

4.39.0: val element: WebElement!
4.40.0: val element: WebElement?
expected: val element: WebElement


ℹ️ Last known working version: 4.39.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-needs-triagingA Selenium member will evaluate this soon!I-defectSomething is not working as intendedI-regressionSomething was working but we "fixed" it

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions