In Selenium, why can a wait on presenceOfElementLocated pass while the element is still invisible?
answer
- One condition runs a lookup only
- Attached to the document is enough
- The rendering check is a different condition
- Hidden markup still satisfies the lookup
- No isDisplayed call anywhere in it
basics
~10 sBecause 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.
solid answer
~40 s`presenceOfElementLocated` runs a single `findElement` per poll and returns the element as soon as one matches, treating `NoSuchElementException` as “not yet”. It never asks whether the browser renders that node, so an element hidden by `display: none`, a zero-size box, or a collapsed ancestor satisfies it on the first poll. `visibilityOfElementLocated` is the same lookup plus one `isDisplayed()` check, and `elementToBeClickable` adds `isEnabled()` on top of that. On a cinema showtime picker whose screening rows ship in the initial HTML but stay hidden until seat availability loads, a presence wait returns instantly and the test proceeds against elements the user cannot see. Presence is the right condition only when your next step is a DOM assertion, not an interaction.
go deeper
Learn the one-line distinction: presence means the node is in the DOM, visibility means the browser also renders it. Choose visibility before you click or type, presence before you assert on markup.
Explain the mechanics: presence is a findElement per poll, visibility is that plus isDisplayed, clickable is that plus isEnabled. Be able to say where the ladder stops and what it still does not promise.
Show you can spot a decorative wait in review. A presence wait that returns on its first poll consumes none of its timeout, gives a false impression of synchronisation, and pushes the failure far from its cause.
Own the framing that a condition is chosen by what the next step needs, not by habit. Standardising on one condition everywhere trades a real signal for a comfortable one, and that trade shows up as failures nobody can localise.
## Presence is a lookup, nothing more `ExpectedConditions.presenceOfElementLocated(By)` is one of the thinnest conditions Selenium 4 ships. Per poll it does one thing: call `driver.findElement(locator)`, and if that raises `NoSuchElementException`, return `null` so the wait keeps polling. Any element it finds is returned as-is. That means the condition is satisfied the instant a matching node is **attached to the document**. It never calls `isDisplayed()`, so it makes no claim about whether the node is rendered, has a non-zero box, is inside a collapsed ancestor, or sits behind a `display: none` on a parent. Presence answers "does the DOM contain a match?" and stops there. ## Visibility adds exactly one call `visibilityOfElementLocated(By)` does the lookup and then passes the result through an internal helper that returns the element if `isDisplayed()` is true and `null` otherwise. So visibility is presence **plus one boolean**. It also treats a `StaleElementReferenceException` from the lookup as "not yet" and keeps polling. Then `elementToBeClickable` adds one more boolean on top. The three conditions form a strict ladder, and it is worth seeing where the ladder stops: | Condition | Node in the DOM | `isDisplayed()` | `isEnabled()` | Anything covering it | |---|---|---|---|---| | `presenceOfElementLocated` | required | not checked | not checked | not checked | | `visibilityOfElementLocated` | required | required | not checked | not checked | | `elementToBeClickable` | required | required | required | **still not checked** | The top of the ladder is still two rungs short of "the click will work". That is the single most useful thing to carry away from the comparison. ## Where the gap opens on a cinema showtime picker Server-rendered and client-rendered pages both produce the classic version of this: - The showtimes grid ships in the initial HTML with its screening rows already present, wrapped in a container the app reveals only after the seat-availability call returns. - A wait on `presenceOfElementLocated(By.cssSelector(".showtime"))` is satisfied on its first poll, because those nodes were in the DOM before the page ever finished loading. - The test proceeds against elements the user cannot see. Reads come back empty or default, and the first interaction fails. - Switching to `visibilityOfElementLocated` fixes precisely this case, because the reveal flips `isDisplayed()` from false to true and that is the boolean the condition reads. The mirror-image mistake is just as common: using visibility for something that is **deliberately** hidden, such as asserting that a validation message exists in the markup for a sold-out screening even though the app renders it collapsed. There, visibility never becomes true and you get a `TimeoutException` on a page that is behaving correctly. ## Choosing between them 1. **Ask what your next line does.** If it is a click or a keystroke, presence is not enough — the node must at minimum be rendered. If it is an assertion about the DOM, presence may be exactly right. 2. **Ask whether "hidden" is part of what you are testing.** Asserting that something is absent from view is a job for a condition about invisibility, not for waiting on visibility and catching the timeout. 3. **Ask whether the element pre-exists the state you care about.** A node that is always in the markup makes presence a no-op wait: it returns immediately and gives you a false sense that you synchronised on something. ## The trap presence sets for the reader of the test - A presence wait that returns instantly **looks** like a synchronised test. There is a `WebDriverWait` on the line, a timeout was configured, and nothing failed. The synchronisation is decorative. - The timeout you set is never consumed, so the test does not get slower when the app gets slower — it gets **wronger**, failing later and in a place further from the cause. - Because `presenceOfElementLocated` returns the `WebElement`, a reference obtained this way is easy to stash and reuse; if the container is re-rendered on reveal, that stashed reference points at a detached node. - Reaching for a longer timeout when a presence wait "did not work" is a category error. The condition was true; you asked the wrong question, and asking it for longer changes nothing. Stated compactly: **presence means found, visibility means found and shown, clickable means found, shown and not disabled — and none of the three means the click will land.**
- When is presenceOfElementLocated actually the right condition to use?When the next thing you do is read or assert on the DOM rather than interact. Checking that a node exists, counting matches, or waiting for a hidden marker the app writes into the page are all legitimate. It is also the honest choice when the element is deliberately not rendered and visibility would never become true.
- What exactly does visibilityOfElementLocated add over presence?One boolean. It performs the same `findElement` and then returns the element only if `isDisplayed()` is true, otherwise it returns null and keeps polling. It also treats a stale reference from the lookup as “not yet”. That single extra call is the whole difference between the two conditions.
- Why is a presence wait that returns instantly worse than no wait at all?Because it looks like synchronisation. The line carries a WebDriverWait and a timeout, so a reader assumes the test pauses for the app, when in fact the timeout is never consumed. The failure then surfaces further down, on an unrelated line, and the misleading wait is the last place anyone looks.
saying these in an interview costs you the question
- Uses presence and visibility as interchangeable synonyms
- Thinks findElement refuses to return hidden elements
- Assumes a wait that passes must have paused for something
- Raises the timeout when a presence wait returned too early
- Believes visibility is the safe default for every situation