In Appium on iOS, why can an `accessibility id` lookup match an element that has no identifier?
answer
- the strategy does not read the identifier directly
- one attribute, two possible sources
- empty identifier, visible label instead
- a caption match survives no translation
basics
~20 sBecause the XCUITest driver answers that lookup with the element's name attribute, and name falls back to the element's visible localised label when the accessibilityIdentifier is empty. The match then depends on product copy, not on a stable token.
solid answer
~40 sOn Apple platforms the XCUITest driver does not compare your string against `accessibilityIdentifier` directly. It compares it against the element's `name`, and `name` is the `identifier` **only while that identifier is non-empty**; when it is empty, `name` becomes the element's `label` — the visible caption, which comes from `accessibilityLabel` and is localised. So a lookup for the string *Scan pass* on a stadium turnstile screen can match a control nobody ever gave an identifier, purely because that is what the button reads in the current language. The find succeeds, the response looks the same as a real identifier match, and the test passes for a reason that will not survive a translation or a copy edit. Android has no such fallback: an empty `content-desc` means no match.
go deeper
Learn the fallback order as a single sentence: on Apple platforms the name attribute is the identifier, and the visible label only when that identifier is empty. Being able to say that much already puts you ahead of most candidates.
Explain the mechanism and one concrete consequence, such as the same locator passing in English and failing in another language. Say plainly that Android offers no fallback, so the identical omission fails loudly there.
Demonstrate how you separate a real identifier match from a caption match during triage, and be ready to argue why swapping to a different strategy on the failing platform hides the defect rather than fixing it.
Frame it as an evidence problem: a green cross-platform result can be produced by two different mechanisms, and you should be able to say what your suite does so that the difference between them is visible rather than assumed.
## The attribute that actually answers the lookup On Apple platforms the XCUITest driver resolves the `accessibility id` strategy through the element's **`name`** attribute. That indirection is the source of the surprise, because `name` is derived, not stored. Its rule is short: - If the element's `identifier` (app-side `accessibilityIdentifier`) is non-empty, `name` is that identifier. - If the identifier is empty, `name` is the element's `label` — the visible caption, whose app-side source is `accessibilityLabel`. So the strategy is really *match against whatever `name` currently resolves to*. An element that nobody ever gave an identifier is still perfectly findable, as long as your search string happens to equal the words on its face. ## What that costs a stadium turnstile suite Suppose the entry screen's primary control reads *Scan pass*, and the Apple build never set an identifier on it. A locator searching for `Scan pass` matches, the step goes green, and everyone moves on. The cost arrives later, in four recognisable shapes: - **Localisation.** The label is user-visible text, so it is translated. The identical locator that passes against the English build finds nothing against the French one, and the failure looks like a missing element rather than a locator built on copy. - **Copy edits.** A product change from *Scan pass* to *Scan ticket* breaks the test with no code change anywhere near it, and the diff that broke it contains no test file. - **Ambiguity.** Captions repeat. Several turnstile lanes rendering the same word are several elements resolving to the same `name`, and the find returns one of them without telling you it had a choice. - **False confidence.** The worst case is the green one. A cross-platform run that passes on both platforms suggests the address exists on both, when in fact the Apple half matched a caption and the identifier was never set. ## Android does not behave this way The asymmetry is the point, and it is easy to state. | Question | Android (UiAutomator2) | Apple platforms (XCUITest) | |---|---|---| | Attribute the strategy reads | `content-desc` | `name` | | When the developer-set field is empty | no match, the find fails | falls back to the element's `label` | | Can a match come from visible copy | no | yes | | Can the display language change the result | no | yes, whenever the fallback fires | On Android the failure is loud and immediate: an empty `content-desc` means the element is not addressable by this strategy at all. On Apple platforms the same omission is silent, because the platform supplies something plausible in its place. A missing address is therefore a red test on one platform and a green one on the other — from the very same app-side omission. ## Telling the two halves of the rule apart You cannot see which branch fired from the find result, so infer it: 1. Read the matched element's `name` on the Apple platform. 2. Compare it, character for character, with the caption the control displays on screen. 3. If they are identical, assume the identifier is empty and you matched through the label, until someone shows you the identifier in the build. 4. If `name` is a token that never appears on screen — something like `turnstile-scan-gate` — you matched a real identifier and the address is stable. 5. Repeat the check in a non-default language if the app ships more than one. That single run separates a stable address from a caption match faster than any amount of reading. ## Living with it A few habits keep the fallback from quietly owning your Apple-platform results: - Prefer search strings that could never be product copy. A token with a hyphenated shape is self-documenting: if it matches, it matched an identifier. - Treat *the locator equals the visible caption* as a smell during review, not just during triage. - When a cross-platform address only works on one platform, fix the missing field in the build rather than switching the Apple half to a different strategy — swapping strategies hides the fact that the address was never there. - Assert what you matched when it matters. Comparing the element's `name` against the token you searched for turns an implicit assumption into a checked one. ## What an interviewer is listening for The weak answer is that iOS matches the accessibility identifier. The strong answer names the indirection through `name`, states the fallback order in one sentence, and then draws the consequence without being prompted: on Apple platforms a passing `accessibility id` lookup is not by itself evidence that the app carries the address you think it does.
- How would you prove, from a passing Apple-platform run, that the element really carries an identifier?Read the matched element's `name` and compare it with the caption on screen. If `name` is a token that appears nowhere in the interface, an identifier exists. If it equals the visible caption, assume the label fallback and confirm against a second display language before trusting the locator.
- Does the same fallback exist on Android?No. UiAutomator2 matches `accessibility id` against `content-desc` only. An empty `content-desc` produces no match and the find fails, so the same app-side omission is a loud failure on Android and a silent, plausible-looking success on Apple platforms.
It is like a building that lets you in on your staff badge, and, when you have no badge, on the name printed on your shirt — fine until the shirts are reprinted in another language.
saying these in an interview costs you the question
- Claims an empty identifier makes the element unmatchable on iOS.
- Treats a passing iOS lookup as proof the identifier was set.
- Blames flaky element location when the label was simply translated.
- Thinks the fallback order runs label first, identifier second.
- Assumes Android has the same fallback and behaves identically.