skip to content

In Appium, how do Android's displayed attribute and iOS's visible and hittable differ?

level: middleimportance: should knowfreq 54%

answer

  1. one name on one platform, two on the other
  2. drawn is not the same as reachable
  3. overlays are where the split shows
  4. geometry substitutes where the name is missing

basics

~20 s

Android's UiAutomator2 driver answers the whole question with one attribute, displayed. iOS's XCUITest driver splits it in two: visible says the element is drawn, hittable says a touch aimed at it would actually land on it.

solid answer

~40 s

In a milk-round delivery app, the last crate row can sit under a sticky **confirm round** bar. On **iOS**, through the XCUITest driver, that element reads `visible` as true and `hittable` as false — it is drawn, but a touch at its own point hits the bar instead. On **Android**, through the UiAutomator2 driver, there is one name for this territory, `displayed`, and it does not separate *rendered* from *reachable*. Both are read the same way, `GET /session/:sessionId/element/:elementId/attribute/:name`, one name per request. The practical consequence is asymmetric: an iOS test can assert reachability directly, an Android test has to get it from geometry or from the interaction failing. Android's `simpleBoundsCalculation` setting also changes whether `bounds` is clipped to what is actually showing.

go deeper

for a junior

Be ready to say that Android uses displayed while iOS uses visible and hittable, and that the two iOS names answer different questions about the same element.

for a middle

Explain the case that separates them: an element drawn on screen but covered by an overlay reads visible true and hittable false on iOS, and Android has no single attribute that expresses it.

for a senior

Show how you handle the asymmetry in a real suite, including when you reach for bounds arithmetic on Android and why you refuse to alias displayed to a reachability helper.

for a principal

Take a position on whether the suite asserts to the coarser shared vocabulary or lets one platform assert more, and say who owns the resulting difference in defect-detection between platforms.

## One question, one name on Android and two on iOS A milk-round delivery app lists tonight's crates, and the last row can end up underneath a sticky **confirm round** bar pinned to the bottom of the screen. The row is on screen. It is also untappable. Whether a test can see that difference depends entirely on which platform it is running against, because the two attribute vocabularies cut this territory differently. On **Android**, through the UiAutomator2 driver, the vocabulary offers `displayed`. It is a single verdict about whether the element is showing. On **iOS**, through the XCUITest driver, the same territory is split across two separate names: - `visible` — the element is drawn within the bounds of the screen. - `hittable` — a touch aimed at the element's own point would be delivered to that element rather than to something on top of it. The crate row under the sticky bar is exactly the case where those two diverge: `visible` true, `hittable` false. Android's single `displayed` cannot express that split, so an Android test asserting *the user can tap this* has to get its answer somewhere other than one attribute read. ## The read is the same; the answer set is not Both platforms answer through `GET /session/:sessionId/element/:elementId/attribute/:name`, one name per request, against an element identifier a find already produced. So the divergence is not in the protocol, the client, or the session — it is purely in which names exist to be asked for. | Question the test is really asking | Android — UiAutomator2 driver | iOS — XCUITest driver | | --- | --- | --- | | Is it rendered on screen? | `displayed` | `visible` | | Would a tap actually land on it? | not a separate attribute | `hittable` | | Where exactly is it? | `bounds` | not in this vocabulary | ## Why the split matters more than it looks Mobile screens stack things constantly, and the stacking is what breaks tests: - A bottom bar, a floating action button or a toast overlaps a list row that is still fully rendered underneath it. - A keyboard slides up over the lower third of a form while every field beneath it is still drawn. - A modal or a banner covers content that a snapshot of the screen still reports as present. - A row is half scrolled off the edge, so part of it is showing and part is not. In each of those, an element can be on screen and still not be a valid touch target. On iOS the XCUITest driver hands you a name for the distinction. On Android the UiAutomator2 driver does not, and a test that asserts `displayed` and then taps is making an inference the attribute never promised. ## What Android gives you instead Android's compensation is geometric rather than semantic: 1. `bounds` returns the element's on-screen rectangle, so a test can compare rectangles itself and reason about overlap. 2. The UiAutomator2 `simpleBoundsCalculation` setting changes what that rectangle means: it toggles between the element's raw geometry and a rectangle that accounts for the element being partly obscured or off-screen. Two runs of the same test can therefore disagree about `bounds` if that setting differs between them. 3. `enabled` is a different axis again and is often confused with this one — it reports whether the control accepts input, and a fully drawn, fully reachable control can still be disabled. None of that reproduces `hittable`. It approximates it, at the cost of the test carrying rectangle arithmetic that the iOS side gets for free. ## Writing assertions that survive both platforms - Decide which of the two questions the test actually cares about: *is it on screen* or *can the user act on it*. They are different tests and they fail for different reasons. - For *on screen*, `displayed` on Android and `visible` on iOS line up well enough to sit behind one helper. - For *can the user act on it*, only iOS has a direct answer. Do not fake an Android equivalent by aliasing `displayed` to `hittable`; a helper that returns true for an obscured Android row is worse than no helper, because it makes the suite lie in one direction only. - Remember `enabled` is not part of this question at all. Reading it as a proxy for reachability produces tests that pass on a control the user cannot reach. - Read one name per request and keep the platform branch in one place, so the asymmetry is documented in the code rather than rediscovered per test. The honest summary is that iOS's vocabulary is finer here and Android's is coarser, and a cross-platform suite either lives with the coarser one on both sides or accepts that one platform can assert something the other cannot.

  • A crate row on Android reads displayed as true but the tap does nothing. How do you investigate?
    `displayed` on the UiAutomator2 driver says the row is drawn, not that a touch reaches it, so suspect an overlay. Read `bounds` for the row and for the suspected covering view and compare the rectangles, and check `enabled` separately — a drawn, reachable control can still refuse input.
  • Would you build one helper that returns hittable-style reachability on both platforms?
    Only if it is honest about the asymmetry. iOS can answer directly through `hittable`; Android has no equivalent name and can only approximate it from `bounds`. A helper that quietly returns Android's `displayed` under a reachability name makes the suite pass on rows the user cannot touch, which is the worst failure mode of the two.

saying these in an interview costs you the question

  • Treats iOS visible and hittable as the same check
  • Assumes Android displayed proves an element is tappable
  • Uses enabled as a stand-in for reachability
  • Expects hittable to exist in the Android vocabulary
  • Ignores that bounds can be clipped by a driver setting