import { test } from "node:test"; import assert from "node:assert/strict"; import { normalizeSocialSvg, socialSvgProblem } from "./settingsSchema"; import { SVG_PROBLEM } from "./socialSvg"; import { scopeSvgIds, sizeSocialSvg } from "./socialLinks"; import { ADVERSARIAL, LOADS_ELSEWHERE, REAL_SHAPES } from "./socialSvg.vectors"; // normalizeSocialSvg runs on every save of a social link (Settings, a site's // form, the homepage config). It used to theme only the ROOT 's fill, so a // child that paints itself kept its colour: the operator's x.com icon — X's // official file, `fill="none"` on the root and `fill="white"` on its one path — // was white on the light footer (1.11:1; release 10, slice O's screenshots). // A SINGLE-colour icon's fills — root and children — now become currentColor // (the footer link's colour, which follows the theme); no paint, gradients and // mask values stay. An icon of two or more colours draws its shape with them // (YouTube's mark, a badge) and keeps every colour as pasted (review, O1). // The two icons in the operator's settings.json, verbatim (2026-09-28). const X_COM = ``; const KIWI_FARMS = ``; // The export e2e fixture's icon (already normalized) and the editor e2e's // un-normalized one. const FIXTURE = ``; const BARE = ``; // YouTube's official mark (Wikimedia's "YouTube full-color icon"): a red // rounded rectangle and a white play triangle. Two colours ARE its shape. const YOUTUBE = ``; // The common "badge": a dark disc with a white glyph cut into it. const BADGE = ``; // Every fill attribute / style declaration, in document order. const fills = (svg: string) => [...svg.matchAll(/\sfill\s*=\s*"([^"]*)"|[;"']\s*fill\s*:\s*([^;"']*)/g)].map( (m) => m[1] ?? m[2], ); function normalized(raw: string): string { const out = normalizeSocialSvg(raw); assert.ok(out, "accepted"); return out; } test("x.com: the path's white becomes currentColor; the root keeps fill=none", () => { const out = normalized(X_COM); assert.deepEqual(fills(out), ["none", "currentColor"]); assert.ok(out.startsWith('`, }; test("the review's five bypasses are refused", () => { for (const [name, raw] of Object.entries(REVIEW_BYPASSES)) { assert.equal(normalizeSocialSvg(raw), null, name); assert.ok(socialSvgProblem(raw), name); } }); const OK = (inner: string, open = ``) => `${open}${inner}`; test("an event handler is refused wherever an attribute can start", () => { for (const raw of [ ``, ``, ``, ``, OK(``), OK(``), ]) { assert.equal(socialSvgProblem(raw), SVG_PROBLEM.handler, raw); } // A `/` between attributes (which HTML takes as a separator) is not markup // this reads. assert.equal(socialSvgProblem(``), SVG_PROBLEM.markup); }); test("a script, or a link that runs one, in any spelling", () => { for (const raw of [ OK(``), OK(``), OK(``), OK(``), OK(``), OK(``), OK(``), ]) { assert.equal(socialSvgProblem(raw), SVG_PROBLEM.script, raw); } }); test("a link to anything but a fragment of this icon", () => { for (const raw of [ OK(``), OK(``), OK(``), OK(``), OK(``), OK(``), OK(``), OK(``), ]) { assert.equal(socialSvgProblem(raw), SVG_PROBLEM.external, raw); } // A fragment, in each spelling a reference takes, is fine. for (const raw of [ OK(``), OK(``), ]) { assert.equal(socialSvgProblem(raw), null, raw); } }); test("elements an icon has no use for, named", () => { for (const [inner, name] of [ [`
`, "foreignObject"], [``, "style"], [``, "a"], [``, "image"], [`