tinyrelayfile
tinyrelay/tinyclient/public_pages_test.go/

tinyclient/public_pages_test.go raw
1package tinyclient
2
3import (
4 "context"
5 "encoding/json"
6 "net/http"
7 "net/http/httptest"
8 "strings"
9 "testing"
10
11 "github.com/FelineStateMachine/tinyrelay/internal/policy"
12)
13
14type publicBackend struct {
15 fakeBackend
16 eventQueries int
17}
18
19func (b *publicBackend) Query(_ context.Context, method string, _ []json.RawMessage, actor string) (any, error) {
20 if method != "queryevents" {
21 return b.fakeBackend.Query(context.Background(), method, nil, actor)
22 }
23 b.eventQueries++
24 return []map[string]any{{"id": "event-1", "pubkey": actor, "content": "visible result"}}, nil
25}
26
27func TestHomeShowsRelayInformationWithoutQueryingSocialEvents(t *testing.T) {
28 owner := strings.Repeat("a", 64)
29 for _, actor := range []string{"", owner} {
30 backend := &publicBackend{fakeBackend: fakeBackend{policy: policy.Defaults(owner)}}
31 backend.policy.Description = "A place to connect."
32 app, err := New(backend, Options{Actor: func(*http.Request) (string, error) { return actor, nil }})
33 if err != nil {
34 t.Fatal(err)
35 }
36 for _, path := range []string{"/", "/?kinds=all"} {
37 recorder := httptest.NewRecorder()
38 app.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, path, nil))
39 body := recorder.Body.String()
40 if recorder.Code != http.StatusOK || !strings.Contains(body, "A place to connect.") || !strings.Contains(body, `href="/social"`) {
41 t.Fatalf("home lost relay information or Social navigation: status=%d", recorder.Code)
42 }
43 if backend.eventQueries != 0 || strings.Contains(body, "Recent activity") || strings.Contains(body, "visible result") {
44 t.Fatalf("home still loads the duplicate feed: queries=%d", backend.eventQueries)
45 }
46 }
47 }
48}
49
50type articleBackend struct{ fakeBackend }
51
52func (b *articleBackend) Query(_ context.Context, method string, _ []json.RawMessage, _ string) (any, error) {
53 if method == "queryevents" {
54 return []map[string]any{{"id": strings.Repeat("b", 64), "kind": 30023, "created_at": float64(1700000000), "content": "A title\nbody"}}, nil
55 }
56 return nil, nil
57}
58
59type articleDetailBackend struct{ fakeBackend }
60
61func (b *articleDetailBackend) Query(_ context.Context, method string, _ []json.RawMessage, _ string) (any, error) {
62 if method == "eventdetail" {
63 return map[string]any{"id": "article-1", "kind": 30023, "created_at": float64(1700000000), "pubkey": strings.Repeat("a", 64), "content": "# Heading\n\nBody"}, nil
64 }
65 return nil, nil
66}
67
68func TestArticleDetailRendersMarkdownContent(t *testing.T) {
69 backend := &articleDetailBackend{fakeBackend: fakeBackend{policy: policy.Defaults(strings.Repeat("a", 64))}}
70 app, err := New(backend, Options{})
71 if err != nil {
72 t.Fatal(err)
73 }
74 recorder := httptest.NewRecorder()
75 app.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/e/article-1", nil))
76 body := recorder.Body.String()
77 if recorder.Code != http.StatusOK || !strings.Contains(body, `<nostr-event id="event-article-1">`) || !strings.Contains(body, "<article><h1>Heading</h1>") {
78 t.Fatalf("article detail did not render markdown within the shared event viewer: status=%d", recorder.Code)
79 }
80 if strings.Contains(body, "<pre># Heading") {
81 t.Fatalf("article detail retained plaintext rendering: %s", body)
82 }
83}
84
85func TestPublicSearchAndInboxRenderBackendResults(t *testing.T) {
86 owner := strings.Repeat("a", 64)
87 backend := &publicBackend{fakeBackend: fakeBackend{policy: policy.Defaults(owner)}}
88 app, err := New(backend, Options{Actor: func(*http.Request) (string, error) { return owner, nil }})
89 if err != nil {
90 t.Fatal(err)
91 }
92 for _, path := range []string{"/search?q=visible", "/inbox", "/outbox"} {
93 recorder := httptest.NewRecorder()
94 app.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, path, nil))
95 body := recorder.Body.String()
96 if recorder.Code != http.StatusOK || !strings.Contains(body, "visible result") || !strings.Contains(body, "event-1") {
97 t.Fatalf("%s: status=%d body=%s", path, recorder.Code, body)
98 }
99 }
100}
101
102func TestArticleFeedsContainStoredRecordsAndRespectPagesFeature(t *testing.T) {
103 backend := &articleBackend{fakeBackend: fakeBackend{policy: policy.Defaults(strings.Repeat("a", 64))}}
104 app, err := New(backend, Options{})
105 if err != nil {
106 t.Fatal(err)
107 }
108 for _, path := range []string{"/articles.json", "/feed.xml"} {
109 recorder := httptest.NewRecorder()
110 app.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, path, nil))
111 if recorder.Code != http.StatusOK || !strings.Contains(recorder.Body.String(), strings.Repeat("b", 64)) || !strings.Contains(recorder.Body.String(), "A title") {
112 t.Fatalf("%s: status=%d body=%s", path, recorder.Code, recorder.Body.String())
113 }
114 }
115 backend.policy.Features.Pages = false
116 for _, path := range []string{"/articles.json", "/feed.xml", "/e/" + strings.Repeat("b", 64), "/a/title"} {
117 recorder := httptest.NewRecorder()
118 app.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, path, nil))
119 if recorder.Code != http.StatusNotFound {
120 t.Fatalf("%s: status=%d", path, recorder.Code)
121 }
122 }
123}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs