Files
sm-seo-plugin/sitemap_filter_test.go
Jakub Zych 17b810dfde feat: sitemap filter excludes noindex, canonicalised and redirected URLs (tracer)
- classes.SitemapFilter implements the sitemap plugin's contract.Filter on
  the production values: redirected, noindex and canonicalised addresses
  leave the sitemaps with their reason; staging lists the same set
- the plugin requires golem15.sitemap and publishes the filter in Register
- go.mod requires sm-sitemap-plugin, go.work mounts the sibling checkout
2026-11-04 13:02:39 +01:00

91 lines
3.3 KiB
Go

package seo_test
import (
"net/http"
"strings"
"testing"
sitemapclasses "git.golem15.com/golem15/sm-sitemap-plugin/classes"
)
// rebuildSitemap runs the sitemap plugin's rebuild on the test app, as its
// job and command do.
func (e *testEnv) rebuildSitemap(t *testing.T) {
t.Helper()
if _, err := sitemapclasses.Rebuild(t.Context(), e.app); err != nil {
t.Fatalf("sitemap rebuild: %v", err)
}
}
// sitemapFile fetches one sitemap file by name; a missing file is "".
func (e *testEnv) sitemapFile(t *testing.T, name string) string {
t.Helper()
rec := e.call(t, http.MethodGet, "/_sitemap/files/"+name, "", nil)
if rec.Code == http.StatusNotFound {
return ""
}
if rec.Code != http.StatusOK {
t.Fatalf("GET %s = %d: %s", name, rec.Code, rec.Body.String())
}
return rec.Body.String()
}
// sitemapReason is the excluded reason the sitemap stored for a record's
// address in a locale ("" while it is listed).
func (e *testEnv) sitemapReason(t *testing.T, typeKey, id, locale string) string {
t.Helper()
var rows []string
if err := e.db.Raw(`SELECT excluded_reason FROM golem15_sitemap_urls WHERE type_key = ? AND record_id = ? AND locale = ?`, typeKey, id, locale).Scan(&rows).Error; err != nil {
t.Fatal(err)
}
if len(rows) == 0 {
t.Fatalf("no sitemap row for %s %s %s", typeKey, id, locale)
}
return rows[0]
}
// TestSitemapFilterTracer is the plan's tracer: an editor sets a page to
// noindex in the SEO tab, the sitemap rebuild asks the SEO plugin's
// published filter, and the page leaves the sitemap file with the reason
// noindex. Staging lists the same set as production (the non-production
// lock never excludes an address).
func TestSitemapFilterTracer(t *testing.T) {
for _, envName := range []string{"production", "staging"} {
t.Run(envName, func(t *testing.T) {
env := bootEnv(t, "SUMMER_ENV="+envName)
token := env.admin(t, true)
first := env.createPage(t, token, map[string]any{"title": "First", "slug": "first", "published": true})
second := env.createPage(t, token, map[string]any{"title": "Second", "slug": "second", "published": true})
env.rebuildSitemap(t)
file := env.sitemapFile(t, "sitemap-pages-1.xml")
if !strings.Contains(file, ".test/pages/first</loc>") || !strings.Contains(file, ".test/pages/second</loc>") {
t.Fatalf("before noindex the file lists both pages:\n%s", file)
}
env.expect(t, http.StatusOK, http.MethodPut, adminAPI("/acme/pages/pages/"+first), token, map[string]any{
"title": "First", "slug": "first", "published": true,
"seo_robots": map[string]any{"en": "noindex"},
})
env.rebuildSitemap(t)
file = env.sitemapFile(t, "sitemap-pages-1.xml")
if strings.Contains(file, ".test/pages/first</loc>") {
t.Fatalf("the noindex page is still listed:\n%s", file)
}
if !strings.Contains(file, ".test/pages/second</loc>") {
t.Fatalf("the indexable page left the file:\n%s", file)
}
if got := env.sitemapReason(t, "acme-page", first, "en"); got != "noindex" {
t.Fatalf("excluded reason = %q, want noindex", got)
}
if got := env.sitemapReason(t, "acme-page", second, "en"); got != "" {
t.Fatalf("second page reason = %q, want listed", got)
}
// The pl address has no noindex of its own and stays listed.
if got := env.sitemapReason(t, "acme-page", first, "pl"); got != "" {
t.Fatalf("pl address reason = %q, want listed", got)
}
})
}
}