Repository navigation
clear() and fill() silently leave residual text on Android — the empty-field guard reads value, which the Android driver never populates #275
Description
Mobilewright version
0.0.52
Operating system
macOS
Target platform
Android
Device or simulator
Real Android device
Driver
driver-mobilecli
Minimal reproduction
Versions:
mobilewright: 0.0.52@mobilewright/core: 0.0.52@mobilewright/driver-mobilecli: 0.0.52@mobilewright/protocol: 0.0.52
Symptom: locator.clear() removes only a single character instead of completely clearing the field. This was observed directly on a real Android device.
Because fill() uses the same clear path before entering the new value, calling fill() on an already populated field can leave residual text and append the new value to it, resulting in an incorrect final value.
Suspected root cause
There appears to be a verification guard in core/src/locator.ts → _tapAndClear() intended to detect when the field was not completely cleared:
await this._resolveAndTap(timeout);
await this.driver.clearText();
// Verify the clear actually emptied the field.
if ((await this._currentValue()) !== '') {
throw new LocatorError('Failed to clear element', this.strategy);
}However, _currentValue() appears to rely on the node's value property:
return queryAll(roots, this.strategy)[0]?.value ?? '';In driver-mobilecli, elementToViewNode() appears to populate the node value using:
value: el.value || undefinedThe issue is that Android UI dumps for EditText elements appear to expose the current content through the text property rather than value.
For example, an Android EditText node can look like:
{
"type": "android.widget.EditText",
"text": "<FIELD_VALUE>",
"identifier": "<RESOURCE_ID>",
"rect": {
"x": 42,
"y": 1272,
"width": 996,
"height": 142
},
"focused": true
}In the Android dumps observed during testing, the value property was not present.
As a result, _currentValue() falls back to '', meaning this condition:
(await this._currentValue()) !== ''never detects the residual text.
Therefore, a partial clear can be reported as successful even though the field still contains characters.
Two potentially separate issues
-
Android
clearText()does not reliably clear the entire field.
The current select-all / delete behavior appears to remove only one character in some AndroidEditTextfields. -
The post-clear verification does not detect the failure on Android.
_currentValue()appears to rely onvalue, while Android UI dumps expose the field content throughtext.
Reproduction
- Enter a value into an Android text field.
- Call
fill()with a different value. - Observe the resulting field value.
Expected:
The original value is completely cleared and replaced with the new value.
Actual:
One or more characters from the original value remain, and the new value is appended to the residual text.
Suggested fixes
1. Make _currentValue() Android-aware
Consider falling back to text and/or label when value is unavailable, consistent with the existing text resolution behavior:
return queryAll(roots, this.strategy)[0]?.text
?? queryAll(roots, this.strategy)[0]?.label
?? queryAll(roots, this.strategy)[0]?.value
?? '';The implementation should ideally avoid querying the locator multiple times.
2. Improve Android text clearing
On Android, relying solely on Ctrl+A followed by delete/backspace may not be reliable for all EditText implementations.
Potential alternatives include:
- Repeated
KEYCODE_DEL - Android key combinations
- Another driver-level mechanism for selecting and replacing the complete text
Important consideration
A text-based verification mechanism should account for Android fields where the text property may contain the hint/placeholder when the field is empty. For example, an empty field may expose its hint as text.
Therefore, simply switching from value to text may require additional handling to distinguish actual field content from placeholder/hint text.
Additional context
The issue was reproduced consistently on a real Android device using the driver-mobilecli driver.
Activity