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

+10 -1
View File
@@ -176,6 +176,7 @@ const SELECTOR_KEYS: readonly string[] = [
"placeholderValue",
"resource-id",
"scrollable",
"secure",
"selected",
"tag",
"testID",
@@ -552,6 +553,8 @@ function elementHandle(
const y = Math.round(rect.top + rect.height / 2);
const ariaLabel = element.getAttribute("aria-label") ?? "";
const text = (element.textContent ?? "").trim().slice(0, 200);
const editable =
element.matches(EDITABLE_SELECTOR) && isEditableElement(element as HTMLElement);
const datasetCopy: Record<string, string> = {};
const dataset = (element as HTMLElement).dataset ?? {};
for (const key of Object.keys(dataset)) {
@@ -579,7 +582,7 @@ function elementHandle(
// a contenteditable container typeable here while collectTargets and the
// hierarchy dump, which both require the element ITSELF to match
// EDITABLE_SELECTOR, called the same span inert.
editable: element.matches(EDITABLE_SELECTOR) && isEditableElement(element as HTMLElement),
editable,
focused: focusedElement === element,
// Checkbox and option state lives in the DOM PROPERTY: the markup attribute
// records only what the page started with, so a handle reading it reports a
@@ -588,6 +591,12 @@ function elementHandle(
// dump the goja host gets.
checked: state.checked === true,
selected: state.selected === true,
// Three-valued, unlike the other state flags: null on anything that is not
// a field, matching the hierarchy dump in internal/driver/chrome/driver.go.
// A consumer deciding what a typed value may be written into a record has
// to tell "not a password field" apart from "nobody said", and Android says
// nothing.
secure: editable ? state.type === "password" : null,
x,
y,
bounds: {