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 "io/fs"
5 "path"
6
7 "amadan.net/oficina/estilo.git/busy"
8 "bytes"
9 "crypto/sha256"
10 "fmt"
11 "net/http"
12 "net/http/httptest"
13 "strings"
14 "testing"
15
16 "amadan.net/oficina/estilo.git/theme"
17 "amadan.net/rastrillo/rastrillo/ui"
18)
19
20func TestSharedThemeAssetFingerprintAndCache(t *testing.T) {
21 app, err := NewForTest(t)
22 if err != nil {
23 t.Fatal(err)
24 }
25 page := serve(app, httptest.NewRequest(http.MethodGet, "/signin", nil))
26 if page.Code != http.StatusOK {
27 t.Fatalf("signin status %d", page.Code)
28 }
29 // Calma with Docs' accent (estilo row 8), not rastrillo's day.
30 docsTheme, ok := theme.ForApp("docs")
31 if !ok {
32 t.Fatal("estilo's theme ring has no docs")
33 }
34 for _, item := range []struct {
35 name string
36 data []byte
37 }{
38 {"theme", docsTheme}, {"tokens", ui.TokensCSS()},
39 } {
40 sum := sha256.Sum256(item.data)
41 hashed := fmt.Sprintf("/static/%s.%x.css", item.name, sum[:8])
42 if !strings.Contains(page.Body.String(), `href="`+hashed+`"`) {
43 t.Fatalf("missing selected %s fingerprint", item.name)
44 }
45 for _, path := range []string{hashed, "/static/" + item.name + ".css", "/static/" + item.name + ".0000000000000000.css"} {
46 res := serve(app, httptest.NewRequest(http.MethodGet, path, nil))
47 if res.Code != http.StatusOK || !bytes.Equal(res.Body.Bytes(), item.data) {
48 t.Fatalf("%s asset response mismatch status%d", item.name, res.Code)
49 }
50 if !strings.HasPrefix(res.Header().Get("Content-Type"), "text/css") {
51 t.Fatal("asset MIME mismatch")
52 }
53 want := "no-cache"
54 if path == hashed {
55 want = "public, max-age=31536000, immutable"
56 }
57 if res.Header().Get("Cache-Control") != want {
58 t.Fatal("asset cache policy mismatch")
59 }
60 }
61 }
62}
63
64// The layout names Onest's stylesheet under estilo's versioned prefix, and
65// the app serves it there: when estilo moves the fonts, this fails rather
66// than every page quietly falling back to the system face.
67func TestOnestIsLinkedAndServed(t *testing.T) {
68 app, err := NewForTest(t)
69 if err != nil {
70 t.Fatal(err)
71 }
72 page := serve(app, httptest.NewRequest(http.MethodGet, "/signin", nil))
73 css := theme.FontPrefix + "fonts.css"
74 if !strings.Contains(page.Body.String(), `href="`+css+`"`) {
75 t.Fatalf("layout does not link %s", css)
76 }
77 for _, path := range []string{css, theme.FontPrefix + "onest-latin.woff2"} {
78 if res := serve(app, httptest.NewRequest(http.MethodGet, path, nil)); res.Code != http.StatusOK {
79 t.Fatalf("GET %s = %d", path, res.Code)
80 }
81 }
82}
83
84// The busy rule (estilo's busy): the page links busy.css and busy.js, and
85// the shim it serves is estilo's — rastrillo's without the old busy rule,
86// which would fight the new one.
87func TestBusyRuleIsLinkedAndServed(t *testing.T) {
88 app, err := NewForTest(t)
89 if err != nil {
90 t.Fatal(err)
91 }
92 page := serve(app, httptest.NewRequest(http.MethodGet, "/signin", nil)).Body.String()
93 for name, body := range map[string][]byte{"static/estilo/busy.css": busy.CSS(), "static/rastrillo.js": busy.ShimJS(), "static/estilo/busy.js": busy.JS()} {
94 sum := sha256.Sum256(body)
95 hashed := "/" + strings.TrimSuffix(name, path.Ext(name)) + fmt.Sprintf(".%x", sum[:8]) + path.Ext(name)
96 if !strings.Contains(page, `"`+hashed+`"`) {
97 t.Errorf("sign-in page does not link %s", hashed)
98 }
99 if res := serve(app, httptest.NewRequest(http.MethodGet, hashed, nil)); res.Code != http.StatusOK || !bytes.Equal(res.Body.Bytes(), body) {
100 t.Errorf("GET %s = %d or the wrong bytes", hashed, res.Code)
101 }
102 }
103 // No rastrillo script on disk. Docs serves them from memory
104 // (vendoredStaticFS); `rastrillo doctor --fix` copies the ones the
105 // library ships into a static/ it finds, and the shim it would copy
106 // still carries the old busy rule, which fights estilo's busy.js.
107 // Delete anything --fix adds.
108 for _, tree := range []fs.FS{staticFS, brandFS} {
109 _ = fs.WalkDir(tree, ".", func(name string, d fs.DirEntry, err error) error {
110 if err == nil && !d.IsDir() {
111 switch path.Base(name) {
112 case "rastrillo.js", "busy.js", "select.js", "datetime.js", "calendar.js", "tokens.css", "theme.css":
113 t.Errorf("%s is on disk; Docs serves rastrillo's and estilo's assets from memory, and doctor's shim would bring the old busy rule back", name)
114 }
115 }
116 return nil
117 })
118 }
119}
120