skip to content

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

level: middleimportance: should knowfreq 50%

answer

  1. More than one state satisfies it
  2. A locator that matches nothing still passes
  3. Detached counts the same as hidden
  4. Nothing to hand back, so Boolean
  5. Prove it appeared before waiting

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.

solid answer

~30 s

On each poll it calls `driver.findElement(locator)` and returns the negation of `isDisplayed()`, wrapped in a catch for `NoSuchElementException` and `StaleElementReferenceException` that returns `true` for either. So hidden, absent and detached all count as invisible, and the result is a `Boolean` because two of those three states leave no element to hand back. The practical consequence is that a wrong or not-yet-injected locator satisfies the condition immediately. The fix is ordering: wait for `visibilityOfElementLocated` on the same `By` first, so the transition is proven, then wait for it to become invisible. `ExpectedConditions.invisibilityOf(WebElement)` is the variant for a reference you already hold.

code

java · 9 lines
java
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(20));
By spinner = By.cssSelector(".grading-spinner");

// prove it appeared, so the disappearance wait means something
wait.until(ExpectedConditions.visibilityOfElementLocated(spinner));
wait.until(ExpectedConditions.invisibilityOfElementLocated(spinner));

WebElement level = wait.until(
    ExpectedConditions.visibilityOfElementLocated(By.id("placement-level")));

go deeper

for a junior

Know that this is the shipped way to wait for something to go away, that it gives back true rather than an element, and that an element which is simply not there also counts as invisible.

for a middle

Explain the three satisfying states and the catch block behind them, and be able to say why the condition returns a Boolean rather than the node it looked for.

for a senior

Demonstrate the ordering discipline: a disappearance wait proves nothing unless appearance was proven first, and be ready to read the timeout message as a stuck-busy diagnosis.

for a principal

Own the convention that a wait must assert a transition rather than a single edge, and make sure the team's shared helpers do not encode a check that passes on a typo.

## The predicate is three states in one `ExpectedConditions.invisibilityOfElementLocated(By)` is the shipped **negative** check in Selenium 4: it is how you wait for something to go away rather than arrive. Its body is short, and knowing the shape of it explains everything about how it behaves. On each poll it calls `driver.findElement(locator)` and returns the negation of `isDisplayed()`. It wraps that in a `catch` for `NoSuchElementException` and `StaleElementReferenceException`, and for either of those it returns `true`. So three distinct page states all satisfy it: 1. The element **exists and is hidden** — found, and `isDisplayed()` returned `false`. 2. The element **does not exist** — `findElement` threw `NoSuchElementException`. 3. The element **was detached** between the find and the display read — `StaleElementReferenceException`. The return type is `Boolean`, not the element, which follows from there being no element to hand back in two of the three cases. ## What counts as hidden `isDisplayed()` is the browser's rendered-ness verdict rather than a CSS text match, so all of these read as invisible: `display: none`, `visibility: hidden`, and a box laid out with zero width or zero height. A node scrolled out of view is a different matter — it is still displayed. There is a sibling for the case where you already hold the reference, `ExpectedConditions.invisibilityOf(WebElement)`, and one that keys on rendered text, `ExpectedConditions.invisibilityOfElementWithText(By, String)`, which is satisfied when no matching element carries that exact text visibly. ## The consequence you must be able to state Because absence satisfies the condition, `invisibilityOfElementLocated` returns `true` **immediately** when the locator matches nothing at all. On a language-school placement quiz, a wait on `.grading-spinner` passes instantly if the class is really `grading-spinner__inner`, if the spinner has not been injected yet, or if grading has not started. The wait ends green and the very next line reads a results panel that is not populated. The discipline that fixes it is ordering, not tuning: - Wait for the spinner to be **visible** first, with `visibilityOfElementLocated` on the same `By`. - Then wait for the same `By` to become invisible. - Only then read the outcome. That pair proves the transition happened rather than assuming it. It is also why the second wait is usually given a longer timeout than the first: appearing is fast, grading is not. | Situation on the page | `visibilityOfElementLocated` | `invisibilityOfElementLocated` | |---|---|---| | Element present and painted | passes, returns the `WebElement` | keeps polling | | Element present but `display: none` | keeps polling | passes, returns `true` | | Locator matches nothing | keeps polling, ends in `TimeoutException` | passes at once, returns `true` | | Element detached mid-check | keeps polling | passes, returns `true` | ## Where it sits among the negative checks Selenium 4 ships more than one way to say "gone", and they are not synonyms: - `invisibilityOfElementLocated(By)` re-runs the lookup every poll, so it tracks a **locator**. It is satisfied by hidden, absent or detached. - `stalenessOf(WebElement)` takes a **reference you already hold** and calls a method on it purely to force the driver's staleness check; it returns `true` only once that reference is no longer attached. A node that is still attached but hidden does not satisfy it. - `not(...)` wrapped around a positive condition inverts the result, but it does not catch exceptions the way `invisibilityOfElementLocated` does. So `invisibilityOfElementLocated` is the right tool for a spinner or a toast that is added and removed from the DOM or toggled with a class; `stalenessOf` is the right tool when you are holding a specific element and want to know that *that* object is finished. ## Reading the failure When the element never goes away, the wait ends in `TimeoutException`, and the message carries the condition's own `toString()`, which reads `element found by <locator> to become invisible`. That phrasing is worth recognising: it tells you the wait was a disappearance wait, so the page is stuck in a busy state rather than failing to render — a genuinely different diagnosis from an appearance timeout. A last point of technique: because the condition returns a plain `Boolean`, there is nothing to keep from the call. Anything you need after the spinner clears must be located afterwards, and locating it with its own positive wait — visibility or clickability on the results panel — is what turns "the spinner went" into "the result is there".

  • How does invisibilityOfElementLocated differ from stalenessOf?
    `invisibilityOfElementLocated(By)` re-runs the lookup each poll and is satisfied by hidden, absent or detached. `stalenessOf(WebElement)` takes a reference you already hold and calls a method on it to force the staleness check, so it is satisfied only when that specific object is detached — a node still attached but hidden does not satisfy it.
  • Does an element scrolled out of the viewport satisfy this condition?
    No. The condition negates `isDisplayed()`, which is about being rendered, not about being within the current scroll position. An off-screen element with a real box is still displayed, so the wait keeps polling and eventually raises `TimeoutException`.
  • What does the TimeoutException message look like when this condition never passes?
    The wait prints the condition's own `toString()`, which reads `element found by <locator> to become invisible`, together with the timeout and the poll interval. That phrasing identifies it as a disappearance wait, so the diagnosis is a page stuck busy rather than a page that never rendered.

saying these in an interview costs you the question

  • Says the condition fails when the locator matches nothing
  • Expects it to return the element that became hidden
  • Thinks an element scrolled out of view satisfies it
  • Treats it as interchangeable with stalenessOf
  • Waits for disappearance without first proving appearance