oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1package docs
2
3import (
4 "context"
5 "net/http"
6 "strings"
7 "testing"
8)
9
10// The searchable-select enhancement's strings reach the page resolved,
11// not as raw catalog keys.
12//
13// This goes through the real handler rather than calling
14// newToolbarView, and that is the entire point of it. rastrillo.T
15// returns its key verbatim when no locale middleware has run —
16// documented, and what every direct view-data test in this package sees
17// — so a unit test here would compare "rastrillo.ui.select_filter"
18// against itself and pass whether or not the key exists.
19//
20// These three are the only keys this app resolves out of the
21// FRAMEWORK's namespace rather than its own Catalog, so they are the
22// only ones a typo would strand: our own are held by
23// TestEveryMenuKeyIsInTheCatalog against a map we control. A stranded
24// key here raises no error anywhere — ui/select.js carries English
25// fallbacks and would simply use the attribute's value as its
26// placeholder — so the whole failure is a person reading the literal
27// text "rastrillo.ui.select_filter" inside the filter box.
28func TestTheSelectEnhancementStringsResolve(t *testing.T) {
29 app, err := NewForTest(t)
30 if err != nil {
31 t.Fatalf("NewForTest: %v", err)
32 }
33 owner := app.TestPerson(t, "selects@example.com")
34 doc, err := app.Store().Create(context.Background(), owner, "Selects")
35 if err != nil {
36 t.Fatalf("Create: %v", err)
37 }
38
39 body := serve(app, app.TestRequest(t, "selects@example.com", http.MethodGet, "/d/"+doc.Sqid, nil)).Body.String()
40
41 // The opt-in is present at all. Without this the checks below would
42 // be looking for keys in a page that emits no such attributes, and
43 // would pass by finding nothing.
44 if !strings.Contains(body, "data-rst-select") {
45 t.Fatal("no select carries data-rst-select — the searchable enhancement is not opted into, so the checks below verify nothing")
46 }
47
48 // CALIBRATE AGAINST OUR OWN KEYS FIRST, and skip if they are raw.
49 //
50 // The first version of this test asserted the framework's three keys
51 // resolve, full stop. It went red, and the finding looked serious:
52 // cmd/docs/main.go sets opts.BaseCatalog = docs.Catalog, which — if
53 // it REPLACED the framework's own strings rather than extending
54 // them — would leave every rastrillo.ui.* key unresolved app-wide,
55 // including the shell's skip link, which is a WCAG bypass-blocks
56 // mechanism that would have been rendering the literal text
57 // "rastrillo.ui.shell_skip".
58 //
59 // It does not replace them. rastrillo's serve.go builds `base :=
60 // BaseCatalog()` and merges opts.BaseCatalog on top, so the
61 // framework's strings sit under the app's and both resolve.
62 //
63 // Confirmed by running the app rather than only by reading that
64 // source: `scripts/run-dev.sh`, sign in, fetch a document, and the
65 // page carries `data-rst-select-filter="Type to filter"` with zero
66 // occurrences of any `rastrillo.ui.*` or `docs.*` key anywhere in
67 // its 34KB. That is the observation this test cannot make, and it
68 // is worth having made once — the alternative was believing a
69 // source-read about a merge that happens two packages away.
70 //
71 // This test still cannot make it, because the harness serves
72 // through app.Handler() directly and rastrillo installs its locale
73 // middleware in Serve, so in a test NOTHING resolves, ours
74 // included, and rastrillo.T returns every key verbatim exactly as
75 // documented.
76 //
77 // An assertion that reports the same failure whether or not the bug
78 // exists is not evidence of the bug. That is AGENTS.md's "cannot
79 // distinguish no from I can't see it", written by me rather than
80 // found in a tool, and it cost an hour it should not have.
81 //
82 // So this compares like with like: if our own catalog keys came
83 // back raw, the environment resolves nothing and there is nothing
84 // here to learn. If they resolved, the framework's must have too —
85 // and if they did not, the replacement-versus-merge bug above is
86 // real and this is what finds it.
87 ourKey := "docs.editor.toolbar.bold"
88 if strings.Contains(body, ourKey) {
89 t.Skipf("this harness resolves no catalog keys at all (%q is raw in the page), so it cannot say whether the framework's resolve — see this test's own comment", ourKey)
90 }
91
92 for _, key := range []string{
93 "rastrillo.ui.select_filter",
94 "rastrillo.ui.select_results",
95 "rastrillo.ui.select_result_one",
96 } {
97 if strings.Contains(body, key) {
98 t.Errorf("our own keys resolved but the framework's %q did not — opts.BaseCatalog replaces rastrillo's base catalog instead of extending it, and a person reads this key as the filter box's placeholder", key)
99 }
100 }
101}
102
103// All three selects opt in, not just the one with enough options to
104// earn a filter on the framework's own judgement.
105//
106// Paul's instruction, and the reasoning is in views/show.html's comment:
107// they sit side by side in one group, and one combobox flanked by two
108// native selects looks worse than either extreme. Asserted because the
109// opposite is a tempting tidy-up — field-select.html's ten-option rule
110// is right there in the framework — and because reverting it should be
111// a decision someone takes on purpose rather than a plausible-looking
112// diff.
113func TestEveryToolbarSelectIsSearchable(t *testing.T) {
114 app, err := NewForTest(t)
115 if err != nil {
116 t.Fatalf("NewForTest: %v", err)
117 }
118 owner := app.TestPerson(t, "allselects@example.com")
119 doc, err := app.Store().Create(context.Background(), owner, "Selects")
120 if err != nil {
121 t.Fatalf("Create: %v", err)
122 }
123
124 body := serve(app, app.TestRequest(t, "allselects@example.com", http.MethodGet, "/d/"+doc.Sqid, nil)).Body.String()
125
126 if got := strings.Count(body, `data-docs-select=`); got != 3 {
127 t.Fatalf("the toolbar renders %d selects, expected 3 — this test's arithmetic no longer describes the bar", got)
128 }
129 if got := strings.Count(body, ` data-rst-select `); got != 3 {
130 t.Errorf("%d of the 3 toolbar selects opt into the searchable enhancement", got)
131 }
132}
133