test(16.2-06): full unit coverage of the Journal Blog Editor field types

- Decode: clean values byte for byte, nil, non-string refusal, the 35
  unsafe payloads stripped with notices exactly when changed
- notices order, ten-name cut, plural forms in lang/en and lang/pl
- LooksLikeHTML, options, ListValue, Upload sniffing and safe names
- StoreMedia layout, suffixes, no overwrite, size and folder rules
- editor corpus and policy cross-check extended in place: more negatives,
  notices only when stripped, stable second pass
- TestPostsEditorHooks: create and update, default and non-default
  writes, no writes, no writer
- TestCategoriesAdminBlogEditor (Docker host): untouched saves keep
  imported markup and NULL, clean edit, strip and report, blank to NULL,
  editor upload
This commit is contained in:
2026-10-10 15:55:00 +02:00
parent d5a5413525
commit da7a0732c3
5 changed files with 1110 additions and 0 deletions

View File

@@ -66,6 +66,25 @@ func tagAttrs(doc, tag string) [][]string {
// and with an empty removal report, and its four editor-output additions
// (figure data-embed and data-id, img alt, ol start) admit nothing else.
func TestEditorOutputPassesPolicy(t *testing.T) {
t.Run("corpus is the editor's full output set", func(t *testing.T) {
corpus := editorCorpus(t)
if len(corpus) < 15 {
t.Fatalf("corpus has %d entries, want at least 15", len(corpus))
}
names := map[string]bool{}
for _, e := range corpus {
if e.Name == "" || strings.TrimSpace(e.HTML) == "" || names[e.Name] {
t.Fatalf("corpus entry %q is empty or repeated", e.Name)
}
names[e.Name] = true
}
for _, want := range []string{"embed-youtube", "image-with-caption", "image-without-caption", "ordered-list-start-3", "table-header-row", "links", "combined"} {
if !names[want] {
t.Fatalf("corpus has no %s entry", want)
}
}
})
for _, e := range editorCorpus(t) {
t.Run("corpus "+e.Name, func(t *testing.T) {
if got := SanitizeHTML(e.HTML); got != e.HTML {
@@ -77,6 +96,7 @@ func TestEditorOutputPassesPolicy(t *testing.T) {
if err := CheckHTML(e.HTML); err != nil {
t.Fatalf("CheckHTML = %v", err)
}
assertNoActiveContent(t, e.HTML)
})
}
@@ -114,6 +134,15 @@ func TestEditorOutputPassesPolicy(t *testing.T) {
{"negative start", `<ol start="-1"><li>a</li></ol>`, `<ol><li>a</li></ol>`},
{"start on ul", `<ul start="3"><li>a</li></ul>`, `<ul><li>a</li></ul>`},
{"alt on p", `<p alt="x">y</p>`, `<p>y</p>`},
{"upper-case provider", `<figure data-embed="YouTube" data-id="dQw4w9WgXcQ"></figure>`, `<figure data-id="dQw4w9WgXcQ"></figure>`},
{"provider with white space", `<figure data-embed=" youtube" data-id="dQw4w9WgXcQ"></figure>`, `<figure data-id="dQw4w9WgXcQ"></figure>`},
{"empty id", `<figure data-embed="youtube" data-id=""></figure>`, `<figure data-embed="youtube"></figure>`},
{"id with a URL", `<figure data-embed="youtube" data-id="javascript:1"></figure>`, `<figure data-embed="youtube"></figure>`},
{"iframe alone", `<iframe src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ"></iframe>`, ``},
{"script inside the placeholder", `<figure data-embed="youtube" data-id="dQw4w9WgXcQ"><script>alert(1)</script></figure>`, editorPlaceholder},
{"embed attributes on section", `<section data-embed="youtube" data-id="dQw4w9WgXcQ">x</section>`, `<section>x</section>`},
{"embed attributes on a", `<a href="/x" data-embed="youtube" data-id="dQw4w9WgXcQ">x</a>`, `<a href="/x">x</a>`},
{"start with a fraction", `<ol start="1.5"><li>a</li></ol>`, `<ol><li>a</li></ol>`},
}
for _, tc := range stripped {
t.Run("strips "+tc.name, func(t *testing.T) {
@@ -248,6 +277,29 @@ func TestSanitizeHTMLReport(t *testing.T) {
if got != SanitizeHTML(in) {
t.Fatalf("SanitizeHTMLReport and SanitizeHTML disagree on %q", in)
}
// Notices only when something was stripped (D-10 amended).
if notices := removalNotices(r); (len(notices) == 0) != (got == in) {
t.Fatalf("SanitizeHTMLReport(%q): %d notices, output changed = %v", in, len(notices), got != in)
}
// The report is stable: sanitizing the output again changes nothing.
if again, r2 := SanitizeHTMLReport(got); again != got || !r2.Empty() {
t.Fatalf("second pass over %q = %q, %+v", got, again, r2)
}
}
})
t.Run("the imported post is stripped of exactly its style block", func(t *testing.T) {
fixture, err := os.ReadFile("../tests/blogeditor/fixtures/imported-post.html")
if err != nil {
t.Fatal(err)
}
got, r := SanitizeHTMLReport(string(fixture))
if got == string(fixture) || r.Empty() {
t.Fatalf("the imported post passed the policy unchanged; the fixture should hold markup the policy strips")
}
if !slices.Contains(r.Elements, "style") {
t.Fatalf("report = %+v, want the style element named", r)
}
assertNoActiveContent(t, got)
})
}