oficina / estilo Public

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

Plain git — no account needed to clone.

Download

Download this file

1package savestatus
2
3import (
4 "bytes"
5 "html/template"
6 "os/exec"
7 "strings"
8 "testing"
9)
10
11func render(t *testing.T, data Data) string {
12 t.Helper()
13 view, err := template.New("test").Parse(Template())
14 if err != nil {
15 t.Fatal(err)
16 }
17 var b bytes.Buffer
18 if err := view.ExecuteTemplate(&b, "estilo-save-status", data); err != nil {
19 t.Fatal(err)
20 }
21 return b.String()
22}
23
24func TestRenderStatesAndSilentUnknown(t *testing.T) {
25 for _, tc := range []struct{ state, want string }{
26 {"saved", "gespeichert"}, {"saving", "guardando"},
27 {"retrying", "再試行"}, {"failed", "فشل"},
28 {"idle", ""}, {"unsupported", ""},
29 } {
30 t.Run(tc.state, func(t *testing.T) {
31 got := render(t, Data{State: tc.state, Saved: "gespeichert", Saving: "guardando", Retrying: "再試行", Failed: "فشل"})
32 if !strings.HasSuffix(got, ">"+tc.want+"</span>") {
33 t.Fatalf("wrong initial text: %s", got)
34 }
35 for _, attr := range []string{`role="status"`, `aria-live="polite"`, `aria-atomic="true"`, `estilo-save-status="inline"`} {
36 if !strings.Contains(got, attr) {
37 t.Errorf("missing %s in %s", attr, got)
38 }
39 }
40 if strings.Contains(got, "aria-hidden") || strings.Contains(got, " hidden") || strings.Contains(got, "aria-label") {
41 t.Errorf("silent or unnamed region changed semantics: %s", got)
42 }
43 if tc.want == "" && !strings.Contains(got, `data-state="idle"`) {
44 t.Errorf("unknown state was not normalized: %s", got)
45 }
46 })
47 }
48 got := render(t, Data{State: "failed", Placement: "floating"})
49 if !strings.HasSuffix(got, "></span>") || !strings.Contains(got, `estilo-save-status="floating"`) {
50 t.Fatalf("missing state text must stay empty: %s", got)
51 }
52}
53
54func TestLabelsAndStatusTextAreEscaped(t *testing.T) {
55 unsafe := `"><script>globalThis.fixture=1</script>&`
56 got := render(t, Data{State: "failed", Failed: unsafe, Label: unsafe, Placement: unsafe})
57 if strings.Contains(got, "<script>") || strings.Count(got, "<span ") != 1 || strings.Count(got, "</span>") != 1 {
58 t.Fatalf("text became markup: %s", got)
59 }
60 if !strings.Contains(got, `estilo-save-status="inline"`) || !strings.Contains(got, `aria-label="&#34;&gt;&lt;script&gt;`) || !strings.HasSuffix(got, "&lt;/script&gt;&amp;</span>") {
61 t.Fatalf("attribute or text escaping failed: %s", got)
62 }
63}
64
65func TestJavaScriptStateTransitions(t *testing.T) {
66 output, err := exec.Command("node", "--test", "status.test.mjs").CombinedOutput()
67 if err != nil {
68 t.Fatalf("status module: %v\n%s", err, output)
69 }
70}
71