docs: @Override
    public <V> V until(Function<? super T, V> isTrue) {
      Instant end = clock.instant().plus(timeout);
  
      Throwable lastException;
      while (true) {
        try {
          V value = isTrue.apply(input);
          if (value != null && (Boolean.class != value.getClass() || Boolean.TRUE.equals(value))) {
            return value;
          }
  
          // Clear the last exception; if another retry or timeout exception would
          // be caused by a false or null value, the last exception is not the
          // cause of the timeout.
          lastException = null;
        } catch (Throwable e) {
          lastException = propagateIfNotIgnored(e);
        }
  
        // Check the timeout after evaluating the function to ensure conditions
        // with a zero timeout can succeed.
        if (end.isBefore(clock.instant())) {
          String message = messageSupplier != null ?
                           messageSupplier.get() : null;
  
          String timeoutMessage = String.format(
              "Expected condition failed: %s (tried for %d second(s) with %d milliseconds interval)",
              message == null ? "waiting for " + isTrue : message,
              timeout.getSeconds(), interval.toMillis());
          throw timeoutException(timeoutMessage, lastException);
        }
  
        try {
          sleeper.sleep(interval);
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt();
          throw new WebDriverException(e);
        }
      }
    }