Files
bun.sh/test/bun.js/html-rewriter.test.js
Colin McDonnell f7f1b60444 Add bun-types, add typechecking, add child_process types (#1475)
* Add bun-types to packages

* Improve typing

* Fix types in tests

* Fix dts tests

* Run formatter

* Fix all type errors

* Add strict mode, fix type errors

* Add ffi changes

* Move workflows to root

* Add workflows

* Remove labeler

* Add child_process types

* Fix synthetic defaults issue

* Remove docs

* Move scripts

* Run prettier

* Include examples in typechecking

* captureStackTrace types

* moved captureStackTrace types to globals

* Address reviews

Co-authored-by: Colin McDonnell <colinmcd@alum.mit.edu>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2022-11-09 15:40:40 -08:00

294 lines
9.2 KiB
JavaScript

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("<span>replace</span>", { html: true });
}, 5);
},
})
.transform(new Response("<div>example.com</div>"));
await gcTick();
expect(await res.text()).toBe("<div><span>replace</span></div>");
await gcTick();
});
it("supports element handlers", async () => {
var rewriter = new HTMLRewriter();
rewriter.on("div", {
element(element) {
element.setInnerContent("<blink>it worked!</blink>", { html: true });
},
});
var input = new Response("<div>hello</div>");
var output = rewriter.transform(input);
expect(await output.text()).toBe("<div><blink>it worked!</blink></div>");
});
it("(from file) supports element handlers", async () => {
var rewriter = new HTMLRewriter();
rewriter.on("div", {
element(element) {
element.setInnerContent("<blink>it worked!</blink>", { html: true });
},
});
await Bun.write("/tmp/html-rewriter.txt.js", "<div>hello</div>");
var input = new Response(Bun.file("/tmp/html-rewriter.txt.js"));
var output = rewriter.transform(input);
expect(await output.text()).toBe("<div><blink>it worked!</blink></div>");
});
it("supports attribute iterator", async () => {
var rewriter = new HTMLRewriter();
var expected = [
["first", ""],
["second", "alrihgt"],
["third", "123"],
["fourth", "5"],
["fifth", "helloooo"],
];
rewriter.on("div", {
element(element2) {
for (let attr of element2.attributes) {
const stack = expected.shift();
expect(stack[0]).toBe(attr[0]);
expect(stack[1]).toBe(attr[1]);
}
},
});
var input = new Response(
'<div first second="alrihgt" third="123" fourth=5 fifth=helloooo>hello</div>',
);
var output = rewriter.transform(input);
expect(await output.text()).toBe(
'<div first second="alrihgt" third="123" fourth=5 fifth=helloooo>hello</div>',
);
expect(expected.length).toBe(0);
});
it("handles element specific mutations", async () => {
// prepend/append
let res = new HTMLRewriter()
.on("p", {
element(element) {
element.prepend("<span>prepend</span>");
element.prepend("<span>prepend html</span>", { html: true });
element.append("<span>append</span>");
element.append("<span>append html</span>", { html: true });
},
})
.transform(new Response("<p>test</p>"));
expect(await res.text()).toBe(
[
"<p>",
"<span>prepend html</span>",
"&lt;span&gt;prepend&lt;/span&gt;",
"test",
"&lt;span&gt;append&lt;/span&gt;",
"<span>append html</span>",
"</p>",
].join(""),
);
// setInnerContent
res = new HTMLRewriter()
.on("p", {
element(element) {
element.setInnerContent("<span>replace</span>");
},
})
.transform(new Response("<p>test</p>"));
expect(await res.text()).toBe("<p>&lt;span&gt;replace&lt;/span&gt;</p>");
res = new HTMLRewriter()
.on("p", {
element(element) {
element.setInnerContent("<span>replace</span>", { html: true });
},
})
.transform(new Response("<p>test</p>"));
expect(await res.text()).toBe("<p><span>replace</span></p>");
// removeAndKeepContent
res = new HTMLRewriter()
.on("p", {
element(element) {
element.removeAndKeepContent();
},
})
.transform(new Response("<p>test</p>"));
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("<p>test</p>"));
expect(await res.text()).toBe("<p>new</p>");
});
const commentsMutationsInput = "<p><!--test--></p>";
const commentsMutationsExpected = {
beforeAfter: [
"<p>",
"&lt;span&gt;before&lt;/span&gt;",
"<span>before html</span>",
"<!--test-->",
"<span>after html</span>",
"&lt;span&gt;after&lt;/span&gt;",
"</p>",
].join(""),
replace: "<p>&lt;span&gt;replace&lt;/span&gt;</p>",
replaceHtml: "<p><span>replace</span></p>",
remove: "<p></p>",
};
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("<p><!--test--></p>"));
expect(await res.text()).toBe("<p><!--new--></p>");
};
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("*", "<h1>1</h1><p>2</p>", "<h1>new</h1><p>new</p>");
await checkSelector("p", "<h1>1</h1><p>2</p>", "<h1>1</h1><p>new</p>");
await checkSelector(
"p:nth-child(2)",
"<div><p>1</p><p>2</p><p>3</p></div>",
"<div><p>1</p><p>new</p><p>3</p></div>",
);
await checkSelector(
"p:first-child",
"<div><p>1</p><p>2</p><p>3</p></div>",
"<div><p>new</p><p>2</p><p>3</p></div>",
);
await checkSelector(
"p:nth-of-type(2)",
"<div><p>1</p><h1>2</h1><p>3</p><h1>4</h1><p>5</p></div>",
"<div><p>1</p><h1>2</h1><p>new</p><h1>4</h1><p>5</p></div>",
);
await checkSelector(
"p:first-of-type",
"<div><h1>1</h1><p>2</p><p>3</p></div>",
"<div><h1>1</h1><p>new</p><p>3</p></div>",
);
await checkSelector(
"p:not(:first-child)",
"<div><p>1</p><p>2</p><p>3</p></div>",
"<div><p>1</p><p>new</p><p>new</p></div>",
);
await checkSelector(
"p.red",
'<p class="red">1</p><p>2</p>',
'<p class="red">new</p><p>2</p>',
);
await checkSelector(
"h1#header",
'<h1 id="header">1</h1><h1>2</h1>',
'<h1 id="header">new</h1><h1>2</h1>',
);
await checkSelector(
"p[data-test]",
"<p data-test>1</p><p>2</p>",
"<p data-test>new</p><p>2</p>",
);
await checkSelector(
'p[data-test="one"]',
'<p data-test="one">1</p><p data-test="two">2</p>',
'<p data-test="one">new</p><p data-test="two">2</p>',
);
await checkSelector(
'p[data-test="one" i]',
'<p data-test="one">1</p><p data-test="OnE">2</p><p data-test="two">3</p>',
'<p data-test="one">new</p><p data-test="OnE">new</p><p data-test="two">3</p>',
);
await checkSelector(
'p[data-test="one" s]',
'<p data-test="one">1</p><p data-test="OnE">2</p><p data-test="two">3</p>',
'<p data-test="one">new</p><p data-test="OnE">2</p><p data-test="two">3</p>',
);
await checkSelector(
'p[data-test~="two"]',
'<p data-test="one two three">1</p><p data-test="one two">2</p><p data-test="one">3</p>',
'<p data-test="one two three">new</p><p data-test="one two">new</p><p data-test="one">3</p>',
);
await checkSelector(
'p[data-test^="a"]',
'<p data-test="a1">1</p><p data-test="a2">2</p><p data-test="b1">3</p>',
'<p data-test="a1">new</p><p data-test="a2">new</p><p data-test="b1">3</p>',
);
await checkSelector(
'p[data-test$="1"]',
'<p data-test="a1">1</p><p data-test="a2">2</p><p data-test="b1">3</p>',
'<p data-test="a1">new</p><p data-test="a2">2</p><p data-test="b1">new</p>',
);
await checkSelector(
'p[data-test*="b"]',
'<p data-test="abc">1</p><p data-test="ab">2</p><p data-test="a">3</p>',
'<p data-test="abc">new</p><p data-test="ab">new</p><p data-test="a">3</p>',
);
await checkSelector(
'p[data-test|="a"]',
'<p data-test="a">1</p><p data-test="a-1">2</p><p data-test="a2">3</p>',
'<p data-test="a">new</p><p data-test="a-1">new</p><p data-test="a2">3</p>',
);
await checkSelector(
"div span",
"<div><h1><span>1</span></h1><span>2</span><b>3</b></div>",
"<div><h1><span>new</span></h1><span>new</span><b>3</b></div>",
);
await checkSelector(
"div > span",
"<div><h1><span>1</span></h1><span>2</span><b>3</b></div>",
"<div><h1><span>1</span></h1><span>new</span><b>3</b></div>",
);
});
});