In a React Native app under Appium, what does the `testID` prop set on iOS and on Android?
answer
- one prop, two different app-side fields
- iOS gets the identifier, not the label
- Android reports it as resource-id
- content-desc comes from accessibilityLabel instead
basics
~20 sA React Native testID sets the iOS accessibilityIdentifier, which the XCUITest driver exposes behind the name attribute, and on Android it surfaces as the view's resource-id in the page source. Android's content-desc is filled by accessibilityLabel instead.
solid answer
~40 s`testID` is React Native's one cross-platform hook for automation, but it lands in two different app-side fields. On **iOS** it sets the view's `accessibilityIdentifier`; the XCUITest driver surfaces that behind the `name` attribute and aliases both the `id` and the `accessibility id` strategies onto `name`, so either one finds the element. On **Android** the value surfaces as the view's `resource-id`, which is what Appium's `id` strategy matches — it does *not* land in `content-desc`, and `content-desc` is exactly what `accessibility id` matches there. Android's `content-desc` comes from React Native's `accessibilityLabel`. That asymmetry is why an id a suite finds on one platform can return nothing on the other, and why teams end up asking the app to fill more than one field.
go deeper
Be ready to say that testID sets the iOS accessibilityIdentifier and surfaces as resource-id on Android. Naming the two fields, not just the prop, is what the question is testing.
Explain why an accessibility id locator misses a testID on Android: that strategy matches content-desc, which accessibilityLabel fills, while testID lands in resource-id.
Show how you verify that an id landed on each platform before a suite leans on it, and what you do about screens where the prop never reached the native view.
Decide which app-side field each platform will fill across the whole app, so cross-platform screens and hand-written native screens present the same identifier to a suite.
## One prop, two app-side fields React Native gives a component a `testID` prop so that automation can address it later. Appium never sees that prop. Appium talks to a driver, the driver reads the platform's own view tree, and a locator matches an **attribute that a native view publishes**. `testID` matters only because the React Native renderer writes it into a native field before Appium ever looks — and it writes into a *different* field on each platform. That is the whole content of this topic: one prop, two destinations, and a suite that has to know which one it is addressing. ## Where the value lands on each platform On **iOS**, `testID` sets the view's `accessibilityIdentifier`. The XCUITest driver surfaces that value behind the `name` attribute, and it aliases both the `id` and the `accessibility id` locator strategies onto `name`. Either strategy therefore finds the element, and on that platform three ways of asking collapse into one. On **Android**, the value surfaces as the view's `resource-id`, which is the attribute Appium's `id` strategy matches. It does **not** land in `content-desc` — and `content-desc` is exactly what the `accessibility id` strategy matches on Android. That field is filled by React Native's `accessibilityLabel`. So on Android the two strategies address two genuinely different fields, written by two different props. | | Android | iOS | |---|---|---| | Field `testID` fills | the view id, reported as `resource-id` | `accessibilityIdentifier` | | Attribute it appears under | `resource-id` | `name` | | Strategy that matches it | `id` | `id` and `accessibility id` | | Field `accessibility id` matches | `content-desc` | `name` | | Prop that fills that field | `accessibilityLabel` | `accessibilityLabel`, only when the identifier is empty | ## Why the asymmetry bites - A scouting badge-tracker sets a `testID` of `badge-row-first-aid` on a badge row, the iOS suite finds it with `accessibility id`, and the identical locator returns nothing on Android. - Reaching for Android's `id` strategy is the right correction, but the string the renderer wrote carries no package prefix, so a bare `id` locator can still miss until the driver's id autocompletion is turned off. - Adding `accessibilityLabel` does make `accessibility id` work on Android, at the price of coupling the locator to user-facing text that a content team may reword. - On iOS the reverse trap waits: when `accessibilityIdentifier` is empty, `name` resolves to the element's label instead, so the find still succeeds — against localised copy — and the missing identifier stays invisible until the app ships in a second language. - A `testID` set on a wrapper component that does not forward props down to its underlying native view reaches no field at all, and the page source simply shows an empty attribute. ## Confirming the id actually landed The prop is a request, not a guarantee, so verify per platform before the suite depends on the value: 1. Run the screen on Android and look for the string in the `resource-id` attribute of the page source. 2. Run the same screen on iOS and look for the same string under `name`. 3. Only then write the locator; a screen that fails either check is an app change that is not finished. ## What teams usually settle on - Treat `testID` as the machine identity and the thing the suite addresses. - Set `accessibilityLabel` separately for human-facing text, and never assume the two are interchangeable. - Expect the Android locator and the iOS locator to be written against different strategies, unless the app deliberately fills Android's `content-desc` as well. - Keep the value stable across releases: it exists for the suite, so a rename is a breaking change even though nothing visible moved. - Address elements one screen at a time, because the plumbing is a per-screen property of the app rather than a global switch. The short version worth being able to say out loud: `testID` is React Native's cross-platform hook, but the platforms are not symmetric underneath it. iOS gets a dedicated machine field that the driver reads behind `name`; Android gets the view id reported as `resource-id`, while the field an `accessibility id` locator reads on Android is filled by a different prop entirely. Anyone who says that `testID` sets the accessibility id on both platforms has skipped the only thing this topic is about.
- If the scouting badge-tracker sets `testID` but no `accessibilityLabel`, which Android locator strategies can still match it?`id` can, because the value surfaces as the view's `resource-id`. `accessibility id` cannot: on Android that strategy matches `content-desc`, which stays empty without `accessibilityLabel`. XPath over the same `resource-id` attribute works too, at page-source cost. On iOS the single `testID` covers both strategies, because XCUITest aliases `id` and `accessibility id` onto `name`.
- Does setting `testID` on a React Native component guarantee that Appium sees it on both platforms?No. It has to reach a real native view. A `testID` on a component that does not forward props to its underlying native view never becomes an `accessibilityIdentifier` on iOS or a view id on Android, and the page source shows an empty attribute. Confirm the value per platform in the page source before a suite leans on it.
A test id is like a part number stamped inside a machine: the same number can be stamped in a different place on each model. Knowing the number is useless until you know where each model stamps it.
saying these in an interview costs you the question
- Thinks testID sets content-desc on Android
- Assumes one prop produces one identical field on both platforms
- Believes an accessibility id locator matches testID on Android
- Treats a visible label and a machine test id as interchangeable
- Assumes the prop always reaches the underlying native view