skip to content

Readiness Predicates

The condition side of a wait: what each poll actually checks, how ready-made predicates differ from ones you write, and why a check that passes is not always a safe next action.

on this pageshow

explore

questions

13

In Selenium, which two checks does ExpectedConditions.elementToBeClickable actually perform before returning?

level: juniorimportance: must knowfreq 74%

answer

  1. Fewer checks than the name suggests
  2. Two booleans on one element
  3. Rendering first, then form state
  4. Nothing asks what is painted above
  5. isDisplayed then isEnabled, and stop

basics

~10 s

Just two: isDisplayed and isEnabled. Selenium's elementToBeClickable locates the element, confirms the browser renders it and that it is not disabled, then returns it. Nothing in the condition asks whether something covers it.

solid answer

~40 s

`ExpectedConditions.elementToBeClickable` is thinner than its name. On each poll it locates the element, calls `isDisplayed()`, then calls `isEnabled()`; if either is false the poll returns `null` and `WebDriverWait` sleeps and tries again. When both are true it returns the `WebElement` and `until` hands it back. That is the whole contract — “clickable” here means *shown and not disabled*, not *reachable by a pointer*. On a cinema showtime picker, a `19:45` button under a translucent “checking seat availability” panel is displayed and enabled, so the wait is satisfied on its first poll and the very next `click()` can still fail. Read it as a signal about the element itself, never as a promise about what is painted on top of it.

code

java · 21 lines
java
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

public class ShowtimePicker {

  public static void bookSevenFortyFive(WebDriver driver) {
    WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    By slot = By.cssSelector(".showtime[data-time='19:45']");

    WebElement showtime = wait.until(ExpectedConditions.elementToBeClickable(slot));

    System.out.println(showtime.isDisplayed());
    System.out.println(showtime.isEnabled());

    showtime.click();
  }
}

go deeper

for a junior

Be ready to name the two checks without hedging: isDisplayed and isEnabled. Knowing that the condition returns the element itself, rather than a boolean, is the other half interviewers listen for.

for a middle

Explain the mechanics: each poll locates, checks the two booleans, and returns null to keep polling. Say which exceptions the poll swallows, and note that the two overloads differ only in whether they re-locate.

for a senior

Show that you design around the gap. Demonstrate that you pick predicates whose truth actually implies the next command can succeed, and that you can name why a passing wait is still followed by a failing click.

for a principal

Own the guidance that a wait predicate is a statement about one element and never about the page. Where a codebase treats elementToBeClickable as a safety guarantee, that assumption is the thing to name and remove.

## The condition is two boolean calls, in order `ExpectedConditions.elementToBeClickable` lives in Selenium 4's Java support library (`org.openqa.selenium.support.ui`), and its body is far smaller than its name suggests. Every time `WebDriverWait` polls it, the `By` overload runs exactly this sequence: 1. Call `driver.findElement(locator)`. If that raises `NoSuchElementException` or `StaleElementReferenceException`, the condition records a "was not found" message and returns `null`, which tells the wait to sleep and poll again. 2. Call `element.isDisplayed()`. If it is `false`, the condition records "was not visible" and returns `null`. 3. Call `element.isEnabled()`. If it is `false`, the condition records "was not enabled" and returns `null`. 4. Otherwise return the located `WebElement`, which ends `until` and becomes the value handed back to your test. There is no fifth step. **In Selenium's vocabulary "clickable" means displayed and enabled** — and that is the whole of it. The recorded message is only used to build the `TimeoutException` text if the wait runs out; it never adds a check. ## What each of the two checks actually answers - **`isDisplayed()`** is a rendering question answered by the browser. It accounts for `display: none`, `visibility: hidden`, a zero-width or zero-height box, and hidden ancestors. It is a statement about the element itself. - **`isEnabled()`** is a form-state question. On a form control it reports the inverse of the `disabled` state; on an ordinary element it is simply `true`, which means a `<div>` styled to look like a button passes this check unconditionally. - Neither call knows anything about **stacking order, overlays, pointer-events, animation, or what is painted on top of the target**. Those are properties of the page around the element, and the condition never asks the page about them. - Neither call is a promise about the future. It is a reading taken at one poll, on one element. ## The two overloads, and the one way they differ | Overload | Re-locates on every poll | A stale reference | Returns from `until` | |---|---|---|---| | `elementToBeClickable(By)` | yes — `findElement` runs each poll | caught, treated as "not yet"; the next poll re-finds, so a re-render is survived | the freshly located `WebElement` | | `elementToBeClickable(WebElement)` | no — it reuses the reference you passed | also caught and treated as "not yet", but nothing ever re-finds, so the wait spins out to `TimeoutException` | the same reference you passed in | The `WebElement` overload is the one that surprises people: handing it a reference captured before a re-render does not make the wait recover, it makes the wait fail slowly. ## A cinema showtime picker, and the shape of the failure Picture a screening-times page. Pick a date and the grid of showtime buttons is already in the markup and already enabled, but a translucent "checking seat availability" panel is drawn over the whole grid while the seat counts load. Every showtime button in that grid is **displayed** (it has a box, it is not `display: none`) and **enabled** (no `disabled` attribute). So: - `elementToBeClickable(By.cssSelector(".showtime[data-time='19:45']"))` is satisfied on its very first poll. - `until` returns immediately, typically in single-digit milliseconds, spending none of the timeout you configured. - The next line calls `click()`, the browser performs its own obstruction check as part of the click command, finds the panel over the button's centre, and the command fails with `ElementClickInterceptedException`. Nothing malfunctioned. The condition answered the question it was asked, truthfully; the question just was not the one the test needed answered. ## Using the condition for what it is - Treat it as a **readiness signal about one element's own state**, exactly equivalent to asserting `isDisplayed() && isEnabled()` in a loop. - It is genuinely the right tool when the thing you are waiting on **is** the element's own state — a submit button that starts disabled until a date is chosen, or a node that is rendered hidden and then revealed. - It is the wrong tool when the thing standing between you and the click is **something else on the page**. No amount of timeout makes a predicate check a property it never reads. - Because the condition returns the `WebElement` rather than a boolean, it is tempting to chain `wait.until(...).click()` on one line. That reads well and hides the fact that two independent operations, with a gap between them, are happening. The single sentence worth memorising: `elementToBeClickable` is `isDisplayed()` plus `isEnabled()`, and the word "clickable" in its name is aspiration, not contract.

  • How does the elementToBeClickable(WebElement) overload behave differently from the By overload?
    The `By` overload calls `findElement` on every poll, so a re-render is survived: the lookup exception is treated as “not yet” and the next poll finds the replacement. The `WebElement` overload runs the same `isDisplayed()`/`isEnabled()` pair against the reference you already hold. A stale reference is also swallowed as “not yet”, but nothing ever re-finds, so the wait simply spins until `TimeoutException`.
  • If the condition never checks obstruction, what does raise the error when something covers the button?
    The browser does, as part of executing the click command. When the target is obscured the remote end returns an `element click intercepted` error and the Java binding surfaces it as `ElementClickInterceptedException`, a subclass of `ElementNotInteractableException`. The check lives in the command, not in the wait, which is why a passing wait cannot predict it.
  • Does isEnabled() mean anything for an element that is not a form control?
    Very little. `isEnabled()` reports the inverse of a control's disabled state, and for an element that cannot be disabled it is simply `true`. A `<div>` or `<a>` styled as a showtime button therefore passes that half of `elementToBeClickable` unconditionally, leaving `isDisplayed()` as the only check with any content.

saying these in an interview costs you the question

  • Says elementToBeClickable guarantees the click will succeed
  • Thinks the condition inspects overlays, z-index or stacking order
  • Believes it waits for animations or CSS transitions to finish
  • Assumes displayed and enabled means reachable by a pointer
  • Claims a passing wait makes the following line safe
open as a page

In Selenium, how does ExpectedConditions.stalenessOf decide that the element it was given is gone?

level: middleimportance: must knowfreq 53%

basics

~20 s

By calling a method on the reference each poll and watching for it to fail. Selenium 4 calls isEnabled and discards the result; when that raises a stale element reference or no such element error, the condition returns true.

open as a page

In Selenium's ExpectedConditions, which helpers hand back a usable WebElement and which only hand back a Boolean?

level: middleimportance: must knowfreq 61%

basics

~20 s

Helpers that ask for a node return it: presenceOfElementLocated, visibilityOfElementLocated, visibilityOf and elementToBeClickable give a WebElement, the all-elements helpers give a list, alertIsPresent gives an Alert. Helpers that assert a page fact, such as invisibilityOfElementLocated, stalenessOf and titleIs, give only a Boolean.

open as a page

In Selenium, why can a click throw ElementClickInterceptedException on the line right after elementToBeClickable passed?

level: seniorimportance: must knowfreq 61%

basics

~20 s

Because the two ask different questions at different moments. The wait only confirmed displayed and enabled; obstruction is checked by the browser when the click command runs, and the page is free to change in between.

open as a page

In Selenium's ExpectedConditions, how do or(), and(), not() and refreshed() compose other conditions?

level: seniorimportance: must knowfreq 48%

basics

~20 s

or() passes when any branch is satisfied, and() when every branch is, and not() when the wrapped one is not. All three yield a Boolean, losing any element. refreshed() wraps a single condition, keeps its return type, and absorbs staleness so the poll retries.

open as a page

In Selenium, what shape must a custom condition passed to WebDriverWait.until have?

level: juniorimportance: should knowfreq 64%

basics

~20 s

A function from WebDriver to some value. The wait passes the driver in on every poll, and the first result that is neither null nor false ends the wait and becomes the return value of until.

open as a page

In a Selenium custom wait condition, how do you poll a page state that no element reflects?

level: juniorimportance: should knowfreq 41%

basics

~20 s

Cast the driver the wait hands you to JavascriptExecutor and return the result of executeScript from the condition. The fragment needs an explicit return statement, or every poll receives null and the wait just times out.

open as a page

In Selenium's ExpectedConditions, what do presenceOfElementLocated, visibilityOfElementLocated and elementToBeClickable each check?

level: juniorimportance: should knowfreq 72%

basics

~10 s

presenceOfElementLocated only requires the element to exist in the DOM. visibilityOfElementLocated additionally requires it to be displayed with a non-zero box. elementToBeClickable requires that displayed state plus the element reporting itself as enabled.

open as a page

In Selenium, why can a wait on presenceOfElementLocated pass while the element is still invisible?

level: middleimportance: should knowfreq 57%

basics

~10 s

Because presence only means the lookup succeeded. Selenium's presenceOfElementLocated calls findElement and returns whatever it finds; it never calls isDisplayed, so a node hidden by CSS or a collapsed parent satisfies it immediately.

open as a page

In Selenium's Java WebDriverWait, which values returned by a custom condition keep it polling?

level: middleimportance: should knowfreq 58%

basics

~20 s

Only 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.

open as a page

In Selenium, which page states make ExpectedConditions.invisibilityOfElementLocated return true instead of polling again?

level: middleimportance: should knowfreq 50%

basics

~20 s

Three states satisfy it: the element is found but not displayed, the locator matches nothing, or the element went stale mid-check. It returns a Boolean, not the element, and passes instantly when the locator never matched.

open as a page

Why must a custom condition passed to Selenium's WebDriverWait.until be free of side effects?

level: seniorimportance: should knowfreq 52%

basics

~20 s

The condition is re-evaluated on every poll until it succeeds or times out, so any action inside it runs many times over. Selenium documents conditions as idempotent: keep the body to reads and act after until returns.

open as a page

Your custom Selenium wait condition reuses a WebElement found before the wait and dies with StaleElementReferenceException. Why?

level: seniorimportance: should knowfreq 47%

basics

~20 s

The lambda captured an element handle taken before the page re-rendered, so a later poll touches a detached node. WebDriverWait ignores only NotFoundException by default, and staleness is not one, so it aborts the wait.

open as a page