e2e/profileweb_test.go
138 lines · 5252 bytes
1package e2e
2
3import (
4 "net/url"
5 "strings"
6 "testing"
7)
8
9// TestProfileSettingsWeb covers profile set from the account settings page
10// (#161): description, website and links round-trip through the form, and
11// emptying a field actually clears it rather than being skipped. The about
12// text is not on this form — it is a file, covered below.
13func TestProfileSettingsWeb(t *testing.T) {
14 t.Parallel()
15 inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n")
16 aliceKey := inst.newKey(t, "alice")
17 inst.admin(t, "admin", "user", "create", "alice",
18 "--key", aliceKey+".pub", "--email", "alice@example.test", "--verified")
19 alice := inst.login(t, aliceKey)
20 settingsURL := inst.base() + "/settings"
21
22 // The form is on the page, every input labelled.
23 _, body := browserGet(t, alice, settingsURL)
24 for _, want := range []string{
25 `<label for="p-description">`, `<label for="p-website">`,
26 `<label for="p-links">`,
27 } {
28 if !strings.Contains(body, want) {
29 t.Fatalf("profile form missing %q:\n%s", want, body)
30 }
31 }
32
33 // Setting every field lands where the CLI reads it.
34 status, _ := browserPost(t, alice, settingsURL, url.Values{
35 "field": {"profile"},
36 "description": {"builds small tools"},
37 "website": {"https://alice.example"},
38 "links": {"Mastodon|https://fosstodon.example/@alice\nhttps://alice.example/now"},
39 })
40 if status != 200 && status != 303 {
41 t.Fatalf("profile post: %d", status)
42 }
43 out, _, _ := inst.ssh(t, aliceKey, "", "profile", "show", "--json")
44 for _, want := range []string{
45 `"description":"builds small tools"`, `"website":"https://alice.example"`,
46 `"label":"Mastodon"`, `"url":"https://fosstodon.example/@alice"`,
47 `"url":"https://alice.example/now"`,
48 } {
49 if !strings.Contains(out, want) {
50 t.Fatalf("profile set missing %q: %s", want, out)
51 }
52 }
53
54 // The page shows what was just saved.
55 _, body = browserGet(t, alice, settingsURL)
56 for _, want := range []string{
57 "builds small tools", "https://alice.example", "Mastodon|https://fosstodon.example/@alice",
58 "https://alice.example/now",
59 } {
60 if !strings.Contains(body, want) {
61 t.Fatalf("settings page did not round-trip %q:\n%s", want, body)
62 }
63 }
64
65 // The whole form resubmits every time, the way a settings page does:
66 // each step below carries the fields already in place and changes one.
67 links := "Mastodon|https://fosstodon.example/@alice\nhttps://alice.example/now"
68
69 // Emptying the website clears it, not leaves it alone.
70 if status, _ := browserPost(t, alice, settingsURL, url.Values{
71 "field": {"profile"}, "description": {"builds small tools"},
72 "website": {""}, "links": {links},
73 }); status != 200 && status != 303 {
74 t.Fatalf("profile post (clear website): %d", status)
75 }
76 out, _, _ = inst.ssh(t, aliceKey, "", "profile", "show", "--json")
77 if strings.Contains(out, "alice.example") && strings.Contains(out, `"website"`) {
78 t.Fatalf("website not cleared: %s", out)
79 }
80 if !strings.Contains(out, "builds small tools") {
81 t.Fatalf("clearing website clobbered the description: %s", out)
82 }
83 if !strings.Contains(out, `"label":"Mastodon"`) {
84 t.Fatalf("clearing website clobbered the links: %s", out)
85 }
86
87 // Emptying the links field clears the whole list.
88 if status, _ := browserPost(t, alice, settingsURL, url.Values{
89 "field": {"profile"}, "description": {"builds small tools"}, "links": {""},
90 }); status != 200 && status != 303 {
91 t.Fatalf("profile post (clear links): %d", status)
92 }
93 out, _, _ = inst.ssh(t, aliceKey, "", "profile", "show", "--json")
94 if strings.Contains(out, "Mastodon") || strings.Contains(out, `"links"`) {
95 t.Fatalf("links not cleared: %s", out)
96 }
97}
98
99// The settings page does not edit the about text; it creates the
100// repository that holds it and points at the file editor.
101func TestProfileAboutRepoFromWeb(t *testing.T) {
102 t.Parallel()
103 inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n")
104 aliceKey := inst.newKey(t, "alice")
105 inst.admin(t, "admin", "user", "create", "alice",
106 "--key", aliceKey+".pub", "--email", "alice@example.test", "--verified")
107 alice := inst.login(t, aliceKey)
108 settingsURL := inst.base() + "/settings"
109
110 // With no repository yet, the page offers to create one.
111 _, body := browserGet(t, alice, settingsURL)
112 if !strings.Contains(body, "Create alice/.gitbay") {
113 t.Fatalf("settings page does not offer the profile repository:\n%s", body)
114 }
115
116 if status, _ := browserPost(t, alice, settingsURL, url.Values{
117 "field": {"profile-repo"},
118 }); status != 200 && status != 303 {
119 t.Fatalf("profile-repo post: %d", status)
120 }
121
122 // The repository exists with a starter file, and the page now links to
123 // the editor instead of offering to create it again.
124 out, _, code := inst.ssh(t, aliceKey, "", "profile", "show", "alice", "--json")
125 if code != 0 {
126 t.Fatalf("profile show: %d", code)
127 }
128 if !strings.Contains(out, `"about_path":"profile/README.md"`) {
129 t.Fatalf("starter about not committed: %s", out)
130 }
131 _, body = browserGet(t, alice, settingsURL)
132 if !strings.Contains(body, "/alice/.gitbay/edit/main/profile/README.md") {
133 t.Fatalf("settings page does not link to the about file:\n%s", body)
134 }
135 if strings.Contains(body, "Create alice/.gitbay") {
136 t.Error("settings page still offers to create an existing repository")
137 }
138}