Files
sm-sitemap-plugin/type_titles_test.go
Jakub Zych da32044d5b fix: HTML sitemap headings follow each locale until an editor sets one
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.
2026-11-04 23:08:38 +01:00

129 lines
4.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}
}
}