In Selenium's Java WebDriverWait, which values returned by a custom condition keep it polling?
answer
- Two values keep the loop alive
- The false test is type-aware
- An empty list is still a result
- findElements never returns null
- Return null yourself when not ready
basics
~20 sOnly two: null, and a Boolean whose value is false. Every other result ends the wait and is returned by until, including an empty list, an empty string and a zero, which is why an empty findElements result never waits.
solid answer
~40 sIn Selenium 4 the Java loop keeps going only while the condition returns `null` or a `Boolean` that is `false`. Anything else is treated as the answer, returned from `until`, and ends the wait — and the `false` test is type-aware, so it applies to a `Boolean` and to nothing else. That is why returning `driver.findElements(...)` straight out of a condition never waits: an empty `List` is neither `null` nor a false `Boolean`, so the first poll succeeds with zero rows and the failure surfaces later as an index or size error. The same applies to an empty `String` from `getText()`. Decide emptiness yourself and return `null` while the page is not ready. Selenium's Python binding differs: its `until` uses Python truthiness, so there an empty list does keep polling.
code
java · 6 linesWebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
List<WebElement> rows = wait.until(d -> {
List<WebElement> found = d.findElements(By.cssSelector("#nursery-order tbody tr"));
return found.isEmpty() ? null : found;
});go deeper
Learn the two stop-the-loop exceptions: null and false keep waiting, everything else counts as the answer. When in doubt, return null explicitly for the not-ready case rather than relying on emptiness.
Be able to state the rule precisely, including that the false check only applies to a Boolean. Then explain from that rule why a condition returning findElements ends on the first poll.
Show how you diagnose it in a suite: a wait that never waits, and an index or size failure a few lines later. Point at the condition's return type as the first thing you inspect.
Frame it as an API shape the team relies on. Decide whether shared wait helpers should ever return collections, and what convention keeps not-ready expressed as null everywhere in the codebase.
## The exact rule Selenium applies `FluentWait.until` — the loop behind `WebDriverWait` — does not ask whether your value is "truthy" in any loose sense. In the Java bindings it applies one precise test to whatever your condition returned: - the value is **not `null`**, and - the value is **not the `Boolean` `false`**. Everything that passes both checks ends the wait and is handed back as the return value of `until`. In Selenium 4 that means exactly two results keep the loop running: `null`, and a `Boolean` whose value is `false`. Nothing else does. A `Boolean.TRUE` stops it, and so does every non-`Boolean` object, whatever it contains. That is stricter than most people's mental model, because the rule is **type-aware**: the `false` check applies only when the returned object's class is `Boolean`. A `String` that happens to be empty, a `List` that happens to have no members, and a `Long` that happens to be `0` are all "not null and not a false Boolean", so all three **end the wait**. ## Values that surprise people | Your condition returns | Java `WebDriverWait` | Python `WebDriverWait` | |---|---|---| | `null` / `None` | keeps polling | keeps polling | | `false` / `False` | keeps polling | keeps polling | | `""` (empty string) | **stops and returns it** | keeps polling | | `List` with no elements | **stops and returns it** | keeps polling | | `Long` `0` from a script | **stops and returns it** | keeps polling | | a `WebElement` | stops and returns it | stops and returns it | | `true` / `True` | stops and returns it | stops and returns it | The right-hand column is the cross-binding footnote worth knowing: Selenium's Python `WebDriverWait.until` returns the value when `if value:` is satisfied, so it follows **Python truthiness** and an empty list, an empty string or `0` all keep it polling. The Java rule is narrower. If you move a condition between the two bindings, the empty-collection row is where the behaviour silently diverges. ## Why findElements is the classic trap The most common way to write a custom condition on a **plant-nursery order form** is to look for the order lines and wait until some exist: ```java List<WebElement> rows = new WebDriverWait(driver, Duration.ofSeconds(10)) .until(d -> d.findElements(By.cssSelector("#nursery-order tbody tr"))); ``` This never waits. `findElements` returns an **empty list** when nothing matches — it does not throw and it does not return `null` — and an empty `ArrayList` is neither `null` nor a `false` `Boolean`, so the very first poll succeeds and `rows` comes back with zero elements. The failure then surfaces somewhere else entirely, usually as an `IndexOutOfBoundsException` or an assertion on a size of zero, several lines below the wait that was supposed to prevent it. The fix is to make the "not ready" case return `null` explicitly: 1. Do the read: `List<WebElement> found = d.findElements(...)`. 2. Decide readiness in your own code: is `found.isEmpty()`, or is the count below what you expect? 3. Return `null` when it is not ready, and the list itself when it is. The same pattern applies to text. `getText()` on an empty cell gives `""`, which stops the wait, so a condition waiting for the subtotal to be populated must return `null` while the text is blank or still a placeholder, and only return the string once it actually carries a value. ## Choosing what to return - Return the **thing you need next** — the `WebElement`, the `List<WebElement>`, the `String` — so `until` hands it straight to the following line and you do not re-find it. - Return `null`, not `false`, when the useful result is an object; mixing `null` and `false` in one condition makes the return type awkward and gains nothing. - Return `Boolean` only for genuine yes/no checks, where the value of `until` is not interesting. - Never return a **collection or a string** without deciding emptiness yourself; the wait will not decide it for you. - Remember that `until` is declared to return a non-null value, so a condition that can only ever produce `null` will always end in `TimeoutException`. ## Reading a failure back to this rule When a custom wait "does not wait", check the return type first. A condition typed to return `List`, `String`, `Map` or a boxed number is nearly always the cause, because those are the types with a natural empty value that Java's rule still counts as a result. A condition typed to return `WebElement` or `Boolean` is far harder to get wrong: the element case is either found or throws, and the boolean case matches the rule exactly.
- Your condition returns getText() on the subtotal cell and the wait ends instantly. What is happening?`getText()` on a cell that has not been populated yet returns an empty string, and an empty `String` is neither `null` nor a false `Boolean`, so the first poll counts as success. Compare the text against what you actually expect and return `null` while it is blank or still a placeholder, returning the string only once it carries a real value.
- Does returning Boolean.FALSE differ from returning null in how the wait behaves?Not in behaviour: both keep the loop running until the timeout. They differ in what `until` can give you back. A boolean condition can only ever return `true`, which is useless as a value, whereas returning the element or the text you were waiting for lets the next line use the result directly instead of finding it again.
- Can a condition legitimately return zero as a successful result?Yes, and Java will accept it, because a boxed `0` is neither `null` nor a false `Boolean`. If you are waiting for a count to fall to zero — no pending nursery order lines left — returning the number works. Just be aware the same rule is what makes an accidental empty list look like success.
saying these in an interview costs you the question
- Thinks an empty list from findElements keeps the wait polling
- Believes any falsy value ends the polling loop in Java
- Expects findElements to return null when nothing matches
- Assumes Java and Python bindings judge results identically
- Returns getText output without checking it is non-blank