Why can acting on an off-screen element that the element tree reports as present still fail?
answer
- Existing is not the same as reachable
- A contact is delivered to a coordinate
- The visible area decides, not the tree
- A fixed bar can own that coordinate
- Scroll to the target, then check bounds
basics
~20 sPresence in the element tree is not the same as being touchable. A contact is delivered to a screen coordinate, so an element scrolled out of view or covered by a fixed bar receives nothing, or the wrong element does.
solid answer
~50 sTwo different questions get conflated: *does this element exist* and *can a contact reach it*. The element tree answers the first. Delivery answers the second, and it works on **coordinates** - the system routes a contact to whatever is drawn at that point and willing to accept input. An element scrolled beyond the visible area has coordinates outside it; an element under a sticky footer, a floating control or the on-screen keyboard has coordinates that belong to something else. Harnesses that scroll for you use a strategy you did not choose. So make reach an explicit step: **scroll the container that owns the element, confirm its bounds are inside the visible area and unobstructed, then act.** No amount of extra waiting helps, because the element is already there. Capture the screenshot at the failed action, while the obstruction is still visible.
code
pseudocode · 15 linesdef bring_into_reach(container, element, max_scrolls = 10):
for attempt in 1 .. max_scrolls:
if element.bounds inside container.visible_bounds
and not covered_by_any(fixed_overlays, element.centre):
return
container.scroll(direction = DOWN,
amount = container.visible_height * 0.6)
fail("element never entered the visible area after "
+ max_scrolls + " scrolls of its own container")
case "the submit control is reachable and commits the form":
dismiss_on_screen_keyboard() # this case opened it while typing
bring_into_reach(form_scroller, submit_control)
tap(submit_control)
assert confirmation.is_visible()go deeper
Be ready to say that an element can exist on a screen and still be untouchable, either scrolled past the visible area or covered by something drawn on top, and that a case should bring it into view before acting.
Explain that a contact is routed by coordinate, so a covering bar or an open on-screen keyboard receives the input instead. Show how you check the element's bounds against the visible area rather than checking only that it exists.
Show the diagnosis: a case that passes on a tall screen and fails on a short one, an action landing on the neighbouring item, a screenshot captured at the moment of the contact. Explain why more waiting never fixes it.
Own the position that reachability is product behaviour rather than a harness chore, and decide when a suite should scroll to a control and when the inability to reach it should be reported as a defect instead of smoothed over.
## Present, visible and reachable are three different states An automated case usually asks the screen one question — *is this element there?* — and treats a yes as permission to act. Three separate properties actually have to hold before an interaction lands: - **Presence**: the element exists in the screen's reported element tree, with bounds and attributes. - **Visibility**: those bounds fall inside the area currently drawn, with a non-zero size and no attribute hiding it. - **Reachability**: the point the case is about to contact really belongs to that element — the coordinate is inside the visible area and nothing is drawn over it. Presence is the cheapest to check and the only one many cases check. Reachability is what the interaction depends on, because a contact is not addressed to an element at all. It is addressed to a **coordinate**, and the system delivers it to whatever is drawn there and accepting input. ## How the failure actually shows up | State of the element | What the element tree reports | What a contact at its coordinate does | |---|---|---| | Scrolled outside the visible area | present, bounds outside the viewport | lands on whatever is drawn there, or is discarded | | Inside the visible area but covered | present, bounds overlapping the viewport | is delivered to the element drawn on top | | Rendered with zero width or height | present | nothing accepts it | | Inside the visible area, unobstructed | present, bounds inside the viewport | reaches the intended element | Several signatures recur, and recognising them saves hours: - The case passes on a tall screen and fails on a short one, because the target sat below the fold only on the short one. - The case passes with the on-screen keyboard closed and fails once an earlier step opened it, because the keyboard now owns the lower part of the screen. - The wrong item is actioned: after a partial scroll the coordinate landed on a neighbouring row. - The harness reports something as not interactable and names an element the case never mentioned — the one actually drawn at that point. **None of these is a readiness problem, and none of them is fixed by waiting longer.** The element is already present; it is simply not somewhere a contact can reach. Time does not move it. Recognising that is the difference between a real fix and a longer timeout that hides the cause. ## Why leaving it to the harness is not a plan Many harnesses scroll automatically before acting, which is exactly why this failure is intermittent rather than constant. That automatic behaviour is a policy you did not choose and cannot see in the case: - it may scroll the outermost scrollable container when the element lives in an inner one; - it may stop as soon as the bounds intersect the visible area, leaving the element half under a fixed bar; - it may do nothing at all for a container it does not recognise as scrollable; - and it may change when the tooling is upgraded, turning a stable suite red for no product reason. Writing the step yourself costs three lines. Not writing it costs a class of failure whose cause is invisible in the source. ## Making reach an explicit step 1. **Scroll the container that owns the element**, not the whole screen. Nested scrollers are the usual reason an automatic scroll moves the wrong thing. 2. **Scroll toward a target, not by an amount.** Repeat a bounded scroll until the bounds fall inside the visible area, with a maximum count and a failure message saying the element never arrived. 3. **Check geometry immediately before acting**: bounds inside the visible area, non-zero size, and the contact point not covered by a fixed overlay. 4. **Undo what the case put in the way.** If an earlier step opened the on-screen keyboard, dismiss it before acting on anything beneath it. 5. **Capture the screenshot at the moment of the failed action**, not at the end of the case. By then the obstruction has usually gone and the artefact proves nothing. ## When unreachable is the finding The last point separates a mechanical fix from judgment. Scrolling to a control makes the case pass; it does not make the control reachable for a person. If a form's submit control cannot be brought into view by ordinary scrolling on a small screen — because the container does not scroll, or the keyboard covers it and the layout does not inset for it — then **the product has a defect and the suite has just hidden it.** Keep the functional case, and add a check that states reachability as an expectation: after the flow's ordinary interactions, the control is inside the visible area and unobstructed. That check fails for a product reason, which is precisely what you want it to do. The distinction is worth making explicit in review, because both halves are true at once: scrolling is a legitimate part of using a screen and automating it is right, while silently arranging conditions a person cannot arrange is not.
- The harness already scrolls before acting. Why write the step yourself anyway?Because the automatic behaviour is a policy you did not choose and cannot see. It may scroll the wrong container, stop as soon as the bounds merely intersect the visible area, or do nothing for a container it does not recognise. An explicit step puts the intent in the case and gives a specific failure message when reach is genuinely impossible.
- A case scrolls to a submit control that a person on that screen size cannot reach. Is the case still valuable?It is proving the wrong thing. Reachability is product behaviour on a small screen: if the control cannot be brought into view by ordinary interaction, that is a defect, and a case that quietly arranges it hides the defect. Keep the functional case and add a check that the control enters the visible area under the interactions a person would actually perform.
- How would you tell an unreachable element apart from one whose bounds are simply stale?Re-read the bounds immediately before acting and compare them with the visible area. Stale bounds change on re-read; an unreachable element reports the same bounds and they still sit outside the visible area or beneath an overlay. Capturing a screenshot at that instant settles it, because the obstruction is visible in the image.
saying these in an interview costs you the question
- Treats presence in the element tree as proof of reachability
- Raises the wait time when a contact lands on nothing
- Scrolls by a fixed number of pixels and hopes
- Relies on the harness scrolling automatically without saying so
- Captures the screenshot after the case ends, not at the failure