Files
RenewCMS/test/article_editorial_context_http_test.go
T

129 lines
4.9 KiB
Go

package test
import (
"RenewCMS/internal/domain/article"
"encoding/json"
"net/http"
"testing"
)
func editorialField[T any](t *testing.T, response storyResponse, key string) T {
t.Helper()
var value T
if err := json.Unmarshal(response.fields(t)[key], &value); err != nil {
t.Fatalf("%s: %v in %s", key, err, response.text())
}
return value
}
func translationEntry(t *testing.T, response storyResponse, id string) map[string]json.RawMessage {
t.Helper()
for _, entry := range translationsOf(t, response) {
if string(entry["id"]) == id {
return entry
}
}
t.Fatalf("no translation %s in %s", id, response.text())
return nil
}
func putTrackingDraft(w *storyWorld) {
source := uint32(12)
w.put(article.Article{ID: 14, Title: "Costes", CreatedBy: storyRestrict, Slug: "costes", Lang: "es", StoryID: storyStory, SourceArticleID: &source, SourceRevision: 2})
}
func TestArticleEditorialContextHTTP(t *testing.T) {
t.Run("Missing languages are the enabled languages without a readable version", func(t *testing.T) {
w := newStoryWorld(t)
cases := []struct {
userID uint32
missing []string
}{
{storyOwner, []string{}},
{storyRestrict, []string{"de", "fr"}},
{storyReader, []string{}},
}
for _, c := range cases {
got := editorialField[[]string](t, w.send(c.userID, http.MethodGet, "/v1/article/10", ""), "missing_langs")
if len(got) != len(c.missing) || len(got) > 0 && (got[0] != c.missing[0] || got[1] != c.missing[1]) {
t.Errorf("user %d: missing_langs %v, want %v", c.userID, got, c.missing)
}
}
})
t.Run("A version in a disabled language or without language is left out of public surfaces", func(t *testing.T) {
w := newStoryWorld(t)
putTrackingDraft(w)
w.put(article.Article{ID: 30, Title: "Unassigned", CreatedBy: storyWriter1, Slug: "unassigned", StoryID: 30, IsOnline: true})
owner := w.send(storyOwner, http.MethodGet, "/v1/article/14", "")
if !editorialField[bool](t, owner, "excluded_from_public") || string(translationEntry(t, owner, "14")["excluded_from_public"]) != "true" || string(translationEntry(t, owner, "10")["excluded_from_public"]) != "false" {
t.Errorf("es must be left out, en kept: %s", owner.text())
}
if !editorialField[bool](t, w.send(storyOwner, http.MethodGet, "/v1/article/30", ""), "excluded_from_public") {
t.Error("a version without language must be left out of the public language surfaces")
}
if editorialField[bool](t, w.send(storyOwner, http.MethodGet, "/v1/article/10", ""), "excluded_from_public") {
t.Error("an enabled language must not be left out")
}
})
t.Run("A deleted source and an unreadable source read the same", func(t *testing.T) {
w := newStoryWorld(t)
putTrackingDraft(w)
tracked := w.send(storyOwner, http.MethodGet, "/v1/article/14", "")
unreadable := w.send(storyRestrict, http.MethodGet, "/v1/article/14", "")
delete(w.articles.articles, 12)
deleted := w.send(storyOwner, http.MethodGet, "/v1/article/14", "")
if string(tracked.fields(t)["source"]) != `{"article_id":12,"revision":2}` || editorialField[bool](t, tracked, "source_unavailable") {
t.Fatalf("a readable source is shown: %s", tracked.text())
}
for name, response := range map[string]storyResponse{"unreadable": unreadable, "deleted": deleted} {
if string(response.fields(t)["source"]) != "null" || !editorialField[bool](t, response, "source_unavailable") {
t.Errorf("%s source: %s", name, response.text())
}
}
})
t.Run("Translations name the source they track only when it is readable", func(t *testing.T) {
w := newStoryWorld(t)
putTrackingDraft(w)
owner := w.send(storyOwner, http.MethodGet, "/v1/article/10", "")
restricted := w.send(storyRestrict, http.MethodGet, "/v1/article/14", "")
if string(translationEntry(t, owner, "14")["source_article_id"]) != "12" || string(translationEntry(t, owner, "10")["source_article_id"]) != "null" {
t.Errorf("owner translations: %s", owner.text())
}
if string(translationEntry(t, restricted, "14")["source_article_id"]) != "null" {
t.Errorf("an unreadable source is named: %s", restricted.text())
}
})
t.Run("Partial view follows the read scope of the caller only", func(t *testing.T) {
w := newStoryWorld(t)
if editorialField[bool](t, w.send(storyOwner, http.MethodGet, "/v1/article/10", ""), "partial_view") {
t.Error("a caller who reads every version has a complete view")
}
if !editorialField[bool](t, w.send(storyRestrict, http.MethodGet, "/v1/article/13", ""), "partial_view") {
t.Error("a caller limited to own versions has a partial view")
}
})
t.Run("Anonymous reads carry no editorial keys", func(t *testing.T) {
w := newStoryWorld(t)
fields := w.send(storyAnon, http.MethodGet, "/v1/article/10", "").fields(t)
for _, key := range []string{"missing_langs", "excluded_from_public", "source_unavailable", "partial_view"} {
if _, present := fields[key]; present {
t.Errorf("anonymous read carries %s", key)
}
}
})
}