How would you write one Appium switch-state assertion that works on Android and iOS?
answer
- map the fact, not the attribute
- a name and a token, per platform
- normalise on the line that reads
- empty means mapping bug, not false
basics
~20 sMap the fact, not the attribute: hold one pair per platform - checked with true on Android's UiAutomator2 driver, value with 1 on iOS's XCUITest driver - normalise the reply to a boolean at the read, and assert on that.
solid answer
~40 sStart from the fact the test asserts, in platform-free words: *the milk-round skip-tomorrow switch is on*. Then hold **one pair per platform** — an attribute name and the token that means on. Android's UiAutomator2 driver: `checked`, `true`. iOS's XCUITest driver: `value`, `1`. Both are read through `GET /session/:sessionId/element/:elementId/attribute/:name`, so only the name and the token vary. Normalise on the line that reads: trim, fold case, compare to the platform's token, and hand a boolean upward. Two rules keep it durable: treat an empty reply as a mapping bug and fail loudly rather than as false, and never invent a shared name that neither driver carries. Keep the pairs in one lookup so adding a platform-divergent control is a one-line change.
code
python · 12 linesSWITCH_ON = {
"Android": ("checked", "true"), # UiAutomator2 driver
"iOS": ("value", "1"), # XCUITest driver
}
def switch_is_on(element, platform_name):
name, on_token = SWITCH_ON[platform_name]
raw = element.get_attribute(name)
if raw is None or str(raw).strip() == "":
raise AssertionError(f"no {name} attribute on {platform_name}")
return str(raw).strip().lower() == on_tokengo deeper
Be ready to say that the two platforms use different attribute names and different tokens for on, and that a test should compare against the right token rather than testing truthiness.
Explain the pair-per-platform mapping and why normalising the reply into a boolean at the read stops raw attribute strings spreading through the suite.
Show the failure modes you design against: empty replies read as false, truthiness on non-empty strings, and text assertions that lean on an iOS name which can fall back to a localised label.
Own the trade you are making by asserting to the narrower shared vocabulary, and set the rule that any platform-only assertion is named as such rather than hidden behind a portable helper.
## Start from the fact, not the attribute The instinct when a suite has to cover two platforms is to look for the attribute that works on both. There isn't one. For a milk-round delivery app's **skip tomorrow** switch, Android's UiAutomator2 driver answers `checked` with `true` or `false`, and iOS's XCUITest driver answers `value` with `1` or `0`. The four names pinned on each side — `checked`, `enabled`, `displayed`, `bounds` against `value`, `label`, `visible`, `hittable` — overlap in nothing. Any design that begins by hunting for a shared name ends in a helper that quietly reads the wrong thing on one platform. So begin one level up. The fact the test asserts is *the skip-tomorrow switch for this customer is on*. That sentence is platform-free, it is what a failure report should say, and it is the only thing the test body should mention. ## The mapping is a pair, not a name Beneath that sentence sits a table of **pairs**: an attribute name plus the token that means on. | Platform and driver | Attribute name | Token meaning on | | --- | --- | --- | | Android, UiAutomator2 | `checked` | `true` | | iOS, XCUITest | `value` | `1` | Carrying the token alongside the name is what makes the mapping honest. A design that maps only names, and then compares every result to `true`, gets Android right and reports every iOS switch as off. The token is half the fact. ## Normalise at the read, assert on a boolean 1. Read the platform's name through `GET /session/:sessionId/element/:elementId/attribute/:name`. 2. Guard the empty case first: a name the element does not carry comes back empty, and that is a **mapping bug**, not a false. Fail on it loudly, with the platform and the attribute name in the message. 3. Trim whitespace and fold case, then compare to the platform's token. 4. Return a boolean. From this line upward, nothing in the suite knows that `1` was ever involved. The reason to normalise at the read rather than at the assertion is that raw attribute strings are contagious. Let one escape and the comparisons against `true`, `false`, `1` and `0` spread through the suite, and each one is a place a future platform difference has to be re-fixed. ## The traps a senior is expected to name - **Truthiness.** The reply is JSON, usually text. `false` and `0` are non-empty strings and therefore truthy in Python, JavaScript and Ruby, so a bare truthiness check reports every switch as on. - **Empty as false.** The single most damaging shortcut in this area: it makes a wrong platform mapping look like a passing test on one platform and a real defect on the other. - **Text that moves.** If the assertion reaches for descriptive text instead of state, remember iOS's `name` resolves to the element's identifier or, when that is empty, its label — which can be localised. An assertion built on it passes in one language and fails in another for reasons that have nothing to do with the switch. - **Geometry as a shared concept.** `bounds` is in Android's vocabulary and not in iOS's, so a comparison written against it does not port at all. - **Inventing an alias.** A helper named for a concept neither driver carries — a cross-platform `isChecked` that falls back to something unrelated on the platform without it — hides the divergence instead of encoding it. ## Where the mapping lives One lookup, in one file, keyed by platform. Not scattered `if platform == "Android"` branches in test bodies, for three reasons: - Adding a control whose vocabulary diverges is then a one-line change instead of a search across the suite. - The lookup is readable as documentation: it is the shortest honest statement of what the two platforms disagree about. - When a driver's behaviour surprises you, there is exactly one place to instrument. ## What you accept in exchange This design deliberately asserts to the **narrower** of the two vocabularies. Where iOS can say something Android cannot — `hittable` has no Android counterpart, and `visible` alone does not carry it — a shared assertion either drops that precision or the suite accepts that one platform tests something the other does not. Both answers are defensible; what is not defensible is pretending the difference is not there. Say which you chose, and say it in the code: a platform-only assertion should be named as platform-only rather than hidden inside a helper that claims to be portable. The test body ends up reading like the fact it asserts, one adapter beneath it holds the two pairs, and the divergence lives in a table a reader can check in ten seconds — which is the most anyone can ask of two vocabularies that were never designed to agree.
- Why keep the on-token in the mapping rather than comparing everything to true?Because the token is half the divergence. Android's UiAutomator2 driver returns `true` under `checked`, but iOS's XCUITest driver returns `1` under `value`. A mapping that carries only names, then compares to `true`, is correct on Android and reports every iOS switch as off — a failure that looks like a product defect on exactly one platform.
- How do you handle a state iOS can assert and Android cannot?Do not fake it. `hittable` has no Android counterpart, so either drop the precision and assert only what both vocabularies support, or keep the iOS-only assertion and name it as platform-specific so nobody reads the suite as symmetric. What breaks trust is a helper that claims portability and silently returns a weaker answer on one platform.
saying these in an interview costs you the question
- Looks for one attribute name that works on both platforms
- Maps attribute names but compares every result to true
- Treats an empty attribute reply as the switch being off
- Scatters platform branches through individual test bodies
- Hides an iOS-only assertion inside a portable-looking helper
- Asserts on iOS name text that can fall back to a localised label