import { describe, expect, it } from "vitest"; import { applyPatch, applyPatchByTarget, readAttributeByTarget, readTagSnippetByTarget, type PatchOperation, } from "./sourcePatcher"; describe("applyPatchByTarget", () => { it("updates a composition host by data-composition-id selector", () => { const html = `
`; const op: PatchOperation = { type: "attribute", property: "start", value: "2.5" }; expect(applyPatchByTarget(html, { selector: '[data-composition-id="intro"]' }, op)).toContain( 'data-start="2.5"', ); }); it("updates a class-based layer when the clip has no DOM id", () => { const html = ``; const op: PatchOperation = { type: "attribute", property: "track-index", value: "3" }; expect(applyPatchByTarget(html, { selector: ".headline" }, op)).toContain( 'data-track-index="3"', ); }); it("updates inline z-index by selector when the clip has no DOM id", () => { const html = ``; const op: PatchOperation = { type: "inline-style", property: "z-index", value: "3" }; expect(applyPatchByTarget(html, { selector: ".headline" }, op)).toContain( 'style="position: absolute; opacity: 1; z-index: 3"', ); }); it("patches inline move styles by target", () => { const html = ``; const withLeft = applyPatchByTarget( html, { id: "card" }, { type: "inline-style", property: "left", value: "160px" }, ); const withTop = applyPatchByTarget( withLeft, { id: "card" }, { type: "inline-style", property: "top", value: "140px" }, ); expect(withTop).toContain('style="position: absolute; left: 160px; top: 140px"'); }); it("patches inline resize styles by target", () => { const html = ``; const withWidth = applyPatchByTarget( html, { id: "card" }, { type: "inline-style", property: "width", value: "420px" }, ); const withHeight = applyPatchByTarget( withWidth, { id: "card" }, { type: "inline-style", property: "height", value: "220px" }, ); expect(withHeight).toContain('style="position: absolute; width: 420px; height: 220px"'); }); it("escapes quoted CSS urls inside double-quoted style attributes", () => { const html = ``; const withBackground = applyPatchByTarget( html, { id: "card" }, { type: "inline-style", property: "background-image", value: `url("../ChatGPT Image Apr 22, 2026.png")`, }, ); const withRadius = applyPatchByTarget( withBackground, { id: "card" }, { type: "inline-style", property: "border-radius", value: "12px" }, ); expect(withRadius).toContain( "background-image: url("../ChatGPT Image Apr 22, 2026.png")", ); expect(withRadius).toContain("border-radius: 12px"); }); it("updates media timing attributes by selector", () => { const html = ``; const withDuration = applyPatchByTarget( html, { selector: ".hero" }, { type: "attribute", property: "duration", value: "1.1", }, ); const withMediaStart = applyPatchByTarget( withDuration, { selector: ".hero" }, { type: "attribute", property: "media-start", value: "0.7", }, ); expect(withMediaStart).toContain('data-duration="1.1"'); expect(withMediaStart).toContain('data-media-start="0.7"'); }); it("reads media timing attributes by selector", () => { const html = ``; expect(readAttributeByTarget(html, { selector: ".hero" }, "media-start")).toBe("0.4"); expect(readAttributeByTarget(html, { selector: ".hero" }, "duration")).toBe("1.4"); }); it("reads the matched tag snippet by target", () => { const html = ``; expect(readTagSnippetByTarget(html, { id: "hero" })).toBe( `Outside
'; const patched = applyPatch(html, "panel", { type: "text-content", property: "text", value: "New headlineNew supporting copy", }); expect(patched).toContain( 'Outside
"); }); it("does not stop at the first child closing tag when patching nested text", () => { const html = 'Outside
'; const patched = applyPatchByTarget( html, { id: "card" }, { type: "text-content", property: "text", value: "New headline", }, ); expect(patched).toBe( 'Outside
', ); }); it("patches the correct duplicate selector occurrence", () => { const html = [ ``, ``, ].join(""); const patched = applyPatchByTarget( html, { selector: ".headline", selectorIndex: 1 }, { type: "attribute", property: "start", value: "2.5", }, ); expect(patched).toContain(``); expect(patched).toContain(``); }); });