fix(spec): a secure selector names the password field on web

secure is derived from the field type, not written by the markup, so
matching it as a raw attribute reached nothing: the key is accepted, no
unknown-key error fires, and find answered undefined on web for the
field it answers with on ios. false is every editable field that is not
a password entry, since an element that is no field reports null and
answers to neither value.
This commit is contained in:
pj committed 2026-08-18 20:14:01 +05:30
1 parent 8414953135
commit b0895ef179
3 files changed
+49 -1

No files matched your search

+1 -1
View File
@@ -109,7 +109,7 @@ export function fakeElement(spec: FakeElementSpec): FakeElement {
const element: FakeElement = {
...spec,
tagName: spec.tag.toUpperCase(),
type: spec.tag === "input" ? "text" : "",
type: spec.tag === "input" ? (attributes.type ?? "text") : "",
isContentEditable: editable && spec.tag !== "input" && spec.tag !== "textarea",
id: spec.id ?? "",
className: attributes.class ?? "",
+31
View File
@@ -735,6 +735,37 @@ test("secure states the field type either way, and nothing off a field", () => {
assert.equal(handleOf(heading).secure, null);
});
// The fact above and the selector below have to name the same field. `secure` is
// derived from the field's type, not written by the markup, so matching it as a
// raw attribute reaches nothing: `secure` is an accepted key, no unknown-key
// error fires, and find answers undefined here for the field it answers with on
// ios. A spec that names the password entry that way types the password into
// nothing and every property over it passes vacuously.
test("secure selects the field this host reports secure", () => {
const password = fakeElement({
tag: "input", x: 0, y: 0, width: 100, height: 20,
id: "login_password", editable: true, attrs: { type: "password" },
});
const email = fakeElement({
tag: "input", x: 0, y: 20, width: 100, height: 20,
id: "login_email", editable: true, attrs: { type: "email" },
});
const heading = fakeElement({ tag: "h1", x: 0, y: 40, width: 100, height: 20, id: "title" });
withFakeDocument([password, email, heading], () => {
const ax = __testing__.buildAx() as { findAll(selector: unknown): Record<string, unknown>[] };
assert.deepEqual(
ax.findAll({ secure: true }).map((field) => [field.id, field.secure]),
[["login_password", true]],
);
// Not the heading: an element that is no field at all reports null, the way
// android reports null for every element, and answers to neither value.
assert.deepEqual(
ax.findAll({ secure: false }).map((field) => [field.id, field.secure]),
[["login_email", false]],
);
});
});
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?" } }),