test(chrome): compare the secure fact across both producers

it is the fourth fact the dump and the web runtime derive independently,
and the one that decides whether a typed value is written into the
shared record. three-valued, so the fixture guard requires all three
states rather than both polarities.
This commit is contained in:
pj committed 2026-08-18 20:14:07 +05:30
1 parent 6aecccd2d6
commit 9a920444b3
4 files changed
+67

No files matched your search

@@ -10,6 +10,7 @@ import (
"path/filepath"
"runtime"
"slices"
"strconv"
"testing"
"time"
@@ -51,6 +52,11 @@ type elementFacts struct {
editable bool
scrollable bool
hintText string
// secure is three-valued: "true", "false", or "" where the producer states
// nothing, which android states for every element. It decides whether a
// typed value may be written into the shared record, so the two producers
// disagreeing about it writes a credential into a run's trace.
secure string
// handleClickable and handleEditable are the same facts on the ax element a
// spec reaches through state.ax.find, a third place they are computed and the
// one that has twice been the odd one out: clickable answered a hardcoded
@@ -100,6 +106,7 @@ func TestHierarchy_DerivesTheSameFactsAsTheWebRuntime(t *testing.T) {
requireEveryElementNamed(t, "the hierarchy dump", fromDump)
requireEveryElementNamed(t, "the web runtime", fromWebRuntime)
requireBothPolarities(t, fromWebRuntime)
requireEverySecureState(t, fromWebRuntime)
requireTheHandleAgreesWithTheEnumeration(t, fromWebRuntime)
compareEnumeratedElements(t, fromDump, fromWebRuntime)
compareDerivedFacts(t, fromDump, fromWebRuntime)
@@ -127,6 +134,7 @@ func factsFromHierarchyDump(t *testing.T, dump string) []factRow {
editable: element.Editable,
scrollable: element.Attributes["scrollable"] == "true",
hintText: element.Attributes["hintText"],
secure: secureFromDump(element),
positiveBounds: hasPositiveBounds(
element.Bounds.Width(),
element.Bounds.Height(),
@@ -175,6 +183,7 @@ func factsFromWebRuntime(
HintText string `json:"hintText"`
HandleClickable bool `json:"handleClickable"`
HandleEditable bool `json:"handleEditable"`
Secure *bool `json:"secure"`
Width int `json:"width"`
Height int `json:"height"`
}
@@ -194,6 +203,7 @@ func factsFromWebRuntime(
hintText: item.HintText,
handleClickable: item.HandleClickable,
handleEditable: item.HandleEditable,
secure: secureFromWebRuntime(item.Secure),
positiveBounds: hasPositiveBounds(item.Width, item.Height),
},
})
@@ -201,6 +211,24 @@ func factsFromWebRuntime(
return rows
}
// secureFromDump and secureFromWebRuntime read the same three-valued fact off
// the two producers. The dump leaves the field out entirely for an element it
// states nothing about, the web runtime reports null for it, and both mean the
// same thing: unknown, not "not a secure entry".
func secureFromDump(element *hierarchy.Element) string {
if !element.SecureReported() {
return ""
}
return strconv.FormatBool(element.Secure)
}
func secureFromWebRuntime(secure *bool) string {
if secure == nil {
return ""
}
return strconv.FormatBool(*secure)
}
// hasPositiveBounds is the positiveBounds fact of pkg/spec/src/targets.ts,
// applied to both producers so the geometry comparison cannot drift from the
// rule it stands in for.
@@ -262,6 +290,27 @@ func requireBothPolarities(t *testing.T, rows []factRow) {
}
}
// requireEverySecureState is requireBothPolarities for the one fact that is not
// a boolean. A fixture holding no password entry would compare "false" against
// "false" over the whole page and pass while proving nothing about the state
// that decides whether a typed value may be written down.
func requireEverySecureState(t *testing.T, rows []factRow) {
t.Helper()
seen := map[string]bool{}
for _, row := range rows {
seen[row.facts.secure] = true
}
for _, state := range []string{"true", "false", ""} {
if !seen[state] {
t.Errorf(
"the fixture no longer holds an element the web runtime reports "+
"secure=%q for, so comparing that state proves nothing",
state,
)
}
}
}
// requireTheHandleAgreesWithTheEnumeration compares the V8 host against itself.
// An element a spec reaches through state.ax and the same element in the
// enumeration must be clickable, and typeable, to the same degree, or a spec
@@ -371,6 +420,17 @@ func compareDerivedFacts(t *testing.T, fromDump, fromWebRuntime []factRow) {
web.hintText,
)
}
if dump.secure != web.secure {
t.Errorf(
"%q (<%s>): the hierarchy dump derives secure=%q, the web runtime "+
"derives secure=%q; one host would write into the record a value "+
"the other redacts",
row.id,
dump.tag,
dump.secure,
web.secure,
)
}
for _, fact := range []struct {
name string
dump bool
@@ -26,6 +26,7 @@
<button id="shadow-save">save</button>
<button id="shadow-cancel" disabled>cancel</button>
<input id="shadow-amount" type="text" value="10" placeholder="0.00" />
<input id="shadow-password" type="password" placeholder="Password" />
<div id="shadow-plain">plain</div>
</div>
<div id="shadow-scroller"><div id="shadow-scroller-content"></div></div>`;
+1
View File
@@ -61,6 +61,7 @@
<input id="hint-aria" type="text" aria-label="Search" placeholder="Type here" name="q" />
<input id="hint-placeholder" type="text" placeholder="What's this for?" name="note-field" />
<input id="hint-name" type="text" name="reference-field" />
<input id="password" type="password" placeholder="Password" />
<input id="agree" type="checkbox" placeholder="not a hint" />
<textarea id="notes"></textarea>
<!-- contenteditable is INHERITED, so #bio-word answers isContentEditable