Skip to content
quarry Artifact [23cb6f6305]
Login

Artifact [23cb6f6305]

Artifact 23cb6f63051332630c3d8e90053c253f1439d9f0375684271ea3302b611e3bc4:


package web

import (
	"strings"
	"testing"
)

// A thread's posts are a named template, so the live stream renders
// the same markup the page did. A second renderer for the live half is
// how two views of one thread drift apart.
func TestTheThreadsPostsAreOneTemplate(t *testing.T) {
	data := pageData{
		Repo: "alpha", ForumRoot: "abc123",
		ForumPosts: []forumPostRow{
			{Hash: "aaaaaaaaaaaa1111", User: "lou", HTML: "<p>first</p>", Date: "2026-09-16T09:00:00Z"},
			{Hash: "bbbbbbbbbbbb2222", User: "mia", HTML: "<p>a reply</p>", Date: "2026-09-16T09:05:00Z"},
		},
	}
	var frag strings.Builder
	if err := forumThreadPage.ExecuteTemplate(&frag, "forum-posts", data); err != nil {
		t.Fatal(err)
	}
	got := frag.String()
	// The patch target is on the fragment, or a patch has nowhere to
	// land.
	if !strings.Contains(got, `id="f-posts"`) {
		t.Errorf("FAIL: the fragment carries no patch target")
	}
	for _, want := range []string{"first", "a reply", `id="p-aaaaaaaaaaaa"`} {
		if !strings.Contains(got, want) {
			t.Errorf("FAIL: the fragment is missing %q", want)
		}
	}
	// And the whole page contains the same fragment, rather than a
	// second rendering of the posts.
	var page strings.Builder
	if err := forumThreadPage.ExecuteTemplate(&page, "content", data); err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(page.String(), got) {
		t.Errorf("FAIL: the page does not render the same posts fragment")
	}
}

// The data-init opens the stream, and sits on a WRAPPER rather than on
// the element the patch replaces: a patch morphs its target to match
// the fragment, which carries no data-init, so an attribute on the
// target is deleted by the first patch along with the connection.
func TestTheThreadOpensItsStreamFromAWrapper(t *testing.T) {
	data := pageData{Repo: "alpha", ForumRoot: "abc123",
		ForumStream: "/r/alpha/forum.sse/abc123",
		ForumPosts:  []forumPostRow{{Hash: "aaaaaaaaaaaa1111", User: "lou", HTML: "<p>hi</p>"}}}
	var page strings.Builder
	if err := forumThreadPage.ExecuteTemplate(&page, "content", data); err != nil {
		t.Fatal(err)
	}
	got := page.String()
	if !strings.Contains(got, `data-init="@get('/r/alpha/forum.sse/abc123')"`) {
		t.Errorf("FAIL: the thread does not open its stream")
	}
	// The attribute is BEFORE the target, not on it.
	init := strings.Index(got, "data-init=")
	target := strings.Index(got, `id="f-posts"`)
	if init < 0 || target < 0 || init > target {
		t.Errorf("FAIL: data-init is not on a wrapper outside the patched element")
	}
	// With no change plane there is no stream, and no attribute
	// pointing at one.
	data.ForumStream = ""
	var cold strings.Builder
	if err := forumThreadPage.ExecuteTemplate(&cold, "content", data); err != nil {
		t.Fatal(err)
	}
	if strings.Contains(cold.String(), "data-init") {
		t.Errorf("FAIL: a page with no stream still opens one")
	}
}