junk%s`, body)
})
return mux
}
}
// The three places junk hides: rendered text, an input's value, and
// the label a screen reader announces — each hit shown with its
// surroundings, so a prose false-positive is legible at a glance.
func TestJunkScanReadsTextInputsAndARIA(t *testing.T) {
r := New(t, staticPage(`
the price is undefined today
`))
r.Run(chromedp.Navigate(r.Origin+"/"), chromedp.WaitVisible("#app", chromedp.ByQuery))
hits := r.junkHits("#app")
joined := strings.Join(hits, "\n")
for _, want := range []string{
`undefined in: "the price is undefined today`,
"[object Object]",
"null",
} {
if !strings.Contains(joined, want) {
t.Errorf("scan missed %q:\n%s", want, joined)
}
}
if len(hits) != 3 {
t.Errorf("want 3 hits, got %d:\n%s", len(hits), joined)
}
}
// AllowText spares deliberate prose; the junk value stays banned
// everywhere else on the screen.
func TestAllowTextSparesDeliberateProse(t *testing.T) {
r := New(t, staticPage(`
this contract is null and void
`))
r.AllowText("null and void")
r.Run(chromedp.Navigate(r.Origin+"/"), chromedp.WaitVisible("#app", chromedp.ByQuery))
if hits := r.junkHits("#app"); len(hits) > 0 {
t.Errorf("allowed prose still hit: %v", hits)
}
r.Screen("#app", "the prose screen") // and the full gate passes too
}
// A missing scan root is itself a finding, never a silent pass.
func TestJunkScanReportsAMissingRoot(t *testing.T) {
r := New(t, staticPage(`
no app root here
`))
r.Run(chromedp.Navigate(r.Origin+"/"), chromedp.WaitVisible("#up", chromedp.ByQuery))
hits := r.junkHits("#app")
if len(hits) != 1 || !strings.Contains(hits[0], "#app") {
t.Errorf("missing root not reported: %v", hits)
}
}
// The whole gate, green on a clean page: wait, scan, flush.
func TestScreenPassesACleanPage(t *testing.T) {
r := New(t, staticPage(`