142 lines
5.0 KiB
Go
142 lines
5.0 KiB
Go
package httpserver
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/tim/cairnquire/apps/server/internal/auth"
|
|
"github.com/tim/cairnquire/apps/server/internal/collaboration"
|
|
)
|
|
|
|
func loginTestUser(t *testing.T, server *apiTestServer) *http.Cookie {
|
|
t.Helper()
|
|
login := httptest.NewRecorder()
|
|
server.handler.ServeHTTP(login, jsonRequest(http.MethodPost, "/api/auth/login/password", map[string]string{
|
|
"email": "editor@example.com", "password": "very secure password",
|
|
}))
|
|
if login.Code != http.StatusOK {
|
|
t.Fatalf("login response = %d %q", login.Code, login.Body.String())
|
|
}
|
|
return cookieByName(t, login.Result().Cookies(), auth.SessionCookieName)
|
|
}
|
|
|
|
func authenticatedJSONRequest(t *testing.T, method, target string, body any, session *http.Cookie) *http.Request {
|
|
t.Helper()
|
|
request := jsonRequest(method, target, body)
|
|
request.AddCookie(session)
|
|
return request
|
|
}
|
|
|
|
func TestDocumentLoadsCollaborationControlsAndWatchFlow(t *testing.T) {
|
|
server := newAPITestServer(t)
|
|
session := loginTestUser(t, server)
|
|
|
|
pageRequest := httptest.NewRequest(http.MethodGet, "/docs/hello", nil)
|
|
pageRequest.AddCookie(session)
|
|
page := httptest.NewRecorder()
|
|
server.handler.ServeHTTP(page, pageRequest)
|
|
if page.Code != http.StatusOK {
|
|
t.Fatalf("document response = %d %q", page.Code, page.Body.String())
|
|
}
|
|
for _, expected := range [][]byte{
|
|
[]byte(`/static/notification-bell.js`),
|
|
[]byte(`data-document-id="doc:hello"`),
|
|
[]byte(`data-document-watch`),
|
|
[]byte(`data-comments-history`),
|
|
} {
|
|
if !bytes.Contains(page.Body.Bytes(), expected) {
|
|
t.Errorf("document page missing %q", expected)
|
|
}
|
|
}
|
|
|
|
statusRequest := httptest.NewRequest(http.MethodGet, "/api/watch/status?document_id=doc%3Ahello", nil)
|
|
statusRequest.AddCookie(session)
|
|
status := httptest.NewRecorder()
|
|
server.handler.ServeHTTP(status, statusRequest)
|
|
if status.Code != http.StatusOK || !bytes.Contains(status.Body.Bytes(), []byte(`"watching":false`)) {
|
|
t.Fatalf("initial watch status = %d %q", status.Code, status.Body.String())
|
|
}
|
|
|
|
watch := httptest.NewRecorder()
|
|
server.handler.ServeHTTP(watch, authenticatedJSONRequest(t, http.MethodPost, "/api/watch/document", map[string]string{"documentId": "doc:hello"}, session))
|
|
if watch.Code != http.StatusOK {
|
|
t.Fatalf("watch response = %d %q", watch.Code, watch.Body.String())
|
|
}
|
|
|
|
status = httptest.NewRecorder()
|
|
server.handler.ServeHTTP(status, statusRequest.Clone(statusRequest.Context()))
|
|
if status.Code != http.StatusOK || !bytes.Contains(status.Body.Bytes(), []byte(`"watching":true`)) {
|
|
t.Fatalf("watched status = %d %q", status.Code, status.Body.String())
|
|
}
|
|
|
|
unwatch := httptest.NewRecorder()
|
|
server.handler.ServeHTTP(unwatch, authenticatedJSONRequest(t, http.MethodDelete, "/api/watch/document", map[string]string{"documentId": "doc:hello"}, session))
|
|
if unwatch.Code != http.StatusOK {
|
|
t.Fatalf("unwatch response = %d %q", unwatch.Code, unwatch.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestCommentReplyResolveAndHistoryHTTPFlow(t *testing.T) {
|
|
server := newAPITestServer(t)
|
|
session := loginTestUser(t, server)
|
|
anchor := "section-anchor"
|
|
|
|
create := func(content string, parentID *string) collaboration.Comment {
|
|
t.Helper()
|
|
response := httptest.NewRecorder()
|
|
server.handler.ServeHTTP(response, authenticatedJSONRequest(t, http.MethodPost, "/api/comments", collaboration.CreateCommentInput{
|
|
DocumentID: "doc:hello", VersionHash: "hash", ParentID: parentID, Content: content, AnchorHash: &anchor,
|
|
}, session))
|
|
if response.Code != http.StatusCreated {
|
|
t.Fatalf("create comment response = %d %q", response.Code, response.Body.String())
|
|
}
|
|
var comment collaboration.Comment
|
|
if err := json.NewDecoder(response.Body).Decode(&comment); err != nil {
|
|
t.Fatalf("decode comment: %v", err)
|
|
}
|
|
return comment
|
|
}
|
|
|
|
root := create("Root", nil)
|
|
reply := create("Reply", &root.ID)
|
|
_ = create("Grandchild", &reply.ID)
|
|
|
|
resolve := httptest.NewRecorder()
|
|
server.handler.ServeHTTP(resolve, authenticatedJSONRequest(t, http.MethodPost, "/api/comments/"+root.ID+"/resolve", map[string]any{}, session))
|
|
if resolve.Code != http.StatusOK {
|
|
t.Fatalf("resolve response = %d %q", resolve.Code, resolve.Body.String())
|
|
}
|
|
|
|
list := func(includeResolved bool) []collaboration.Comment {
|
|
t.Helper()
|
|
target := "/api/comments?document_id=doc%3Ahello&anchor_hash=" + anchor
|
|
if includeResolved {
|
|
target += "&include_resolved=true"
|
|
}
|
|
request := httptest.NewRequest(http.MethodGet, target, nil)
|
|
request.AddCookie(session)
|
|
response := httptest.NewRecorder()
|
|
server.handler.ServeHTTP(response, request)
|
|
if response.Code != http.StatusOK {
|
|
t.Fatalf("list comments response = %d %q", response.Code, response.Body.String())
|
|
}
|
|
var body struct {
|
|
Comments []collaboration.Comment `json:"comments"`
|
|
}
|
|
if err := json.NewDecoder(response.Body).Decode(&body); err != nil {
|
|
t.Fatalf("decode comments: %v", err)
|
|
}
|
|
return body.Comments
|
|
}
|
|
|
|
if active := list(false); len(active) != 0 {
|
|
t.Fatalf("active comments = %d, want 0", len(active))
|
|
}
|
|
if history := list(true); len(history) != 3 {
|
|
t.Fatalf("history comments = %d, want 3", len(history))
|
|
}
|
|
}
|