2026-05-16 16:36:51 -07:00
|
|
|
import assert from "node:assert/strict";
|
|
|
|
|
import test from "node:test";
|
2026-05-16 22:07:39 -07:00
|
|
|
import {
|
|
|
|
|
getCosmeticCssForHostname,
|
|
|
|
|
parseFilterRules,
|
|
|
|
|
renderPage,
|
|
|
|
|
shouldBlockRequestWithRules
|
|
|
|
|
} from "../src/archiver.mjs";
|
|
|
|
|
|
|
|
|
|
test("parses EasyList-style network rules, exceptions, and badfilter entries", () => {
|
|
|
|
|
const rules = parseFilterRules(`
|
|
|
|
|
[Adblock Plus 2.0]
|
|
|
|
|
||ads.example.com^$script,third-party
|
|
|
|
|
@@||ads.example.com/allowed.js$script,domain=publisher.test
|
|
|
|
|
banner$~image
|
|
|
|
|
||disabled.example^$script
|
|
|
|
|
||disabled.example^$script,badfilter
|
|
|
|
|
`);
|
|
|
|
|
|
|
|
|
|
assert.equal(
|
|
|
|
|
shouldBlockRequestWithRules(
|
|
|
|
|
rules,
|
|
|
|
|
"https://ads.example.com/banner.js",
|
|
|
|
|
"script",
|
|
|
|
|
"www.publisher.test"
|
|
|
|
|
),
|
|
|
|
|
true
|
|
|
|
|
);
|
|
|
|
|
assert.equal(
|
|
|
|
|
shouldBlockRequestWithRules(
|
|
|
|
|
rules,
|
|
|
|
|
"https://ads.example.com/banner.png",
|
|
|
|
|
"image",
|
|
|
|
|
"www.publisher.test"
|
|
|
|
|
),
|
|
|
|
|
false
|
|
|
|
|
);
|
|
|
|
|
assert.equal(
|
|
|
|
|
shouldBlockRequestWithRules(
|
|
|
|
|
rules,
|
|
|
|
|
"https://ads.example.com/allowed.js",
|
|
|
|
|
"script",
|
|
|
|
|
"www.publisher.test"
|
|
|
|
|
),
|
|
|
|
|
false
|
|
|
|
|
);
|
|
|
|
|
assert.equal(
|
|
|
|
|
shouldBlockRequestWithRules(
|
|
|
|
|
rules,
|
|
|
|
|
"https://disabled.example/ad.js",
|
|
|
|
|
"script",
|
|
|
|
|
"www.publisher.test"
|
|
|
|
|
),
|
|
|
|
|
false
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("applies cosmetic filters with domain exceptions and skips unsupported procedural selectors", () => {
|
|
|
|
|
const rules = parseFilterRules(`
|
|
|
|
|
##.generic-ad
|
|
|
|
|
example.com##.site-ad
|
|
|
|
|
example.com#@#.generic-ad
|
|
|
|
|
~news.example.com,example.com##.except-news
|
|
|
|
|
example.*##.entity-ad
|
|
|
|
|
bad.example##div:has-text(ad)
|
|
|
|
|
foo.com#$#.adguard { display: none !important; }
|
|
|
|
|
`);
|
|
|
|
|
|
|
|
|
|
const exampleCss = getCosmeticCssForHostname(rules, "www.example.com").join("\n");
|
|
|
|
|
assert.doesNotMatch(exampleCss, /\.generic-ad/);
|
|
|
|
|
assert.match(exampleCss, /\.site-ad/);
|
|
|
|
|
assert.match(exampleCss, /\.except-news/);
|
|
|
|
|
assert.match(exampleCss, /\.entity-ad/);
|
|
|
|
|
|
|
|
|
|
const newsCss = getCosmeticCssForHostname(rules, "news.example.com").join("\n");
|
|
|
|
|
assert.doesNotMatch(newsCss, /\.except-news/);
|
|
|
|
|
assert.equal(getCosmeticCssForHostname(rules, "bad.example").length, 1);
|
|
|
|
|
assert.match(getCosmeticCssForHostname(rules, "foo.com").join("\n"), /\.adguard/);
|
|
|
|
|
});
|
2026-05-16 16:36:51 -07:00
|
|
|
|
|
|
|
|
test("renderPage serializes CSSOM-inserted style rules", async () => {
|
|
|
|
|
const html = `<!doctype html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<style id="runtime-style"></style>
|
|
|
|
|
<script>
|
|
|
|
|
document
|
|
|
|
|
.getElementById("runtime-style")
|
|
|
|
|
.sheet
|
|
|
|
|
.insertRule(".runtime-rule { color: rgb(1, 2, 3); }", 0);
|
|
|
|
|
</script>
|
|
|
|
|
</head>
|
|
|
|
|
<body><div class="runtime-rule">Styled by CSSOM</div></body>
|
|
|
|
|
</html>`;
|
|
|
|
|
|
|
|
|
|
const rendered = await renderPage(`data:text/html,${encodeURIComponent(html)}`, {
|
|
|
|
|
userscriptDelay: 0
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
assert.match(rendered, /<style id="runtime-style">[\s\S]*\.runtime-rule/);
|
|
|
|
|
assert.match(rendered, /color:\s*rgb\(1,\s*2,\s*3\)/);
|
|
|
|
|
});
|