oficina / calendar Public

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

Plain git — no account needed to clone.

Download

Download this file

1// Package calendartest tests the app from the outside: real HTTP
2// requests against the real router, wired exactly as
3// cmd/calendar/main.go wires it.
4//
5// The TDD loop: write a failing test here, make it pass in
6// internal/calendar, repeat.
7package calendartest
8
9import (
10 "net/http"
11 "net/http/httptest"
12 "net/url"
13 "testing"
14
15 calendar "amadan.net/oficina/calendar/internal/calendar"
16)
17
18// testOrigin is the origin newApp wires and post presents as its
19// same-origin evidence — the pair a browser form submission would be.
20const testOrigin = calendar.TestOrigin
21
22// newApp builds the whole app per test over a fresh temp database.
23func newApp(t *testing.T) *calendar.App {
24 t.Helper()
25 return calendar.NewForTest(t, t.TempDir())
26}
27
28// signedIn builds an app and a session cookie for address, by driving
29// the real sign-in flow.
30func signedIn(t *testing.T, address string) (*calendar.App, *http.Cookie) {
31 t.Helper()
32 app := newApp(t)
33 return app, app.SignInForTest(t, address)
34}
35
36func get(t *testing.T, h http.Handler, target string) *httptest.ResponseRecorder {
37 t.Helper()
38 rec := httptest.NewRecorder()
39 h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, target, nil))
40 return rec
41}
42
43// getAs is get with a session attached.
44func getAs(t *testing.T, h http.Handler, session *http.Cookie, target string) *httptest.ResponseRecorder {
45 t.Helper()
46 rec := httptest.NewRecorder()
47 h.ServeHTTP(rec, calendar.RequestForTest(session, http.MethodGet, target, nil))
48 return rec
49}
50
51// follow is getAs plus one redirect hop.
52//
53// "/" answers 303 to the viewer's own today, because Today and Day are
54// one page rather than two subtly different ones. A test that wants the
55// page rather than the redirect says so by using this.
56func follow(t *testing.T, h http.Handler, session *http.Cookie, target string) *httptest.ResponseRecorder {
57 t.Helper()
58 rec := getAs(t, h, session, target)
59 if rec.Code != http.StatusSeeOther && rec.Code != http.StatusFound {
60 return rec
61 }
62 loc := rec.Header().Get("Location")
63 if loc == "" {
64 t.Fatalf("GET %s: %d with no Location", target, rec.Code)
65 }
66 return getAs(t, h, session, loc)
67}
68
69func post(t *testing.T, h http.Handler, target string, form url.Values) *httptest.ResponseRecorder {
70 t.Helper()
71 rec := httptest.NewRecorder()
72 h.ServeHTTP(rec, calendar.RequestForTest(nil, http.MethodPost, target, form))
73 return rec
74}
75
76// postAs is post with a session attached.
77func postAs(t *testing.T, h http.Handler, session *http.Cookie, target string, form url.Values) *httptest.ResponseRecorder {
78 t.Helper()
79 rec := httptest.NewRecorder()
80 h.ServeHTTP(rec, calendar.RequestForTest(session, http.MethodPost, target, form))
81 return rec
82}
83
84// openLink is opening an emailed link: a GET that must spend nothing and
85// answer with the confirm door. It returns the door's form action and the
86// token it carries, read off the page rather than the link, so a door
87// that dropped or mangled the token fails here.
88func openLink(t *testing.T, h http.Handler, link string) (action, token string) {
89 t.Helper()
90 rec := get(t, h, link)
91 if rec.Code != http.StatusOK || len(rec.Result().Cookies()) != 0 {
92 t.Fatalf("GET %s = %d with %d cookies, want 200 and the confirm door, minting nothing", link, rec.Code, len(rec.Result().Cookies()))
93 }
94 action, token, ok := calendar.ConfirmFormForTest(rec.Body.String())
95 if !ok {
96 t.Fatalf("GET %s: no confirm form on the page:\n%s", link, rec.Body.String())
97 }
98 return action, token
99}
100
101// postLink is pressing the confirm door's Sign in button: the token,
102// POSTed back to the door's action with a browser's same-origin
103// evidence. This is the request that spends the link.
104func postLink(t *testing.T, h http.Handler, action, token string) *httptest.ResponseRecorder {
105 t.Helper()
106 r := calendar.RequestForTest(nil, http.MethodPost, action, url.Values{"token": {token}})
107 r.Header.Set("Sec-Fetch-Site", "same-origin")
108 rec := httptest.NewRecorder()
109 h.ServeHTTP(rec, r)
110 return rec
111}
112
113// serve runs one request through h.
114func serve(h http.Handler, r *http.Request) *httptest.ResponseRecorder {
115 rec := httptest.NewRecorder()
116 h.ServeHTTP(rec, r)
117 return rec
118}
119