package web
import (
"context"
"net/http"
"net/http/httptest"
"strings"
"testing"
"craftdesign.group/quarry/internal/ops"
)
type dashFeedIn struct {
Kind string `json:"kind"`
Find string `json:"find"`
Repo string `json:"repo"`
Offset int `json:"offset"`
}
type dashAcrossIn struct {
Awaiting bool `json:"awaiting"`
Limit int `json:"limit"`
}
// The home page is a frame that streams its content, so it never waits
// on the trackers; and the waiting-on-you band, which reaches into every
// tracker the reader can see, is asked for only under ticket changes,
// the one chip that draws it. Computed under every chip and before the
// page could arrive, it cost the home page four seconds whenever those
// trackers were cold.
func TestTheHomeAsksForTheWaitingBandOnlyWhereItIsDrawn(t *testing.T) {
r := ops.NewRegistry()
across := 0
type empty struct{}
must := func(err error) {
t.Helper()
if err != nil {
t.Fatal(err)
}
}
must(ops.Register(r, ops.Op[dashFeedIn, struct {
Total int `json:"total"`
}]{Name: "me.feed", Doc: "test double", Kind: ops.Query, Auth: ops.Token, Route: "GET /api/v1/me/feed",
Run: func(context.Context, dashFeedIn) (struct {
Total int `json:"total"`
}, error) {
return struct {
Total int `json:"total"`
}{}, nil
}}))
must(ops.Register(r, ops.Op[dashAcrossIn, struct {
Tickets []struct{} `json:"tickets"`
}]{Name: "ticket.across", Doc: "test double", Kind: ops.Query, Auth: ops.Token, Route: "GET /api/v1/me/tickets",
Run: func(context.Context, dashAcrossIn) (struct {
Tickets []struct{} `json:"tickets"`
}, error) {
across++
return struct {
Tickets []struct{} `json:"tickets"`
}{}, nil
}}))
must(ops.Register(r, ops.Op[empty, struct {
Version string `json:"version"`
}]{Name: "meta.version", Doc: "test double", Kind: ops.Query, Auth: ops.Anonymous, Route: "GET /api/v1/version",
Run: func(context.Context, empty) (struct {
Version string `json:"version"`
}, error) {
return struct {
Version string `json:"version"`
}{"t"}, nil
}}))
h := HandlerWith(r, nil, nil, []Option{WithSessions(fakeSessions{user: "jan", roles: map[string]ops.Auth{"": ops.Token}})})
get := func(path string) (int, string) {
req := httptest.NewRequest("GET", path, nil)
req.AddCookie(&http.Cookie{Name: sessionCookie, Value: "good"})
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fatalf("%s: %d", path, w.Code)
}
return across, w.Body.String()
}
// The page is its frame: it asks for nothing and names where its
// content comes from, keeping the reader's query.
n, body := get("/?kind=t")
if n != 0 || !strings.Contains(body, `data-hook="dash-frame"`) || !strings.Contains(body, `data-init="@get('/?frag=all&kind=t')"`) {
t.Fatalf("FAIL: the page waited for its content (asked %d), or does not stream it", n)
}
for _, path := range []string{"/?frag=all", "/?frag=all&kind=c", "/?frag=all&kind=w"} {
if n, body := get(path); n != 0 || !strings.Contains(body, `id="dash-feed"`) {
t.Errorf("FAIL: %s asked for the waiting band (%d), or brought no feed", path, n)
}
}
if n, _ := get("/?frag=all&kind=t"); n != 1 {
t.Errorf("FAIL: ticket changes did not ask for its band (%d)", n)
}
}
// homeContent is the home page's content URL for path: the page itself
// is a frame, and what fills it is ?frag=all with the same query.
func homeContent(path string) string {
if !strings.HasPrefix(path, "/") || strings.HasPrefix(path, "/?view=explore") {
return path
}
rest := strings.TrimPrefix(strings.TrimPrefix(path, "/"), "?")
if path != "/" && !strings.HasPrefix(path, "/?") {
return path
}
if rest == "" {
return "/?frag=all"
}
return "/?frag=all&" + rest
}
// unpatch is a Datastar element patch read back as the HTML it carries,
// so a test reads the streamed content as it would the page.
func unpatch(body string) string {
if !strings.HasPrefix(body, "event: datastar-patch-elements") {
return body
}
var out []string
for _, l := range strings.Split(body, "\n") {
if rest, ok := strings.CutPrefix(l, "data: elements "); ok {
out = append(out, rest)
}
}
return strings.Join(out, "\n")
}