diff options
Diffstat (limited to 'testing/web-platform/tests/trusted-types/TrustedTypePolicyFactory-metadata.html')
-rw-r--r-- | testing/web-platform/tests/trusted-types/TrustedTypePolicyFactory-metadata.html | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/testing/web-platform/tests/trusted-types/TrustedTypePolicyFactory-metadata.html b/testing/web-platform/tests/trusted-types/TrustedTypePolicyFactory-metadata.html new file mode 100644 index 0000000000..70a5b44666 --- /dev/null +++ b/testing/web-platform/tests/trusted-types/TrustedTypePolicyFactory-metadata.html @@ -0,0 +1,154 @@ +<!DOCTYPE html> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js" ></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/helper.sub.js"></script> + +<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script';"> +<body> +<div id="target"></div> +<script> + const policy = trustedTypes.createPolicy("anythinggoes", { + "createHTML": x => x, + "createScript": x => x, + "createScriptURL": x => x, + }); + + const create_value = { + "TrustedHTML": policy.createHTML("hello"), + "TrustedScript": policy.createScript("x => x + x"), + "TrustedScriptURL": policy.createScriptURL("https://url.invalid/blubb.js"), + null: "empty", + }; + + // The tests will assign all values to all sink types. To prevent spurious + // errors when assigning "hello" to a script sink, we'll just define a + // varaible of that name. + const hello = ""; + + // We seed our elements and properties with one element/property that has no + // 'trusted type' sinks, and one non-specced (madeup) element/property. + // Also add several event handlers (onclick). + let elements = ['madeup', 'b']; + let properties = ['madeup', 'id', "onerror", "onclick"]; + const types = [null, "TrustedHTML", "TrustedScript", "TrustedScriptURL"]; + + // We'll wrap construction of the elements/properties list in a test, mainly + // so we'll get decent error messages when it might fail. + test(t => { + // Collect all element and property names from getTypeMapping(). + const map = trustedTypes.getTypeMapping(); + for (let elem in map) { + elements.push(elem); + properties = properties.concat(Object.keys(map[elem].properties)); + } + + // Remove "*" entries and de-duplicate properties. + elements = elements.filter(s => !s.includes("*")); + properties = properties.filter(s => !s.includes("*")); + properties = Array.from(new Set(properties)); + }, "Prepare parameters for generic test series below."); + + // Iterate one test for each combination of element, property, and sink type. + const target = document.getElementById("target"); + for (elem of elements) { + for (property of properties) { + for (type of types) { + // Conceptually, our test is beautifully simple: Ask getPropertyType + // about the expected trusted type. If it's the one we're testing, + // expect the assignment to pass, and expect we can read back the same + // value. If it's a different type, expect the assignment to fail. + // + // The idealized test case would look something like this: + // const value = ....; + // const test_fn = _ => { element[property] = value }; + // if (type == expected_type || !expected_type) { + // test_fn(); + // assert_equals(element[property], value); + // } else { + // assert_throws_js(..., test_fn, ...); + // } + // + // Below is the same logic, but extended to handle the various edge + // cases. + // + // Some difficulties we need to accomodate: + // - Some properties have built-in behaviours. (E.g. the "innerHTML" + // value depends on whether elements are visible or not.) To + // accomodate this, we have a big switch-statement that handles + // those types of exceptions. + // - Some properties parse their values, so that you can't easily get + // the original text value back (e.g. error handlers). + // - Some properties cause actions as side-effects (e.g. loading a + // script), which will cause errors in the test (despite the actual + // code-under-test meeting our expectations). This is handled with + // a cleanup script which removes the element (and thus cancels + // the loading actions). + test(t => { + const element = target.appendChild(document.createElement(elem)); + t.add_cleanup(_ => element.remove()); + const expected_type = trustedTypes.getPropertyType(elem, property); + const value = create_value[type]; + const test_fn = _ => { element[property] = value; }; + if (type == expected_type || !expected_type) { + test_fn(); + let result_value = element[property]; + switch (property) { + // Node.innerText returns the rendered text of an Element, which + // in this test case is usually empty. For this specific case, + // let's just check "textContent" instead. + // Node.innerHTML re-creates a text representation from the DOM, + // which may not always match the exact input. + case "innerText": + case "innerHTML": + result_value = element["textContent"]; + break; + // Node.outerHTML replaces the node, which means the simple + // checking logic below does not work. In this case, we'll just + // return and hence skip the result comparison. + case "outerHTML": + return; + // URL-typed accessors + case "src": + if (elem == "iframe") + return; + break; + // Properties starting with "on" are usually error handlers, + // which will parse their input as a function. In this case, + // also skip the result comparison. + default: + if (property.startsWith("on")) return; + break; + } + assert_equals("" + result_value, "" + value); + } else { + assert_throws_js(TypeError, test_fn, "throws"); + } + }, `Test assignment of ${type ? type : "string"} on ${elem}.${property}`); + + // And once more, for attributes. + test(t => { + const element = target.appendChild(document.createElement(elem)); + t.add_cleanup(_ => element.remove()); + const expected_type = trustedTypes.getAttributeType(elem, property); + const value = create_value[type]; + const test_fn = _ => { element.setAttribute(property, value); }; + if (type == expected_type || !expected_type) { + test_fn(); + assert_equals("" + element.getAttribute(property), "" + value); + } else if (elem == "script" && (property == "innerText" || + property == "textContent" || property == "text")) { + // Due to the "slot setting" mechnanism, setting script's innerText, + // textContent and text attributes dosn't throw. So we can't use + // that in our tests. + // ref: https://w3c.github.io/trusted-types/dist/spec/#setting-slot-values + test_fn(); + } else { + assert_throws_js(TypeError, test_fn, "throws"); + } + }, `Test assignment of ${type ? type : "string"} on ${elem}.setAttribute(${property},..)`); + } + } + } +</script> +</body> |