package web
import (
"strings"
"testing"
)
// The two regions a changed ticket sends are the two the page draws,
// rendered by the same templates. The saver's own patch and every
// watcher's stream go through this, so they cannot show different
// things.
func TestAChangedTicketSendsItsTwoRegions(t *testing.T) {
data := pageData{
Repo: "alpha", CanWrite: true,
Ticket: ticketDetail{ID: "abc123def456"},
Timeline: []ticketEvent{{Login: "lou", Date: "2026-09-16T09:00:00Z", HTML: "<p>a comment</p>"}},
}
got := ticketParts(data)
for _, want := range []string{
"event: datastar-patch-elements",
"data: selector #tkt-timeline",
"data: selector #tkt-side",
// Inner, because the wrapper carries the id the patch targets
// — and on the page, the data-init that opened the stream.
"data: mode inner",
"a comment",
} {
if !strings.Contains(got, want) {
t.Errorf("FAIL: the patch is missing %q", want)
}
}
// Two patches, not one: the timeline and the sidebar are separate
// regions with separate targets.
if n := strings.Count(got, "event: datastar-patch-elements"); n != 2 {
t.Errorf("FAIL: %d patches, want 2", n)
}
// It is comparable, which is what lets a stream stay quiet when
// nothing moved.
if ticketParts(data) != got {
t.Errorf("FAIL: the same ticket renders differently twice")
}
}
// The page opens its stream from a wrapper, and says nothing when
// there is no stream to open.
func TestATicketOpensItsStreamFromAWrapper(t *testing.T) {
data := pageData{Repo: "alpha", CanWrite: true,
Ticket: ticketDetail{ID: "abc123def456"},
TicketStream: "/r/alpha/ticket.sse/abc123def456"}
var page strings.Builder
if err := ticketPage.ExecuteTemplate(&page, "content", data); err != nil {
t.Fatal(err)
}
got := page.String()
if !strings.Contains(got, `data-init="@get('/r/alpha/ticket.sse/abc123def456')"`) {
t.Errorf("FAIL: the ticket does not open its stream")
}
// Outside the patched region, not on it.
init := strings.Index(got, "data-init=")
target := strings.Index(got, `id="tkt-timeline"`)
if init < 0 || target < 0 || init > target {
t.Errorf("FAIL: data-init is not on a wrapper outside the patched region")
}
data.TicketStream = ""
var cold strings.Builder
if err := ticketPage.ExecuteTemplate(&cold, "content", data); err != nil {
t.Fatal(err)
}
if strings.Contains(cold.String(), "data-init=\"@get('/r/alpha/ticket.sse") {
t.Errorf("FAIL: a page with no stream still opens one")
}
}