Skip to content

clear() and fill() silently leave residual text on Android — the empty-field guard reads value, which the Android driver never populates #275

Description

@rahulLeadsquared

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 || undefined

The 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

  1. Android clearText() does not reliably clear the entire field.
    The current select-all / delete behavior appears to remove only one character in some Android EditText fields.

  2. The post-clear verification does not detect the failure on Android.
    _currentValue() appears to rely on value, while Android UI dumps expose the field content through text.

Reproduction

  1. Enter a value into an Android text field.
  2. Call fill() with a different value.
  3. 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions