In Appium, why do shared `id` and `class name` locators make one suite two different tests?
answer
- the strategy name is shared, the meaning is not
- one constant, two app-side contracts
- class name values overlap nowhere
- green on one platform proves nothing
- share the flow, not the strings
basics
~20 sBecause only the strategy name is shared. On Android the driver compares against resource-id and a Java widget class; on iOS against the name attribute and an XCUIElementType. One locator constant therefore exercises two unrelated app-side contracts.
solid answer
~40 sA locator has two halves: the **strategy name**, which the protocol standardises, and the **meaning**, which each driver defines. `id` and `class name` are declared by both native drivers, so shared code compiles, runs and often goes green — but on **Android** `id` matches `resource-id` and `class name` matches a fully qualified widget class, while on **Apple platforms** `id` aliases the `name` attribute and `class name` matches an `XCUIElementType`. Nothing in the protocol reports the difference, so the two runs assert against different app-side fields written by different code. The practical consequence is that a green Android run tells you nothing about whether the iOS build populated its identifiers, and a shared constant is a silent claim that two unrelated fields agree.
go deeper
Be ready to state that the same locator keyword means different attributes on Android and iOS, so a locator that works on one platform is not evidence about the other.
Explain the four resolutions involved and why the protocol reports no error when they diverge, including the iOS label fallback that lets a wrong match look correct.
Show the diagnosis and the seam: read the live source per platform, count matches, and move the divergence into a per-platform locator table behind a shared page object.
Own the coverage argument. Two platforms reading different app-side fields do not share test coverage, and you should be able to say what your suite guarantees per platform.
## The illusion, stated precisely A WebDriver locator is a pair: a **strategy name** and a **value**. The protocol standardises the pair's shape and the endpoint it is sent to — `POST /session/:sessionId/element` with `{"using": ..., "value": ...}` — and standardises nothing about meaning. Both native Appium drivers declare `id` and `class name`, so a locator built from either is syntactically valid on both platforms. That is the entire basis of the portability people assume, and it is a claim about spelling, not about behaviour. ## What each half actually resolves to | locator | Android (UiAutomator2) | Apple platforms (XCUITest) | |---|---|---| | `id` | the `resource-id` attribute, package-qualified | the `name` attribute, from `accessibilityIdentifier` | | `class name` | a fully qualified widget class, e.g. `android.widget.EditText` | an `XCUIElementType`, e.g. `XCUIElementTypeTextField` | | who writes the value app-side | the build's resources | accessibility-layer code | | overlap between the two vocabularies | none | none | So a shared `id` constant asserts that two independently maintained app-side fields hold the same string, and a shared `class name` constant asserts something that cannot be true at all, because no value is legal on both platforms. ## Why the suite still goes green for a while Several things conspire to delay the discovery: - The `class name` case fails loudly and early, so teams usually split it first — and then conclude, wrongly, that `id` must be fine because it did not fail. - The `id` case fails **loudly only when the field is missing**. If both fields were populated with the same string, everything works and the assumption is never tested. - On Apple platforms, `name` falls back to the element's accessibility label when the identifier is unset, so an `id` locator can match a visible, translated caption. That looks like success until the app is localised or the copy changes. - A single-element find returns the first match without complaint, so an ambiguous locator on either platform produces a wrong-element bug rather than an error. ## The symptoms, in the order teams usually meet them 1. An `id` that resolves on one platform and returns nothing on the other, blamed on timing and wrapped in a wait that can never help. 2. A `class name` value that is obviously from the other platform's vocabulary, discovered when someone finally reads the failing locator aloud. 3. An iOS test that passes in the default language and fails in the localised pipeline, because the match was riding the label fallback. 4. A test that taps the wrong control and fails three steps later, because the locator described a kind of element rather than a particular one. ## How to make the divergence visible - **Name the platform in the locator itself.** Two constants that cannot be confused beat one constant plus a comment. - **Read the live tree per platform** with `GET /session/:sessionId/source` and compare the attributes for the same control; this is the only ground truth that reflects the build on the device. - **Count matches before trusting one.** A multi-element find on both platforms turns an assumption about uniqueness into a measurement. - **Check whether an iOS match is also a visible caption.** If it is, treat the locator as unverified until the identifier is confirmed present. - **Assume nothing transfers from a green run on the other platform.** The two runs exercise different app-side contracts, so coverage does not transfer either. ## What actually is portable The portable part of a cross-platform suite is the **structure**, not the strings: the same flow, the same assertions, the same page-object shape, with a per-platform locator table underneath. Once the divergence is explicit at that one seam, both platforms can use the strongest addressing available to them instead of the weakest addressing they happen to share. Cross-platform reuse fails when it is attempted at the level of the locator value and succeeds when it is attempted at the level of the flow. ## The answer to give Say that `id` and `class name` are portable **keywords with per-driver meanings**, name the two resolutions on each side, and point out that the protocol gives no signal when they diverge. Then add the operational consequence, which is the part that separates a senior answer: a green run on one platform does not validate the other platform's locator, because the two runs are reading fields that different code wrote.
- Where is the right seam for a cross-platform Appium suite if not the locator value?At the page object. Keep the flow, the assertions and the test bodies shared, and put a per-platform locator table behind the page object's interface. Each platform then uses the strongest addressing it actually has, and the divergence is written down in exactly one place rather than discovered per test.
- Why does adding a wait never fix an `id` that resolves on one platform only?Because the element is not late, it is absent from that attribute. A wait polls the same comparison against the same tree, so it converts an immediate failure into a slow one. The fix is to confirm which attribute the platform reads and whether the app populated it.
saying these in an interview costs you the question
- Says a locator that compiles on both is portable
- Blames timing for a locator that resolves on one platform
- Counts a green Android run as iOS coverage
- Shares one class name constant across both platforms
- Assumes both app-side fields were given the same string