Settings > Sitemaps no longer prefills a content type's heading with its label in the administrator's language, so a save that did not touch the heading stores none and each locale's HTML sitemap keeps the label translated into it. The field's comment says so.
129 lines
4.4 KiB
Go
129 lines
4.4 KiB
Go
package sitemap_test
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"io/fs"
|
||
"net/http"
|
||
"testing"
|
||
"testing/fstest"
|
||
"time"
|
||
|
||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||
"git.golem15.com/golem15/summercms/modules/pact"
|
||
"git.golem15.com/golem15/summercms/modules/party"
|
||
)
|
||
|
||
// labelsPluginID is a fake content plugin whose type label is a phrase
|
||
// with an English and a Polish translation, as a real plugin's is.
|
||
const labelsPluginID = "acme.labels"
|
||
|
||
const noteType = "acme-note"
|
||
|
||
type labelsPlugin struct{}
|
||
|
||
func (labelsPlugin) ID() string { return labelsPluginID }
|
||
func (labelsPlugin) Requires() []string { return nil }
|
||
func (labelsPlugin) Register(*backpack.App) error { return nil }
|
||
func (labelsPlugin) Boot(*backpack.App) error { return nil }
|
||
|
||
func (labelsPlugin) LangFS() fs.FS {
|
||
return fstest.MapFS{
|
||
"lang/en/lang.yaml": {Data: []byte("types:\n notes: Notes\n")},
|
||
"lang/pl/lang.yaml": {Data: []byte("types:\n notes: Notatki\n")},
|
||
}
|
||
}
|
||
|
||
func (labelsPlugin) MenuItemTypes() []pact.MenuItemType {
|
||
return []pact.MenuItemType{{
|
||
Key: noteType, Label: "acme.labels::lang.types.notes", DefaultPattern: "/notes/:slug", Placeholders: []string{"slug"},
|
||
Resolve: func(context.Context, pact.MenuItemResolve) (*pact.ResolvedMenuItem, error) { return nil, nil },
|
||
Content: &pact.ContentDescriptor{
|
||
Model: "acme_notes",
|
||
Records: func(_ context.Context, in pact.ContentList) (pact.ContentPage, error) {
|
||
return contentStore.page(noteType, in), nil
|
||
},
|
||
Describe: func(context.Context, pact.ContentDescribe) (*pact.ContentRecord, error) { return nil, nil },
|
||
},
|
||
}}
|
||
}
|
||
|
||
var (
|
||
_ pact.HasMenuItemTypes = labelsPlugin{}
|
||
_ pact.HasLang = labelsPlugin{}
|
||
)
|
||
|
||
func init() {
|
||
party.Register(labelsPlugin{})
|
||
}
|
||
|
||
// TestTypeTitlesNotPinned pins L2 WR-05 (D-34): an administrator with an
|
||
// English admin loads Settings › Sitemaps and saves it back unchanged; no
|
||
// heading is stored for the content type, so the Polish HTML sitemap keeps
|
||
// the Polish translation of the type's label and the English one the
|
||
// English.
|
||
func TestTypeTitlesNotPinned(t *testing.T) {
|
||
contentStore.reset(t)
|
||
e := bootPlugins(t, []string{labelsPluginID, "golem15.sitemap"})
|
||
e.exec(t, `UPDATE golem15_sitemap_settings SET default_locale = 'pl', html_enabled = TRUE WHERE id = 1`)
|
||
at := time.Date(2026, 10, 1, 8, 0, 0, 0, time.UTC)
|
||
contentStore.put(noteType, fakeRecord{ID: 1, Published: true, LastMod: at, Locales: []pact.ContentLocale{
|
||
{Locale: "pl", URL: "/notes/pierwsza", Title: "Pierwsza"},
|
||
{Locale: "en", URL: "/en/notes/first", Title: "First"},
|
||
}})
|
||
token := e.admin(t, permSitemap)
|
||
const base = "/golem15/sitemap/settings"
|
||
rec := e.call(t, http.MethodGet, base+"/1", token, nil)
|
||
if rec.Code != http.StatusOK {
|
||
t.Fatalf("GET settings: %d %s", rec.Code, rec.Body.String())
|
||
}
|
||
var loaded struct {
|
||
Data map[string]any `json:"data"`
|
||
}
|
||
if err := json.Unmarshal(rec.Body.Bytes(), &loaded); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
values := loaded.Data
|
||
if values == nil {
|
||
if err := json.Unmarshal(rec.Body.Bytes(), &values); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
}
|
||
title, ok := values["type_acme_note_title"]
|
||
if !ok {
|
||
t.Fatalf("the form loads no heading field: %s", rec.Body.String())
|
||
}
|
||
m, _ := title.(map[string]any)
|
||
if len(m) != 0 {
|
||
t.Errorf("the form loads a heading %v for a type without one", title)
|
||
}
|
||
// Without a translation writer the form sends the default locale's
|
||
// text of the loaded value back.
|
||
sent, _ := m["pl"].(string)
|
||
if rec := e.call(t, http.MethodPut, base+"/1", token, map[string]any{
|
||
"type_acme_note_include": values["type_acme_note_include"],
|
||
"type_acme_note_slug": values["type_acme_note_slug"],
|
||
"type_acme_note_title": sent,
|
||
}); rec.Code != http.StatusOK {
|
||
t.Fatalf("PUT settings: %d %s", rec.Code, rec.Body.String())
|
||
}
|
||
var stored []string
|
||
e.gdb.Raw(`SELECT titles::text FROM golem15_sitemap_types WHERE type_key = ?`, noteType).Scan(&stored)
|
||
for _, s := range stored {
|
||
if s != "{}" && s != "null" {
|
||
t.Fatalf("a save that did not touch the heading stored %s", s)
|
||
}
|
||
}
|
||
e.rebuild(t)
|
||
for locale, want := range map[string]string{"pl": "Notatki", "en": "Notes"} {
|
||
ov := e.htmlJSON(t, "/_sitemap/api/v1/html?locale="+locale, http.StatusOK)
|
||
groups, _ := ov["groups"].([]any)
|
||
if len(groups) != 1 {
|
||
t.Fatalf("%s groups = %v", locale, ov)
|
||
}
|
||
if got := groups[0].(map[string]any)["title"]; got != want {
|
||
t.Errorf("%s group title = %v, want %s", locale, got, want)
|
||
}
|
||
}
|
||
}
|