e2e/previewweb_test.go

bd5cf5d7d1f34fa780660fd7562b9ffd9746ee27
gitbay/e2e/previewweb_test.go history · blame · raw

162 lines · 7024 bytes

  1package e2e
  2
  3import (
  4	"net/url"
  5	"os"
  6	"path/filepath"
  7	"strings"
  8	"testing"
  9)
 10
 11// Every markup form has a Preview button that renders the draft above
 12// the textarea and writes nothing (#235). The forms are: issue and MR
 13// create, their edit and comment boxes, release create and edit, the
 14// profile about text, and the file editor on a path the forge renders.
 15func TestMarkupPreviewWeb(t *testing.T) {
 16	t.Parallel()
 17	inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n")
 18	aliceKey := inst.newKey(t, "alice")
 19	inst.admin(t, "admin", "user", "create", "alice",
 20		"--key", aliceKey+".pub", "--email", "alice@example.test", "--verified")
 21	if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/app"); code != 0 {
 22		t.Fatalf("repo create: %s", errOut)
 23	}
 24	env := inst.gitEnv(aliceKey)
 25	work := t.TempDir()
 26	mustGit(t, work, env, "clone", inst.sshURL("alice/app"), "w")
 27	dir := filepath.Join(work, "w")
 28	mustGit(t, dir, env, "checkout", "-q", "-b", "main")
 29	os.WriteFile(filepath.Join(dir, "README.md"), []byte("# hi\n"), 0o644)
 30	os.WriteFile(filepath.Join(dir, "a.txt"), []byte("a\n"), 0o644)
 31	mustGit(t, dir, env, "add", ".")
 32	mustGit(t, dir, env, "commit", "-q", "-m", "base")
 33	mustGit(t, dir, env, "push", "-q", "origin", "main")
 34	mustGit(t, dir, env, "checkout", "-q", "-b", "topic")
 35	os.WriteFile(filepath.Join(dir, "b.txt"), []byte("b\n"), 0o644)
 36	mustGit(t, dir, env, "add", ".")
 37	mustGit(t, dir, env, "commit", "-q", "-m", "topic")
 38	mustGit(t, dir, env, "push", "-q", "origin", "topic")
 39	mustGit(t, dir, env, "tag", "v1")
 40	mustGit(t, dir, env, "push", "-q", "origin", "v1")
 41
 42	alice := inst.login(t, aliceKey)
 43	base := inst.base() + "/alice/app"
 44
 45	post := func(where string, v url.Values) string {
 46		t.Helper()
 47		status, body := browserPost(t, alice, where, v)
 48		if status != 200 {
 49			t.Fatalf("post %s %v: %d", where, v, status)
 50		}
 51		return body
 52	}
 53	// previewed asserts the rendering is on the page and the draft came
 54	// back with it.
 55	previewed := func(what, body, want, kept string) {
 56		t.Helper()
 57		if !strings.Contains(body, `<p class="previewmark">Preview</p>`) {
 58			t.Fatalf("%s: no preview block:\n%s", what, body)
 59		}
 60		if !strings.Contains(body, want) {
 61			t.Fatalf("%s: preview does not contain %q:\n%s", what, want, body)
 62		}
 63		if kept != "" && !strings.Contains(body, kept) {
 64			t.Fatalf("%s: form lost %q:\n%s", what, kept, body)
 65		}
 66	}
 67
 68	// Issue create: markdown renders, and the title and labels survive.
 69	b := post(base+"/issues/new", url.Values{
 70		"title": {"draft title"}, "body": {"# heading\n"}, "labels": {"bug"},
 71		"format": {"md"}, "preview": {"1"},
 72	})
 73	previewed("issue create", b, "<h1", `value="draft title"`)
 74	if !strings.Contains(b, `value="bug"`) {
 75		t.Fatalf("issue create preview lost the labels:\n%s", b)
 76	}
 77	// Nothing was opened.
 78	if out, _, _ := inst.ssh(t, aliceKey, "", "issue", "list", "alice/app", "--json"); strings.Contains(out, "draft title") {
 79		t.Fatalf("preview created an issue: %s", out)
 80	}
 81
 82	// The org choice previews as org, not markdown.
 83	b = post(base+"/issues/new", url.Values{
 84		"title": {"t"}, "body": {"Some /emphasis/ here.\n"}, "format": {"org"}, "preview": {"1"},
 85	})
 86	previewed("issue create org", b, "<em>emphasis</em>", `<option value="org" selected>`)
 87
 88	// A real issue, then its comment and edit boxes.
 89	if _, errOut, code := inst.ssh(t, aliceKey, "", "issue", "create", "alice/app", "--title", "real", "--body", "body"); code != 0 {
 90		t.Fatalf("issue create: %s", errOut)
 91	}
 92	b = post(base+"/issues/1/comment", url.Values{"body": {"a **bold** remark"}, "preview": {"1"}})
 93	previewed("issue comment", b, "<strong>bold</strong>", "a **bold** remark")
 94	b = post(base+"/issues/1/edit", url.Values{
 95		"title": {"real"}, "body": {"## edited"}, "preview": {"1"},
 96	})
 97	previewed("issue edit", b, "<h2", "## edited")
 98	if !strings.Contains(b, `<details class="editbox" open>`) {
 99		t.Fatalf("issue edit preview left the box shut:\n%s", b)
100	}
101	// Neither wrote: one comment would show in the thread, an edit in the body.
102	if out, _, _ := inst.ssh(t, aliceKey, "", "issue", "show", "alice/app", "1", "--json"); strings.Contains(out, "bold") || strings.Contains(out, "edited") {
103		t.Fatalf("preview wrote to the issue: %s", out)
104	}
105
106	// MR create, comment and edit.
107	b = post(base+"/mrs/new", url.Values{
108		"source": {"topic"}, "target": {"main"}, "title": {"mr draft"},
109		"body": {"# mr heading"}, "format": {"md"}, "preview": {"1"},
110	})
111	previewed("mr create", b, "<h1", `value="mr draft"`)
112	if out, _, _ := inst.ssh(t, aliceKey, "", "mr", "list", "alice/app", "--json"); strings.Contains(out, "mr draft") {
113		t.Fatalf("preview opened a merge request: %s", out)
114	}
115	if _, errOut, code := inst.ssh(t, aliceKey, "", "mr", "create", "alice/app",
116		"--source", "topic", "--target", "main", "--title", "'real mr'"); code != 0 {
117		t.Fatalf("mr create: %s", errOut)
118	}
119	b = post(base+"/mrs/1/comment", url.Values{"body": {"a `code` remark"}, "preview": {"1"}})
120	previewed("mr comment", b, "<code>code</code>", "a `code` remark")
121	b = post(base+"/mrs/1/edit", url.Values{"title": {"real mr"}, "body": {"## mr edited"}, "preview": {"1"}})
122	previewed("mr edit", b, "<h2", "## mr edited")
123
124	// Release create, then edit.
125	b = post(base+"/releases", url.Values{
126		"tag": {"v1"}, "title": {"first"}, "notes": {"* a bullet"}, "preview": {"1"},
127	})
128	previewed("release create", b, "<li>", "* a bullet")
129	if out, _, _ := inst.ssh(t, aliceKey, "", "release", "list", "alice/app", "--json"); strings.Contains(out, "first") {
130		t.Fatalf("preview created a release: %s", out)
131	}
132	if _, errOut, code := inst.ssh(t, aliceKey, "", "release", "create", "alice/app", "v1", "--title", "first"); code != 0 {
133		t.Fatalf("release create: %s", errOut)
134	}
135	b = post(base+"/releases", url.Values{
136		"action": {"edit"}, "tag": {"v1"}, "title": {"first"},
137		"notes": {"## release notes"}, "preview": {"1"},
138	})
139	previewed("release edit", b, "<h2", "## release notes")
140
141	// The profile form takes no markup: the about text is a file, and the
142	// file editor below is what previews it.
143	if _, body := browserGet(t, alice, inst.base()+"/settings"); strings.Contains(body, `name="preview"`) {
144		t.Fatalf("the profile form offers a preview:\n%s", body)
145	}
146
147	// The file editor previews a rendered path and offers nothing on one
148	// it does not render.
149	b = post(base+"/edit/main/README.md", url.Values{
150		"content": {"# from the editor"}, "message": {"kept message"}, "preview": {"1"},
151	})
152	previewed("file editor", b, "from the editor", `value="kept message"`)
153	if _, body := browserGet(t, alice, base+"/blob/main/README.md"); strings.Contains(body, "from the editor") {
154		t.Fatalf("preview committed the file:\n%s", body)
155	}
156	if _, body := browserGet(t, alice, base+"/edit/main/a.txt"); strings.Contains(body, `name="preview"`) {
157		t.Fatalf("a plain text file offers a preview:\n%s", body)
158	}
159	if _, body := browserGet(t, alice, base+"/edit/main/README.md"); !strings.Contains(body, `name="preview"`) {
160		t.Fatalf("no preview button on a markdown file:\n%s", body)
161	}
162}