import { describe, it, expect } from "bun:test"; import { gcTick } from "./gc"; var setTimeoutAsync = (fn, delay) => { return new Promise((resolve, reject) => { setTimeout(() => { try { resolve(fn()); } catch (e) { reject(e); } }, delay); }); }; describe("HTMLRewriter", () => { it("HTMLRewriter: async replacement", async () => { await gcTick(); const res = new HTMLRewriter() .on("div", { async element(element) { await setTimeoutAsync(() => { element.setInnerContent("replace", { html: true }); }, 5); }, }) .transform(new Response("
test
")); expect(await res.text()).toBe( [ "", "prepend html", "<span>prepend</span>", "test", "<span>append</span>", "append html", "
", ].join(""), ); // setInnerContent res = new HTMLRewriter() .on("p", { element(element) { element.setInnerContent("replace"); }, }) .transform(new Response("test
")); expect(await res.text()).toBe("<span>replace</span>
"); res = new HTMLRewriter() .on("p", { element(element) { element.setInnerContent("replace", { html: true }); }, }) .transform(new Response("test
")); expect(await res.text()).toBe("replace
"); // removeAndKeepContent res = new HTMLRewriter() .on("p", { element(element) { element.removeAndKeepContent(); }, }) .transform(new Response("test
")); expect(await res.text()).toBe("test"); }); it("handles element class properties", async () => { class Handler { constructor(content) { this.content = content; } // noinspection JSUnusedGlobalSymbols element(element) { element.setInnerContent(this.content); } } const res = new HTMLRewriter().on("p", new Handler("new")).transform(new Response("test
")); expect(await res.text()).toBe("new
"); }); const commentsMutationsInput = ""; const commentsMutationsExpected = { beforeAfter: [ "", "<span>before</span>", "before html", "", "after html", "<span>after</span>", "
", ].join(""), replace: "<span>replace</span>
", replaceHtml: "replace
", remove: "", }; const commentPropertiesMacro = async func => { const res = func(new HTMLRewriter(), comment => { expect(comment.removed).toBe(false); expect(comment.text).toBe("test"); comment.text = "new"; expect(comment.text).toBe("new"); }).transform(new Response("")); expect(await res.text()).toBe(""); }; it("HTMLRewriter: handles comment properties", () => commentPropertiesMacro((rw, comments) => { rw.on("p", { comments }); return rw; })); it("selector tests", async () => { const checkSelector = async (selector, input, expected) => { const res = new HTMLRewriter() .on(selector, { element(element) { element.setInnerContent("new"); }, }) .transform(new Response(input)); expect(await res.text()).toBe(expected); }; await checkSelector("*", "2
", "new
"); await checkSelector("p", "2
", "new
"); await checkSelector( "p:nth-child(2)", "1
2
3
1
new
3
1
2
3
new
2
3
1
3
5
1
new
5
2
3
new
3
1
2
3
1
new
new
1
2
', 'new
2
'); await checkSelector("h1#header", '1
2
", "new
2
"); await checkSelector( 'p[data-test="one"]', '1
2
', 'new
2
', ); await checkSelector( 'p[data-test="one" i]', '1
2
3
', 'new
new
3
', ); await checkSelector( 'p[data-test="one" s]', '1
2
3
', 'new
2
3
', ); await checkSelector( 'p[data-test~="two"]', '1
2
3
', 'new
new
3
', ); await checkSelector( 'p[data-test^="a"]', '1
2
3
', 'new
new
3
', ); await checkSelector( 'p[data-test$="1"]', '1
2
3
', 'new
2
new
', ); await checkSelector( 'p[data-test*="b"]', '1
2
3
', 'new
new
3
', ); await checkSelector( 'p[data-test|="a"]', '1
2
3
', 'new
new
3
', ); await checkSelector( "div span", "