e2e/forkweb_test.go

8dcfa45a8ac03a5ff9c36828274d05acadcf846c
gitbay/e2e/forkweb_test.go history · blame · raw

102 lines · 4421 bytes

  1package e2e
  2
  3import (
  4	"net/url"
  5	"os"
  6	"path/filepath"
  7	"strings"
  8	"testing"
  9)
 10
 11// Forking from the browser completes the contributor path: fork, edit a
 12// file in the fork, open the merge request against the parent, without a
 13// terminal at any step (#174).
 14func TestForkWeb(t *testing.T) {
 15	t.Parallel()
 16	inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n")
 17	aliceKey := inst.newKey(t, "alice")
 18	bobKey := inst.newKey(t, "bob")
 19	inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub",
 20		"--email", "alice@example.test", "--verified")
 21	inst.admin(t, "admin", "user", "create", "bob", "--key", bobKey+".pub",
 22		"--email", "bob@example.test", "--verified")
 23
 24	if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/app"); code != 0 {
 25		t.Fatalf("repo create: %s", errOut)
 26	}
 27	env := inst.gitEnv(aliceKey)
 28	work := t.TempDir()
 29	mustGit(t, work, env, "clone", inst.sshURL("alice/app"), "w")
 30	dir := filepath.Join(work, "w")
 31	os.WriteFile(filepath.Join(dir, "f.txt"), []byte("x\n"), 0o644)
 32	mustGit(t, dir, env, "checkout", "-q", "-b", "main")
 33	mustGit(t, dir, env, "add", ".")
 34	mustGit(t, dir, env, "commit", "-q", "-m", "base")
 35	mustGit(t, dir, env, "push", "-q", "origin", "main")
 36
 37	bob := inst.login(t, bobKey)
 38	base := inst.base() + "/alice/app"
 39
 40	// The control is on the repository header for a signed-in visitor.
 41	if _, page := browserGet(t, bob, base); !strings.Contains(page, `/alice/app/fork"`) {
 42		t.Fatalf("no fork control on the repository header:\n%s", page)
 43	}
 44
 45	// Forking lands on the fork, which carries the parent's history.
 46	if status, body := browserPost(t, bob, base+"/fork", url.Values{}); status != 200 ||
 47		!strings.Contains(body, "bob/app") {
 48		t.Fatalf("fork did not land on the new repository: %d\n%s", status, body)
 49	}
 50	out, _, _ := inst.ssh(t, bobKey, "", "repo", "list", "--json")
 51	if !strings.Contains(out, `"path":"bob/app"`) {
 52		t.Fatalf("fork not created:\n%s", out)
 53	}
 54
 55	// Editing a file in the fork from the browser — the editor commits to
 56	// the ref in the URL — then proposing it to the parent through the
 57	// source picker.
 58	if status, _ := browserPost(t, bob, inst.base()+"/bob/app/edit/main/f.txt", url.Values{
 59		"content": {"y\n"}, "message": {"change f"}}); status != 200 {
 60		t.Fatal("web edit in the fork failed")
 61	}
 62	if _, page := browserGet(t, bob, base+"/mrs/new"); !strings.Contains(page, `value="bob/app:main"`) {
 63		t.Fatalf("the fork's branch is not offered:\n%s", page)
 64	}
 65	if status, _ := browserPost(t, bob, base+"/mrs/new", url.Values{
 66		"source": {"bob/app:main"}, "target": {"main"}, "title": {"change"}}); status != 200 {
 67		t.Fatal("mr create from the fork failed")
 68	}
 69	if out, _, _ := inst.ssh(t, aliceKey, "", "mr", "show", "alice/app", "1", "--json"); !strings.Contains(out, `"source":"bob/app:main"`) {
 70		t.Fatalf("merge request not opened from the fork:\n%s", out)
 71	}
 72
 73	// Forking twice collides on the name, and says so on the form rather
 74	// than failing silently.
 75	_, body := browserPost(t, bob, base+"/fork", url.Values{})
 76	if !strings.Contains(body, `class="error"`) {
 77		t.Errorf("a second fork reported nothing:\n%s", body)
 78	}
 79
 80	// A fork can land in an organization the forker administers, under a
 81	// name of its own — which is also how you fork the same repository
 82	// twice.
 83	inst.ssh(t, bobKey, "", "org", "create", "bobco")
 84	if _, page := browserGet(t, bob, base+"/fork"); !strings.Contains(page, `<option value="bobco"`) {
 85		t.Fatalf("the fork form does not offer the organization:\n%s", page)
 86	}
 87	if status, body := browserPost(t, bob, base+"/fork", url.Values{
 88		"owner": {"bobco"}, "name": {"app2"}}); status != 200 || !strings.Contains(body, "bobco/app2") {
 89		t.Fatalf("fork into the organization did not land: %d\n%s", status, body)
 90	}
 91	if out, _, _ := inst.ssh(t, bobKey, "", "repo", "show", "bobco/app2", "--json"); !strings.Contains(out, `"fork_of":"alice/app"`) {
 92		t.Fatalf("the organization's fork does not name its parent:\n%s", out)
 93	}
 94
 95	// An organization you are only a member of is not somewhere you can
 96	// put one: the owner is checked as it is on repo create.
 97	inst.ssh(t, aliceKey, "", "org", "create", "aliceco")
 98	inst.ssh(t, aliceKey, "", "org", "members", "add", "aliceco", "bob")
 99	if _, _, code := inst.ssh(t, bobKey, "", "repo", "fork", "alice/app", "--owner", "aliceco"); code != 4 {
100		t.Errorf("fork into an org bob does not administer exited %d, want 4", code)
101	}
102}