In Appium on Android, when should a test use mobile: replaceElementValue rather than send keys?
answer
- one enters, one replaces
- UiAutomator2 declares it, Android only
- retries double the field's text
- replacing skips per-keystroke reactions
- setup replaces, behaviour types
basics
~20 sUse it when the field must end up holding exactly one string. UiAutomator2's mobile: replaceElementValue replaces an element's value, while the shared send-keys endpoint enters text into the field as it stands. Send keys when the app reacts per keystroke.
solid answer
~40 sOn Android the UiAutomator2 driver declares `mobile: replaceElementValue` in its own execute-method map, alongside `mobile: type`. The shared endpoint `POST /session/:sessionId/element/:elementId/value` enters text into the field in the state it finds it, so a re-run over a quota box that already holds a weight can leave you with two values run together. `mobile: replaceElementValue` states its semantics in its name: the element ends up holding what you passed, not what it had plus what you passed. The trade is that replacing a value is not the same event stream as a person typing, so per-keystroke behaviour the app has — input masking, live validation, a character counter — may never fire. Type when the typing is the thing under test; replace when the field is only setup for the assertion that follows.
go deeper
Remember that entering text goes into the field as it stands, so a box that is not empty needs deliberate handling before you type into it.
Be able to name mobile: replaceElementValue as the UiAutomator2 driver's own execute method, contrast it with the shared send-keys route, and say why replacing can skip the app's per-keystroke behaviour.
Show the judgment call per case: setup gets the fast idempotent path, behaviour under test gets the typing path, and every entry is verified by reading the field back.
Decide the suite-wide convention and enforce it, knowing that an Android-only method inside a shared helper is a divergence you have chosen to carry and must document.
## Two ways to put a string in an Android field An Appium session driving Android with the UiAutomator2 driver has more than one route into a text field, and choosing between them is a real design decision rather than a style preference. - The **inherited WebDriver command**, `POST /session/:sessionId/element/:elementId/value`, carrying the string in the body's `text` field. This is the portable route — the XCUITest driver answers the same request on iOS. - **`mobile: replaceElementValue`**, declared by the UiAutomator2 driver in its own execute-method map and posted to `/session/:sessionId/execute/sync` as a `mobile:` name plus one parameter map. - **`mobile: type`**, also UiAutomator2's own, declared in the same map. The first is cross-platform; the second and third are not. The XCUITest driver declares no `mobile: replaceElementValue`, so any use of it is an Android branch by definition, and a helper that calls it must say so. ## Entering into a non-empty field, and what that costs on a re-run The send-keys command enters text into the field in the state it finds it. That is invisible on a screen you have just navigated to for the first time, because the box is empty. It stops being invisible in three situations a fishing-quota logging app hits constantly: 1. **A retried step.** The first attempt entered `Njord II`, something later failed, the retry ran the same step, and the vessel field now reads `Njord IINjord II`. 2. **A field the app pre-fills.** The catch-weight box opens holding the last recorded value, and the test's `12.5` lands beside it rather than instead of it. 3. **A shared fixture.** Two cases reuse one screen without a reset between them, and the second inherits the first one's text. Every one of those produces an assertion failure whose message points at the assertion rather than at the entry, which is why this shows up in interviews as a debugging story rather than as an API question. ## What replacing skips Replacing a value is not a simulation of a person typing, and that is the whole trade-off: | | Send keys to the element | `mobile: replaceElementValue` | |---|---|---| | Portability | answered by the Android and iOS drivers alike | UiAutomator2's own, Android only | | Existing content | the string is entered into the field as it stands | the field is made equal to your string | | Per-keystroke app behaviour | exercised | may not be exercised | | Best used for | the case where entering the text is the behaviour under test | setup for a later assertion | If the licence-number box on the catch-entry screen masks input, uppercases as you go, counts remaining characters, or enables the save button only once a valid pattern is reached, those behaviours are reactions to input. A case that is about them must go through the typing path, or it asserts on a state the user can never actually reach. A case that merely needs a valid licence number in the box before submitting is setup, and setup should be fast, exact and boring. ## Choosing between them per case - **Does the case's title mention the typing?** If yes, send keys. - **Is the field a precondition for the real assertion?** If yes, replace it and get on with the test. - **Is the string awkward — non-ASCII, long, or heavily punctuated?** Replacing removes a class of delivery problems, at the cost of the event stream. - **Does the screen re-run under retry?** Replacing makes the step idempotent, which is worth a great deal in a suite that retries. - **Is this code shared with the iOS lane?** Then it is a branch, not a helper default; iOS has no equivalent method and needs its own answer to the same problem. ## The habit that makes either choice safe Whichever route you take, read the field back and assert on what it holds before moving on. That single habit catches the entered-into-a-non-empty-field bug, catches a partially delivered string, and turns a confusing downstream failure into an obvious local one. It costs one round trip per entry, which is nothing next to the hours a suite loses to a doubled vessel name that only appears on retried runs. The interview-grade summary: the shared endpoint enters into the field as it stands, UiAutomator2's `mobile: replaceElementValue` makes the field equal to your string, replacing may skip whatever the app does per keystroke, and neither choice is safe without a read-back.
- What is the iOS equivalent of mobile: replaceElementValue?There is no equivalent execute method in the XCUITest driver, so this is an Android-only branch. On iOS you empty the field and re-enter through the shared send-keys route, with the `useClearTextShortcut` setting bearing on how the field is emptied. A cross-platform helper has to encode both answers rather than pretend one command covers it.
- Which cases would you deliberately keep on the typing path?Any case whose subject is the app's reaction to input: masking, live validation, character counters, a save button that enables only once the field is valid, and search-as-you-type. Replacing a value can bypass the very behaviour those cases exist to prove, so they belong on the send-keys route even though it is slower.
saying these in an interview costs you the question
- Believing send keys always empties the field first
- Calling mobile: replaceElementValue a cross-platform command
- Using replace for a case about input masking
- Blaming a doubled field value on device flake
- Assuming the XCUITest driver declares the same method