In Selenium's Java bindings, what does the FluentWait class let a test configure about a wait?
answer
- A wait with its own dials
- Chained setters returning the same instance
- Deadline, gap, swallowed types, failure text
- withTimeout, pollingEvery, ignoring, withMessage
- until takes the function and returns its value
basics
~10 sFluentWait is Selenium's configurable wait. withTimeout sets how long it keeps trying, pollingEvery sets the gap between tries, ignoring and ignoreAll list exception types to swallow and retry, and withMessage sets the timeout text.
solid answer
~40 s`FluentWait<T>` in `org.openqa.selenium.support.ui` is Selenium's general polling wait, and `WebDriverWait` is a subclass of it with the settings pre-filled. Four things are yours to set, each through a setter that returns the same instance so the calls chain: `withTimeout(Duration)` for the overall deadline, `pollingEvery(Duration)` for the sleep between attempts, `ignoring(Class)` or `ignoreAll(Collection)` for the throwable types that should cause a retry rather than a failure, and `withMessage(String)` or `withMessage(Supplier<String>)` for the text that goes into the `TimeoutException`. You then call `until(Function)`, which returns the first non-null, non-false value the function produces. In Selenium 4 both duration setters take `java.time.Duration`. Note that a bare `FluentWait` starts with a 500 ms timeout and an empty ignore list, so configuring it is not optional.
code
java · 26 linesimport java.time.Duration;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
public final class QuoteTotals {
public static WebElement annualYield(WebDriver driver) {
Wait<WebDriver> wait =
new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(20))
.pollingEvery(Duration.ofMillis(750))
.ignoreAll(
List.of(
NoSuchElementException.class,
StaleElementReferenceException.class))
.withMessage("annual-yield figure never refreshed after roof area changed");
return wait.until(d -> d.findElement(By.id("annual-yield")));
}
}go deeper
Be ready to name the four setters and what each one changes, and to write the chain from memory. Interviewers ask this as a screening question because it shows you have configured a wait rather than copied one.
Explain that the setters return the same instance, that a bare FluentWait starts at 500 milliseconds for both timeout and interval, and that until returns the first non-null, non-false value rather than just blocking.
Show that you treat the ignore list and the message as part of the failure report your team will read at three in the morning, not as boilerplate, and that you know which exception types belong on that list.
Own the question of where these waits are constructed at all: a single configured factory versus a chain rebuilt in every test decides whether timeout and ignore policy can ever be changed in one place.
## What FluentWait is `FluentWait<T>` is Selenium's **general polling wait**. It lives in the package `org.openqa.selenium.support.ui` and implements the single-method `Wait<T>` interface. You construct it with one input object — for browser work that object is the `WebDriver` — and then hand `until()` a function. `FluentWait` applies that function to the input over and over until it succeeds or the clock runs out. Every knob that controls *how* it polls is set by a **fluent setter** that returns the same instance, which is why the calls chain into one expression. `WebDriverWait` is nothing more than a subclass of `FluentWait<WebDriver>` with those knobs filled in by its constructor, so anything below applies to it too. ## The knobs, and the method that sets each | What you are changing | Method | Argument | |---|---|---| | How long to keep trying | `withTimeout(Duration)` | a `java.time.Duration` | | How long to sleep between tries | `pollingEvery(Duration)` | a `java.time.Duration` | | Which throwables to swallow and retry | `ignoring(Class)`, `ignoring(Class, Class)`, `ignoreAll(Collection)` | exception classes | | What the failure text says | `withMessage(String)`, `withMessage(Supplier<String>)` | fixed text, or text built at failure time | Two things that table hides: - In **Selenium 4** both duration setters take `java.time.Duration`, so `withTimeout(Duration.ofSeconds(20))` and `pollingEvery(Duration.ofMillis(750))` are the spellings you write. The Selenium 3 number-plus-`TimeUnit` overloads are gone. - `ignoreAll(Collection)` is the primitive; both `ignoring` overloads simply call it with a small list. There is no matching remove or reset method. ## What you get before you configure anything A freshly constructed `FluentWait` is **not** an unlimited wait. Its starting state is: - **timeout: 500 ms**, taken from the constant `DEFAULT_SLEEP_TIMEOUT`; - **polling interval: 500 ms**, taken from the same constant; - **ignore list: empty**, so any throwable out of the function ends the wait; - **message: none**, so the failure text falls back to describing the function itself. The first line is the one that catches people out: `new FluentWait<>(driver).until(...)` retries for half a second, not thirty. On a rooftop-solar quote builder, where the panel-count and the annual-yield figures are recomputed after a round trip, half a second is usually one attempt and a failure. `withTimeout` is not optional decoration on a `FluentWait`; it is the setting that turns it into a real wait. Because the ignore list also starts empty, a bare `FluentWait` aborts on the first `NoSuchElementException` it sees, which is why `ignoring(...)` almost always appears in the same chain. ## How until() decides it is finished `until(Function<? super T, ? extends V>)` loops, and it stops on exactly one of four things: 1. the function returns a value that is neither `null` nor `Boolean.FALSE` — that value is returned to the caller; 2. the function throws something that is **not** on the ignore list — that throwable propagates and the wait ends; 3. the deadline passes — a `TimeoutException` is thrown; 4. the thread is interrupted during the sleep — the interrupt flag is restored and a `WebDriverException` is thrown. Because the truthy return value comes back to you, a `FluentWait` is more than a delay. `wait.until(d -> d.findElement(By.id("quote-total")))` hands you the located `WebElement`, so waiting and locating are one statement rather than two. The function may be a lambda, a `Function<WebDriver, T>`, or an `ExpectedCondition<T>` — that interface exists precisely to extend `Function<WebDriver, T>`. ## What the ignore list actually does An ignored throwable is not a pass; it is a **retry**. When the function throws a type on the list, `FluentWait` records it, sleeps, and tries again — and if the wait eventually times out, the recorded throwable is attached as the **cause** of the `TimeoutException`. Anything not on the list ends the wait immediately, which is what you want for a genuine bug. Keep the list to the types you honestly expect to see transiently while the page settles, and no wider. ## The failure message When the deadline passes, the text is assembled in a fixed shape: ```text Expected condition failed: <your message, or "waiting for " plus the function> (tried for 20 seconds with 750 milliseconds interval) ``` `withMessage` replaces the middle clause only; the `Expected condition failed:` prefix and the `(tried for ... with ... interval)` suffix are always there. Without a message you get the function's `toString()`, which for a lambda is an unreadable synthetic class name. `withMessage("annual-yield total never refreshed after the roof-area change")` is the difference between a diagnosable CI failure and a shrug. The `Supplier<String>` overload is evaluated at failure time, so it can fold in state the test only learns while it waits.
- What does until() give you back when the condition finally passes?The first value the function returns that is neither `null` nor `Boolean.FALSE`, typed to whatever the function produces. So `until(d -> d.findElement(By.id("annual-yield")))` returns the located `WebElement` and you can act on it straight away. A condition that only reports readiness returns `true`, and you ignore the result.
- What happens if you never call withTimeout on a FluentWait?It keeps the class default of 500 milliseconds, which comes from the `DEFAULT_SLEEP_TIMEOUT` constant. That is one or two attempts on a real page, so the wait fails almost immediately with a `TimeoutException`. The default polling interval is the same 500 milliseconds, so an unconfigured `FluentWait` behaves like a single check.
- Can you pass an ExpectedCondition to a FluentWait's until()?Yes. `ExpectedCondition<T>` is declared as extending `Function<WebDriver, T>` precisely so it can be handed to `until`, which accepts any `Function` over the wait's input type. A lambda, a named `Function` implementation and an `ExpectedCondition` are all the same thing to `FluentWait`.
saying these in an interview costs you the question
- Thinks a new FluentWait waits forever until configured
- Believes withTimeout is optional because a default is generous
- Says ignoring makes the condition pass rather than retry
- Thinks withMessage changes the exception type thrown
- Cannot say what value until actually returns