clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

feat/ui-updates
tinyrelay / tinyclient / public_pages_test.go
public_pages_test.go 4.8K
1package tinyclient23import (4 "context"5 "encoding/json"6 "net/http"7 "net/http/httptest"8 "strings"9 "testing"1011 "github.com/FelineStateMachine/tinyrelay/internal/policy"12)1314type publicBackend struct {15 fakeBackend16 eventQueries int17}1819func (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"}}, nil25}2627func 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}4950type articleBackend struct{ fakeBackend }5152func (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"}}, nil55 }56 return nil, nil57}5859type articleDetailBackend struct{ fakeBackend }6061func (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"}, nil64 }65 return nil, nil66}6768func 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}8485func 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}101102func 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 = false116 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}