clone

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

feat/tinyagent
tinyrelay / tinyclient / profile_test.go
profile_test.go 3.3K
1package tinyclient23import (4 "context"5 "encoding/json"6 "errors"7 "net/http"8 "net/http/httptest"9 "strings"10 "testing"1112 "github.com/FelineStateMachine/tinyrelay/internal/policy"13)1415type profileBackend struct {16 fakeBackend17 params json.RawMessage18}1920func (b *profileBackend) Query(_ context.Context, method string, params []json.RawMessage, actor string) (any, error) {21 if method != "browseprofile" {22 return nil, nil23 }24 if actor == "" {25 return nil, errors.New("auth-required: sign in")26 }27 b.params = params[0]28 return map[string]any{"pubkey": actor, "event": map[string]any{"kind": 0, "created_at": 1788900000}, "profile": map[string]any{"name": "dami", "about": "keeps <cats>", "lud16": "dami@wallet.example", "banner": ""}, "relays": []any{"wss://relay.one", "wss://relay.two"}}, nil29}3031func TestProfilePagePrefillsTheFormAndOffersItFromHome(t *testing.T) {32 backend := &profileBackend{fakeBackend: fakeBackend{policy: policy.Defaults(strings.Repeat("a", 64))}}33 app, err := New(backend, Options{Actor: func(*http.Request) (string, error) { return backend.policy.Owner, nil }})34 if err != nil {35 t.Fatal(err)36 }37 recorder := httptest.NewRecorder()38 app.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/profile", nil))39 body := recorder.Body.String()40 for _, marker := range []string{41 `<profile-form pubkey="` + backend.policy.Owner + `" existing="{`,42 `&#34;name&#34;:&#34;dami&#34;`,43 `<input name="name" maxlength="64" value="dami"`,44 `<textarea name="about" maxlength="2000">keeps &lt;cats&gt;</textarea>`,45 `<input name="lud16" value="dami@wallet.example"`,46 "wss://relay.one\nwss://relay.two\n</textarea>",47 `<button>Sign and publish</button>`,48 "Current profile published <time",49 } {50 if !strings.Contains(body, marker) {51 t.Errorf("profile page missing %q", marker)52 }53 }54 if strings.Contains(body, "class=") {55 t.Fatal("profile page carries a class attribute")56 }57 if !strings.Contains(string(backend.params), `"pubkey":"`+backend.policy.Owner+`"`) {58 t.Fatalf("profile query params = %s", backend.params)59 }60 recorder = httptest.NewRecorder()61 app.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/", nil))62 home := recorder.Body.String()63 if !strings.Contains(home, `<li><a href="/profile">profile</a></li>`) || strings.Contains(home, `<a href="/manage/people">manage</a>`) {64 t.Fatal("home panel does not offer the profile action, or still offers manage")65 }66}6768func TestProfilePageAsksGuestsToSignIn(t *testing.T) {69 backend := &profileBackend{fakeBackend: fakeBackend{policy: policy.Defaults(strings.Repeat("a", 64))}}70 app, err := New(backend, Options{Actor: func(*http.Request) (string, error) { return "", nil }})71 if err != nil {72 t.Fatal(err)73 }74 recorder := httptest.NewRecorder()75 app.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/profile", nil))76 body := recorder.Body.String()77 if recorder.Code != http.StatusOK || !strings.Contains(body, "Sign in to edit your profile.") || strings.Contains(body, "<profile-form") {78 t.Fatalf("guest profile page: %d %s", recorder.Code, body)79 }80 recorder = httptest.NewRecorder()81 app.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/", nil))82 if home := recorder.Body.String(); !strings.Contains(home, `<li><a href="/signin?next=%2F">sign in</a></li>`) || strings.Contains(home, `href="/profile"`) {83 t.Fatal("guest home panel should offer sign in, not the profile")84 }85}