package web
import (
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"craftdesign.group/quarry/internal/api"
"craftdesign.group/quarry/internal/ops"
)
// The inbox page is live the way the badge is: it opens the attention
// stream itself, asking for the list, and the live region it patches
// carries an id the stream can address.
func TestInboxPageOpensTheStreamForItsList(t *testing.T) {
r := ops.NewRegistry()
if err := api.RegisterAll(r, api.Deps{Version: "v", Repos: api.NewRepos(map[string]*api.Repo{})}); err != nil {
t.Fatal(err)
}
srv := httptest.NewServer(HandlerWith(r, nil, nil, []Option{WithSessions(fakeSessions{user: "dan"})}))
t.Cleanup(srv.Close)
req, _ := http.NewRequest("GET", srv.URL+"/inbox?f=mentions", nil)
req.AddCookie(&http.Cookie{Name: sessionCookie, Value: "good"})
res, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
page := body(res)
if !strings.Contains(page, `id="inbox-live"`) {
t.Error("the inbox has no live region to patch")
}
if !strings.Contains(page, `@get('/me.sse?inbox=1&f=mentions')`) {
t.Errorf("the inbox does not open the stream for its list")
}
if strings.Count(page, "/me.sse") != 1 {
t.Errorf("the page opens the attention stream %d times, want once", strings.Count(page, "/me.sse"))
}
}
// On the stream, an event re-renders the list and patches it; an event
// that leaves the list as it was sends nothing.
func TestAttentionStreamPatchesTheInboxList(t *testing.T) {
rec := httptest.NewRecorder()
frag := `<div id="inbox-live">one</div>`
s := &attentionSSE{w: rec, fl: rec, ctx: t.Context(), r: ops.NewRegistry(), inbox: func() string { return frag }}
_ = s.Emit(1, attentionEvent{})
out := rec.Body.String()
if !strings.Contains(out, "data: elements "+frag) {
t.Fatalf("no inbox patch on the stream:\n%s", out)
}
_ = s.Emit(2, attentionEvent{})
if n := strings.Count(rec.Body.String(), "data: elements "+frag); n != 1 {
t.Fatalf("an unchanged list was patched %d times", n)
}
frag = `<div id="inbox-live">two</div>`
_ = s.Emit(3, attentionEvent{})
if !strings.Contains(rec.Body.String(), "data: elements "+frag) {
t.Fatal("a changed list was not patched")
}
quiet := &attentionSSE{w: httptest.NewRecorder(), fl: httptest.NewRecorder(), ctx: t.Context(), r: ops.NewRegistry()}
_ = quiet.Emit(1, attentionEvent{})
if strings.Contains(quiet.w.(*httptest.ResponseRecorder).Body.String(), "inbox-live") {
t.Fatal("a stream opened without the inbox patched an inbox")
}
}
// A page restored from the back-forward cache is the page as it was
// left, with its streams closed: a live page reloads on restore.
func TestLivePagesReloadFromTheBackCache(t *testing.T) {
js, err := os.ReadFile("assets/onerror.js")
if err != nil {
t.Fatal(err)
}
src := string(js)
for _, want := range []string{`"pageshow"`, "ev.persisted", "location.reload()", `querySelector("[data-init]")`} {
if !strings.Contains(src, want) {
t.Errorf("onerror.js lacks %s", want)
}
}
}