package web
import (
"strings"
"testing"
)
// /me draws your agents' requests for sign-off only when there are
// any: a waiting one answers with two POSTed buttons (never a link, so
// nothing that deletes a repository runs from a GET), a decided one
// says how it ended.
func TestMeShowsRequestsForSignOff(t *testing.T) {
render := func(reqs []meSignOff) string {
var b strings.Builder
me := meView{Name: "ann", Notify: &prefsView{}, SignOffs: reqs}
if err := noHooks.template(mePageTmpl).ExecuteTemplate(&b, "content", pageData{Title: "ann", User: "ann", Me: &me}); err != nil {
t.Fatal(err)
}
return b.String()
}
if got := render(nil); strings.Contains(got, `id="signoffs"`) || strings.Contains(got, `href="#signoffs"`) {
t.Errorf("FAIL: an empty sign-off section is drawn")
}
got := render([]meSignOff{
{ID: "abc", Agent: "ann-bot", Repo: "r", Summary: "delete r", State: "pending", Requested: "2026-10-21T10:00:00Z"},
{ID: "def", Agent: "ann-bot", Repo: "s", Summary: "stop serving s", State: "denied", Requested: "2026-10-20T10:00:00Z"},
})
for what, want := range map[string]string{
"the rail reaches it": `href="#signoffs"`,
"approve is a post": `<form method="post" action="/me/signoffs/abc"><input type="hidden" name="approve" value="true">`,
"deny is a post": `<form method="post" action="/me/signoffs/abc"><input type="hidden" name="approve" value="false">`,
"a decided one is kept": `data-hook="signoff" data-state="denied"`,
} {
if !strings.Contains(got, want) {
t.Errorf("FAIL: %s (%q)", what, want)
}
}
if strings.Contains(got, `action="/me/signoffs/def"`) {
t.Errorf("FAIL: a decided request can still be answered")
}
}
// RFC 0027: the page an email links to shows one request, who asks and
// why, and answers it with two posted buttons that return to it; a
// decided request has no buttons left.
func TestASignOffHasAPageOfItsOwn(t *testing.T) {
render := func(s meSignOff) string {
var b strings.Builder
if err := noHooks.template(signOffPageTmpl).ExecuteTemplate(&b, "content", pageData{Title: "Approve?", SignOff: &s}); err != nil {
t.Fatal(err)
}
return b.String()
}
got := render(meSignOff{ID: "abc", Agent: "zeitgeist", Summary: "agent.new for rajeev", Reason: "a QA tester", State: "pending", Requested: "2026-11-08T10:00:00Z"})
for what, want := range map[string]string{
"who asks": `data-hook="signoff-agent">zeitgeist<`,
"what runs": `data-hook="signoff-summary">agent.new for rajeev<`,
"why": `data-hook="signoff-reason"`,
"approve posts": `<form method="post" action="/me/signoffs/abc"><input type="hidden" name="approve" value="true"><input type="hidden" name="back" value="page">`,
"deny posts": `<form method="post" action="/me/signoffs/abc"><input type="hidden" name="approve" value="false"><input type="hidden" name="back" value="page">`,
"its state is read": `data-hook="signoff-page" data-state="pending"`,
} {
if !strings.Contains(got, want) {
t.Errorf("FAIL: %s (%q)", what, want)
}
}
if done := render(meSignOff{ID: "abc", Agent: "zeitgeist", Summary: "x", State: "approved", Requested: "2026-11-08T10:00:00Z"}); strings.Contains(done, "<form") {
t.Errorf("FAIL: an approved request can still be answered")
}
}