oficina / estilo Public

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

Plain git — no account needed to clone.

Download

Download this file

1package chrome
2
3import (
4 "html/template"
5 "strings"
6 "testing"
7 "time"
8)
9
10// The door's copy is the suite's one copy set (shared-chrome spec §9.2,
11// with Paul's 2026-10-01 ruling that the submit reads "Sign in"). Pinned
12// word for word: a change here is a copy decision, made on purpose, in one
13// place.
14func TestDoorCopyIsPinned(t *testing.T) {
15 if LinkLifetime != 15*time.Minute {
16 t.Fatalf("LinkLifetime = %v; the copy below says 15 minutes", LinkLifetime)
17 }
18 for _, c := range []struct{ name, got, want string }{
19 {"Heading", English.Heading, "Sign in"},
20 {"AddressLabel", English.AddressLabel, "Email address"},
21 {"Help", English.Help, "We’ll email you a link that signs you in. It works once and expires in 15 minutes."},
22 {"Submit", English.Submit, "Sign in"},
23 {"SentHeading", English.SentHeading, "Check your email"},
24 {"SentBody", English.SentBody, "If that address can sign in here, we’ve sent it a link. It works once and expires in 15 minutes."},
25 {"Again", English.Again, "Use a different address"},
26 {"SignedOutPage", English.SignedOutPage, "Signed out"},
27 {"SignedOutHeading", English.SignedOutHeading, "You’re signed out"},
28 {"SignedOutBody", English.signedOutBody("Calls"), "You’ve signed out of Calls on this device."},
29 {"SignIn", English.SignIn, "Sign in"},
30 } {
31 if c.got != c.want {
32 t.Errorf("%s = %q, want %q", c.name, c.got, c.want)
33 }
34 }
35 for _, retired := range []string{"Email me a link", "Continue", "expires shortly", "on its way", "Back to sign in", "Send another link", "Use a different email address", "You are signed out", "Home"} {
36 for _, s := range []string{English.Heading, English.Help, English.Submit, English.SentHeading, English.SentBody, English.Again, English.SignedOutHeading, English.signedOutBody("Docs"), English.SignIn} {
37 if strings.Contains(s, retired) {
38 t.Errorf("%q carries retired copy %q", s, retired)
39 }
40 }
41 }
42}
43
44// Every door page's tab title is "<Page> · <App>" (shared-chrome spec §10).
45func TestDoorTitles(t *testing.T) {
46 for _, c := range []struct{ got, want string }{
47 {Title("Sign in", "Docs"), "Sign in · Docs"},
48 {Title("Sign in", ""), "Sign in"},
49 {Title("", "Docs"), "Docs"},
50 {SignIn{App: "Memoria"}.Title(), "Sign in · Memoria"},
51 {SignIn{App: "Memoria"}.Page(), "Sign in"},
52 {SignInNotice{App: "Calendar"}.Sent("/signin").Title(), "Check your email · Calendar"},
53 {SignInNotice{App: "Calendar"}.Sent("/signin").Page(), "Check your email"},
54 {SignInNotice{App: "Calls"}.SignedOut("/signin").Title(), "Signed out · Calls"},
55 {SignInNotice{App: "Calls"}.SignedOut("/signin").Page(), "Signed out"},
56 // A notice that is not one of the door's own is titled by its heading.
57 {SignInNotice{App: "Sheets", Heading: "Continue signing in"}.Title(), "Continue signing in · Sheets"},
58 } {
59 if c.got != c.want {
60 t.Errorf("title %q, want %q", c.got, c.want)
61 }
62 }
63}
64
65// The templates draw the door's copy when the app supplies none: the app
66// passes its name, mark, sky and destinations, and nothing else.
67func TestTheDoorDrawsItsOwnCopy(t *testing.T) {
68 html := render(t, "estilo-signin", SignIn{Icon: "/i.svg", App: "Calls", Action: "/signin"})
69 for _, want := range []string{
70 "<h1>Sign in</h1>",
71 ">Email address</label>",
72 "We’ll email you a link that signs you in. It works once and expires in 15 minutes.",
73 `<button rst-btn="primary" type="submit">Sign in</button>`,
74 } {
75 if !strings.Contains(html, want) {
76 t.Errorf("sign-in lacks %q:\n%s", want, html)
77 }
78 }
79 if strings.Contains(html, "Email me a link") {
80 t.Error("the door's submit must never read “Email me a link”")
81 }
82
83 html = render(t, "estilo-signin-sent", SignInNotice{Icon: "/i.svg", App: "Calls"}.Sent("/signin?return_to=%2Fm%2Fabc"))
84 for _, want := range []string{
85 "<h1>Check your email</h1>",
86 `<p estilo-signin-body role="status">If that address can sign in here, we’ve sent it a link. It works once and expires in 15 minutes.</p>`,
87 `<a href="/signin?return_to=%2Fm%2Fabc">Use a different address</a>`,
88 } {
89 if !strings.Contains(html, want) {
90 t.Errorf("sent lacks %q:\n%s", want, html)
91 }
92 }
93
94 html = render(t, "estilo-signed-out", SignInNotice{Icon: "/i.svg", App: "Calls"}.SignedOut("/signin"))
95 for _, want := range []string{
96 "<h1>You’re signed out</h1>",
97 "<p estilo-signin-body>You’ve signed out of Calls on this device.</p>",
98 `<a rst-btn="primary" href="/signin">Sign in</a>`,
99 } {
100 if !strings.Contains(html, want) {
101 t.Errorf("signed-out lacks %q:\n%s", want, html)
102 }
103 }
104}
105
106// The sign-in email names the app and says the true lifetime, the same
107// words as the door (shared-chrome spec §9.2).
108func TestSignInEmail(t *testing.T) {
109 subject, body := SignInEmail("Docs", "https://docs.example/auth/verify?token=x")
110 if subject != "Sign in to Docs" {
111 t.Errorf("subject %q", subject)
112 }
113 want := "Here’s your link to sign in to Docs:\n\nhttps://docs.example/auth/verify?token=x\n\nIt works once and expires in 15 minutes. If you didn’t ask for it, you can ignore this email."
114 if body != want {
115 t.Errorf("body %q\nwant %q", body, want)
116 }
117 if got := EmailBody("Docs")("L"); !strings.Contains(got, "\n\nL\n\n") {
118 t.Errorf("EmailBody does not place the link: %q", got)
119 }
120}
121
122// A locale other than English replaces every word through Copy.
123func TestDoorCopyIsReplaceablePerLocale(t *testing.T) {
124 for locale, label := range locales {
125 t.Run(locale, func(t *testing.T) {
126 esc := template.HTMLEscapeString
127 c := &DoorCopy{Heading: label + "-h", AddressLabel: label + "-addr", Help: label + "-help", Submit: label + "-submit", SentHeading: label + "-sent", SentBody: label + "-sentbody", Again: label + "-again", SignedOutPage: label + "-outpage", SignedOutHeading: label + "-out", SignedOutBody: label + " {app}-outbody", SignIn: label + "-in"}
128 html := render(t, "estilo-signin", SignIn{Icon: "/i.svg", App: "Docs", Copy: c, Action: "/signin"})
129 for _, want := range []string{"<h1>" + esc(label) + "-h</h1>", esc(label) + "-addr", esc(label) + "-help", esc(label) + "-submit"} {
130 if !strings.Contains(html, want) {
131 t.Fatalf("missing %q in %s", want, html)
132 }
133 }
134 n := SignInNotice{Icon: "/i.svg", App: "Docs", Copy: c}
135 if h := render(t, "estilo-signin-sent", n.Sent("/signin")); !strings.Contains(h, esc(label)+"-sentbody") || !strings.Contains(h, esc(label)+"-again") {
136 t.Fatal("sent", h)
137 }
138 if h := render(t, "estilo-signed-out", n.SignedOut("/signin")); !strings.Contains(h, esc(label)+" Docs-outbody") || !strings.Contains(h, esc(label)+"-in") {
139 t.Fatal("signed out", h)
140 }
141 if got := n.SignedOut("/signin").Title(); got != label+"-outpage · Docs" {
142 t.Fatalf("title %q", got)
143 }
144 })
145 }
146}
147
148// The copy's slots are tokens, {app} and {link}, not Printf verbs: a
149// translation that drops the slot, moves it, or carries a literal "%"
150// renders as written rather than as "%!(EXTRA …)" (Fable on estilo #19,
151// finding 4).
152func TestDoorCopyFillsTokensNotFormats(t *testing.T) {
153 c := English
154 c.SignedOutBody = "100% done: {app} is signed out here."
155 if got := (SignInNotice{App: "Docs", Copy: &c}).SignedOut("/signin").Body; got != "100% done: Docs is signed out here." {
156 t.Errorf("signed-out body %q", got)
157 }
158 c.SignedOutBody = "Signed out."
159 if got := (SignInNotice{App: "Docs", Copy: &c}).SignedOut("/signin").Body; got != "Signed out." {
160 t.Errorf("a body without {app} rendered %q", got)
161 }
162 // With no app, the suite is named, as the hub's own page does.
163 if got := (SignInNotice{}).SignedOut("/signin").Body; got != "You’ve signed out of Oficina on this device." {
164 t.Errorf("no-app signed-out body %q", got)
165 }
166 // The link is substituted once: a link that happens to carry "{app}"
167 // is not rewritten.
168 if _, body := English.SignInEmail("Docs", "https://x.example/?q={app}"); !strings.Contains(body, "\n\nhttps://x.example/?q={app}\n\n") {
169 t.Errorf("the link was rewritten: %q", body)
170 }
171}
172
173// The email is part of the copy set: a locale's subject and body are what
174// a locale's email says (Fable on estilo #19, finding 3), and the package
175// helpers are English's.
176func TestSignInEmailReadsTheCopy(t *testing.T) {
177 c := English
178 c.EmailSubject = "Entra en {app}"
179 c.EmailBody = "{app}: {link} (100%)"
180 subject, body := c.SignInEmail("Docs", "L")
181 if subject != "Entra en Docs" || body != "Docs: L (100%)" {
182 t.Errorf("locale email = %q, %q", subject, body)
183 }
184 if got := c.MailSubject("Docs"); got != "Entra en Docs" {
185 t.Errorf("MailSubject %q", got)
186 }
187 if got := c.MailBody("Docs")("L"); got != "Docs: L (100%)" {
188 t.Errorf("MailBody %q", got)
189 }
190 s, b := SignInEmail("Docs", "L")
191 if es, eb := English.SignInEmail("Docs", "L"); s != es || b != eb || EmailSubject("Docs") != es || EmailBody("Docs")("L") != eb {
192 t.Error("the package helpers are not English's email")
193 }
194}
195