oficina / sheets Public

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

Plain git — no account needed to clone.

Download

Download this file

1package sheets
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 := New(Config{})
22 page := do(t, app, httptest.NewRequest(http.MethodGet, "/signin", nil))
23 if page.Code != http.StatusOK {
24 t.Fatalf("signin status %d", page.Code)
25 }
26 // Calma with Sheets' accent (estilo row 8), not rastrillo's day.
27 want, ok := theme.ForApp("sheets")
28 if !ok || !bytes.Equal(sheetsTheme, want) {
29 t.Fatal("Sheets does not serve estilo's theme for sheets")
30 }
31 for _, item := range []struct {
32 name string
33 data []byte
34 }{
35 {"theme", sheetsTheme}, {"tokens", ui.TokensCSS()},
36 } {
37 sum := sha256.Sum256(item.data)
38 hashed := fmt.Sprintf("/static/%s.%x.css", item.name, sum[:8])
39 if !strings.Contains(page.Body.String(), `href="`+hashed+`"`) {
40 t.Fatalf("missing selected %s fingerprint", item.name)
41 }
42 for _, path := range []string{hashed, "/static/" + item.name + ".css", "/static/" + item.name + ".0000000000000000.css"} {
43 res := do(t, app, httptest.NewRequest(http.MethodGet, path, nil))
44 if res.Code != http.StatusOK || !bytes.Equal(res.Body.Bytes(), item.data) {
45 t.Fatalf("%s asset response mismatch status%d", item.name, res.Code)
46 }
47 if !strings.HasPrefix(res.Header().Get("Content-Type"), "text/css") {
48 t.Fatal("asset MIME mismatch")
49 }
50 want := "no-cache"
51 if path == hashed {
52 want = "public, max-age=31536000, immutable"
53 }
54 if res.Header().Get("Cache-Control") != want {
55 t.Fatal("asset cache policy mismatch")
56 }
57 }
58 }
59}
60
61// The layout names Onest's stylesheet under estilo's versioned prefix, and
62// the app serves it there: when estilo moves the fonts, this fails rather
63// than every page quietly falling back to the system face.
64func TestOnestIsLinkedAndServed(t *testing.T) {
65 app := New(Config{})
66 page := do(t, app, httptest.NewRequest(http.MethodGet, "/signin", nil))
67 css := theme.FontPrefix + "fonts.css"
68 if !strings.Contains(page.Body.String(), `href="`+css+`"`) {
69 t.Fatalf("layout does not link %s", css)
70 }
71 for _, path := range []string{css, theme.FontPrefix + "onest-latin.woff2"} {
72 if res := do(t, app, httptest.NewRequest(http.MethodGet, path, nil)); res.Code != http.StatusOK {
73 t.Fatalf("GET %s = %d", path, res.Code)
74 }
75 }
76}
77
78// The busy rule (estilo's busy): the page links busy.css after tokens.css
79// and busy.js after the shim, all three are served, and the shim served is
80// estilo's — rastrillo's without the old busy rule, which would fight the
81// new one.
82func TestBusyRuleIsLinkedAndServed(t *testing.T) {
83 app := New(Config{})
84 page := do(t, app, httptest.NewRequest(http.MethodGet, "/signin", nil)).Body.String()
85 for _, name := range []string{"static/estilo/busy.css", "static/rastrillo.js", "static/estilo/busy.js"} {
86 body := map[string][]byte{"static/estilo/busy.css": busy.CSS(), "static/rastrillo.js": busy.ShimJS(), "static/estilo/busy.js": busy.JS()}[name]
87 sum := sha256.Sum256(body)
88 hashed := "/" + strings.TrimSuffix(name, path.Ext(name)) + fmt.Sprintf(".%x", sum[:8]) + path.Ext(name)
89 if !strings.Contains(page, `"`+hashed+`"`) {
90 t.Errorf("sign-in page does not link %s", hashed)
91 }
92 if res := do(t, app, httptest.NewRequest(http.MethodGet, hashed, nil)); res.Code != http.StatusOK || !bytes.Equal(res.Body.Bytes(), body) {
93 t.Errorf("GET %s = %d or the wrong bytes", hashed, res.Code)
94 }
95 }
96 if i, j := strings.Index(page, "static/rastrillo."), strings.Index(page, "static/estilo/busy."); i < 0 || j < 0 {
97 t.Error("the shim or busy.js is missing")
98 }
99 // No rastrillo script on disk. `rastrillo doctor --fix` adds the ones
100 // the library ships and the app lacks, and the shim it adds at this
101 // pin is the old one, with the busy rule inside: loaded beside
102 // estilo's busy.js, the two rules fight. Delete what --fix adds.
103 for _, name := range []string{"static/rastrillo.js", "static/busy.js", "static/select.js", "static/datetime.js", "static/calendar.js"} {
104 if _, err := fs.Stat(staticFS, name); err == nil {
105 t.Errorf("%s is on disk; Sheets serves estilo's shim and busy.js, and no other rastrillo script", name)
106 }
107 }
108}
109