Commit 508463cf79

508463cf79be7509772a2a151ea1f7c9fce1dc9e

parent: c0b5c739d1

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-28 22:20 UTC

web: Discussion heading before the comment thread on issue and MR pages

Ref #271

Layout: unified · split

internal/httpd/issuecreate_test.go +27
@@ -1,6 +1,7 @@
11package httpd
22
33import (
4 "html/template"
45 "net/http"
56 "net/http/httptest"
67 "net/url"
@@ -10,8 +11,34 @@ import (
1011
1112 "gitbay.org/gitbay/internal/config"
1213 "gitbay.org/gitbay/internal/store"
14 "gitbay.org/gitbay/internal/web"
1315)
1416
17// A heading precedes the issue's comment thread, matching the merge
18// request page, so a screen-reader user skimming by heading has a
19// landmark before the first comment rather than falling straight from
20// the edit box into the body (#271).
21func TestIssuePageHasDiscussionHeading(t *testing.T) {
22 var sb strings.Builder
23 if err := web.Render(&sb, "issue.html", struct {
24 repoPage
25 Issue store.Issue
26 BodyHTML template.HTML
27 Comments []renderedComment
28 CanEdit bool
29 CanWrite bool
30 Milestones []store.Milestone
31 Notice string
32 LabelColors map[string]template.CSS
33 Draft *draft
34 }{repoPage: testRepoPage(), Issue: store.Issue{Number: 1, Title: "bug", Author: "cmc", State: "open"}}); err != nil {
35 t.Fatalf("render: %v", err)
36 }
37 if !strings.Contains(sb.String(), "<h2>Discussion</h2>") {
38 t.Error("no Discussion heading")
39 }
40}
41
1542// sessionCookieFor gives uid a real web session, the way canWriteRepo's
1643// call to s.viewer(r) needs (internal/httpd/accounts.go:37-47), since
1744// issueCreateForm gates the milestone/assignee fields on it rather than
internal/httpd/mrpage_test.go +15
@@ -59,6 +59,21 @@ func TestMRDiffViewNamesAPrunedHead(t *testing.T) {
5959 }
6060}
6161
62// A heading precedes the comment thread, so a screen-reader user
63// skimming by heading does not fall from the aside's groups straight
64// into the first comment with no landmark (#271).
65func TestMRPageHasDiscussionHeading(t *testing.T) {
66 var sb strings.Builder
67 if err := web.Render(&sb, "mr.html", mrPageData{
68 repoPage: testRepoPage(), MR: testMR("open"), View: "conversation",
69 }); err != nil {
70 t.Fatalf("render: %v", err)
71 }
72 if !strings.Contains(sb.String(), "<h2>Discussion</h2>") {
73 t.Error("no Discussion heading")
74 }
75}
76
6277// The watch button names all three states it cycles through, including
6378// muted, which MR 1 made reachable (#271).
6479func TestRepoHeaderWatchButtonNamesMutedState(t *testing.T) {
internal/web/templates/issue.html +1
@@ -10,6 +10,7 @@
1010
1111<div class="withaside">
1212<div class="mainside">
13<h2>Discussion</h2>
1314{{if .CanEdit}}<details class="editbox"{{if .Draft.Is "edit"}} open{{end}}><summary>edit</summary>
1415{{if .Draft.Is "edit"}}{{template "previewblock" .Draft.HTML}}{{end}}
1516<form method="post" action="/{{.Repo.OwnerName}}/{{.Repo.Name}}/issues/{{.Issue.Number}}/edit" class="commentform">
internal/web/templates/mr.html +1
@@ -26,6 +26,7 @@
2626
2727{{if eq .View "conversation"}}
2828<div class="prose">
29<h2>Discussion</h2>
2930{{if .CanEdit}}<details class="editbox"{{if .Draft.Is "edit"}} open{{end}}><summary>Edit</summary>
3031{{if .Draft.Is "edit"}}{{template "previewblock" .Draft.HTML}}{{end}}
3132<form method="post" action="{{$base}}/edit" class="commentform">