import { describe, expect, test } from "bun:test"; import { mergeSectionTranslations, transformLocalizedPaths, validateSectionPayload, } from "./pages"; describe("Page section payload validation", () => { test("accepts a DIVIDER payload", () => { const result = validateSectionPayload("DIVIDER", { width: "narrow", style: "dotted", thickness: 2, spacing: "xl", }); expect(result.success).toBe(true); }); test.each(["#123", "#AbC8", "#12aBcD", "#12aBcD80"])( "accepts DIVIDER color %s", (color) => { const result = validateSectionPayload("DIVIDER", { width: "container", style: "solid", thickness: 1, spacing: "md", color, }); expect(result.success).toBe(true); }, ); test.each(["red", "#12", "#12345", "#123456789", "#fff; background: url(javascript:alert(1))"])( "rejects unsafe DIVIDER color %s", (color) => { const result = validateSectionPayload("DIVIDER", { width: "container", style: "solid", thickness: 1, spacing: "md", color, }); expect(result.success).toBe(false); expect(result.issues?.[0]?.path).toEqual(["color"]); expect(result.issues?.[0]?.message).toBe( "Color must be a hex value in #RGB, #RGBA, #RRGGBB, or #RRGGBBAA format", ); }, ); test("rejects an unsupported DIVIDER width", () => { const result = validateSectionPayload("DIVIDER", { width: "wide", style: "solid", thickness: 1, spacing: "sm", }); expect(result.success).toBe(false); expect(result.issues?.[0]?.path).toEqual(["width"]); }); }); describe("Page section localization", () => { const paths = ["title", "items[].title", "items[].note"]; const payload = { title: { th: "เอกสารอ้างอิง", en: "References" }, items: [{ title: { th: "เทคโนโลยีไฟน์แบลงก์", en: "Fine blanking technology" }, note: { th: "ข้อมูลทางเทคนิค" }, url: "https://example.com/reference", }], variant: "numbered", }; test("resolves only the requested language and reports missing nested fields", () => { const result = transformLocalizedPaths(payload, paths, "zh", false); expect(result.payload).toEqual({ title: null, items: [{ title: null, note: null, url: "https://example.com/reference", }], variant: "numbered", }); expect(result.fallbackPaths).toEqual([ "title", "items[0].title", "items[0].note", ]); }); test("merges one language while preserving other languages and configuration", () => { const result = mergeSectionTranslations(payload, { title: "参考资料", items: [{ title: "精密冲裁技术", note: "技术资料", }], }, paths, "zh"); expect(result.payload).toEqual({ title: { th: "เอกสารอ้างอิง", en: "References", zh: "参考资料" }, items: [{ title: { th: "เทคโนโลยีไฟน์แบลงก์", en: "Fine blanking technology", zh: "精密冲裁技术", }, note: { th: "ข้อมูลทางเทคนิค", zh: "技术资料" }, url: "https://example.com/reference", }], variant: "numbered", }); expect(result.translatedPaths).toEqual([ "title", "items[0].title", "items[0].note", ]); }); test("rejects an array shape that cannot be merged safely", () => { expect(() => mergeSectionTranslations(payload, { items: [], }, paths, "zh")).toThrow("Translation array shape mismatch at items"); }); });