Repository navigation
Description
Purpose
On Android, a view that has a content description and no text is published exactly like a view whose text is that string. A caller cannot tell whether label is text on the screen, so a text check passes on an empty view.
Reproduction
Any view with a description and no text:
TextView saved = new TextView(this);
saved.setId(R.id.saved_task);
saved.setContentDescription("saved_task"); // no text yetadb shell uiautomator dump reports it as text="" content-desc="saved_task".
agent-device get attrs 'id="dev.retest.bench.tasks:id/saved_task"' --json
# "node": {"type":"android.widget.TextView","label":"saved_task","identifier":"dev.retest.bench.tasks:id/saved_task", ...}
agent-device get text 'id="dev.retest.bench.tasks:id/saved_task"' --json
# "text": "saved_task"When the app then sets the view's text to saved_task, the node is the same, field for field. snapshot --raw gives the same answer as the regular snapshot.
Cause
normalizeAndroidUiHierarchyNode in packages/platform-android/src/ui-hierarchy.ts labels a node with attrs.text || attrs.desc and publishes contentDescription only when it differs from the label (#2912). When the description is the label, nothing on the node says so. labelFacts in packages/provider-webdriver/src/webdriver-source.ts follows the same rule.
Required behavior
A node labelled by its content description can be told apart from a node labelled by its text. label and contentDescription keep their current values.
Proposed shape
Publish text when the view's text is not already the label, the rule contentDescription follows today. That is an empty string on a view with a description and no text, and no field anywhere else. text ?? label is then the text the view shows.
{"type":"android.widget.TextView","label":"saved_task","text":"","identifier":"dev.retest.bench.tasks:id/saved_task"}Alternative: publish text on every view that has text. The rule is simpler, but it repeats the label on every text node.
Completion
- A view with a description and no text, and a view whose text is that same string, produce different nodes in snapshot JSON,
get attrsandfind. - Nodes that are labelled by their text are unchanged.
iOS
Not affected. XCTest gives one label per element, so there is no second attribute to keep apart.
Environment
- agent-device 0.21.38-nightly.20261113.167 (helper backend
android-helper); same code on main at ddbfc85 - Android 15 emulator (API 35, arm64), build-tools 35.0.0
- macOS, Node 24.12.0
Found through a text assertion in Retest, which drives Android through agent-device. A pull request with the proposed shape follows.
Activity
thymikee commentedon Nov 14, 2026
Triage: bug; current Android normalization loses whether the label came from visible text or content description. #4531 covers the missing node provenance. Its review still needs to settle whether that alone satisfies the reported text assertion, since
get textandtext=are unchanged by that PR. No additional reproduction is needed.