package memoriatest import ( "net/http" "strings" "testing" ) // The corpus every test in this file searches. // // Two passages match "june revenue", and that is the point rather than // an incidental. The first version of this file used a corpus where // every query returned exactly ONE result, which made "the primed one is // the first one" unfalsifiable: with a single list item, priming the // first, priming all and priming the last are the same markup. Fable's // review caught it by mutating the template to `{{if $.Primed}}` and // watching the suite stay green. Any test below that asserts a POSITION // must therefore check it has more than one result to be wrong about. func withCorpus(t *testing.T) http.Handler { t.Helper() h := newApp(t) if rec := store(t, h, "Q3 board pack", "## Revenue\n\nJune revenue was 1,350,000 across all regions.\n\n"+ "## Costs\n\nHosting fell after the migration.\n\n"+ "## Risks\n\nOne customer is 22% of June revenue, and that has not improved.", ); rec.Code != http.StatusSeeOther { t.Fatalf("store: status %d, want 303", rec.Code) } return h } // results counts the rendered result items, so a positional assertion // can refuse to run against a list too short to hold a wrong answer. func results(body string) int { return strings.Count(body, "
") if open < 0 { return "" } rest = rest[open+len("
"):] shut := strings.Index(rest, "
") if shut < 0 { return "" } return strings.TrimSpace(rest[:shut]) } // attr pulls one attribute's value out of rendered markup. Small enough // to be obvious, and obvious beats a parser for one attribute. func attr(t *testing.T, body, name string) string { t.Helper() i := strings.Index(body, name+`="`) if i < 0 { return "" } rest := body[i+len(name)+2:] j := strings.Index(rest, `"`) if j < 0 { return "" } return rest[:j] } // The stamp is what search.js reads to decide whether the results on // screen still describe what is in the box. Reading the input instead // was the bug Fable found: after a Back, a browser restores the field on // a schedule of its own, and a script that trusted it would treat a // stale screen as current and send Enter to the wrong document. // // Broken by deleting rst-search-results-for from index.html — red, then // reverted. 2026-09-05. func TestThePageStampsTheQueryItRendered(t *testing.T) { h := withCorpus(t) for _, c := range []struct{ url, want string }{ {"/?q=june+revenue", `rst-search-results-for="june revenue"`}, {"/", `rst-search-results-for=""`}, } { if body := get(t, h, c.url).Body.String(); !strings.Contains(body, c.want) { t.Errorf("GET %s does not stamp the query it rendered (want %s):\n%s", c.url, c.want, body) } } } // search.js is an enhancement. The page it enhances must work with it // deleted, which means the form is a real GET form to a real route and // the script is not what makes results appear. func TestSearchWorksWithoutTheScript(t *testing.T) { h := withCorpus(t) body := get(t, h, "/").Body.String() if !strings.Contains(body, `action="/"`) || !strings.Contains(body, `method="get"`) { t.Errorf("the search form is not a plain GET form:\n%s", body) } if !strings.Contains(get(t, h, "/?q=june+revenue").Body.String(), "Q3 board pack") { t.Error("a plain form submit does not produce results") } }