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, "
  • opener rather than comparing indexes, because // "rst-result" is a prefix of "rst-result-primed" and an index // comparison would be measuring the same attribute twice. items := strings.Split(body, "
  • 0` alone, dropping the question // term — red, then reverted. 2026-09-05. func TestAQuestionPrimesNothing(t *testing.T) { h := withCorpus(t) body := get(t, h, "/?q=what+was+june+revenue").Body.String() if !strings.Contains(body, "Q3 board pack") { t.Fatalf("the question found nothing, so this test proves nothing:\n%s", body) } if strings.Contains(body, "rst-result-primed") { t.Error("a question primed a result; Enter would navigate away from " + "a page the reader was still reading") } } // There is deliberately no test here for "a page with no results primes // nothing". It was written, and it could not fail: with no results the // template renders no list items, so priming nothing and priming a // result that does not exist are the same bytes. The invariant is real // and is guarded where it is visible — query.TestPrimesFirstResult. // The live-search endpoint returns the results region and nothing else. // A fragment that shipped a whole page would nest inside the list // on every keystroke. // // Broken by pointing searchResults at render instead of renderFragment — // red, then reverted. 2026-09-05. func TestSearchFragmentIsResultsOnly(t *testing.T) { h := withCorpus(t) rec := get(t, h, "/search?q=june+revenue") if rec.Code != http.StatusOK { t.Fatalf("status %d, want 200", rec.Code) } body := rec.Body.String() if !strings.Contains(body, "Q3 board pack") { t.Errorf("the fragment carries no result:\n%s", body) } if !strings.Contains(body, "rst-result-primed") { t.Error("the fragment does not prime, so live search and a form " + "submit would disagree about where Enter goes") } // rst-refresh is on the list because a fragment that ever grew the // wrapper would nest a refreshable region inside one, and drop.js // would then find two regions with the same name. for _, chrome := range []string{"

    ") 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") } }