Skip to content

[πŸ› Bug]: WebDriverWait polling consistency between Java and Python implementationsΒ #14623

@guillaumepichenot

Description

@guillaumepichenot

What happened?

I have noticed that on my Python-based Seleniums runs, when using a WebDriverWait to check (let's say by CSS selector) for a non existing element in the DOM, the call never takes less than 500ms, whereas I consistently get <100ms for existing elements.

The behavior does not arise in Java implementations of the same scenario.

My best guess is that the Java and Python implementation have different sleep strategy orchestration.

Current python loop :

while True:
try:
value = method(self._driver)
if value:
return value
except self._ignored_exceptions as exc:
screen = getattr(exc, "screen", None)
stacktrace = getattr(exc, "stacktrace", None)
time.sleep(self._poll)
if time.monotonic() > end_time:
break
raise TimeoutException(message, screen, stacktrace)

Current java loop :

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);
}
}

Note that the Python orchestration is :

  1. Timestamp the timeout end
  2. Perform the lookup
  3. sleep
  4. Check now vs. timeout to exit

The Java implementation is :

  1. Timestamp the timeout end
  2. Perform the lookup
  3. Check new vs. timeout to exit
  4. Sleep

The inversion of steps 3 and 4 is manifest IMO.
The Java version looks more sensible to me, as it allows for effectively having timeout=0 checks, while python implementations in practice will never get a sub pollingInterval check (for non-existing elements).

How can we reproduce the issue?

WebDriverWait(driver, 0).until(
  visibility_of_any_elements_located((By.CSS_SELECTOR, "#anyIdThatDoesNotExist"))
);


Notice you will never get <500ms (`POLL_FREQUENCY`) results.

Relevant log output

N/A

Operating System

macOs, Linux

Selenium version

4.0.25

What are the browser(s) and version(s) where you see this issue?

Chrome 129

What are the browser driver(s) and version(s) where you see this issue?

ChromeDriver 129

Are you using Selenium Grid?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-needs-triagingA Selenium member will evaluate this soon!I-defectSomething is not working as intended

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions