1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
package handlers
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"git.mihna123.com/openstore/internal/config"
)
func newTestConfig() *config.Config {
return &config.Config{
Serve: config.Serve{Addr: ":3000"},
Instance: config.Instance{
Name: "TestStore",
ContactEmail: "test@store.com",
BaseURL: "https://test.store.com",
},
}
}
func get(t *testing.T, mux *http.ServeMux, method, path string) *httptest.ResponseRecorder {
t.Helper()
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, httptest.NewRequest(method, path, nil))
return rec
}
func TestRoutes(t *testing.T) {
mux := Routes(newTestConfig())
tests := []struct {
name string
method string
path string
want int
}{
{"home", http.MethodGet, "/", http.StatusOK},
{"stylesheet", http.MethodGet, "/css/style.css", http.StatusOK},
{"missing stylesheet", http.MethodGet, "/css/nope.css", http.StatusNotFound},
{"templates not served", http.MethodGet, "/templates/index.html", http.StatusNotFound},
{"unknown path", http.MethodGet, "/nonsense", http.StatusNotFound},
{"wrong method on home", http.MethodPost, "/", http.StatusMethodNotAllowed},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rec := get(t, mux, tt.method, tt.path)
if rec.Code != tt.want {
t.Errorf("%s %s: got status %d, want %d", tt.method, tt.path, rec.Code, tt.want)
}
})
}
}
func TestStylesheetIsServed(t *testing.T) {
mux := Routes(newTestConfig())
rec := get(t, mux, http.MethodGet, "/css/style.css")
if rec.Code != http.StatusOK {
t.Fatalf("got status %d, want 200", rec.Code)
}
if ct := rec.Header().Get("Content-Type"); !strings.HasPrefix(ct, "text/css") {
t.Errorf("got Content-Type %q, want text/css", ct)
}
if rec.Body.Len() == 0 {
t.Error("stylesheet served empty")
}
}
func TestHomeLinksServedStylesheet(t *testing.T) {
mux := Routes(newTestConfig())
body := get(t, mux, http.MethodGet, "/").Body.String()
if !strings.Contains(body, `href="/css/style.css"`) {
t.Fatalf("home does not link the stylesheet, got:\n%s", body)
}
if code := get(t, mux, http.MethodGet, "/css/style.css").Code; code != http.StatusOK {
t.Errorf("linked stylesheet returned %d, want 200", code)
}
}
func TestHomeRendersInstanceName(t *testing.T) {
cfg := newTestConfig()
cfg.Instance.Name = "Prodavnica123"
mux := Routes(cfg)
rec := get(t, mux, http.MethodGet, "/")
if rec.Code != http.StatusOK {
t.Fatalf("got status %d, want 200", rec.Code)
}
body := rec.Body.String()
if strings.Count(body, "Prodavnica123") != 2 {
t.Errorf("instance name should appear in title and heading, got:\n%s", body)
}
if ct := rec.Header().Get("Content-Type"); !strings.HasPrefix(ct, "text/html") {
t.Errorf("got Content-Type %q, want text/html", ct)
}
}
func TestHomeEscapesInstanceName(t *testing.T) {
cfg := newTestConfig()
cfg.Instance.Name = `<script>alert("xss")</script>`
mux := Routes(cfg)
body := get(t, mux, http.MethodGet, "/").Body.String()
if strings.Contains(body, "<script>") {
t.Errorf("instance name rendered unescaped, got:\n%s", body)
}
if !strings.Contains(body, "<script>") {
t.Errorf("expected escaped instance name in body, got:\n%s", body)
}
}
func TestHomeUsesConfiguredNameNotDefault(t *testing.T) {
cfg := newTestConfig()
cfg.Instance.Name = "ConfiguredName"
mux := Routes(cfg)
body := get(t, mux, http.MethodGet, "/").Body.String()
if strings.Contains(body, "Openstore") {
t.Errorf("handler rendered a hardcoded name instead of the config, got:\n%s", body)
}
}
|