oficina / calendar Public

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

Plain git — no account needed to clone.

Download

Download this file

1package calendartest
2
3import (
4 "net/http"
5 "net/url"
6 "regexp"
7 "strings"
8 "testing"
9)
10
11// The sign-in pages are the Oficina door (estilo chrome, Paul
12// 2026-09-29): one card on the suite's sky, Calendar's mark and name at
13// its head. Only the drawing changed — the form still posts "address" to
14// /signin and gets the same answer it always did.
15func TestSignInPageIsTheDoor(t *testing.T) {
16 app := newApp(t)
17 h := app.Handler()
18
19 rec := get(t, h, "/signin")
20 if rec.Code != http.StatusOK {
21 t.Fatalf("GET /signin: status %d, want 200", rec.Code)
22 }
23 body := rec.Body.String()
24 for _, want := range []string{
25 "estilo-door",
26 "<span>Calendar</span>",
27 `<form rst-form estilo-signin-form method="post" action="/signin"`,
28 `name="address"`,
29 "<title>Sign in · Calendar</title>",
30 // Paul, 2026-10-01: the door's button says "Sign in".
31 `<button rst-btn="primary" type="submit">Sign in</button>`,
32 "We’ll email you a link that signs you in. It works once and expires in 15 minutes.",
33 } {
34 if !strings.Contains(body, want) {
35 t.Errorf("sign-in page is missing %q:\n%s", want, body)
36 }
37 }
38
39 // The door owns its words (Paul, 2026-10-01): the submit is "Sign in",
40 // and Calendar's own lede and button copy are gone.
41 for _, gone := range []string{"Email me a link", "There is no password", "A calendar for one team"} {
42 if strings.Contains(body, gone) {
43 t.Errorf("sign-in page still says %q", gone)
44 }
45 }
46
47 // The sky: an inline placeholder, and served layers reachable signed
48 // out through estilo's handler, not the app's /static/ one.
49 if !regexp.MustCompile(`<img estilo-sky-layer="placeholder"[^>]*src="data:image/png;base64,`).MatchString(body) {
50 t.Errorf("sign-in page has no inline estilo-sky-layer placeholder:\n%s", body)
51 }
52 layer := regexp.MustCompile(`<img estilo-sky-layer="[a-z]+"[^>]*src="(/static/estilo/sky/v1/[^"]+)"`).FindStringSubmatch(body)
53 if layer == nil {
54 t.Fatalf("sign-in page links no served estilo-sky-layer img:\n%s", body)
55 }
56 if got := get(t, h, layer[1]); got.Code != http.StatusOK || got.Header().Get("Content-Type") != "image/svg+xml" {
57 t.Errorf("GET %s signed out: %d %q, want 200 image/svg+xml", layer[1], got.Code, got.Header().Get("Content-Type"))
58 }
59
60 // The door's own styles are linked and served.
61 for _, name := range []string{"chrome", "sky"} {
62 href := regexp.MustCompile(`/static/` + name + `\.[0-9a-f]{16}\.css`).FindString(body)
63 if href == "" {
64 t.Errorf("sign-in page does not link static/%s.css", name)
65 continue
66 }
67 if got := get(t, h, href); got.Code != http.StatusOK {
68 t.Errorf("GET %s: status %d, want 200", href, got.Code)
69 }
70 }
71
72 // POST address= still begins sign-in exactly as before.
73 posted := post(t, h, "/signin", url.Values{"address": {"someone@example.com"}})
74 if posted.Code != http.StatusSeeOther || posted.Header().Get("Location") != "/signin?sent=1" {
75 t.Fatalf("POST /signin: %d to %q, want 303 to /signin?sent=1", posted.Code, posted.Header().Get("Location"))
76 }
77 if mail, err := app.LastMailForTest(); err != nil || !strings.Contains(mail, "/auth/verify?token=") {
78 t.Fatalf("POST /signin address= mailed no link (err %v)", err)
79 }
80}
81
82// Every outcome the auth plugin redirects back with keeps its sentence;
83// a bad address is the field's own error, the rest are the page's.
84func TestSignInDoorOutcomes(t *testing.T) {
85 h := newApp(t).Handler()
86 for query, want := range map[string][]string{
87 "sent=1": {"estilo-door", "<title>Check your email · Calendar</title>", "Check your email", "If that address can sign in here, we’ve sent it a link. It works once and expires in 15 minutes.", `href="/signin"`, "Use a different address"},
88 "err=rate": {"estilo-signin-form", `role="alert"`, "Too many attempts. Wait a few minutes, then try again."},
89 "err=expired": {"estilo-signin-form", "That link has expired. Ask for a new one."},
90 "err=nope": {"estilo-signin-form", "That link did not work. Ask for a new one."},
91 "err=expired&sent=1": {"estilo-signin-form", "<title>Sign in · Calendar</title>", "That link has expired. Ask for a new one.", "If that address can sign in here, we’ve sent it a link."},
92 "err=address": {`rst-field-error id="estilo-signin-address-error" role="alert">That does not look like an email address.`},
93 } {
94 body := get(t, h, "/signin?"+query).Body.String()
95 for _, w := range want {
96 if !strings.Contains(body, w) {
97 t.Errorf("/signin?%s is missing %q:\n%s", query, w, body)
98 }
99 }
100 }
101 if body := get(t, h, "/signin?sent=1").Body.String(); strings.Contains(body, "estilo-signin-form") {
102 t.Error("/signin?sent=1 still draws the form; the check-your-email card replaces it")
103 }
104 for _, query := range []string{"sent=1", "err=expired&sent=1"} {
105 body := get(t, h, "/signin?"+query).Body.String()
106 for _, gone := range []string{"expires shortly", "Send another link"} {
107 if strings.Contains(body, gone) {
108 t.Errorf("/signin?%s still says %q", query, gone)
109 }
110 }
111 }
112}
113