internal/httpd/reactions_test.go

v1.41.0
gitbay/internal/httpd/reactions_test.go history · blame · raw

106 lines · 3494 bytes

  1package httpd
  2
  3import (
  4	"net/http"
  5	"net/http/httptest"
  6	"net/url"
  7	"strings"
  8	"testing"
  9
 10	"gitbay.org/gitbay/internal/config"
 11	"gitbay.org/gitbay/internal/store"
 12)
 13
 14func reactServer(t *testing.T) (*Server, *store.Store, store.User, store.User) {
 15	t.Helper()
 16	st, err := store.Open(":memory:")
 17	if err != nil {
 18		t.Fatal(err)
 19	}
 20	t.Cleanup(func() { st.Close() })
 21	if err := st.MigrateUp(); err != nil {
 22		t.Fatal(err)
 23	}
 24	aid, _ := st.CreateUser("alice", false)
 25	bid, _ := st.CreateUser("bob", false)
 26	rid, err := st.CreateRepo("user", aid, "app", "public")
 27	if err != nil {
 28		t.Fatal(err)
 29	}
 30	n, _ := st.CreateIssue(rid, aid, "bug", "body", "md")
 31	iss, _ := st.IssueByNumber(rid, n)
 32	st.AddIssueComment(iss.ID, aid, "a comment", "md")
 33	cfg := config.Default()
 34	cfg.Web.Mode = "accounts"
 35	return New(cfg, st, nil), st, store.User{ID: aid, Username: "alice"}, store.User{ID: bid, Username: "bob"}
 36}
 37
 38func issueReq(method, target string, form url.Values) *http.Request {
 39	var r *http.Request
 40	if form != nil {
 41		r = httptest.NewRequest(method, target, strings.NewReader(form.Encode()))
 42		r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 43	} else {
 44		r = httptest.NewRequest(method, target, nil)
 45	}
 46	r.SetPathValue("owner", "alice")
 47	r.SetPathValue("repo", "app")
 48	r.SetPathValue("n", "1")
 49	return r
 50}
 51
 52func TestIssueReactionsOnPage(t *testing.T) {
 53	s, st, _, bob := reactServer(t)
 54
 55	// Bob reacts to the body and to the comment through the form.
 56	for _, form := range []url.Values{
 57		{"add": {"+1"}},
 58		{"add": {"rocket"}, "comment": {"1"}},
 59	} {
 60		rr := httptest.NewRecorder()
 61		s.issueReactSubmit(rr, issueReq("POST", "/alice/app/issues/1/react", form), bob)
 62		if rr.Code != http.StatusSeeOther {
 63			t.Fatalf("%v: status %d: %s", form, rr.Code, rr.Body)
 64		}
 65	}
 66
 67	// Signed in: a button for every reaction, his own marked pressed.
 68	req := issueReq("GET", "/alice/app/issues/1", nil)
 69	req.AddCookie(sessionCookieFor(t, s, st, bob.ID))
 70	rr := httptest.NewRecorder()
 71	s.issue(rr, req)
 72	body := rr.Body.String()
 73	if n := strings.Count(body, `class="react"`) + strings.Count(body, `class="react mine"`); n != 16 {
 74		t.Errorf("%d reaction buttons, want 16 (8 on the body, 8 on the comment)", n)
 75	}
 76	if !strings.Contains(body, `name="remove" value="+1" class="react mine" aria-pressed="true"`) {
 77		t.Errorf("own reaction not marked:\n%s", body)
 78	}
 79	if !strings.Contains(body, `name="add" value="eyes"`) || !strings.Contains(body, `<input type="hidden" name="comment" value="1">`) {
 80		t.Error("add buttons or comment field missing")
 81	}
 82
 83	// Signed out: counts only, no forms or buttons.
 84	rr = httptest.NewRecorder()
 85	s.issue(rr, issueReq("GET", "/alice/app/issues/1", nil))
 86	body = rr.Body.String()
 87	if strings.Contains(body, `class="react"`) && strings.Contains(body, "<button type=\"submit\" name=\"add\"") {
 88		t.Error("buttons shown to a signed-out viewer")
 89	}
 90	if strings.Contains(body, `/react"`) {
 91		t.Error("react form shown to a signed-out viewer")
 92	}
 93	if n := strings.Count(body, `<span class="react"`); n != 2 {
 94		t.Errorf("%d counts, want 2:\n%s", n, body)
 95	}
 96	if !strings.Contains(body, "👍 1") || !strings.Contains(body, "🚀 1") {
 97		t.Error("counts missing")
 98	}
 99
100	// Pressing a pressed button takes it back.
101	rr = httptest.NewRecorder()
102	s.issueReactSubmit(rr, issueReq("POST", "/alice/app/issues/1/react", url.Values{"remove": {"+1"}}), bob)
103	if got, _ := st.ReactionCounts("issue", 1, bob.ID); len(got[0]) != 0 {
104		t.Errorf("reaction not removed: %+v", got)
105	}
106}