skip to content

In Appium, which request reads one attribute from an element on Android and iOS?

level: juniorimportance: should knowfreq 71%

answer

  1. session, element, then one name
  2. no plural form of this request
  3. an identifier from a previous match
  4. empty reply is not a false value

basics

~10 s

Both platforms use the same request: GET /session/:sessionId/element/:elementId/attribute/:name, with an element identifier from an earlier find and exactly one attribute name in the final segment. Only which names are valid differs by platform.

solid answer

~40 s

The request is `GET /session/:sessionId/element/:elementId/attribute/:name`. It takes the session, the element identifier a previous find returned, and **one** attribute name — there is no way to ask for two names in a single call. Android's UiAutomator2 driver and iOS's XCUITest driver both answer it, so the shape is genuinely shared. What is not shared is the vocabulary that goes in `:name`: on Android you can ask for `checked`, `enabled`, `displayed` or `bounds`; on iOS for `value`, `label`, `visible` or `hittable`. Asking a driver for a name it does not carry gets you an empty result rather than an error, which is why a ported assertion can silently report the wrong thing rather than failing loudly.

code

bash · 9 lines
bash
SESSION_ID=e1f6ac5c-1d0f-4f0e-9a1c-9c5b1b2f7a10
ELEMENT_ID=00000000-0000-0000-0000-000000000042
BASE="http://127.0.0.1:4723/session/$SESSION_ID/element/$ELEMENT_ID/attribute"

# Android, UiAutomator2 driver: the milk-round skip-tomorrow switch
curl -s "$BASE/checked"

# iOS, XCUITest driver: the same switch on the same screen
curl -s "$BASE/value"

go deeper

for a junior

Be ready to write the request from memory: session, element identifier, one attribute name in the last segment, and one value back as JSON.

for a middle

Explain why the shared endpoint does not make the code shared, and what an empty reply actually means when a name belongs to the other platform's vocabulary.

for a senior

Show that you count round trips on list screens and that you normalise the reply where it is read, so no raw attribute string reaches an assertion.

for a principal

Frame the portable part against the platform part: the call, retries and logging travel, the name and expected token do not, and that boundary is what a suite standardises.

## The request itself Every attribute read in Appium goes through one request: ```http GET /session/:sessionId/element/:elementId/attribute/:name ``` Three things go into it and one thing comes back. - `:sessionId` — the session the client created, which fixes the device and the driver answering. - `:elementId` — an opaque identifier a previous find returned. You never construct one; you receive it and pass it back. - `:name` — **exactly one** attribute name. There is no plural form of this request, so three facts about one element are three calls. The reply is the value stored under that name, as JSON. If the element carries no such attribute, the reply is empty rather than an error. ## The shape is shared; the vocabulary is not A milk-round delivery app's *skip tomorrow* switch is the standard example. The Android session and the iOS session make the *same* request against the *same* endpoint, and get their answers from different names: | | Android — UiAutomator2 driver | iOS — XCUITest driver | | --- | --- | --- | | Endpoint | `/session/:sessionId/element/:elementId/attribute/:name` | identical | | Names available here | `checked`, `enabled`, `displayed`, `bounds` | `value`, `label`, `visible`, `hittable` | | Switch is on | `checked` reads `true` | `value` reads `1` | That asymmetry is the whole reason this is worth learning as a junior. It is tempting to conclude from *the request is the same* that *the code is the same*, and it is not. The request is protocol; the names are platform. ## What the reply is, and what it is not - It is **one value**, for **one element**, under **one name**. - It arrives as JSON and most often as text, so `true` and `1` come back as strings that need turning into a boolean before an assertion reads them. - An empty reply means the element does not carry that name on that driver. It does **not** mean the attribute is false, and it does not raise an error you would notice in a log skim. - It is a snapshot of the moment the driver answered. Nothing about the read waits for anything, and nothing about it promises the screen has stopped moving. That third bullet is the one that catches people. Send Android's `checked` to an iOS session and you get an empty result, and code that treats empty as false reports every switch as off. The test still runs, still reports, and is now lying in one direction. ## Where the element identifier comes from The attribute read is always the *second* step. Something has to have matched an element first, and the identifier that comes back from that match is what makes the attribute call addressable. Two practical consequences follow: 1. An identifier belongs to its session. It is not a durable handle you can store between runs, and it is meaningless in another session. 2. If the screen changes underneath you, the identifier can stop referring to anything usable, and the attribute read is where you find out. ## A habit worth forming early 1. Write the platform next to the attribute name, in the code, every time — a bare `checked` in a shared helper tells the next reader nothing about which driver answers it. 2. Normalise the reply on the line that reads it, so no raw attribute string reaches an assertion. 3. Treat an empty reply as a bug in your mapping rather than as a false value, and fail loudly on it. 4. Count your reads. Three attributes across forty rows is a hundred and twenty round trips, and the endpoint gives you no way to batch them. ## Why the endpoint being shared still helps None of this makes the shared shape useless. Because both drivers answer the same request in the same way, everything *around* the read is portable: the client call, the error handling, the retry decision, the logging, the place in your code where the value is normalised. Only the name and the expected token change. A well-built helper therefore has exactly one platform-dependent line in it, and a badly built one has the platform difference smeared across every test that reads state. The short version to carry into an interview: one endpoint, one name per call, an element identifier from a prior find, a JSON value back, an empty reply when the name does not exist on that platform — and two vocabularies that overlap in nothing.

  • How many requests does it take to read three attributes off one element?
    Three. The endpoint's last segment takes a single attribute name and there is no plural form, so each fact is its own round trip to the Appium server and on to the device agent. On a list screen that multiplies by row count, which is why attribute-heavy assertions dominate the runtime of otherwise simple tests.
  • What happens if you ask an iOS session for the checked attribute?
    You get an empty reply rather than an error, because `checked` belongs to Android's UiAutomator2 vocabulary and the XCUITest driver has no such name for the element. Code that treats empty as false then reports the switch as off on every iOS run — a silent wrong answer rather than a visible failure.

saying these in an interview costs you the question

  • Thinks the request can take several attribute names at once
  • Believes each platform has its own attribute endpoint
  • Reads an empty reply as the attribute being false
  • Expects the value to arrive as a native boolean
  • Assumes an element identifier survives between sessions