commit 24853c3c9f7b03d4c7f479ae0175a59702bfade6
parent 7af27067438e287edde460a32cc5f234c15b261f
Author: Tom Schuster <tschuster@mozilla.com>
Date: Tue, 21 Oct 2025 12:02:59 +0000
Bug 1995299 - More tests for the Sanitizer constructor. r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D269375
Diffstat:
1 file changed, 155 insertions(+), 71 deletions(-)
diff --git a/testing/web-platform/tests/sanitizer-api/sanitizer-config.tentative.html b/testing/web-platform/tests/sanitizer-api/sanitizer-config.tentative.html
@@ -231,89 +231,129 @@ test(() => {
// This is tested in the sanitizer-config test file.
// 4. None of config[elements], config[removeElements], config[replaceWithChildrenElements], config[attributes], or config[removeAttributes], if they exist, has duplicates.
+const DUPLICATE_NAMES = [
+ ["", ""],
+ ["abc", "abc"],
+ ["data-xyz", "data-xyz"],
+ ["abc", {name: "abc"}],
+ [{name: "abc", namespace: "xyz"}, {name: "abc", namespace: "xyz"}],
+ [{name: "abc", namespace: ""}, {name: "abc", namespace: null}]
+];
+
+// NOTE: Elements and attributes have different default namespaces.
+const DUPLICATE_ELEMENT_NAMES = DUPLICATE_NAMES.concat([
+ ["abc", {name: "abc", namespace: "http://www.w3.org/1999/xhtml"}],
+ [{name: "abc"}, {name: "abc", namespace: "http://www.w3.org/1999/xhtml"}]
+]);
+
+const DUPLICATE_ATTRIBUTE_NAMES = DUPLICATE_NAMES.concat([
+ ["abc", {name: "abc", namespace: null}],
+ [{name: "abc"}, {name: "abc", namespace: null}]
+]);
+
test(() => {
- assert_throws_js(TypeError, () => {
- new Sanitizer({ elements: ["div", { name: "div" }] });
- });
+ for (let names of DUPLICATE_ELEMENT_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({ elements: names });
+ });
+ }
}, "config[elements] should not allow duplicates");
test(() => {
- assert_throws_js(TypeError, () => {
- new Sanitizer({ removeElements: ["div", { name: "div" }] });
- });
+ for (let names of DUPLICATE_ELEMENT_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({ removeElements: names });
+ });
+ }
}, "config[removeElements] should not allow duplicates");
test(() => {
- assert_throws_js(TypeError, () => {
- new Sanitizer({ replaceWithChildrenElements: ["div", { name: "div" }] });
- });
+ for (let names of DUPLICATE_ELEMENT_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({ replaceWithChildrenElements: names });
+ });
+ }
}, "config[replaceWithChildrenElements] should not allow duplicates");
test(() => {
- assert_throws_js(TypeError, () => {
- new Sanitizer({ attributes: ["title", { name: "title" }] });
- });
+ for (let names of DUPLICATE_ATTRIBUTE_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({ attributes: names });
+ });
+ }
}, "config[attributes] should not allow duplicates");
test(() => {
- assert_throws_js(TypeError, () => {
- new Sanitizer({ removeAttributes: ["title", { name: "title" }] });
- });
+ for (let names of DUPLICATE_ATTRIBUTE_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({ removeAttributes: names });
+ });
+ }
}, "config[removeAttributes] should not allow duplicates");
// 5. If both config[elements] and config[replaceWithChildrenElements] exist, then the intersection of config[elements] and config[replaceWithChildrenElements] is empty.
test(() => {
- assert_throws_js(TypeError, () => {
- new Sanitizer({
- elements: ["div"],
- replaceWithChildrenElements: ["div"],
+ for (let [a, b] of DUPLICATE_ELEMENT_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({
+ elements: [a],
+ replaceWithChildrenElements: [b],
+ });
});
- });
+ }
}, "config[elements] and config[replaceWithChildrenElements] should not intersect");
// 6. If both config[removeElements] and config[replaceWithChildrenElements] exist, then the intersection of config[removeElements] and config[replaceWithChildrenElements] is empty.
test(() => {
- assert_throws_js(TypeError, () => {
- new Sanitizer({
- removeElements: ["div"],
- replaceWithChildrenElements: ["div"],
+ for (let [a, b] of DUPLICATE_ELEMENT_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({
+ removeElements: [a],
+ replaceWithChildrenElements: [b],
+ });
});
- });
+ }
}, "config[removeElements] and config[replaceWithChildrenElements] should not intersect");
-// If config[attributes] exists:
-// Neither element[attributes] nor element[removeAttributes], if they exist, has duplicates.
+// 7. If config[attributes] exists:
+// 7.1. If config[elements] exists:
+// 7.1.1. For each element of config[elements]:
+// 7.1.1.1. Neither element[attributes] nor element[removeAttributes], if they exist, has duplicates.
test(() => {
- assert_throws_js(TypeError, () => {
- new Sanitizer({
- attributes: [],
- elements: [{ name: "div", attributes: ["title", { name: "title" }] }],
+ for (let names of DUPLICATE_ATTRIBUTE_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({
+ attributes: [],
+ elements: [{ name: "div", attributes: names }],
+ });
});
- });
-}, "Duplicates in element[attributes] should not be allowed.");
+ }
+}, "Duplicates in element[attributes] with config[attributes] should not be allowed.");
test(() => {
- assert_throws_js(TypeError, () => {
- new Sanitizer({
- removeAttributes: [],
- elements: [
- { name: "div", removeAttributes: ["title", { name: "title" }] },
- ],
+ for (let names of DUPLICATE_ATTRIBUTE_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({
+ attributes: [],
+ elements: [{ name: "div", removeAttributes: names }],
+ });
});
- });
-}, "Duplicates in element[removeAttributes] should not be allowed.");
+ }
+}, "Duplicates in element[removeAttributes] with config[attributes] should not be allowed.");
-// The intersection of config[attributes] and element[attributes] with default « » is empty.
+// 7.1.1.2. The intersection of config[attributes] and element[attributes] with default « » is empty.
test(() => {
- assert_throws_js(TypeError, () => {
- new Sanitizer({
- attributes: ["title"],
- elements: [{ name: "div", attributes: ["title"] }],
+ for (let [a, b] of DUPLICATE_ATTRIBUTE_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({
+ attributes: [a],
+ elements: [{ name: "div", attributes: [b] }],
+ });
});
- });
+ }
}, "config[attributes] and element[attributes] should not intersect.");
-// element[removeAttributes] with default « » is a subset of config[attributes].
+// 7.1.1.3. element[removeAttributes] with default « » is a subset of config[attributes].
test(() => {
assert_throws_js(TypeError, () => {
new Sanitizer({
@@ -323,8 +363,8 @@ test(() => {
});
}, "element[removeAttributes] should be a subset of config[attributes]");
-// If dataAttributes exists and dataAttributes is true:
-// element[attributes] does not contain a custom data attribute.
+// 7.1.1.4. If dataAttributes exists and dataAttributes is true:
+// 7.1.1.4.1. element[attributes] does not contain a custom data attribute.
test(() => {
assert_throws_js(TypeError, () => {
new Sanitizer({
@@ -333,23 +373,37 @@ test(() => {
elements: [{ name: "div", attributes: ["data-foo"] }],
});
});
-}, "Per-element allow list with a data attribute must not co-exist with config[dataAttributes] set to true.");
-// If dataAttributes is true:
-// config[attributes] does not contain a custom data attribute.
-test(() => {
assert_throws_js(TypeError, () => {
new Sanitizer({
attributes: [],
dataAttributes: true,
+ elements: [{ name: "div", attributes: [{ name: "data-bar", namespace: null }] }],
+ });
+ });
+}, "element[attributes] with a data attribute must not co-exist with config[dataAttributes] set to true.");
+
+// 7.2. If dataAttributes is true:
+// 7.2.1. config[attributes] does not contain a custom data attribute.
+test(() => {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({
attributes: ["data-bar"],
+ dataAttributes: true,
});
});
-}, "Global attribute allow-list with a data attribute must not co-exist with config[dataAttributes] set to true.");
-// If config[removeAttributes] exists:
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({
+ attributes: [{ name: "data-foo", namespace: null }],
+ dataAttributes: true,
+ });
+ });
+}, "config[attributes] with a data attribute must not co-exist with config[dataAttributes] set to true.");
-// Not both element[attributes] and element[removeAttributes] exist.
+// 8. If config[removeAttributes] exists:
+// 8.1. If config[elements] exists, then for each element of config[elements]:
+// 8.1.1. Not both element[attributes] and element[removeAttributes] exist.
test(() => {
assert_throws_js(TypeError, () => {
new Sanitizer({
@@ -359,33 +413,63 @@ test(() => {
});
}, "element[attributes] and element[removeAttributes] should not both exist with config[removeAttributes].");
-// The intersection of config[removeAttributes] and element[attributes] with default « » is empty.
+// 8.1.2. Neither element[attributes] nor element[removeAttributes], if they exist, has duplicates.
test(() => {
- assert_throws_js(TypeError, () => {
- new Sanitizer({
- removeAttributes: ["class"],
- elements: [{ name: "div", attributes: ["class"] }],
+ for (let names of DUPLICATE_ATTRIBUTE_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({
+ removeAttributes: [],
+ elements: [{ name: "div", attributes: names }],
+ });
});
- });
+ }
+}, "Duplicates in element[attributes] with config[removeAttributes] should not be allowed.");
+
+test(() => {
+ for (let names of DUPLICATE_ATTRIBUTE_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({
+ removeAttributes: [],
+ elements: [{ name: "div", removeAttributes: names }],
+ });
+ });
+ }
+}, "Duplicates in element[removeAttributes] with config[removeAttributes] should not be allowed.");
+
+// 8.1.3. The intersection of config[removeAttributes] and element[attributes] with default « » is empty.
+test(() => {
+ for (let [a, b] of DUPLICATE_ATTRIBUTE_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({
+ removeAttributes: [a],
+ elements: [{ name: "div", attributes: [b] }],
+ });
+ });
+ }
}, "config[removeAttributes] and element[attributes] should not intersect.");
-// The intersection of config[removeAttributes] and element[removeAttributes] with default « » is empty.
+// 8.1.4. The intersection of config[removeAttributes] and element[removeAttributes] with default « » is empty.
test(() => {
- assert_throws_js(TypeError, () => {
- new Sanitizer({
- removeAttributes: ["class"],
- elements: [{ name: "div", removeAttributes: ["class"] }],
+ for (let [a, b] of DUPLICATE_ATTRIBUTE_NAMES) {
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({
+ removeAttributes: [a],
+ elements: [{ name: "div", removeAttributes: [b] }],
+ });
});
- });
+ }
}, "config[removeAttributes] and element[removeAttributes] should not intersect.");
-// config[dataAttributes] is an extension of the config[attributes] allow-list. It isn't compatible work with a block-list approach.
+// 8.2. config[dataAttributes] does not exist.
test(() => {
assert_throws_js(TypeError, () => {
new Sanitizer({ removeAttributes: [], dataAttributes: true });
});
-}, "Can not use config[dataAttributes] and config[attributes] together.");
+ assert_throws_js(TypeError, () => {
+ new Sanitizer({ removeAttributes: [], dataAttributes: false });
+ });
+}, "Can not use config[dataAttributes] and config[removeAttributes] together.");
</script>
</body>
</html>