internal/httpd/mrpage_test.go
105 lines · 3481 bytes
1package httpd
2
3import (
4 "html/template"
5 "strings"
6 "testing"
7 "time"
8
9 "gitbay.org/gitbay/internal/gitutil"
10 "gitbay.org/gitbay/internal/store"
11 "gitbay.org/gitbay/internal/web"
12)
13
14// mrPageData mirrors the anonymous struct the mr handler renders with.
15type mrPageData struct {
16 repoPage
17 MR store.MR
18 View string
19 BodyHTML template.HTML
20 Checks []store.Check
21 Combined string
22 Comments []renderedComment
23 Reviews []store.MRReview
24 DiffFiles []diffFile
25 Stat diffStat
26 Commits []struct{}
27 Branches []gitutil.Ref
28 CanEdit bool
29 CanWrite bool
30 Unresolved int
31 Revisions []store.MRHead
32 Notice string
33 DetachedThreads []diffThread
34}
35
36func renderMR(t *testing.T, m store.MR, reviews []store.MRReview, checks []store.Check) string {
37 t.Helper()
38 var sb strings.Builder
39 if err := web.Render(&sb, "mr.html", mrPageData{
40 repoPage: testRepoPage(), MR: m, View: "conversation",
41 Reviews: reviews, Checks: checks, Combined: "",
42 }); err != nil {
43 t.Fatalf("render: %v", err)
44 }
45 return sb.String()
46}
47
48func testMR(state string) store.MR {
49 return store.MR{Number: 42, Title: "org native rendering", Author: "cmc", State: state,
50 SourcePath: "krz/hutch", SourceRef: "org-native-rendering", TargetRef: "main",
51 HeadSHA: "ff6271a9d4570cd46f169091637a9d2e40ad5c2b"}
52}
53
54// The header states what happened to the MR. "wants to merge" is only true
55// while it is still open.
56func TestMRHeaderByState(t *testing.T) {
57 open := renderMR(t, testMR("open"), nil, nil)
58 if !strings.Contains(open, "wants to merge") {
59 t.Errorf("open MR does not say wants to merge:\n%s", open)
60 }
61
62 merged := testMR("merged")
63 merged.MergedAt, merged.MergedBy = "2026-08-27T14:03:11.000Z", "cmc"
64 out := renderMR(t, merged, nil, nil)
65 for _, want := range []string{"merged", "krz/hutch:org-native-rendering", "2026-08-27 14:03"} {
66 if !strings.Contains(out, want) {
67 t.Errorf("merged header missing %q:\n%s", want, out)
68 }
69 }
70 if strings.Contains(out, "wants to merge") {
71 t.Errorf("merged MR still wants to merge:\n%s", out)
72 }
73
74 closed := testMR("closed")
75 closed.ClosedAt, closed.ClosedBy = "2026-08-27T14:03:11.000Z", "cmc"
76 out = renderMR(t, closed, nil, nil)
77 if !strings.Contains(out, "without merging") || strings.Contains(out, "wants to merge") {
78 t.Errorf("closed header:\n%s", out)
79 }
80
81 // Imports and pre-0029 merges carry no stamp; the wording drops the
82 // claim rather than inventing a time.
83 out = renderMR(t, testMR("merged"), nil, nil)
84 if strings.Contains(out, "wants to merge") || strings.Contains(out, " on 20") {
85 t.Errorf("unstamped merged header:\n%s", out)
86 }
87}
88
89// Approvals and checks carry their times in the aside, so reading the MR
90// does not mean opening the build.
91func TestMRAsideTimestamps(t *testing.T) {
92 out := renderMR(t, testMR("open"),
93 []store.MRReview{{Reviewer: "cmc", Verdict: "approve", CreatedAt: "2026-08-27T14:03:11.000Z"}},
94 []store.Check{
95 {CommitStatus: store.CommitStatus{Context: "ci/test", State: "success",
96 UpdatedAt: "2026-08-27T14:05:00.000Z"}, Duration: 72 * time.Second, Build: 60},
97 {CommitStatus: store.CommitStatus{Context: "external/lint", State: "success",
98 UpdatedAt: "2026-08-27T14:06:00.000Z"}},
99 })
100 for _, want := range []string{"2026-08-27 14:03", "2026-08-27 14:05", "1m12s", "2026-08-27 14:06"} {
101 if !strings.Contains(out, want) {
102 t.Errorf("aside missing %q:\n%s", want, out)
103 }
104 }
105}