feat(hierarchy): an element reports whether it masks what is typed into it

ios reads it off SecureTextField, which the companion already sent and
nothing read; web reads input[type=password]. Android cannot: the native
tree mapper drops the password attribute before the sidecar sees it, so
the fact is three-valued and null there rather than a false that would
read as "not secure".
This commit is contained in:
pj committed 2026-08-18 17:16:55 +05:30
1 parent 5f1f50c2fb
commit b1e95739ad
11 files changed
+186 -5

No files matched your search

+2 -1
View File
@@ -29,6 +29,7 @@
"placeholderValue",
"resource-id",
"scrollable",
"secure",
"selected",
"tag",
"testID",
@@ -40,5 +41,5 @@
"unknownKeyExample": [
"descripton"
],
"unknownKeyMessage": "selector key \"descripton\" cannot match: no element carries that attribute, and it is not one of the accepted keys: accessibilityIdentifier, accessibilityLabel, accessibilityText, aria-label, ariaLabel, bounds, checked, class, className, clickable, content-desc, contentDescription, data-testid, desc, descPrefix, editable, elementType, enabled, focused, hintText, id, idPrefix, identifier, label, package, placeholder, placeholderValue, resource-id, scrollable, selected, tag, testID, testTag, text, title, value"
"unknownKeyMessage": "selector key \"descripton\" cannot match: no element carries that attribute, and it is not one of the accepted keys: accessibilityIdentifier, accessibilityLabel, accessibilityText, aria-label, ariaLabel, bounds, checked, class, className, clickable, content-desc, contentDescription, data-testid, desc, descPrefix, editable, elementType, enabled, focused, hintText, id, idPrefix, identifier, label, package, placeholder, placeholderValue, resource-id, scrollable, secure, selected, tag, testID, testTag, text, title, value"
}
+17 -1
View File
@@ -628,11 +628,12 @@ function domElement(spec: {
text?: string;
checked?: boolean;
contentEditable?: boolean;
type?: string;
}): unknown {
const attributes = spec.attributes ?? {};
return {
tagName: spec.tag.toUpperCase(),
type: spec.tag === "input" ? "text" : "",
type: spec.type ?? (spec.tag === "input" ? "text" : ""),
isContentEditable: spec.contentEditable ?? false,
checked: spec.checked,
id: attributes.id ?? "",
@@ -719,6 +720,21 @@ test("checked reads the live property, not the markup attribute", () => {
assert.equal(handleOf(cleared).checked, false);
});
// `secure` answers three ways. A consumer deciding what a typed value may be
// written into a record has to tell "not a password field" apart from "no
// platform said", and android says nothing: a field answering false only when
// asked about a password would make every web field look like an android one.
test("secure states the field type either way, and nothing off a field", () => {
const password = domElement({ tag: "input", attributes: { id: "pwd" }, type: "password" });
assert.equal(handleOf(password).secure, true);
const email = domElement({ tag: "input", attributes: { id: "email" }, type: "email" });
assert.equal(handleOf(email).secure, false);
const heading = domElement({ tag: "h1", attributes: { id: "title" } });
assert.equal(handleOf(heading).secure, null);
});
test("attrs carries every other attribute alongside tag and aria-label", () => {
const attrs = attrsOf(
domElement({ tag: "input", attributes: { id: "txn-note", placeholder: "What's this for?" } }),