mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 11:07:10 +00:00
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:
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>`;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -21,6 +21,7 @@ type AxHandle = {
|
||||
attrs?: Record<string, string>;
|
||||
clickable?: boolean;
|
||||
editable?: boolean;
|
||||
secure?: boolean | null;
|
||||
};
|
||||
type Ax = { find(selector: unknown): AxHandle | undefined };
|
||||
|
||||
@@ -50,6 +51,10 @@ function domFacts(): unknown[] {
|
||||
hintText: handle?.attrs?.hintText ?? "",
|
||||
handleClickable: handle?.clickable ?? false,
|
||||
handleEditable: handle?.editable ?? false,
|
||||
// Three-valued, so it stays null rather than collapsing onto false: the Go
|
||||
// side compares it against a dump that leaves the fact out entirely for an
|
||||
// element no producer states it for.
|
||||
secure: handle?.secure ?? null,
|
||||
width: target.width ?? 0,
|
||||
height: target.height ?? 0,
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user