diff options
Diffstat (limited to 'testing/web-platform/tests/html/webappapis/dynamic-markup-insertion')
224 files changed, 5252 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document-close-with-pending-script.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document-close-with-pending-script.html new file mode 100644 index 0000000000..1584ca5f97 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document-close-with-pending-script.html @@ -0,0 +1,67 @@ +<!doctype html> +<meta charset=utf-8> +<title>document.close called while a script is pending</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<body> + <script> + window.t = async_test(); + // We want start a document load, create an non-blocking script load inside + // it, have the parser complete, then call document.open()/document.close() + // after the parser is done but before the non-blocking script load + // completes. After we do that, the document should reach the 'complete' + // ready state and the iframe's load event should fire. + var loadFired = false; + var i; + + var finish = t.step_func_done(() => { + assert_equals(loadFired, true, "Should have fired a load event"); + assert_equals(i.contentDocument.readyState, "complete", + "Should be fully loaded"); + }); + + var checkForLoad = t.step_func(() => { + if (loadFired) { + finish(); + } else { + i.addEventListener("load", finish); + } + }); + + window.parserDone = t.step_func(() => { + var doc = i.contentDocument; + i.onload = () => { loadFired = true; } + doc.open(); + doc.close(); + // It's not very clearly specced whether the document is + // supposed to be fully loaded at this point or not, so allow + // that to be the case, or to happen soonish. + assert_true(doc.readyState == "interactive" || + doc.readyState == "complete", "Should be almost loaded"); + if (doc.readyState == "complete") { + checkForLoad(); + } else { + doc.addEventListener("readystatechange", checkForLoad); + } + }); + + t.step(() => { + i = document.createElement("iframe"); + i.srcdoc = ` + <script> + parent.t.step(() => { + var s = document.createElement("script"); + s.src = "/common/slow.py"; + document.documentElement.appendChild(s); + // Call into the parent async, so we finish our "end of parse" + // work before it runs. + document.addEventListener( + "DOMContentLoaded", + () => parent.t.step_timeout(parent.parserDone, 0)); + }); + <\/script> + `; + document.body.appendChild(i); + }); + </script> +</body> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document.close-01.xhtml b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document.close-01.xhtml new file mode 100644 index 0000000000..164d71d191 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document.close-01.xhtml @@ -0,0 +1,19 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>document.close in XHTML</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#closing-the-input-stream"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<script> +test(function() { + assert_throws_dom("INVALID_STATE_ERR", function() { + document.close(); + }, "document.close in XHTML should throw an INVALID_STATE_ERR "); +}, "document.close in XHTML"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/load-event-after-location-set-during-write.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/load-event-after-location-set-during-write.window.js new file mode 100644 index 0000000000..d5c8469baf --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/load-event-after-location-set-during-write.window.js @@ -0,0 +1,19 @@ +// Make sure that the load event for an iframe doesn't fire at the +// point when a navigation triggered by document.write() starts in it, +// but rather when that navigation completes. + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + const doc = frame.contentDocument; + const url = URL.createObjectURL(new Blob(["PASS"], { type: "text/html"})); + + frame.onload = t.step_func_done(() => { + assert_equals(frame.contentDocument.body.textContent, "PASS", + "Why is our load event firing before the new document loaded?"); + }); + + doc.open(); + doc.write(`FAIL<script>location = "${url}"</` + "script>"); + doc.close(); +}, "Setting location from document.write() call should not trigger load event until that load completes"); + diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/001.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/001.html new file mode 100644 index 0000000000..3ac6423f4a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/001.html @@ -0,0 +1,12 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("PASS"); + assert_equals(document.body.textContent, "PASS"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/002.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/002.html new file mode 100644 index 0000000000..08975bca7b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/002.html @@ -0,0 +1,13 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i>Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/003.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/003.html new file mode 100644 index 0000000000..915e1f6d61 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/003.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<"); + document.write("i>Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/004.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/004.html new file mode 100644 index 0000000000..dd01725860 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/004.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i"); + document.write(">Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.html new file mode 100644 index 0000000000..4c161c4d47 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i>"); + document.write("Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.js new file mode 100644 index 0000000000..ebfd7e2585 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.js @@ -0,0 +1 @@ +order.push(3);
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.html new file mode 100644 index 0000000000..92bfb44c3a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i id='test'>Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.getAttribute("id"), "test"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.js new file mode 100644 index 0000000000..ebfd7e2585 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.js @@ -0,0 +1 @@ +order.push(3);
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.html new file mode 100644 index 0000000000..753316b89c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i "); + document.write("id='test'>Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.getAttribute("id"), "test"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.js new file mode 100644 index 0000000000..31fcf18d49 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.js @@ -0,0 +1,4 @@ +t.step(function() { + order.push(2); + document.write("<script>t.step(function() {order.push(3)})</script>"); + });
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008-1.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008-1.js new file mode 100644 index 0000000000..ef90c722b7 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008-1.js @@ -0,0 +1,3 @@ +t.step(function() { + order.push(3); + });
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.html new file mode 100644 index 0000000000..4818bc388f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i i"); + document.write("d='test'>Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.getAttribute("id"), "test"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.js new file mode 100644 index 0000000000..367597515d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.js @@ -0,0 +1,4 @@ +t.step(function() { + order.push(2); + document.write("<script src=\"008-1.js\"></script>"); + });
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/009.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/009.html new file mode 100644 index 0000000000..d7b78333b8 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/009.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i id"); + document.write("='test'>Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.getAttribute("id"), "test"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010-1.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010-1.js new file mode 100644 index 0000000000..fd815bab77 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010-1.js @@ -0,0 +1,4 @@ +t.step(function() { + order.push(4); + assert_equals(document.getElementsByTagName("meta").length, 1); + });
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.html new file mode 100644 index 0000000000..c8b9958258 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i id="); + document.write("'test'>Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.getAttribute("id"), "test"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.js new file mode 100644 index 0000000000..bb328ad55a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.js @@ -0,0 +1,4 @@ +t.step(function() { + order.push(3); + assert_equals(document.getElementsByTagName("meta").length, 0); + }); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011-1.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011-1.js new file mode 100644 index 0000000000..944b70d2d0 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011-1.js @@ -0,0 +1,5 @@ +t.step(function() { + order.push(4); + document.write("<meta>"); + assert_equals(document.getElementsByTagName("meta").length, 1); + });
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.html new file mode 100644 index 0000000000..33464429e6 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i id='"); + document.write("test'>Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.getAttribute("id"), "test"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.js new file mode 100644 index 0000000000..ce47bcd283 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.js @@ -0,0 +1,5 @@ +t.step(function() { + order.push(3); + document.write("<script src='011-1.js'></script" + "><meta>"); + assert_equals(document.getElementsByTagName("meta").length, 0); + });
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.html new file mode 100644 index 0000000000..c9902a4875 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i id='te"); + document.write("st'>Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.getAttribute("id"), "test"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.js new file mode 100644 index 0000000000..7ab4c6b386 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.js @@ -0,0 +1,5 @@ +t.step( +function() { + order.push(5); + assert_equals(document.getElementsByTagName("meta").length, 0); +});
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.html new file mode 100644 index 0000000000..7b87d28976 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i id='test"); + document.write("'>Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.getAttribute("id"), "test"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.js new file mode 100644 index 0000000000..b5ce5f27da --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.js @@ -0,0 +1 @@ +document.write('<svg><![CDATA[');
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/014.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/014.html new file mode 100644 index 0000000000..75518a8981 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/014.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i id='test'"); + document.write(">Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.getAttribute("id"), "test"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/015.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/015.html new file mode 100644 index 0000000000..3dd79a63ef --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/015.html @@ -0,0 +1,16 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i id='test'"); + document.write("class='a'>Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.getAttribute("id"), "test"); + assert_equals(document.body.firstChild.getAttribute("class"), "a"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/016.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/016.html new file mode 100644 index 0000000000..4c2f58912a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/016.html @@ -0,0 +1,16 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<i>Filler Text"); + document.write("</i><b>Filler Text"); + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); + assert_equals(document.body.childNodes[1].localName, "b"); + assert_equals(document.body.childNodes[1].textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/017.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/017.html new file mode 100644 index 0000000000..8d1b24b06e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/017.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + var s = "<i id=test>Filler Text</i><b>Filler Text" + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } + assert_equals(document.body.firstChild.localName, "i"); + assert_equals(document.body.firstChild.getAttribute('id'), "test"); + assert_equals(document.body.firstChild.textContent, "Filler Text"); + assert_equals(document.body.childNodes[1].localName, "b"); + assert_equals(document.body.childNodes[1].textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/018.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/018.html new file mode 100644 index 0000000000..cf8dddbc54 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/018.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( +function() { + document.write("<body>"); + var s = "<!--comment--><i>Filler Text</i>" + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } + assert_equals(document.body.firstChild.nodeType, document.COMMENT_NODE); + assert_equals(document.body.firstChild.data, "comment"); + assert_equals(document.body.childNodes[1].localName, "i"); + assert_equals(document.body.childNodes[1].textContent, "Filler Text"); +} +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/019.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/019.html new file mode 100644 index 0000000000..5e988f79ef --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/019.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<i"); +}); +</script> +>Filler Text</i> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "i"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/020.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/020.html new file mode 100644 index 0000000000..1d31bbf35d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/020.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><"); +}); +</script>!--comment--> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].nodeType, document.COMMENT_NODE); + assert_equals(document.body.childNodes[0].data, "comment"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/021.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/021.html new file mode 100644 index 0000000000..500bb19398 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/021.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><sp"); +}); +</script>an>Filler Text</span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "span"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/022.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/022.html new file mode 100644 index 0000000000..53ba299012 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/022.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><span>"); +}); +</script>Filler Text</span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "span"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/023.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/023.html new file mode 100644 index 0000000000..ca89e0e0bc --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/023.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><span "); +}); +</script>id=a>Filler Text</span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "span"); + assert_equals(document.body.childNodes[0].getAttribute("id"), "a"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/024.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/024.html new file mode 100644 index 0000000000..2a47d76cb3 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/024.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><span i"); +}); +</script>d=a>Filler Text</span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "span"); + assert_equals(document.body.childNodes[0].getAttribute("id"), "a"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/025.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/025.html new file mode 100644 index 0000000000..31c68cf7df --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/025.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><span id"); +}); +</script>=a>Filler Text</span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "span"); + assert_equals(document.body.childNodes[0].getAttribute("id"), "a"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/026.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/026.html new file mode 100644 index 0000000000..a9bce7743e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/026.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><span id="); +}); +</script>a>Filler Text</span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "span"); + assert_equals(document.body.childNodes[0].getAttribute("id"), "a"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/027.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/027.html new file mode 100644 index 0000000000..dcfd67c0f7 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/027.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><span id=a"); +}); +</script>>Filler Text</span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "span"); + assert_equals(document.body.childNodes[0].getAttribute("id"), "a"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/028.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/028.html new file mode 100644 index 0000000000..f5b7e9ef2b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/028.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><span id=a>Filler Text<"); +}); +</script>/span><b>Filler Text</b></span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "span"); + assert_equals(document.body.childNodes[0].getAttribute("id"), "a"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); + assert_equals(document.body.childNodes[1].localName, "b"); + assert_equals(document.body.childNodes[1].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/029.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/029.html new file mode 100644 index 0000000000..f005a72227 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/029.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><span id=a>Filler Text</"); +}); +</script>span><b>Filler Text</b></span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "span"); + assert_equals(document.body.childNodes[0].getAttribute("id"), "a"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); + assert_equals(document.body.childNodes[1].localName, "b"); + assert_equals(document.body.childNodes[1].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/030.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/030.html new file mode 100644 index 0000000000..cc361d3aaf --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/030.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><span id=a>Filler Text</sp"); +}); +</script>an><b>Filler Text</b></span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "span"); + assert_equals(document.body.childNodes[0].getAttribute("id"), "a"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); + assert_equals(document.body.childNodes[1].localName, "b"); + assert_equals(document.body.childNodes[1].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/031.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/031.html new file mode 100644 index 0000000000..32c97c5056 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/031.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><span id=a>Filler Text</span"); +}); +</script>><b>Filler Text</b></span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "span"); + assert_equals(document.body.childNodes[0].getAttribute("id"), "a"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); + assert_equals(document.body.childNodes[1].localName, "b"); + assert_equals(document.body.childNodes[1].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/032.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/032.html new file mode 100644 index 0000000000..1a33408f1b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/032.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + var tag_name_length = 100000; + var tag_name = ""; + for (var i=0; i<tag_name_length; i++) { + tag_name += "a"; + } + document.write("<body><" + tag_name + ">Filler Text</" + tag_name + ">"); +}); +</script> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/033.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/033.html new file mode 100644 index 0000000000..1b8e1c2706 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/033.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +test( + function() { + document.writeln("<i"); + var s = " b='a'>Filler" + for (var i=0; i<s.length; i++) { + document.write(s[i]+"\n"); + } + document.writeln("</i"); + document.writeln(">"); + assert_equals(document.body.childNodes[0].localName, "i"); + assert_equals(document.body.childNodes[0].getAttribute("b"), "\na\n"); + assert_equals(document.body.childNodes[0].textContent, "\nF\ni\nl\nl\ne\nr\n"); + } +); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/034.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/034.html new file mode 100644 index 0000000000..abd481a64d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/034.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + var s = "<svg><![CDATA[Filler Text]]></svg>"; + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } +}); +</script> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "svg"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/035.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/035.html new file mode 100644 index 0000000000..a1e7f9ee67 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/035.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + var s = "<svg><!"; + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } +}); +</script>[CDATA[Filler Text]]></svg> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "svg"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/036.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/036.html new file mode 100644 index 0000000000..8719e0598d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/036.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + var s = "<svg><![CDATA[Filler Text]"; + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } +}); +</script>]></svg> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "svg"); + assert_equals(document.body.childNodes[0].textContent, "Filler Text"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/037.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/037.html new file mode 100644 index 0000000000..cf0787ce76 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/037.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + var s = "<body><!DOCTYPE html>"; + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } +}); +</script><script> +t.step(function() { + //Nothing should be inserted into the DOM for the doctype node so + //just checking nothing odd happens + assert_equals(document.body.childNodes[0].localName, "script"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/038.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/038.html new file mode 100644 index 0000000000..4ae9d32b23 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/038.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + var s = "<body><"; + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } +}); +</script>!DOCTYPE html><script> +t.step(function() { + //Nothing should be inserted into the DOM for the doctype node so + //just checking nothing odd happens + assert_equals(document.body.childNodes[0].localName, "script"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/039.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/039.html new file mode 100644 index 0000000000..611a01390c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/039.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + var s = "<body><!"; + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } +}); +</script>DOCTYPE html><script> +t.step(function() { + //Nothing should be inserted into the DOM for the doctype node so + //just checking nothing odd happens + assert_equals(document.body.childNodes[0].localName, "script"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/040.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/040.html new file mode 100644 index 0000000000..d76deffa40 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/040.html @@ -0,0 +1,10 @@ +<!doctype html> +<title>document.write entity</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = test(function() { + document.write("<body><span>∉abc"); + assert_equals(document.body.childNodes[0].textContent, "\u2209abc"); +}); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/041.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/041.html new file mode 100644 index 0000000000..592711c94f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/041.html @@ -0,0 +1,13 @@ +<!doctype html> +<title>document.write entity</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = test(function() { + var s = "<body><span>∉abc"; + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } + assert_equals(document.body.childNodes[0].textContent, "\u2209abc"); +}); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/042.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/042.html new file mode 100644 index 0000000000..e15f1d0c0f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/042.html @@ -0,0 +1,16 @@ +<!doctype html> +<title>document.write entity</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><span>¬"); +}); +</script>in;abc</span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].textContent, "\u2209abc"); +}) +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/043.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/043.html new file mode 100644 index 0000000000..4058e7a823 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/043.html @@ -0,0 +1,16 @@ +<!doctype html> +<title>document.write entity</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><span>&"); +}); +</script>notabc</span> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].textContent, "\u00ACabc"); +}) +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/044.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/044.html new file mode 100644 index 0000000000..4c9f50273c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/044.html @@ -0,0 +1,17 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<body><textarea><span>Filler</span></textarea>"); +}); +</script> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "textarea"); + assert_equals(document.body.childNodes[0].textContent, "<span>Filler</span>"); +}) +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/045.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/045.html new file mode 100644 index 0000000000..987eabf0f4 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/045.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + var s = "<body><textarea><span>Filler</span></textarea>"; + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } +}); +</script> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "textarea"); + assert_equals(document.body.childNodes[0].textContent, "<span>Filler</span>"); +}) +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/046.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/046.html new file mode 100644 index 0000000000..e87e9cc825 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/046.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + var s = "<body><textarea>"; + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } +}); +</script><span>Filler</span></textarea> +<script> +t.step(function() { + assert_equals(document.body.childNodes[0].localName, "textarea"); + assert_equals(document.body.childNodes[0].textContent, "<span>Filler</span>"); +}) +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047-1.html new file mode 100644 index 0000000000..6a43faec51 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047-1.html @@ -0,0 +1,7 @@ +<script> +onload = opener.t.step_func_done(function() { + document.write("<body>Filler Text<div id='log'></div>"); + opener.assert_equals(document.body.textContent, "Filler Text"); +}); +</script> +<body>FAIL diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047.html new file mode 100644 index 0000000000..677d3e1786 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047.html @@ -0,0 +1,11 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +var win; +var t = async_test(() => { + win = window.open("047-1.html"); +}); +t.add_cleanup(() => win.close()); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/049.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/049.html new file mode 100644 index 0000000000..0ec282f2bc --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/049.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>document.write plaintext</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<div id="log"></div><script> +test(function() { + var s = "<table><tr><td>Text</tr><plaintext><tr><td>Filler "; + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } + document.close(); + assert_equals(document.body.childNodes[2].nodeType, document.ELEMENT_NODE); + assert_equals(document.body.childNodes[2].localName, "plaintext"); + assert_equals(document.body.childNodes[2].textContent, "<tr><td>Filler "); + assert_equals(document.body.childNodes[3].nodeType, document.ELEMENT_NODE); + assert_equals(document.body.childNodes[3].localName, "table"); + assert_equals(document.body.childNodes[3].textContent, "Text"); +}); +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/050.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/050.html new file mode 100644 index 0000000000..0a37fa4c5f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/050.html @@ -0,0 +1,25 @@ +<!doctype html> +<title>document.write plaintext</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<div id="log"></div><script> +var t = async_test(); + +t.step(function() { + document.write("<plaintext>"); + assert_equals(document.body.childNodes[2].nodeType, document.ELEMENT_NODE); + assert_equals(document.body.childNodes[2].localName, "plaintext"); + var s = "Filler "; + for (var i=0; i<s.length; i++) { + document.write(s[i]); + assert_equals(document.body.childNodes[2].textContent, s.slice(0,i+1)); + } + document.close(); +}); + +onload = function() { + t.step(function() { + assert_equals(document.body.childNodes[2].textContent, "Filler Text\n"); + }); + t.done(); +} +</script>Text diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/051.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/051.html new file mode 100644 index 0000000000..80ea279dad --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/051.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>document.write \r\n</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id="log"></div> + +<script> +var t = async_test(); + +t.step(function() { + document.write("\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nA"); +}) + +onload = function() { + t.step(function() { + const lastNode = document.getElementById('after'); + assert_equals(lastNode.previousSibling.data, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nAB"); + }); + t.done(); +}; +</script>B<div id=after></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/contentType.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/contentType.window.js new file mode 100644 index 0000000000..5a91203874 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/contentType.window.js @@ -0,0 +1,28 @@ +// META: script=/common/media.js + +const videoURL = getVideoURI("/images/pattern"), + videoMIMEType = getMediaContentType(videoURL); + +[ + [videoURL, videoMIMEType, "video"], + ["/images/red.png", "image/png", "image"], + ["/common/text-plain.txt", "text/plain", "text"], + ["/common/blank.html", "text/html", "HTML"] +].forEach(val => { + async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = val[0]; + frame.onload = t.step_func_done(() => { + assert_equals(frame.contentDocument.contentType, val[1]); + frame.contentDocument.write("<b>Heya</b>"); + assert_equals(frame.contentDocument.body.firstChild.localName, "b"); + assert_equals(frame.contentDocument.body.firstChild.textContent, "Heya"); + assert_equals(frame.contentDocument.contentType, val[1]); + + // Make sure a load event is fired across browsers + // https://github.com/web-platform-tests/wpt/pull/10239 + frame.contentDocument.close(); + }); + }, "document.write(): " + val[2] + " document"); +}); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-01.xhtml b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-01.xhtml new file mode 100644 index 0000000000..fc21d4e2bf --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-01.xhtml @@ -0,0 +1,19 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>document.write in XHTML</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#document.write%28%29"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<script> +test(function() { + assert_throws_dom("INVALID_STATE_ERR", function() { + document.write("Failure: document.write actually worked"); + }, "document.write in XHTML should throw an INVALID_STATE_ERR "); +}, "document.write in XHTML"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-02.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-02.html new file mode 100644 index 0000000000..4c25da8b68 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-02.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<title>document.write and null/undefined</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-document-write%28%29"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#documents-in-the-dom"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + doc = iframe.contentDocument; + test(function() { + doc.open(); + doc.write(null); + doc.close(); + assert_equals(doc.documentElement.textContent, "null"); + }, "document.write(null)"); + test(function() { + doc.open(); + doc.write(undefined); + doc.close(); + assert_equals(doc.documentElement.textContent, "undefined"); + }, "document.write(undefined)"); +}, "Calling document.write with null and undefined"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/during-readystatechange.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/during-readystatechange.window.js new file mode 100644 index 0000000000..49d5051c25 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/during-readystatechange.window.js @@ -0,0 +1,24 @@ +// This tests whether the insertion point gets reset before or after the readystatechange event. +// See https://github.com/whatwg/html/pull/6613#discussion_r620171070. +// Recall that resetting the insertion point means that document.write() performs the document open +// steps and blows away previous content in the document. + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => { frame.remove(); }); + frame.src = "../opening-the-input-stream/resources/dummy.html"; + frame.onload = t.step_func_done(() => { + const states = []; + frame.contentDocument.onreadystatechange = t.step_func(() => { + if (frame.contentDocument.readyState === "interactive") { + assert_not_equals(frame.contentDocument.textContent, "", "Precondition check: dummy document is not empty"); + + frame.contentDocument.write("Some text"); + + // If the insertion point is reset before the readystatechange handler, then the + // document.write() call above will blow away the text originally in dummy.html, leaving only what we wrote. + assert_equals(frame.contentDocument.textContent, "Some text"); + } + }); + }); +}, "document.write() during readystatechange to interactive"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/empty.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/empty.html new file mode 100644 index 0000000000..0dc101b533 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/empty.html @@ -0,0 +1 @@ +<html><body></body></html> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_001.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_001.html new file mode 100644 index 0000000000..8b54560c6c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_001.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>document.write into iframe</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<iframe id="test"></iframe> +<script> +test( +function() { + var iframe = document.getElementById("test"); + iframe.contentDocument.write("Filler Text"); + iframe.contentDocument.close(); + assert_equals(iframe.contentDocument.body.textContent, "Filler Text"); +}); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_002.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_002.html new file mode 100644 index 0000000000..f77819adb6 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_002.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>document.write into iframe</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<iframe id="test"></iframe> +<script> +test( +function() { + var iframe = document.getElementById("test"); + var s = "<i id='a'>Filler Text</i><b id=b>Filler Text</b>" + for (var i=0; i<s.length; i++) { + iframe.contentDocument.write(s[i]); + } + iframe.contentDocument.close(); + assert_equals(iframe.contentDocument.body.childNodes[0].textContent, "Filler Text"); + assert_equals(iframe.contentDocument.body.childNodes[0].localName, "i"); + assert_equals(iframe.contentDocument.body.childNodes[0].getAttribute('id'), "a"); + assert_equals(iframe.contentDocument.body.childNodes[1].textContent, "Filler Text"); + assert_equals(iframe.contentDocument.body.childNodes[1].localName, "b"); + assert_equals(iframe.contentDocument.body.childNodes[1].getAttribute('id'), "b"); +}); +</script> +<div id="log"></div>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_003.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_003.html new file mode 100644 index 0000000000..9865874da4 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_003.html @@ -0,0 +1,23 @@ +<!doctype html> +<title>document.write script into iframe</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<iframe id="test"></iframe> +<script> +test( +function() { + var iframe = document.getElementById("test"); + var s = "<script>document.write(\"<i id='a'>Filler Text</i>\")</script" + "><b id=b>Filler Text</b>" + for (var i=0; i<s.length; i++) { + iframe.contentDocument.write(s[i]); + } + iframe.contentDocument.close(); + //Note: <script> ends up in <head> + assert_equals(iframe.contentDocument.body.childNodes[0].textContent, "Filler Text"); + assert_equals(iframe.contentDocument.body.childNodes[0].localName, "i"); + assert_equals(iframe.contentDocument.body.childNodes[0].getAttribute('id'), "a"); + assert_equals(iframe.contentDocument.body.childNodes[1].textContent, "Filler Text"); + assert_equals(iframe.contentDocument.body.childNodes[1].localName, "b"); + assert_equals(iframe.contentDocument.body.childNodes[1].getAttribute('id'), "b"); +}); +</script> +<div id="log"></div>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_004.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_004.html new file mode 100644 index 0000000000..a4d7b1ddad --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_004.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>document.write script into iframe write back into parent</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<iframe id="test"></iframe> +<script> +var t = async_test(); +var iframe = document.getElementById("test"); +var order = []; +t.step(function() { + order.push(1); + var s = "<script>parent.order.push(2); parent.document.write('<script>order.push(3);</script'+'>'); parent.order.push(4)</script" + ">"; + for (var i=0; i<s.length; i++) { + iframe.contentDocument.write(s[i]); + } + iframe.contentDocument.close(); + order.push(5); + assert_array_equals(order, [1,2,3,4,5]) +} +); +t.done(); +</script> +<div id="log"></div>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html new file mode 100644 index 0000000000..7bc3ed6c29 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html @@ -0,0 +1,25 @@ +<!doctype html> +<title>document.write external script into iframe write back into parent</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<iframe id="test"></iframe> +<script> +var t = async_test(); +var iframe = document.getElementById("test"); +var order = []; +t.step(function() { + order.push(1); + var s = "<script src='iframe_005.js'></script" + ">"; + iframe.contentDocument.write(s); + iframe.contentDocument.close(); + order.push(2); + assert_array_equals(order, [1,2]) +} +); +addEventListener("load", function() { + t.step(function() { + assert_array_equals(order, [1,2,3,4,5]) + }); + t.done(); +}, false); +</script> +<div id="log"></div>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.js new file mode 100644 index 0000000000..bf038f7004 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.js @@ -0,0 +1,3 @@ +parent.order.push(3); +document.write("<script>parent.order.push(4)</script>"); +parent.order.push(5);
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_006.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_006.html new file mode 100644 index 0000000000..d080ee3673 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_006.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write external script into iframe write back into parent</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<iframe id="test"></iframe> +<script> +var t = async_test(); +var iframe = document.getElementById("test"); +var order = []; +t.step(function() { + order.push(1); + var s = "<script>parent.order.push(2); parent.document.write('<script>order.push(3); iframe.contentDocument.write(\"<script>parent.order.push(4)</script\"+\">\");order.push(5);</script' + '>'); parent.order.push(6)</script"+">"; + iframe.contentDocument.write(s); + iframe.contentDocument.close(); + order.push(7); + assert_array_equals(order, [1,2,3,4,5,6,7]); +}); +t.done(); +</script> +<div id="log"></div>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_007.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_007.html new file mode 100644 index 0000000000..c00aa7062d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_007.html @@ -0,0 +1,17 @@ +<!doctype html> +<title>document.write comment into iframe</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<iframe id="test"></iframe> +<script> +test(function() { + var iframe = document.getElementById("test"); + var s = "<!--Filler-->"; + for (var i=0; i<s.length; i++) { + iframe.contentDocument.write(s); + } + iframe.contentDocument.close(); + assert_equals(iframe.contentDocument.childNodes[0].nodeType, document.COMMENT_NODE); + assert_equals(iframe.contentDocument.childNodes[0].data, "Filler"); +}); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_008.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_008.html new file mode 100644 index 0000000000..c814958d19 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_008.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>document.write plaintext into iframe</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<iframe id="test"></iframe> +<script> +test(function() { + var iframe = document.getElementById("test"); + var s = "<plaintext><span>Filler Text"; + for (var i=0; i<s.length; i++) { + iframe.contentDocument.write(s[i]); + } + iframe.contentDocument.close(); + assert_equals(iframe.contentDocument.body.childNodes[0].nodeType, document.ELEMENT_NODE); + assert_equals(iframe.contentDocument.body.childNodes[0].localName, "plaintext"); + assert_equals(iframe.contentDocument.body.childNodes[0].textContent, "<span>Filler Text"); +}); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_009.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_009.html new file mode 100644 index 0000000000..8b271c7a03 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_009.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>document.write plaintext into iframe</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<iframe id="test"></iframe> +<script> +test(function() { + var iframe = document.getElementById("test"); + var s = "<table><tr><td>Text</tr><plaintext><tr><td>Filler "; + for (var i=0; i<s.length; i++) { + iframe.contentDocument.write(s[i]); + } + iframe.contentDocument.close(); + assert_equals(iframe.contentDocument.body.childNodes[0].nodeType, document.ELEMENT_NODE); + assert_equals(iframe.contentDocument.body.childNodes[0].localName, "plaintext"); + assert_equals(iframe.contentDocument.body.childNodes[0].textContent, "<tr><td>Filler "); + assert_equals(iframe.contentDocument.body.childNodes[1].nodeType, document.ELEMENT_NODE); + assert_equals(iframe.contentDocument.body.childNodes[1].localName, "table"); + assert_equals(iframe.contentDocument.body.childNodes[1].textContent, "Text"); +}); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_010.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_010.html new file mode 100644 index 0000000000..8dc21a013a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_010.html @@ -0,0 +1,23 @@ +<!doctype html> +<title>document.write plaintext</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<iframe id="test"></iframe> +<script> +var t = async_test(); +var iframe = document.getElementById("test"); + +function check_dom() { + assert_equals(iframe.contentDocument.body.childNodes[0].localName, "plaintext") + assert_equals(iframe.contentDocument.body.childNodes[0].textContent, "Filler ") + assert_equals(iframe.contentDocument.body.childNodes[1].localName, "table") +} + +t.step(function() { + var s = "<script>document.write('<table><plaintext>Filler '); document.close(); top.t.step(function() {top.check_dom()})</script" + ">"; + for (var i=0; i<s.length; i++) { + iframe.contentDocument.write(s[i]); + } + t.done(); +}); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed-iframe.html new file mode 100644 index 0000000000..f97f597238 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed-iframe.html @@ -0,0 +1,9 @@ +<!doctype html> +<script type=module> +window.parent.document.test.step_timeout(() => { + document.write("document.write body contents\n") + document.close(); + window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone")); +}, 0); +</script> +Initial body contents diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed.html new file mode 100644 index 0000000000..acdeab59ff --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed.html @@ -0,0 +1,29 @@ +<!doctype html> +<title>async document.write in a module</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(t => { + // Expose {test} in the iframe for using the step_timeout helper. + document.test = t; + const iframe = document.createElement("iframe"); + + iframe.onerror = t.unreached_func("Error loading iframe"); + + let onLoadWasCalled = false; + iframe.onload = t.step_func(() => { + onLoadWasCalled = true; + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + // Don't call the event handler another time after document.write. + iframe.onload = null; + }); + document.addEventListener("documentWriteDone", t.step_func_done(() => { + assert_true(onLoadWasCalled, "onload must be called"); + assert_equals(iframe.contentDocument.body.textContent, "document.write body contents\n"); + })); + + iframe.src = "module-delayed-iframe.html"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import-iframe.html new file mode 100644 index 0000000000..672bb953d6 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import-iframe.html @@ -0,0 +1,7 @@ +<!doctype html> +<script type=module> +(async () => { + let module = await import("./module-dynamic-import.mjs"); +})(); +</script> +Initial body contents diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.html new file mode 100644 index 0000000000..5939968f05 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>document.write in an imported module</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(t => { + const iframe = document.createElement("iframe"); + + iframe.onerror = t.unreached_func("Error loading iframe"); + + let onLoadWasCalled = false; + iframe.onload = t.step_func(() => { + onLoadWasCalled = true; + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + // Don't call the event handler another time after document.write. + iframe.onload = null; + }); + document.addEventListener("documentWriteDone", t.step_func_done(() => { + assert_true(onLoadWasCalled, "onload must be called"); + assert_equals(iframe.contentDocument.body.textContent, "document.write body contents\n"); + })); + + iframe.src = "module-dynamic-import-iframe.html"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.mjs b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.mjs new file mode 100644 index 0000000000..74d2427537 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.mjs @@ -0,0 +1,4 @@ +document.write("document.write body contents\n"); +document.close(); + +window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone")); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-iframe.html new file mode 100644 index 0000000000..f8646df56b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-iframe.html @@ -0,0 +1,7 @@ +<!doctype html> +<script type=module> +document.write("document.write body contents\n"); +document.close(); +window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone")); +</script> +Initial body contents diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed-iframe.html new file mode 100644 index 0000000000..3ae1464653 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed-iframe.html @@ -0,0 +1,5 @@ +<!doctype html> +<script type=module> +import "./module-static-import-delayed.mjs" +</script> +Initial body contents diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html new file mode 100644 index 0000000000..a6e003907f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html @@ -0,0 +1,28 @@ +<!doctype html> +<title>document.write in an imported module</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(t => { + // Expose {test} in the iframe for using the step_timeout helper. + document.test = t; + const iframe = document.createElement("iframe"); + iframe.onerror = t.unreached_func("Error loading iframe"); + + let onLoadWasCalled = false; + iframe.onload = t.step_func(() => { + onLoadWasCalled = true; + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + // Don't call the event handler another time after document.write. + iframe.onload = null; + }); + document.addEventListener("documentWriteDone", t.step_func_done(() => { + assert_true(onLoadWasCalled, "onload must be called"); + assert_equals(iframe.contentDocument.body.textContent, "document.write body contents\n"); + })); + + iframe.src = "module-static-import-delayed-iframe.html"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.mjs b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.mjs new file mode 100644 index 0000000000..45478d6f63 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.mjs @@ -0,0 +1,5 @@ +window.parent.document.test.step_timeout(() => { + document.write("document.write body contents\n") + document.close(); + window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone")); +}, 0); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-iframe.html new file mode 100644 index 0000000000..ed4f6d1c6c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-iframe.html @@ -0,0 +1,5 @@ +<!doctype html> +<script type=module> +import "./module-static-import.mjs" +</script> +Initial body contents diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.html new file mode 100644 index 0000000000..3cae88047e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>document.write in an imported module</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(t => { + const iframe = document.createElement("iframe"); + + iframe.onerror = t.unreached_func("Error loading iframe"); + + let testEndWasCalled = false; + document.addEventListener("documentWriteDone", t.step_func(() => { + testEndWasCalled = true; + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + })); + iframe.onload = t.step_func_done(() => { + assert_true(testEndWasCalled, "onload must be called"); + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + }); + + iframe.src = "module-static-import-iframe.html"; + document.body.appendChild(iframe); +}); +</script> +ß diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.mjs b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.mjs new file mode 100644 index 0000000000..74d2427537 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.mjs @@ -0,0 +1,4 @@ +document.write("document.write body contents\n"); +document.close(); + +window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone")); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed-iframe.html new file mode 100644 index 0000000000..5629c47be7 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed-iframe.html @@ -0,0 +1,14 @@ +<!doctype html> +<script type=module> +let delay = new Promise( + resolve => window.parent.document.test.step_timeout(resolve, 0)); + +delay.then(() => { + document.write("document.write body contents\n"); + document.close(); + window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone")); +}); + +await delay; +</script> +Initial body contents diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed.html new file mode 100644 index 0000000000..5fa8216600 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed.html @@ -0,0 +1,30 @@ +<!doctype html> +<title>document.write in an imported module</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(t => { + // Expose {test} in the iframe for using the step_timeout helper. + document.test = t; + + const iframe = document.createElement("iframe"); + + iframe.onunhandledrejection = t.unreached_func("Unhandled promise rejection detected"); + iframe.onerror = t.unreached_func("Error loading iframe"); + + let onLoadWasCalled = false; + iframe.onload = t.step_func(() => { + onLoadWasCalled = true; + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + iframe.onload = null; + }); + document.addEventListener("documentWriteDone", t.step_func_done(() => { + assert_true(onLoadWasCalled, "onload must be called"); + assert_equals(iframe.contentDocument.body.textContent, "document.write body contents\n"); + })); + + iframe.src = "module-tla-delayed-iframe.html"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise-iframe.html new file mode 100644 index 0000000000..3e90fb2ea7 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise-iframe.html @@ -0,0 +1,10 @@ +<!doctype html> +<script type=module> +await new Promise(resolve => { + document.write("document.write body contents\n"); + document.close(); + window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone")); + resolve(); +}); +</script> +Initial body contents diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise.html new file mode 100644 index 0000000000..f60aa38e00 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise.html @@ -0,0 +1,29 @@ +<!doctype html> +<title>document.write in an imported module</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(t => { + // Expose {test} in the iframe for using the step_timeout helper. + document.test = t; + + const iframe = document.createElement("iframe"); + iframe.onerror = t.unreached_func("Error loading iframe"); + + let onLoadWasCalled = false; + iframe.onload = t.step_func(() => { + onLoadWasCalled = true; + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + // Don't call the event handler another time after document.write. + iframe.onload = null; + }); + document.addEventListener("documentWriteDone", t.step_func_done(() => { + assert_false(onLoadWasCalled, "onload must not be called yet"); + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + })); + + iframe.src = "module-tla-immediate-promise-iframe.html"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import-iframe.html new file mode 100644 index 0000000000..ec4a6ed6aa --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import-iframe.html @@ -0,0 +1,5 @@ +<!doctype html> +<script type=module> +await import("./module-tla-import.mjs"); +</script> +Initial body contents diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.html new file mode 100644 index 0000000000..20645f4d78 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>document.write in an imported module</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(t => { + const iframe = document.createElement("iframe"); + iframe.onerror = t.unreached_func("Error loading iframe"); + + let onLoadWasCalled = false; + + iframe.onload = t.step_func(() => { + onLoadWasCalled = true; + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + // Don't call the event handler another time after document.write. + iframe.onload = null; + }); + document.addEventListener("documentWriteDone", t.step_func_done(() => { + assert_true(onLoadWasCalled, "onload must be called"); + assert_equals(iframe.contentDocument.body.textContent, "document.write body contents\n"); + })); + + iframe.src = "module-tla-import-iframe.html"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.mjs b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.mjs new file mode 100644 index 0000000000..74d2427537 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.mjs @@ -0,0 +1,4 @@ +document.write("document.write body contents\n"); +document.close(); + +window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone")); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise-iframe.html new file mode 100644 index 0000000000..edc9e80cb3 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise-iframe.html @@ -0,0 +1,11 @@ +<!doctype html> +<script type=module> +await new Promise(resolve => { + window.parent.document.test.step_timeout(resolve, 0); + document.write("document.write body contents\n"); + document.close(); + window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone")); +}); +</script> + +Initial body contents diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise.html new file mode 100644 index 0000000000..4f1281bcce --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise.html @@ -0,0 +1,24 @@ +<!doctype html> +<title>document.write in an imported module</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(t => { + // Expose {test} in the iframe for using the step_timeout helper. + document.test = t; + + const iframe = document.createElement("iframe"); + iframe.onerror = t.unreached_func("Error loading iframe"); + + document.addEventListener("documentWriteDone", t.step_func(() => { + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + })); + iframe.onload = t.step_func_done(() => { + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + }); + + iframe.src = "module-tla-promise-iframe.html"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module.html new file mode 100644 index 0000000000..7e970d3fd9 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module.html @@ -0,0 +1,22 @@ +<!doctype html> +<meta charset=utf-8> +<title>document.write in a module</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(t => { + const iframe = document.createElement("iframe"); + + iframe.onerror = t.unreached_func("Error loading iframe"); + document.addEventListener("documentWriteDone", t.step_func(() => { + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + })); + iframe.onload = t.step_func_done(() => { + assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n"); + }); + + iframe.src = "module-iframe.html"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-1.html new file mode 100644 index 0000000000..c7a7a1db4e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-1.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<body>You should see the word "worked" below<br><script>document.write("\u003cscript>document.write(\"\\u003cscript src='nested-document-write-external.js'>\\u003c/script>r\"); document.write(\"k\");\u003c/script>e"); document.write("d");</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-2.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-2.html new file mode 100644 index 0000000000..60b8eae1ef --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-2.html @@ -0,0 +1,7 @@ +<!DOCTYPE html> +<body> +You should see the word "worked" in the frame below.<br> +<iframe></iframe> +<script> +var doc = document.getElementsByTagName("iframe")[0].contentDocument; +doc.open(); doc.write("\u003cscript>document.write(\"\\u003cscript src='nested-document-write-external.js'>\\u003c/script>r\"); document.write(\"k\");\u003c/script>e"); doc.write("d"); doc.close();</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-external.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-external.js new file mode 100644 index 0000000000..bf91daf986 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-external.js @@ -0,0 +1 @@ +document.write("w"); document.write("o"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/original-id.json b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/original-id.json new file mode 100644 index 0000000000..08bd4d0d4e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/original-id.json @@ -0,0 +1 @@ +{"original_id":"document.write()"}
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_001.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_001.html new file mode 100644 index 0000000000..43c7adb4d4 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_001.html @@ -0,0 +1,10 @@ +<!doctype html> +<title>document.write script</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<script>t.done();<"+"/script>"); +}); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_002.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_002.html new file mode 100644 index 0000000000..3879d8489f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_002.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>document.write script executed synchronously</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +var order = []; +t.step(function() { + document.write("<script>t.step(function() {order.push(1);});<"+"/script>"); + order.push(2); +}); +</script> +<script> +t.step(function() { + order.push(3); + assert_array_equals(order, [1,2,3]); +}) +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_003.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_003.html new file mode 100644 index 0000000000..e669252f75 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_003.html @@ -0,0 +1,10 @@ +<!doctype html> +<title>document.write script writing a further script</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + document.write("<script>document.write('<script>t.done()</script'+'>')<"+"/script>"); +}); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_004.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_004.html new file mode 100644 index 0000000000..15fda325b1 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_004.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write script writing script; order of execution</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +var order = []; +t.step(function() { + order.push(1); + document.write("<script>order.push(2); document.write('<script>order.push(3);</script'+'>'); order.push(4);<"+"/script>"); + order.push(5); +}); +</script> +<script> +t.step(function() { + assert_array_equals(order, [1,2,3,4,5]); +}); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_005.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_005.html new file mode 100644 index 0000000000..b99196c7d0 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_005.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>document.write external script</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +var order = []; +t.step(function() { + order.push(1); + document.write("<script src='005.js'><"+"/script>"); + order.push(2); +}); +</script> +<script> +order.push(4); +t.step(function() { + assert_array_equals(order, [1,2,3,4]); +}); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_006.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_006.html new file mode 100644 index 0000000000..c8dd9a5f9a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_006.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>document.write external script followed by internal script</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +var order = []; +t.step(function() { + order.push(1); + document.write("<script src='006.js'><"+"/script><script>t.step(function(){order.push(4)})</script"+">"); + order.push(2); +}); +</script> +<script> +t.step(function() { + order.push(5); + assert_array_equals(order, [1,2,3,4,5]); +}); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_007.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_007.html new file mode 100644 index 0000000000..fbbe5b2f86 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_007.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write external script that document.writes inline script</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +var order = []; +t.step(function() { + order.push(1); +}); +</script> +<script src="007.js"></script> +<script> +t.step(function() { + order.push(4); + assert_array_equals(order, [1,2,3,4]); +}); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_008.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_008.html new file mode 100644 index 0000000000..c5a44dc700 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_008.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write external script that document.writes external script</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +var order = []; +t.step(function() { + order.push(1); +}); +</script> +<script src="008.js"></script> +<script> +t.step(function() { + order.push(4); + assert_array_equals(order, [1,2,3,4]); +}); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_009.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_009.html new file mode 100644 index 0000000000..d12d934ea0 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_009.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>document.write script that document.writes script</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +var order = []; +t.step(function() { + order.push(1); + document.write("<script>order.push(2); document.write('<script>order.push(3); document.write(\"<script>order.push(4);</script\"+\">\"); order.push(5);</script' + '>'); order.push(6);</script" + ">"); + order.push(7); +}); +</script> +<script> +t.step(function() { + assert_array_equals(order, [1,2,3,4,5,6,7]); +}); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_010.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_010.html new file mode 100644 index 0000000000..93728d6f27 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_010.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>document.write external script tokenizer order</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +var order = []; +t.step(function() { + order.push(1); + document.write("<script src='010.js'></script" + "><meta><script src='010-1.js'></script" + ">"); + order.push(2); + assert_equals(document.getElementsByTagName("meta").length, 0); +}); +</script> +<script> +t.step(function() { + order.push(5); + assert_equals(document.getElementsByTagName("meta").length, 1); + assert_array_equals(order, [1,2,3,4,5]); +}); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_011.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_011.html new file mode 100644 index 0000000000..2bbcaf976e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_011.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>document.write external script that document.writes external script</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +var order = []; +t.step(function() { + order.push(1); + document.write("<script src='011.js'></script" + "><meta>"); + order.push(2); + assert_equals(document.getElementsByTagName("meta").length, 0); +}); +</script> +<script> +t.step(function() { + order.push(5); + assert_equals(document.getElementsByTagName("meta").length, 3, "Number of meta elements at end"); + assert_array_equals(order, [1,2,3,4,5]); +}); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_012.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_012.html new file mode 100644 index 0000000000..57755f4c94 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_012.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>document.write external script tokenizer order</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +var order = []; +t.step(function() { + order.push(1); + document.write("<script>order.push(2); document.write('<script src=\"012.js\"></script' + '><meta>'); order.push(3); t.step(function() {assert_equals(document.getElementsByTagName('meta').length, 0)});</script" + "><meta>"); + order.push(4); + assert_equals(document.getElementsByTagName("meta").length, 0); +}); +</script> +<script> +t.step(function() { + order.push(6); + assert_equals(document.getElementsByTagName("meta").length, 2); + assert_array_equals(order, [1,2,3,4,5,6]); +}); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_013.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_013.html new file mode 100644 index 0000000000..0e71e5eb0c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_013.html @@ -0,0 +1,24 @@ +<!doctype html> +<title>document.write</title> +<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script> +<script> +var t = async_test(); +t.step(function() { + var s = "<script src='013.js'><" + "/script></svg>]]><path></svg>"; + for (var i=0; i<s.length; i++) { + document.write(s[i]); + } +}); +</script><script> +t.step(function() { + assert_equals(document.body.childNodes[0].nodeType, document.ELEMENT_NODE); + assert_equals(document.body.childNodes[0].localName, "svg"); + assert_equals(document.body.childNodes[0].childNodes[0].nodeType, document.TEXT_NODE); + assert_equals(document.body.childNodes[0].childNodes[0].data, "</svg>"); + assert_equals(document.body.childNodes[0].childNodes[1].nodeType, document.ELEMENT_NODE); + assert_equals(document.body.childNodes[0].childNodes[1].localName, "path"); +} +); +t.done(); +</script> +<div id="log"></div> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/write-active-document.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/write-active-document.html new file mode 100644 index 0000000000..6faffd81de --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/write-active-document.html @@ -0,0 +1,35 @@ +<!doctype html> +<title>document.write only writes to active documents</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body><div id="log"></div></body> +<script> + async_test(function(t) { + var child = document.createElement("iframe"); + child.src = "empty.html?1"; + child.onload = t.step_func(function() { + var child1 = child.contentDocument; + var link = child1.createElement("a"); + link.href = "data:text/html,Clicked."; + link.innerText = "Link."; + child1.body.appendChild(link); + var grandchild = child1.createElement("iframe"); + grandchild.src = "empty.html?2"; + grandchild.onload = t.step_func(function() { + var grandchild1 = grandchild.contentDocument; + child.onload = t.step_func(function() { + // This is a write to an inactive document + child1.write('WRITE HAPPENED'); + assert_equals(child1.body.lastChild.tagName, "IFRAME"); + // This is a write to an active but not fully active document + grandchild1.write('WRITE HAPPENED'); + assert_equals(grandchild1.body.innerHTML, "WRITE HAPPENED"); + t.done(); + }); + link.click(); + }); + child1.body.appendChild(grandchild); + }); + document.body.appendChild(child); + }); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-01.xhtml b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-01.xhtml new file mode 100644 index 0000000000..cb5ec3a33a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-01.xhtml @@ -0,0 +1,19 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>document.writeln in XHTML</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#document.writeln%28%29"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<script> +test(function() { + assert_throws_dom("INVALID_STATE_ERR", function() { + document.writeln("Failure: document.writeln actually worked"); + }, "document.writeln in XHTML should throw an INVALID_STATE_ERR "); +}, "document.writeln in XHTML"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-02.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-02.html new file mode 100644 index 0000000000..2a64ac7561 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-02.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<title>document.writeln and null/undefined</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-document-writeln%28%29"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#documents-in-the-dom"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + doc = iframe.contentDocument; + test(function() { + doc.open(); + doc.writeln(null); + doc.close(); + assert_equals(doc.documentElement.textContent, "null\n"); + }, "document.writeln(null)"); + test(function() { + doc.open(); + doc.writeln(undefined); + doc.close(); + assert_equals(doc.documentElement.textContent, "undefined\n"); + }, "document.writeln(undefined)"); +}, "Calling document.writeln with null and undefined"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-03.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-03.html new file mode 100644 index 0000000000..df9a7a15c2 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-03.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>document.writeln with multiple arguments</title> +<link rel="author" title="Sebmaster" href="mailto:wpt@smayr.name"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-document-writeln%28%29"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#documents-in-the-dom"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + var doc = iframe.contentDocument; + doc.open(); + doc.writeln('a', 'b'); + doc.close(); + assert_equals(doc.documentElement.textContent, "ab\n"); +}, "Calling document.writeln with multiple arguments"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/original-id.json b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/original-id.json new file mode 100644 index 0000000000..0cc32be6a2 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/original-id.json @@ -0,0 +1 @@ +{"original_id":"document.writeln()"}
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-encoding.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-encoding.html new file mode 100644 index 0000000000..1debcafa3b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-encoding.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<meta charset="windows-1252"> <!-- intentional to make sure the results are UTF-8 anyway --> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/whatwg/html/pull/9538"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<!-- This was adapted from DOMParser-parseFromString-encoding.html --> + +<script> +function assertEncoding(doc) { + assert_equals(doc.charset, "UTF-8", "document.charset"); + assert_equals(doc.characterSet, "UTF-8", "document.characterSet"); + assert_equals(doc.inputEncoding, "UTF-8", "document.characterSet"); +} + +setup(() => { + assert_equals(document.characterSet, "windows-1252", "the meta charset must be in effect, making the main document windows-1252"); +}); + +test(() => { + const doc = Document.parseHTMLUnsafe(''); + assertEncoding(doc); +}, 'Parse empty string'); + +test(() => { + const doc = Document.parseHTMLUnsafe(`<meta charset="latin2">`); + assertEncoding(doc); +}, "meta charset latin2"); + +test(() => { + const doc = Document.parseHTMLUnsafe(`<?xml version="1.0" encoding="latin2"?><x/>`); + assertEncoding(doc); +}, "XML declaration"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-style-attribute.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-style-attribute.html new file mode 100644 index 0000000000..cd092a6034 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-style-attribute.html @@ -0,0 +1,54 @@ +<!doctype html> +<link rel=author href="mailto:jarhar@chromium.org"> +<!-- This test was adapted from style_attribute_html.html --> +<meta charset=utf-8> +<title>Style attribute in HTML</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> + +var div; +setup(function() { + var input = '<div style="color: red">Foo</div>'; + var doc = Document.parseHTMLUnsafe(input); + div = doc.querySelector('div'); +}); + +test(function() { + var style = div.style; + assert_equals(style.cssText, 'color: red;'); + assert_equals(style.color, 'red'); + assert_equals(div.getAttribute("style"), 'color: red', + 'Value of style attribute should match the string value that was set'); +}, 'Parsing of initial style attribute'); + +test(function() { + var style = div.style; + div.setAttribute('style', 'color:: invalid'); + assert_equals(style.cssText, ''); + assert_equals(style.color, ''); + assert_equals(div.getAttribute('style'), 'color:: invalid', + 'Value of style attribute should match the string value that was set'); +}, 'Parsing of invalid style attribute'); + +test(function() { + var style = div.style; + div.setAttribute('style', 'color: green'); + assert_equals(style.cssText, 'color: green;'); + assert_equals(style.color, 'green'); + assert_equals(div.getAttribute('style'), 'color: green', + 'Value of style attribute should match the string value that was set'); +}, 'Parsing of style attribute'); + +test(function() { + var style = div.style; + style.backgroundColor = 'blue'; + assert_equals(style.cssText, 'color: green; background-color: blue;', + 'Should not drop the existing style'); + assert_equals(style.color, 'green', + 'Should not drop the existing style'); + assert_equals(div.getAttribute('style'), 'color: green; background-color: blue;', + 'Should update style attribute'); +}, 'Update style.backgroundColor'); + +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base-pushstate.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base-pushstate.html new file mode 100644 index 0000000000..a8eab59511 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base-pushstate.html @@ -0,0 +1,15 @@ +<!doctype html> +<link rel=author href="mailto:jarhar@chromium.org"> +<!-- This test was adapted from DOMParser-parseFromString-url-base-pushstate.html --> +<title>parseHTMLUnsafe test of how the document's URL is set (base, pushstate)</title> +<base href="/fake/base-from-outer-frame"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base-pushstate.html" onload="window.resolveLoadPromise();"></iframe> + +<script> +"use strict"; +history.pushState(null, "", "/fake/push-state-from-outer-frame"); +</script> +<script src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js"></script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base.html new file mode 100644 index 0000000000..62b2c09aae --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base.html @@ -0,0 +1,10 @@ +<!doctype html> +<link rel=author href="mailto:jarhar@chromium.org"> +<!-- This was adapted from DOMParser-parseFromString-url-base.html --> +<title>parseHTMLUnsafe test of how the document's URL is set (base, no pushstate)</title> +<base href="/fake/base-from-outer-frame"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base.html" onload="window.resolveLoadPromise();"></iframe> +<script src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js"></script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-moretests.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-moretests.html new file mode 100644 index 0000000000..41335ef035 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-moretests.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<!-- This test was adapted from DOMParser-parseFromString-url-moretests.html --> +<meta charset=utf-8> +<title>Document.parseHTMLUnsafe: Document's url</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement("iframe"); + iframe.onload = this.step_func(function() { + var child = iframe.contentWindow; + + test(function() { + var doc = Document.parseHTMLUnsafe("<html></html>"); + assert_equals(doc.URL, "about:blank"); + }, "Parent window"); + + test(function() { + var doc = child.Document.parseHTMLUnsafe("<html></html>"); + assert_equals(doc.URL, "about:blank"); + }, "Child window"); + + var dpBeforeNavigation = child.Document, urlBeforeNavigation = child.document.URL; + iframe.onload = this.step_func_done(function() { + test(function() { + var doc = dpBeforeNavigation.parseHTMLUnsafe("<html></html>"); + assert_equals(doc.URL, "about:blank"); + }, "Child window crossing navigation"); + + test(function() { + var doc = child.Document.parseHTMLUnsafe("<html></html>"); + assert_equals(doc.URL, "about:blank"); + }, "Child window after navigation"); + }); + iframe.src = "/common/blank.html?2"; + }); + iframe.src = "/common/blank.html?1"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-pushstate.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-pushstate.html new file mode 100644 index 0000000000..7930bf0ddb --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-pushstate.html @@ -0,0 +1,14 @@ +<!doctype html> +<link rel=author href="mailto:jarhar@chromium.org"> +<!-- This test was adapted from DOMParser-parseFromString-url-pushstate.html --> +<title>parseHTMLUnsafe test of how the document's URL is set (no base, pushstate)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-pushstate.html" onload="window.resolveLoadPromise();"></iframe> + +<script> +"use strict"; +history.pushState(null, "", "/fake/push-state-from-outer-frame"); +</script> +<script src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js"></script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url.html new file mode 100644 index 0000000000..911e183706 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url.html @@ -0,0 +1,9 @@ +<!doctype html> +<link rel=author href="mailto:jarhar@chromium.org"> +<!-- This test was adapted from DOMParser-parseFromString-url.html --> +<title>parseHTMLUnsafe test of how the document's URL is set (no pushstate, no base)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe src="resources/parseHTMLUnsafe-iframe.html" onload="window.resolveLoadPromise();"></iframe> +<script src="resources/parseHTMLUnsafe-url-tests.js"></script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe.html new file mode 100644 index 0000000000..2a89370825 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe.html @@ -0,0 +1,77 @@ +<!doctype html> +<link rel=author href="mailto:jarhar@chromium.org"> +<!-- This was adapted from DOMParser-parseFromString-html.html --> +<title>parseHTMLUnsafe basic test of HTML parsing</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +// |expected| should be an object indicating the expected type of node. +function assert_node(actual, expected) { + assert_true(actual instanceof expected.type, + 'Node type mismatch: actual = ' + actual.constructor.name + ', expected = ' + expected.type.name); + if (typeof(expected.id) !== 'undefined') + assert_equals(actual.id, expected.id, expected.idMessage); +} + +var doc; +setup(function() { + doc = Document.parseHTMLUnsafe('<html id="root"><head></head><body></body></html>'); +}); + +test(function() { + var root = doc.documentElement; + assert_node(root, { type: HTMLHtmlElement, id: 'root', + idMessage: 'documentElement id attribute should be root.' }); +}, 'Parsing of id attribute'); + +test(function() { + assert_equals(doc.contentType, "text/html") +}, 'contentType'); + +test(function() { + assert_equals(doc.compatMode, "BackCompat") +}, 'compatMode'); + +test(function() { + doc = Document.parseHTMLUnsafe('<!DOCTYPE html><html id="root"><head></head><body></body></html>'); + assert_equals(doc.compatMode, "CSS1Compat") +}, 'compatMode for a proper DOCTYPE'); + +// URL- and encoding-related stuff tested separately. + +test(function() { + assert_equals(doc.location, null, + 'The document must have a location value of null.'); +}, 'Location value'); + +test(function() { + var htmldoc = Document.parseHTMLUnsafe("<!DOCTYPE foo></><foo></multiple></>"); + assert_equals(htmldoc.documentElement.localName, "html"); + assert_equals(htmldoc.documentElement.namespaceURI, "http://www.w3.org/1999/xhtml"); +}, "Document.parseHTMLUnsafe parses HTML tag soup with no problems"); + +test(function() { + const doc = Document.parseHTMLUnsafe('<noembed><a></noembed>'); + assert_equals(doc.querySelector('noembed').textContent, '<a>'); +}, 'Document.parseHTMLUnsafe should handle the content of <noembed> as raw text'); + +test(() => { + const doc = Document.parseHTMLUnsafe(` +<html><body> +<style> + @import url(/dummy.css) +</style> +<script>document.x = 8<\/script> +</body></html>`); + + assert_not_equals(doc.querySelector('script'), null, 'script must be found'); + assert_equals(doc.x, undefined, 'script must not be executed on the inner document'); + assert_equals(document.x, undefined, 'script must not be executed on the outer document'); +}, 'script is found synchronously even when there is a css import'); + +test(() => { + const doc = Document.parseHTMLUnsafe(`<body><noscript><p id="test1">test1<p id="test2">test2</noscript>`); + assert_node(doc.body.firstChild.childNodes[0], { type: HTMLParagraphElement, id: 'test1' }); + assert_node(doc.body.firstChild.childNodes[1], { type: HTMLParagraphElement, id: 'test2' }); +}, 'must be parsed with scripting disabled, so noscript works'); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Element-setHTMLUnsafe-04.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Element-setHTMLUnsafe-04.html new file mode 100644 index 0000000000..4a9e300afc --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Element-setHTMLUnsafe-04.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>setHTMLUnsafe in HTML</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel=author href="mailto:jarhar@chromium.org"> +<!-- This test was adapted from innerhtml-04.html --> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function testIsChild(p, c) { + assert_equals(p.firstChild, c); + assert_equals(c.parentNode, p); +} +test(function() { + var p = document.createElement('p'); + var b = p.appendChild(document.createElement('b')); + var t = b.appendChild(document.createTextNode("foo")); + testIsChild(p, b); + testIsChild(b, t); + assert_equals(t.data, "foo"); + p.setHTMLUnsafe(""); + testIsChild(b, t); + assert_equals(t.data, "foo"); +}, "setHTMLUnsafe should leave the removed children alone.") +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base-pushstate.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base-pushstate.html new file mode 100644 index 0000000000..53b855968c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base-pushstate.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>An iframe that does parseHTMLUnsafe stuff with base and pushstates itself</title> +<base href="/fake/base-from-iframe"> + +<script> +"use strict"; +history.pushState(null, "", "/fake/push-state-from-iframe"); +</script> +<script src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js"></script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base.html new file mode 100644 index 0000000000..6977e93811 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>An iframe that does parseHTMLUnsafe stuff with base</title> +<base href="/fake/base-from-iframe"> + +<script src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js"></script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-pushstate.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-pushstate.html new file mode 100644 index 0000000000..5e1fae0441 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-pushstate.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>An iframe that does parseHTMLUnsafe stuff and pushstates itself</title> + +<script> +"use strict"; +history.pushState(null, "", "/fake/push-state-from-iframe"); +</script> +<script src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js"></script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.html new file mode 100644 index 0000000000..f47d9605fc --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>An iframe that does parseHTMLUnsafe stuff</title> +<script src="parseHTMLUnsafe-iframe.js"></script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js new file mode 100644 index 0000000000..4a0b56869b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js @@ -0,0 +1,3 @@ +window.doParse = (html) => { + return Document.parseHTMLUnsafe(html); +}; diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js new file mode 100644 index 0000000000..88344d127c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js @@ -0,0 +1,36 @@ +const loadPromise = new Promise(resolve => { window.resolveLoadPromise = resolve; }); + +function assertURL(doc) { + assert_equals(doc.URL, "about:blank", "document.URL"); + assert_equals(doc.documentURI, "about:blank", "document.documentURI"); + assert_equals(doc.baseURI, "about:blank", "document.baseURI"); +} + +const inputs = { + valid: "<html></html>", + "invalid XML": `<span x:test="testing">1</span>` +}; + +for (const [inputName, input] of Object.entries(inputs)) { + test(() => { + const doc = Document.parseHTMLUnsafe(input); + + assertURL(doc); + }, `${inputName}: created normally`); + + promise_test(async () => { + await loadPromise; + + const doc = frames[0].Document.parseHTMLUnsafe(input); + + assertURL(doc); + }, `${inputName}: created using another iframe's parseHTMLUnsafe from this frame`); + + promise_test(async () => { + await loadPromise; + + const doc = frames[0].doParse(input); + + assertURL(doc); + }, `${inputName}: created using another iframe's parseHTMLUnsafe from that frame`); +} diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-CEReactions.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-CEReactions.html new file mode 100644 index 0000000000..3aa14516f2 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-CEReactions.html @@ -0,0 +1,71 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/whatwg/html/issues/9957"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +class MyElement extends HTMLElement { + constructor() { + super(); + this.numConnectedCallback = 0; + this.numDisconnectedCallback = 0; + this.attributeChangedCalls = []; + } + + connectedCallback() { + this.numConnectedCallback++; + } + + disconnectedCallback() { + this.numDisconnectedCallback++; + } + + static observedAttributes = ['foo']; + attributeChangedCallback(name, oldValue, newValue) { + this.attributeChangedCalls.push({name, oldValue, newValue}); + } +} +customElements.define('my-element', MyElement); + +['Element', 'ShadowRoot'].forEach(containerType => { + test(() => { + let container = null; + if (containerType === 'Element') { + container = document.createElement('div'); + document.body.appendChild(container); + } else if (containerType === 'ShadowRoot') { + const host = document.createElement('div'); + document.body.appendChild(host); + container = host.attachShadow({mode: 'closed'}); + } + + container.setHTMLUnsafe('<my-element>'); + const myElement1 = container.querySelector('my-element'); + assert_equals(myElement1.numConnectedCallback, 1, + 'myElement1.numConnectedCallback after first setHTMLUnsafe.'); + assert_equals(myElement1.numDisconnectedCallback, 0, + 'myElement1.numDisconnectedCallback after first setHTMLUnsafe.'); + assert_equals(JSON.stringify(myElement1.attributeChangedCalls), + JSON.stringify([]), + 'myElement1.attributeChangedCalls after first setHTMLUnsafe.'); + + container.setHTMLUnsafe('<my-element foo=bar>'); + const myElement2 = container.querySelector('my-element'); + assert_equals(myElement1.numConnectedCallback, 1, + 'myElement1.numConnectedCallback after second setHTMLUnsafe.'); + assert_equals(myElement1.numDisconnectedCallback, 1, + 'myElement1.numDisconnectedCallback after second setHTMLUnsafe.'); + assert_array_equals(myElement1.attributeChangedCalls, [], + 'myElement1.attributeChangedCalls after second setHTMLUnsafe.'); + assert_equals(myElement2.numConnectedCallback, 1, + 'myElement2.numConnectedCallback after second setHTMLUnsafe.'); + assert_equals(myElement2.numDisconnectedCallback, 0, + 'myElement2.numDisconnectedCallback after second setHTMLUnsafe.'); + assert_equals(JSON.stringify(myElement2.attributeChangedCalls), + JSON.stringify([{name: 'foo', oldValue: null, newValue: 'bar'}]), + 'myElement2.attributeChangedCalls after second setHTMLUnsafe.'); + }, `${containerType}.setHTMLUnsafe should trigger custom element reactions.`); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-xml.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-xml.html new file mode 100644 index 0000000000..d7211e97f1 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-xml.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/whatwg/html/pull/9538"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +test(() => { + const xmlDoc = document.implementation.createDocument(null, 'root', null); + assert_equals(xmlDoc.contentType, 'application/xml'); + // Intentionally unclosed and misnested tags + xmlDoc.documentElement.setHTMLUnsafe('<p><foo><b><i>test</b></i>'); + assert_equals(xmlDoc.documentElement.innerHTML, + '<p xmlns="http://www.w3.org/1999/xhtml"><foo><b><i>test</i></b></foo></p>', + 'Element.setHTMLUnsafe should use the HTML parser in XML documents.'); +}, 'setHTMLUnsafe should still parse HTML even in XML documents.'); + +test(() => { + const svgDoc = document.implementation.createDocument('http://www.w3.org/2000/svg', 'root', null); + assert_equals(svgDoc.contentType, 'image/svg+xml'); + // Intentionally unclosed and misnested tags + svgDoc.documentElement.setHTMLUnsafe('<p><foo><b><i>test</b></i>'); + assert_equals(svgDoc.documentElement.innerHTML, + '<p xmlns="http://www.w3.org/1999/xhtml"><foo><b><i>test</i></b></foo></p>', + 'Element.setHTMLUnsafe should use the HTML parser in SVG documents.'); +}, 'setHTMLUnsafe should still parse HTML even in SVG documents.'); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe.html new file mode 100644 index 0000000000..1c0b115569 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/whatwg/html/pull/9538"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +for (const containerType of ['Element', 'ShadowRoot']) { + const createContainer = () => { + if (containerType == 'ShadowRoot') { + return document.createElement('div').attachShadow({mode: 'open'}); + } else if (containerType == 'Element') { + return document.createElement('div'); + } + }; + + test(() => { + const container = createContainer(); + container.setHTMLUnsafe('<span title=hello>world</span>'); + + assert_equals(container.children.length, 1, 'Only one child node should be created.'); + assert_equals(container.firstChild.tagName, 'SPAN', 'The child element should be a span.'); + assert_equals(container.firstChild.getAttribute('title'), 'hello', + 'The title attribute should be set to hello.'); + assert_equals(container.firstChild.childNodes.length, 1, + 'The span should have one child.'); + assert_true(container.firstChild.childNodes[0] instanceof Text, + 'The spans child should be a text node.'); + assert_equals(container.firstChild.textContent, 'world', + 'The spans textContent should be world.'); + }, `${containerType}: setHTMLUnsafe with no shadowdom.`); + + test(() => { + const container = createContainer(); + container.setHTMLUnsafe(`<div><template shadowrootmode=open><div>hello</div></template></div>`); + + assert_equals(container.children.length, 1, 'One child should be created in the container.'); + const shadowRoot = container.firstChild.shadowRoot; + assert_true(!!shadowRoot, 'The containers child should have a ShadowRoot.'); + assert_equals(shadowRoot.children.length, 1, 'One child should be created in the ShadowRoot.'); + assert_equals(shadowRoot.firstChild.textContent, 'hello', + 'The ShadowRoots childs textContent should be hello.'); + }, `${containerType}: setHTMLUnsafe with shadowdom.`); +} + +test(() => { + const template = document.createElement('template'); + template.setHTMLUnsafe('<div>hello world</div>'); + + assert_equals(template.children.length, 0, 'template should not have any child nodes.'); + assert_equals(template.content.children.length, 1, 'template content should have a child div.'); + assert_equals(template.content.children[0].textContent, 'hello world', 'text content should be set.'); +}, 'template.setHTMLUnsafe() should modify template content fragment rather than actual children.'); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/002.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/002.html new file mode 100644 index 0000000000..5584bf9afb --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/002.html @@ -0,0 +1,12 @@ +<!doctype html> +<title>document.open during parsing</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var log = document.getElementById("log"); + assert_equals(document.open(), document); + assert_equals(document.getElementById("log"), log); +}) +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/004.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/004.html new file mode 100644 index 0000000000..3fb443a993 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/004.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>Reuse of document object after document.open</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<iframe src="/common/blank.html"></iframe> +<script> +var t = async_test(); +var iframe; +onload = t.step_func(function() { + var iframe = document.getElementsByTagName("iframe")[0]; + var handle = iframe.contentDocument; + iframe.contentDocument.test_state = 1; + assert_equals(iframe.contentDocument.open(), handle); + assert_equals(iframe.contentDocument.test_state, 1); + assert_equals(iframe.contentDocument, handle); + t.done(); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/006.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/006.html new file mode 100644 index 0000000000..1dcb92615d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/006.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>Cancelling error after document.open</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<iframe src="/common/blank.html"></iframe> +<script> +var t = async_test(); +var iframe; +onload = t.step_func(function() { + var iframe = document.getElementsByTagName("iframe")[0]; + var img = iframe.contentDocument.createElement("img"); + img.onerror = t.step_func(function() {assert_unreached()}) + img.src = "missing"; + iframe.contentDocument.body.appendChild(img); + assert_equals(iframe.contentDocument.open(), iframe.contentDocument); + setTimeout(function() {t.done();}, 500); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011-1.html new file mode 100644 index 0000000000..37973fd52e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011-1.html @@ -0,0 +1,5 @@ +<script> +parent.t.step(() => { parent.assert_equals(document.open(), document); }); +setTimeout(parent.t.step_func(function() {parent.t.done()}), 0); +document.close(); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011.html new file mode 100644 index 0000000000..2acc884c54 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011.html @@ -0,0 +1,9 @@ +<!doctype html> +<title>Timeout after document.open</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var t = async_test(); +</script> +<iframe src="011-1.html"></iframe> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012-1.html new file mode 100644 index 0000000000..644b30827d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012-1.html @@ -0,0 +1,7 @@ +<script> +onload = parent.t.step_func(function() { + parent.assert_equals(document.open(), document); + setTimeout(parent.t.step_func(function() {parent.t.done()}), 0); + document.close(); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012.html new file mode 100644 index 0000000000..518454858d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012.html @@ -0,0 +1,9 @@ +<!doctype html> +<title>Timeout after document.open in load event</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var t = async_test(); +</script> +<iframe src="012-1.html"></iframe> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013-1.html new file mode 100644 index 0000000000..ea321238ed --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013-1.html @@ -0,0 +1,7 @@ +<script> +addEventListener("DOMContentLoaded", parent.t.step_func(function() { + parent.assert_equals(document.open(), document); + setTimeout(parent.t.step_func(function() {parent.t.done()}), 0); + document.close(); +}), false); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013.html new file mode 100644 index 0000000000..5749361aa8 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013.html @@ -0,0 +1,9 @@ +<!doctype html> +<title>Timeout after document.open in DOMContentLoaded event</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var t = async_test(); +</script> +<iframe src="013-1.html"></iframe> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014-1.html new file mode 100644 index 0000000000..0e97808116 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014-1.html @@ -0,0 +1,9 @@ +<script> +onload = parent.t.step_func(function() { + setTimeout(parent.t.step_func(function() { + parent.assert_equals(document.open(), document); + setTimeout(parent.t.step_func(function() {parent.t.done()}), 0); + document.close(); + }), 100) +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014.html new file mode 100644 index 0000000000..b4e4b17cf4 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014.html @@ -0,0 +1,9 @@ +<!doctype html> +<title>Timeout after document.open after document is completely loaded</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var t = async_test(); +</script> +<iframe src="014-1.html"></iframe> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015-1.html new file mode 100644 index 0000000000..c325bd0801 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015-1.html @@ -0,0 +1,17 @@ +<script> +onload = function() { + window.test_prop = 1; + parent.tests[0].step(function() {parent.assert_equals(test_prop, 1)}); + parent.tests[0].step(function() {parent.assert_equals(document.open(), document)}); + document.write("<script>test_prop = 2;<\/script>"); + document.close(); + parent.tests[0].step(function() {parent.assert_equals(test_prop, 2)}); + parent.tests[1].step(function() {parent.assert_equals(window.test_prop, 2)}); + parent.tests[2].step(function() {parent.assert_equals(get_this(), window)}); + parent.tests_done(); +}; + +function get_this() { + return this; +} +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015.html new file mode 100644 index 0000000000..cce9e65d4c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>Window vs global scope after document.open</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var tests = [async_test("global scope unchanged"), + async_test("window object unchanged"), + async_test("this is the window object")]; +function tests_done() { + tests.forEach(function(t) {t.done()}); +} +</script> +<iframe src="015-1.html"></iframe> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016-1.html new file mode 100644 index 0000000000..ceeeb64df6 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016-1.html @@ -0,0 +1,41 @@ +<script> +window.test_prop = 1; +</script> +<script> +onload = function() { + parent.tests[0].step(function() { + parent.assert_equals(document.open(), document); + }); + document.write("<script>test_prop = 2; timeout_fired=false;<\/script>"); + document.close(); + + setTimeout(function() { + parent.tests[0].step(function() { + parent.assert_equals(test_prop, 2, "Global scope from original window timeout"); + parent.assert_equals(window.test_prop, 2, "Window property from original window timeout") + }); + parent.tests[1].step(function() { + var t = get_this(); + parent.assert_equals(t.test_prop, 2, "Window property from original window timeout"); + parent.assert_equals(t, window, "Global scope from original window timeout"); + }); + }, 0); + + window.setTimeout(function() { + parent.tests[2].step(function() { + parent.assert_equals(test_prop, 2, "Global scope from original window timeout"); + parent.assert_equals(window.test_prop, 2, "Window property from original window timeout") + }); + parent.tests[3].step(function() { + var t = get_this(); + parent.assert_equals(t.test_prop, 2, "Window property from original window timeout"); + parent.assert_equals(t, window, "Global scope from original window timeout"); + }); + parent.tests_done(); + }, 100); +}; + +function get_this() { + return this; +} +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016.html new file mode 100644 index 0000000000..1c70fce591 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>setTimeout document.open</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var tests = [async_test("Timeout on original window, scope"), + async_test("Timeout on original window, this object"), + async_test("Timeout on new window, scope"), + async_test("Timeout on new window, this object")]; +function tests_done() { + tests.forEach(function(t) {t.done()}); +} +</script> +<iframe src="016-1.html"></iframe> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-immediate.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-immediate.window.js new file mode 100644 index 0000000000..8d045b9e0a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-immediate.window.js @@ -0,0 +1,119 @@ +// The following tests deal with the <meta http-equiv=refresh> pragma and the +// `Refresh` header. The spec is still hazy on the precise behavior in those +// cases but we use https://github.com/whatwg/html/issues/4003 as a guideline. + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + + const client = new frame.contentWindow.XMLHttpRequest(); + client.open("GET", "/common/blank.html"); + client.onabort = t.step_func_done(); + client.send(); + + frame.contentDocument.open(); + }); + frame.src = "resources/meta-refresh.py?0"; +}, "document.open() aborts documents that are queued for navigation through <meta> refresh with timeout 0 (XMLHttpRequest)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + + frame.contentWindow.fetch("/common/blank.html").then( + t.unreached_func("Fetch should have been aborted"), + t.step_func_done()); + + frame.contentDocument.open(); + }); + frame.src = "resources/meta-refresh.py?0"; +}, "document.open() aborts documents that are queued for navigation through <meta> refresh with timeout 0 (fetch())"); + +// We cannot test for img element's error event for this test, as Firefox does +// not fire the event if the fetch is aborted while Chrome does. +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + + let happened = false; + const img = frame.contentDocument.createElement("img"); + img.src = new URL("resources/slow-png.py", document.URL); + img.onload = t.unreached_func("Image loading should not have succeeded"); + // The image fetch starts in a microtask, so let's be sure to test after + // the fetch has started. + t.step_timeout(() => { + frame.contentDocument.open(); + happened = true; + }); + // If 3 seconds have passed and the image has still not loaded, we consider + // it aborted. slow-png.py only sleeps for 2 wallclock seconds. + t.step_timeout(t.step_func_done(() => { + assert_true(happened); + }), 3000); + }); + frame.src = "resources/meta-refresh.py?0"; +}, "document.open() aborts documents that are queued for navigation through <meta> refresh with timeout 0 (image loading)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + + const client = new frame.contentWindow.XMLHttpRequest(); + client.open("GET", "/common/blank.html"); + client.onabort = t.step_func_done(); + client.send(); + + frame.contentDocument.open(); + }); + frame.src = "resources/http-refresh.py?0"; +}, "document.open() aborts documents that are queued for navigation through Refresh header with timeout 0 (XMLHttpRequest)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + + frame.contentWindow.fetch("/common/blank.html").then( + t.unreached_func("Fetch should have been aborted"), + t.step_func_done()); + + frame.contentDocument.open(); + }); + frame.src = "resources/http-refresh.py?0"; +}, "document.open() aborts documents that are queued for navigation through Refresh header with timeout 0 (fetch())"); + +// We cannot test for img element's error event for this test, as Firefox does +// not fire the event if the fetch is aborted while Chrome does. +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + + let happened = false; + const img = frame.contentDocument.createElement("img"); + img.src = new URL("resources/slow-png.py", document.URL); + img.onload = t.unreached_func("Image loading should not have succeeded"); + // The image fetch starts in a microtask, so let's be sure to test after + // the fetch has started. + t.step_timeout(() => { + frame.contentDocument.open(); + happened = true; + }); + // If 3 seconds have passed and the image has still not loaded, we consider + // it aborted. slow-png.py only sleeps for 2 wallclock seconds. + t.step_timeout(t.step_func_done(() => { + assert_true(happened); + }), 3000); + }); + frame.src = "resources/http-refresh.py?0"; +}, "document.open() aborts documents that are queued for navigation through Refresh header with timeout 0 (image loading)"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-header.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-header.window.js new file mode 100644 index 0000000000..8c6c1267c4 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-header.window.js @@ -0,0 +1,69 @@ +// The following tests deal with the <meta http-equiv=refresh> pragma and the +// `Refresh` header. The spec is still hazy on the precise behavior in those +// cases but we use https://github.com/whatwg/html/issues/4003 as a guideline. +// +// This is separate from abort-refresh-multisecond-meta.window.js to avoid +// browser interventions that limit the number of connections in a tab. + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + + const client = new frame.contentWindow.XMLHttpRequest(); + client.open("GET", "/common/blank.html"); + client.onload = t.step_func_done(() => { + assert_true(happened); + }); + client.onerror = t.unreached_func("XMLHttpRequest should have succeeded"); + client.onabort = t.unreached_func("XMLHttpRequest should have succeeded"); + client.ontimeout = t.unreached_func("XMLHttpRequest should have succeeded"); + client.send(); + + frame.contentDocument.open(); + happened = true; + }); + frame.src = "resources/http-refresh.py?1"; +}, "document.open() does NOT abort documents that are queued for navigation through Refresh header with 1-sec timeout (XMLHttpRequest)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + frame.contentWindow.fetch("/common/blank.html").then( + t.step_func_done(() => { + assert_true(happened); + }), + t.unreached_func("Fetch should have succeeded") + ); + frame.contentDocument.open(); + happened = true; + }); + frame.src = "resources/http-refresh.py?1"; +}, "document.open() does NOT abort documents that are queued for navigation through Refresh header with 1-sec timeout (fetch())"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + const img = frame.contentDocument.createElement("img"); + img.src = new URL("resources/slow-png.py", document.URL); + img.onload = t.step_func_done(() => { + assert_true(happened); + }); + img.onerror = t.unreached_func("Image loading should not have errored"); + // The image fetch starts in a microtask, so let's be sure to test after + // the fetch has started. + t.step_timeout(() => { + frame.contentDocument.open(); + happened = true; + }); + }); + frame.src = "resources/http-refresh.py?4"; +}, "document.open() does NOT abort documents that are queued for navigation through Refresh header with 4-sec timeout (image loading)"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-meta.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-meta.window.js new file mode 100644 index 0000000000..2895f959e5 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-meta.window.js @@ -0,0 +1,69 @@ +// The following tests deal with the <meta http-equiv=refresh> pragma and the +// `Refresh` header. The spec is still hazy on the precise behavior in those +// cases but we use https://github.com/whatwg/html/issues/4003 as a guideline. +// +// This is separate from abort-refresh-multisecond-header.window.js to avoid +// browser interventions that limit the number of connections in a tab. + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + + const client = new frame.contentWindow.XMLHttpRequest(); + client.open("GET", "/common/blank.html"); + client.onload = t.step_func_done(() => { + assert_true(happened); + }); + client.onerror = t.unreached_func("XMLHttpRequest should have succeeded"); + client.onabort = t.unreached_func("XMLHttpRequest should have succeeded"); + client.ontimeout = t.unreached_func("XMLHttpRequest should have succeeded"); + client.send(); + + frame.contentDocument.open(); + happened = true; + }); + frame.src = "resources/meta-refresh.py?1"; +}, "document.open() does NOT abort documents that are queued for navigation through <meta> refresh with 1-sec timeout (XMLHttpRequest)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + frame.contentWindow.fetch("/common/blank.html").then( + t.step_func_done(() => { + assert_true(happened); + }), + t.unreached_func("Fetch should have succeeded") + ); + frame.contentDocument.open(); + happened = true; + }); + frame.src = "resources/meta-refresh.py?1"; +}, "document.open() does NOT abort documents that are queued for navigation through <meta> refresh with 1-sec timeout (fetch())"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + const img = frame.contentDocument.createElement("img"); + img.src = new URL("resources/slow-png.py", document.URL); + img.onload = t.step_func_done(() => { + assert_true(happened); + }); + img.onerror = t.unreached_func("Image loading should not have errored"); + // The image fetch starts in a microtask, so let's be sure to test after + // the fetch has started. + t.step_timeout(() => { + frame.contentDocument.open(); + happened = true; + }); + }); + frame.src = "resources/meta-refresh.py?4"; +}, "document.open() does NOT abort documents that are queued for navigation through <meta> refresh with 4-sec timeout (image loading)"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js new file mode 100644 index 0000000000..e3efeffb8b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js @@ -0,0 +1,179 @@ +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + const client = new frame.contentWindow.XMLHttpRequest(); + client.open("GET", "/common/blank.html"); + // The abort event handler is called synchronously in Chrome but + // asynchronously in Firefox. See https://crbug.com/879620. + client.onabort = t.step_func_done(); + client.send(); + frame.contentWindow.location.href = new URL("resources/dummy.html", document.URL); + frame.contentDocument.open(); + }); + frame.src = "/common/blank.html"; +}, "document.open() aborts documents that are navigating through Location (XMLHttpRequest)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + frame.contentWindow.fetch("/common/blank.html").then( + t.unreached_func("Fetch should have been aborted"), + t.step_func_done(() => { + assert_true(happened); + })); + frame.contentWindow.location.href = new URL("resources/dummy.html", document.URL); + frame.contentDocument.open(); + happened = true; + }); + frame.src = "/common/blank.html"; +}, "document.open() aborts documents that are navigating through Location (fetch())"); + +// We cannot test for img element's error event for this test, as Firefox does +// not fire the event if the fetch is aborted while Chrome does. +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + const img = frame.contentDocument.createElement("img"); + img.src = new URL("resources/slow-png.py", document.URL); + img.onload = t.unreached_func("Image loading should not have succeeded"); + // The image fetch starts in a microtask, so let's be sure to test after + // the fetch has started. + t.step_timeout(() => { + frame.contentWindow.location.href = new URL("resources/dummy.html", document.URL); + frame.contentDocument.open(); + happened = true; + }); + // If 3 seconds have passed and the image has still not loaded, we consider + // it aborted. slow-png.py only sleeps for 2 wallclock seconds. + t.step_timeout(t.step_func_done(() => { + assert_true(happened); + }), 3000); + }); + frame.src = "/common/blank.html"; +}, "document.open() aborts documents that are navigating through Location (image loading)"); + +async_test(t => { + const div = document.body.appendChild(document.createElement("div")); + t.add_cleanup(() => div.remove()); + div.innerHTML = "<iframe src='/common/slow.py'></iframe>"; + const frame = div.childNodes[0]; + const client = new frame.contentWindow.XMLHttpRequest(); + client.open("GET", "/common/blank.html"); + client.onabort = t.step_func_done(); + client.send(); + frame.contentDocument.open(); +}, "document.open() aborts documents that are navigating through iframe loading (XMLHttpRequest)"); + +async_test(t => { + const div = document.body.appendChild(document.createElement("div")); + t.add_cleanup(() => div.remove()); + div.innerHTML = "<iframe src='/common/slow.py'></iframe>"; + const frame = div.childNodes[0]; + frame.contentWindow.fetch("/common/blank.html").then( + t.unreached_func("Fetch should have been aborted"), + t.step_func_done()); + frame.contentDocument.open(); +}, "document.open() aborts documents that are navigating through iframe loading (fetch())"); + +// We cannot test for img element's error event for this test, as Firefox does +// not fire the event if the fetch is aborted while Chrome does. +// +// We use /common/slow.py here as the source of the iframe, to prevent the +// situation where when document.open() is called the initial about:blank +// document has already become inactive. +async_test(t => { + const div = document.body.appendChild(document.createElement("div")); + t.add_cleanup(() => div.remove()); + div.innerHTML = "<iframe src='/common/slow.py'></iframe>"; + const frame = div.childNodes[0]; + let happened = false; + const img = frame.contentDocument.createElement("img"); + img.src = new URL("resources/slow-png.py", document.URL); + img.onload = t.unreached_func("Image loading should not have succeeded"); + // The image fetch starts in a microtask, so let's be sure to test after + // the fetch has started. + t.step_timeout(() => { + frame.contentDocument.open(); + happened = true; + }); + // If 3 seconds have passed and the image has still not loaded, we consider + // it aborted. slow-png.py only sleeps for 2 wallclock seconds. + t.step_timeout(t.step_func_done(() => { + assert_true(happened); + }), 3000); +}, "document.open() aborts documents that are navigating through iframe loading (image loading)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + const link = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("a")); + link.href = new URL("resources/dummy.html", document.URL); + + const client = new frame.contentWindow.XMLHttpRequest(); + client.open("GET", "/common/blank.html"); + client.onabort = t.step_func_done(); + client.send(); + + link.click(); + frame.contentDocument.open(); + }); + frame.src = "/common/blank.html"; +}, "document.open() aborts documents that are queued for navigation through .click() (XMLHttpRequest)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + const link = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("a")); + link.href = new URL("resources/dummy.html", document.URL); + + frame.contentWindow.fetch("/common/blank.html").then( + t.unreached_func("Fetch should have been aborted"), + t.step_func_done()); + + link.click(); + frame.contentDocument.open(); + }); + frame.src = "/common/blank.html"; +}, "document.open() aborts documents that are queued for navigation through .click() (fetch())"); + +// We cannot test for img element's error event for this test, as Firefox does +// not fire the event if the fetch is aborted while Chrome does. +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + const link = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("a")); + link.href = new URL("resources/dummy.html", document.URL); + + let happened = false; + const img = frame.contentDocument.createElement("img"); + img.src = new URL("resources/slow-png.py", document.URL); + img.onload = t.unreached_func("Image loading should not have succeeded"); + // The image fetch starts in a microtask, so let's be sure to test after + // the fetch has started. + t.step_timeout(() => { + link.click(); + frame.contentDocument.open(); + happened = true; + }); + // If 3 seconds have passed and the image has still not loaded, we consider + // it aborted. slow-png.py only sleeps for 2 wallclock seconds. + t.step_timeout(t.step_func_done(() => { + assert_true(happened); + }), 3000); + }); + frame.src = "/common/blank.html"; +}, "document.open() aborts documents that are queued for navigation through .click() (image loading)"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js new file mode 100644 index 0000000000..b2f05cf056 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js @@ -0,0 +1,104 @@ +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + const client = new frame.contentWindow.XMLHttpRequest(); + client.open("GET", "/common/blank.html"); + client.onload = t.step_func_done(e => { + assert_true(happened); + }); + client.onerror = t.unreached_func("XMLHttpRequest should have succeeded"); + client.onabort = t.unreached_func("XMLHttpRequest should have succeeded"); + client.ontimeout = t.unreached_func("XMLHttpRequest should have succeeded"); + client.send(); + frame.contentDocument.open(); + happened = true; + }); + frame.src = "/common/blank.html"; +}, "document.open() does not abort documents that are not navigating (XMLHttpRequest)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + frame.contentWindow.fetch("/common/blank.html").then( + t.step_func_done(() => { + assert_true(happened); + }), + t.unreached_func("Fetch should have succeeded") + ); + frame.contentDocument.open(); + happened = true; + }); + frame.src = "/common/blank.html"; +}, "document.open() does not abort documents that are not navigating (fetch())"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + const img = frame.contentDocument.createElement("img"); + img.src = new URL("resources/slow-png.py", document.URL); + img.onload = t.step_func_done(() => { + assert_true(happened); + }); + img.onerror = t.unreached_func("Image loading should not have errored"); + // The image fetch starts in a microtask, so let's be sure to test after + // the fetch has started. + t.step_timeout(() => { + frame.contentDocument.open(); + happened = true; + }); + }); + frame.src = "/common/blank.html"; +}, "document.open() does not abort documents that are not navigating (image loading)"); + +async_test(t => { + const __SERVER__NAME = "{{host}}"; + const __PORT = {{ports[ws][0]}}; + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + const ws = new frame.contentWindow.WebSocket(`ws://${__SERVER__NAME}:${__PORT}/echo`); + ws.onopen = t.step_func_done(() => { + assert_true(happened); + }); + ws.onclose = t.unreached_func("WebSocket fetch should have succeeded"); + ws.onerror = t.unreached_func("WebSocket should have no error"); + frame.contentDocument.open(); + happened = true; + }); + frame.src = "/common/blank.html"; +}, "document.open() does not abort documents that are not navigating (establish a WebSocket connection)"); + +// An already established WebSocket connection shouldn't be terminated during +// an "abort a document" anyway. Test just for completeness. +async_test(t => { + const __SERVER__NAME = "{{host}}"; + const __PORT = {{ports[ws][0]}}; + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + const ws = new frame.contentWindow.WebSocket(`ws://${__SERVER__NAME}:${__PORT}/echo`); + ws.onopen = t.step_func(() => { + t.step_timeout(t.step_func_done(() => { + assert_true(happened); + }), 100); + frame.contentDocument.open(); + happened = true; + }); + ws.onclose = t.unreached_func("WebSocket should not be closed"); + ws.onerror = t.unreached_func("WebSocket should have no error"); + }); + frame.src = "/common/blank.html"; +}, "document.open() does not abort documents that are not navigating (already established WebSocket connection)"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js new file mode 100644 index 0000000000..ba7278ef18 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js @@ -0,0 +1,31 @@ +// document.open() bails out early if there is an active parser with non-zero +// script nesting level or if a load was aborted while there was an active +// parser. window.stop() aborts the current parser, so once it has been called +// while a parser is active, document.open() will no longer do anything to that +// document, + +window.handlers = {}; + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "resources/aborted-parser-frame.html"; + window.handlers.afterOpen = t.step_func_done(() => { + const openCalled = frame.contentDocument.childNodes.length === 0; + assert_false(openCalled, "child document should not be empty"); + assert_equals(frame.contentDocument.querySelector("p").textContent, + "Text", "Should still have our paragraph"); + }); +}, "document.open() after parser is aborted"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "resources/aborted-parser-async-frame.html"; + window.handlers.afterOpenAsync = t.step_func_done(() => { + const openCalled = frame.contentDocument.childNodes.length === 0; + assert_false(openCalled, "child document should not be empty"); + assert_equals(frame.contentDocument.querySelector("p").textContent, + "Text", "Should still have our paragraph"); + }); +}, "async document.open() after parser is aborted"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/active.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/active.window.js new file mode 100644 index 0000000000..f96710999a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/active.window.js @@ -0,0 +1,98 @@ +function assertOpenIsEffective(doc, initialNodeCount) { + assert_equals(doc.childNodes.length, initialNodeCount); + + // Test direct document.open() call. + assert_equals(doc.open(), doc); + assert_equals(doc.childNodes.length, 0, "after open: no nodes in document"); + doc.write("<!DOCTYPE html>"); + assert_equals(doc.childNodes.length, 1, "after write: doctype node in document"); + doc.close(); + assert_equals(doc.childNodes.length, 2, "after parser close: doctype node and an html element in document"); + + // Test implicit document.open() call through write(). Since we called + // doc.close() above, which sets the insertion point of the parser to + // undefined, document.write() will run the document open steps. + doc.write(); + assert_equals(doc.childNodes.length, 0, "after implicit open: no nodes in document"); + doc.write("<!DOCTYPE html>"); + assert_equals(doc.childNodes.length, 1, "after write: doctype node in document"); + doc.close(); + assert_equals(doc.childNodes.length, 2, "after parser close: doctype node and an html element in document"); +} + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + assertOpenIsEffective(frame.contentDocument, 1); +}, "document.open() removes the document's children (fully active document)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + const childFrame = frame.contentDocument.querySelector("iframe"); + const childDoc = childFrame.contentDocument; + const childWin = childFrame.contentWindow; + + // Right now childDoc is still fully active. + + frame.onload = t.step_func_done(() => { + // Now childDoc is still active but no longer fully active. + assertOpenIsEffective(childDoc, 1); + }); + frame.src = "/common/blank.html"; + }); + frame.src = "resources/page-with-frame.html"; +}, "document.open() removes the document's children (active but not fully active document)"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + const doc = frame.contentDocument; + + // Right now the frame is connected and it has an active document. + frame.remove(); + + // Now the frame is no longer connected. Its document is no longer active. + assertOpenIsEffective(doc, 1); +}, "document.open() removes the document's children (non-active document with an associated Window object; frame is removed)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "resources/dummy.html"; + + frame.onload = t.step_func(() => { + const firstDocument = frame.contentDocument; + // Right now the frame is connected and it has an active document. + + frame.onload = t.step_func_done(() => { + // Now even though the frame is still connected, its document is no + // longer active. + assert_not_equals(frame.contentDocument, firstDocument); + assertOpenIsEffective(firstDocument, 2); + }); + + frame.src = "/common/blank.html"; + }); +}, "document.open() removes the document's children (non-active document with an associated Window object; navigated away)"); + +test(t => { + const doc = document.implementation.createHTMLDocument(); + assertOpenIsEffective(doc, 2); +}, "document.open() removes the document's children (non-active document without an associated Window object; createHTMLDocument)"); + +test(t => { + const doc = new DOMParser().parseFromString("", "text/html"); + assertOpenIsEffective(doc, 1); +}, "document.open() removes the document's children (non-active document without an associated Window object; DOMParser)"); + +async_test(t => { + const xhr = new XMLHttpRequest(); + xhr.onload = t.step_func_done(() => { + assert_equals(xhr.status, 200); + assertOpenIsEffective(xhr.responseXML, 2); + }); + xhr.responseType = "document"; + xhr.open("GET", "resources/dummy.html"); + xhr.send(); +}, "document.open() removes the document's children (non-active document without an associated Window object; XMLHttpRequest)"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-origin.sub.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-origin.sub.window.js new file mode 100644 index 0000000000..b20c3e3f31 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-origin.sub.window.js @@ -0,0 +1,117 @@ +document.domain = "{{host}}"; + +// In many cases in this test, we want to delay execution of a piece of code so +// that the entry settings object would be the top-level page. A microtask is +// perfect for this purpose as it is executed in the "clean up after running +// script" algorithm, which is generally called right after the callback. +function setEntryToTopLevel(cb) { + Promise.resolve().then(cb); +} + +async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => { iframe.remove(); }); + iframe.onload = t.step_func_done(() => { + // Since this is called as an event handler on an element of this window, + // the entry settings object is that of this browsing context. + assert_throws_dom( + "InvalidStateError", + iframe.contentWindow.DOMException, + () => { + iframe.contentDocument.open(); + }, + "opening an XML document should throw an InvalidStateError" + ); + }); + const frameURL = new URL("resources/bailout-order-xml-with-domain-frame.sub.xhtml", document.URL); + frameURL.port = "{{ports[http][1]}}"; + iframe.src = frameURL.href; +}, "document.open should throw an InvalidStateError with XML document even if it is cross-origin"); + +async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => { iframe.remove(); }); + window.onCustomElementReady = t.step_func(() => { + window.onCustomElementReady = t.unreached_func("onCustomElementReady called again"); + // Here, the entry settings object is still the iframe's, as the function + // is called from a custom element constructor in the iframe document. + // Delay execution in such a way that makes the entry settings object the + // top-level page's, but without delaying too much that the + // throw-on-dynamic-markup-insertion counter gets decremented (which is + // what this test tries to pit against the cross-origin document check). + // + // "Clean up after running script" is executed through the "construct" Web + // IDL algorithm in "create an element", called by "create an element for a + // token" in the parser. + setEntryToTopLevel(t.step_func_done(() => { + assert_throws_dom( + "InvalidStateError", + iframe.contentWindow.DOMException, + () => { + iframe.contentDocument.open(); + }, + "opening a document when the throw-on-dynamic-markup-insertion counter is incremented should throw an InvalidStateError" + ); + })); + }); + const frameURL = new URL("resources/bailout-order-custom-element-with-domain-frame.sub.html", document.URL); + frameURL.port = "{{ports[http][1]}}"; + iframe.src = frameURL.href; +}, "document.open should throw an InvalidStateError when the throw-on-dynamic-markup-insertion counter is incremented even if the document is cross-origin"); + +async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => { iframe.remove(); }); + self.testSynchronousScript = t.step_func(() => { + // Here, the entry settings object is still the iframe's, as the function + // is synchronously called from a <script> element in the iframe's + // document. + // + // "Clean up after running script" is executed when the </script> tag is + // seen by the HTML parser. + setEntryToTopLevel(t.step_func_done(() => { + assert_throws_dom( + "SecurityError", + iframe.contentWindow.DOMException, + () => { + iframe.contentDocument.open(); + }, + "opening a same origin-domain (but not same origin) document should throw a SecurityError" + ); + })); + }); + const frameURL = new URL("resources/bailout-order-synchronous-script-with-domain-frame.sub.html", document.URL); + frameURL.port = "{{ports[http][1]}}"; + iframe.src = frameURL.href; +}, "document.open should throw a SecurityError with cross-origin document even when there is an active parser executing script"); + +for (const ev of ["beforeunload", "pagehide", "unload"]) { + async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => { iframe.remove(); }); + iframe.addEventListener("load", t.step_func(() => { + iframe.contentWindow.addEventListener(ev, t.step_func(() => { + // Here, the entry settings object should be the top-level page's, as + // the callback context of this event listener is the incumbent + // settings object, which is the this page. However, due to a Chrome + // bug (https://crbug.com/606900), the entry settings object may be + // mis-set to the iframe's. + // + // "Clean up after running script" is called in the task that + // navigates. + setEntryToTopLevel(t.step_func_done(() => { + assert_throws_dom( + "SecurityError", + iframe.contentWindow.DOMException, + () => { + iframe.contentDocument.open(); + }, + "opening a same origin-domain (but not same origin) document should throw a SecurityError" + ); + })); + })); + iframe.src = "about:blank"; + }), { once: true }); + iframe.src = "http://{{host}}:{{ports[http][1]}}/common/domain-setter.sub.html"; + }, `document.open should throw a SecurityError with cross-origin document even when the ignore-opens-during-unload counter is greater than 0 (during ${ev} event)`); +} diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-xml.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-xml.window.js new file mode 100644 index 0000000000..45a67f925b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-xml.window.js @@ -0,0 +1,26 @@ +async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => { iframe.remove(); }); + self.testSynchronousScript = t.step_func_done(() => { + assert_throws_dom("InvalidStateError", iframe.contentWindow.DOMException, () => { + iframe.contentDocument.open(); + }, "opening an XML document should throw"); + }); + iframe.src = "resources/bailout-order-xml-with-synchronous-script-frame.xhtml"; +}, "document.open should throw an InvalidStateError with XML document even when there is an active parser executing script"); + +for (const ev of ["beforeunload", "pagehide", "unload"]) { + async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => { iframe.remove(); }); + iframe.addEventListener("load", t.step_func(() => { + iframe.contentWindow.addEventListener(ev, t.step_func_done(() => { + assert_throws_dom("InvalidStateError", iframe.contentWindow.DOMException, () => { + iframe.contentDocument.open(); + }, "opening an XML document should throw"); + })); + iframe.src = "about:blank"; + }), { once: true }); + iframe.src = "/common/dummy.xhtml"; + }, `document.open should throw an InvalidStateError with XML document even when the ignore-opens-during-unload counter is greater than 0 (during ${ev} event)`); +} diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-ignore-opens-during-unload.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-ignore-opens-during-unload.window.js new file mode 100644 index 0000000000..98ffba20a1 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-ignore-opens-during-unload.window.js @@ -0,0 +1,18 @@ +// META: script=resources/document-open-side-effects.js + +for (const ev of ["unload", "beforeunload", "pagehide"]) { + async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => iframe.remove()); + iframe.src = "/common/blank.html"; + iframe.onload = t.step_func(() => { + iframe.contentWindow.addEventListener(ev, t.step_func_done(() => { + const origURL = iframe.contentDocument.URL; + assertDocumentIsReadyForSideEffectsTest(iframe.contentDocument, `ignore-opens-during-unload counter is greater than 0 during ${ev} event`); + assert_equals(iframe.contentDocument.open(), iframe.contentDocument); + assertOpenHasNoSideEffects(iframe.contentDocument, origURL, `ignore-opens-during-unload counter is greater than 0 during ${ev} event`); + })); + iframe.src = "about:blank"; + }); + }, `document.open bailout should not have any side effects (ignore-opens-during-unload is greater than 0 during ${ev} event)`); +} diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-same-origin-domain.sub.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-same-origin-domain.sub.window.js new file mode 100644 index 0000000000..f5edd7aed9 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-same-origin-domain.sub.window.js @@ -0,0 +1,14 @@ +// META: script=/html/resources/common.js +// META: script=resources/document-open-side-effects.js + +document.domain = "{{host}}"; + +testInIFrame("http://{{host}}:{{ports[http][1]}}/common/domain-setter.sub.html", (ctx) => { + const iframe = ctx.iframes[0]; + const origURL = iframe.contentDocument.URL; + assertDocumentIsReadyForSideEffectsTest(iframe.contentDocument, "same origin-domain (but not same origin) document"); + assert_throws_dom("SecurityError", iframe.contentWindow.DOMException, () => { + ctx.iframes[0].contentDocument.open(); + }, "document.open() should throw a SecurityError on a same origin-domain (but not same origin) document"); + assertOpenHasNoSideEffects(iframe.contentDocument, origURL, "same origin-domain (but not same origin) document"); +}, "document.open bailout should not have any side effects (same origin-domain (but not same origin) document)"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-synchronous-script.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-synchronous-script.window.js new file mode 100644 index 0000000000..fb26c70a9c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-synchronous-script.window.js @@ -0,0 +1,19 @@ +// META: script=resources/document-open-side-effects.js + +async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => iframe.remove()); + self.testSynchronousScript = t.step_func(() => { + // Here, the entry settings object is still the iframe's. Delay it in such + // a way that makes the entry settings object the top-level page's, but + // without delaying too much that the parser becomes inactive. A microtask + // is perfect as it's executed in "clean up after running script". + Promise.resolve().then(t.step_func_done(() => { + const origURL = iframe.contentDocument.URL; + assertDocumentIsReadyForSideEffectsTest(iframe.contentDocument, "active parser whose script nesting level is greater than 0"); + assert_equals(iframe.contentDocument.open(), iframe.contentDocument); + assertOpenHasNoSideEffects(iframe.contentDocument, origURL, "active parser whose script nesting level is greater than 0"); + })); + }); + iframe.src = "resources/bailout-order-synchronous-script-frame.html"; +}, "document.open bailout should not have any side effects (active parser whose script nesting level is greater than 0)"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-xml.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-xml.window.js new file mode 100644 index 0000000000..bbfc015c68 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-xml.window.js @@ -0,0 +1,20 @@ +// META: script=resources/document-open-side-effects.js + +async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => iframe.remove()); + iframe.src = "/common/dummy.xhtml"; + iframe.onload = t.step_func_done(() => { + const origURL = iframe.contentDocument.URL; + assertDocumentIsReadyForSideEffectsTest(iframe.contentDocument, "XML document"); + assert_throws_dom( + "InvalidStateError", + iframe.contentWindow.DOMException, + () => { + iframe.contentDocument.open(); + }, + "document.open() should throw on XML documents" + ); + assertOpenHasNoSideEffects(iframe.contentDocument, origURL, "XML document"); + }); +}, "document.open bailout should not have any side effects (XML document)"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/beforeunload.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/beforeunload.window.js new file mode 100644 index 0000000000..1e2f891c17 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/beforeunload.window.js @@ -0,0 +1,18 @@ +// In an earlier version of the HTML Standard, document open steps had "prompt +// to unload document" as a step. Test that this no longer happens. + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.contentWindow.onbeforeunload = t.unreached_func("beforeunload should not be fired"); + frame.contentDocument.open(); + t.step_timeout(t.step_func_done(() => { + // If the beforeunload event has still not fired by this point, we + // consider the test a success. `frame.remove()` above will allow the + // `load` event to be fired on the top-level Window, thus unblocking + // testharness. + }), 500); + }); +}, "document.open() should not fire a beforeunload event"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/crbug-583445-regression.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/crbug-583445-regression.window.js new file mode 100644 index 0000000000..3809c2e081 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/crbug-583445-regression.window.js @@ -0,0 +1,127 @@ +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/common/dispatcher/dispatcher.js +// +// This is a regression test for crbug.com/583445. It checks an obscure bug in +// Chromium's handling of `document.open()` whereby the URL change would affect +// the document's origin after a javascript navigation. +// +// See also dcheng@'s comments on the original code review in which he +// introduced the precursor to this test: +// https://codereview.chromium.org/1675473002. + +function nextMessage() { + return new Promise((resolve) => { + window.addEventListener("message", (e) => { resolve(e.data); }, { + once: true + }); + }); +} + +promise_test(async (t) => { + // Embed a cross-origin frame A and set up remote code execution. + const iframeA = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => { iframeA.remove(); }); + + const uuidA = token(); + iframeA.src = remoteExecutorUrl(uuidA, { host: get_host_info().REMOTE_HOST }); + const ctxA = new RemoteContext(uuidA); + + // Frame A embeds a cross-origin frame B, which is same-origin with the + // top-level frame. Frame B is the center of this test: it is where we will + // verify that a bug does not grant it UXSS in frame A. + // + // Though we could reach into `iframeA.frames[0]` to get a proxy to frame B + // and use `setTimeout()` like below to execute code inside it, we set up + // remote code execution using `dispatcher.js` for better ergonomics. + const uuidB = token(); + await ctxA.execute_script((url) => { + const iframeB = document.createElement("iframe"); + iframeB.src = url; + document.body.appendChild(iframeB); + }, [remoteExecutorUrl(uuidB).href]); + + // Start listening for a message, which will come as a result of executing + // the code below in frame B. + const message = nextMessage(); + + const ctxB = new RemoteContext(uuidB); + await ctxB.execute_script(() => { + // Frame B embeds an `about:blank` frame C. + const iframeC = document.body.appendChild(document.createElement("iframe")); + + // We wish to execute code inside frame C, but it is important to this test + // that its URL remain `about:blank`, so we cannot use `dispatcher.js`. + // Instead we rely on `setTimeout()`. + // + // We use `setTimeout(string, ...)` instead of `setTimeout(function, ...)` + // as the given script executes against the target window's global object + // and does not capture any local variables. + // + // In order to have nice syntax highlighting and avoid quote-escaping hell, + // we use a trick employed by `dispatcher.js`. We rely on the fact that + // functions in JS have a stringifier that returns their source code. Thus + // `"(" + func + ")()"` is a string that executes `func()` when evaluated. + iframeC.contentWindow.setTimeout("(" + (() => { + // This executes in frame C. + + // Frame C calls `document.open()` on its parent, which results in B's + // URL being set to `about:blank` (C's URL). + // + // However, just before `document.open()` is called, B schedules a + // self-navigation to a `javascript:` URL. This will occur after + // `document.open()`, so the document will navigate from `about:blank` to + // the new URL. + // + // This should not result in B's origin changing, so B should remain + // same-origin with the top-level frame. + // + // Due to crbug.com/583445, this used to behave wrongly in Chromium. The + // navigation code incorrectly assumed that B's origin should be inherited + // from its parent A because B's URL was `about:blank`. + // + // It is important to schedule this from within the child, as this + // guarantees that `document.open()` will be called before the navigation. + // A previous version of this test scheduled this from within frame B + // right after scheduling the call to `document.open()`, but that ran the + // risk of races depending on which timeout fired first. + parent.window.setTimeout("(" + (() => { + // This executes in frame B. + + location = "javascript:(" + (() => { + /* This also executes in frame B. + * + * Note that because this whole function gets stuffed in a JS URL, + * single-line comments do not work, as they affect the following + * lines. */ + + let error; + try { + /* This will fail with a `SecurityError` if frame B is no longer + * same-origin with the top-level frame. */ + top.window.testSameOrigin = true; + } catch (e) { + error = e; + } + + top.postMessage({ + error: error?.toString(), + }, "*"); + + }) + ")()"; + + }) + ")()", 0); + + // This executes in frame C. + parent.document.open(); + + }) + ")()", 0); + }); + + // Await the message from frame B after its navigation. + const { error } = await message; + assert_equals(error, undefined, "error accessing top frame from frame B"); + assert_true(window.testSameOrigin, "top frame testSameOrigin is mutated"); + +}, "Regression test for crbug.com/583445"); + diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/custom-element.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/custom-element.window.js new file mode 100644 index 0000000000..1ad06b3d37 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/custom-element.window.js @@ -0,0 +1,39 @@ +// The document open steps have: +// +// 2. If document's throw-on-dynamic-markup-insertion counter is greater than +// 0, then throw an "InvalidStateError" DOMException. +// +// The throw-on-dynamic-markup-insertion counter is only incremented when the +// parser creates a custom element, not when createElement is called. Test for +// this. +// +// See: https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#document-open-steps + +const noError = Symbol("no error"); +let err = noError; + +class CustomElement extends HTMLElement { + constructor() { + super(); + try { + assert_equals(document.open(), document); + } catch (e) { + err = e; + } + } +} +customElements.define("custom-element", CustomElement); + +test(t => { + err = noError; + document.createElement("custom-element"); + assert_equals(err, noError); +}, "document.open() works in custom element constructor for createElement()"); + +test(t => { + err = noError; + document.write("<custom-element></custom-element>"); + assert_throws_dom("InvalidStateError", () => { + throw err; + }); +}, "document.open() is forbidden in custom element constructor when creating element from parser"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document-open-cancels-javascript-url-navigation.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document-open-cancels-javascript-url-navigation.html new file mode 100644 index 0000000000..5596382f22 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document-open-cancels-javascript-url-navigation.html @@ -0,0 +1,17 @@ +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +async_test(t => { + window.onload = t.step_func_done(() => assert_equals(i.contentDocument.body.innerText, "PASS")); + + var i = document.createElement('iframe'); + i.id ='i'; + i.src = "javascript:'FAIL'"; + document.body.appendChild(i); + i.contentDocument.open(); + i.contentDocument.write("PASS") + i.contentDocument.close(); +}); +</script> +</body> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-01.xhtml b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-01.xhtml new file mode 100644 index 0000000000..c02b3e4db5 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-01.xhtml @@ -0,0 +1,19 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>document.open in XHTML</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#opening-the-input-stream"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<script> +test(function() { + assert_throws_dom("INVALID_STATE_ERR", function() { + document.open(); + }, "document.open in XHTML should throw an INVALID_STATE_ERR "); +}, "document.open in XHTML"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-02.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-02.html new file mode 100644 index 0000000000..c7e67a0cf7 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-02.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<title>document.open with three arguments</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-document-open"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function open() { + assert_unreached("The call should be redirected to the real window.open") +} +test(function(t) { + var w; + t.add_cleanup(function() {try {w.close()} catch(e) {}}); + w = document.open("/resources/testharness.js", "", ""); + assert_true(w instanceof w.Window, "Expected a window"); +}, "document.open should redirect to window.open when called with three arguments"); + +test(function() { + var parser = new DOMParser(); + var doc = parser.parseFromString("", "text/html"); + assert_equals(doc.defaultView, null); + assert_throws_dom("INVALID_ACCESS_ERR", function() { + doc.open("/resources/testharness.js", "", ""); + }); +}, "document.open should throw when it has no window and is called with three arguments"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03-frame.html new file mode 100644 index 0000000000..a4b370cea4 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03-frame.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<script> +onload = function() { + document.open(); + document.close(); + parent.report(window.setTimeout === setTimeout, true, "setTimeout"); + parent.report(window === this, true, "this"); + parent.done(); +} +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03.html new file mode 100644 index 0000000000..e446d70219 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>document.open and no singleton replacement</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-document-open"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var t = async_test(); +function report(actual, expected, message) { + t.step(function() { + assert_equals(actual, expected, message); + }); +} +function done() { + t.done(); +} +</script> +<iframe src=document.open-03-frame.html></iframe> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/encoding.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/encoding.window.js new file mode 100644 index 0000000000..f0d133a532 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/encoding.window.js @@ -0,0 +1,12 @@ +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + frame.src = "resources/encoding-frame.html"; + frame.onload = t.step_func_done(t => { + // Using toLowerCase() to avoid an Edge bug + assert_equals(frame.contentDocument.characterSet.toLowerCase(), "shift_jis", "precondition"); + assert_equals(frame.contentDocument.open(), frame.contentDocument); + assert_equals(frame.contentDocument.characterSet.toLowerCase(), "shift_jis", "actual test"); + frame.contentDocument.close(); + assert_equals(frame.contentDocument.characterSet.toLowerCase(), "shift_jis", "might as well"); + }); +}, "doucment.open() and the document's encoding"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/event-listeners.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/event-listeners.window.js new file mode 100644 index 0000000000..df07124d81 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/event-listeners.window.js @@ -0,0 +1,308 @@ +// Many of the active-related test cases in this file came from +// active.window.js. However, we cannot test the "navigated away" non-active +// case right now due to https://github.com/whatwg/html/issues/3997. + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")), + body = frame.contentDocument.body; + t.add_cleanup(() => frame.remove()); + const div = body.appendChild(frame.contentDocument.createElement("div")); + div.addEventListener("click", t.unreached_func("element event listener not removed")); + frame.contentDocument.open(); + div.click(); + frame.contentDocument.close(); +}, "Standard event listeners are to be removed"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")), + body = frame.contentDocument.body; + t.add_cleanup(() => frame.remove()); + frame.contentDocument.addEventListener("x", t.unreached_func("document event listener not removed")); + body.addEventListener("x", t.unreached_func("body event listener not removed")); + frame.contentDocument.open(); + frame.contentDocument.dispatchEvent(new Event("x")); + body.dispatchEvent(new Event("x")); + frame.contentDocument.close(); +}, "Custom event listeners are to be removed"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")), + body = frame.contentDocument.body; + t.add_cleanup(() => frame.remove()); + // Focus on the current window so that the frame's window is blurred. + window.focus(); + assert_false(frame.contentDocument.hasFocus()); + frame.contentWindow.addEventListener("focus", t.unreached_func("window event listener not removed")); + body.onfocus = t.unreached_func("body event listener not removed"); + frame.contentDocument.open(); + assert_equals(body.onfocus, null); + frame.contentWindow.focus(); + frame.contentDocument.close(); +}, "Standard event listeners are to be removed from Window"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + const childFrame = frame.contentDocument.querySelector("iframe"); + const childWin = childFrame.contentWindow; + const childDoc = childFrame.contentDocument; + const childBody = childDoc.body; + + // Right now childDoc is still fully active. + + frame.onload = t.step_func_done(() => { + // Focus on the current window so that the frame's window is blurred. + window.focus(); + // Now childDoc is still active but no longer fully active. + childWin.addEventListener("focus", t.unreached_func("window event listener not removed")); + childBody.onfocus = t.unreached_func("body event listener not removed"); + + childDoc.open(); + assert_equals(childBody.onfocus, null); + + // Now try to fire the focus event two different ways. + childWin.focus(); + const focusEvent = new FocusEvent("focus"); + childWin.dispatchEvent(focusEvent); + childDoc.close(); + }); + frame.src = "/common/blank.html"; + }); + frame.src = "resources/page-with-frame.html"; +}, "Standard event listeners are to be removed from Window for an active but not fully active document"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + const win = frame.contentWindow; + const doc = frame.contentDocument; + const body = doc.body; + + // Right now the frame is connected and it has an active document. + frame.remove(); + + win.addEventListener("focus", t.unreached_func("window event listener not removed")); + body.onfocus = t.unreached_func("body event listener not removed"); + doc.open(); + assert_equals(body.onfocus, null); + + // Now try to fire the focus event two different ways. + win.focus(); + const focusEvent = new FocusEvent("focus"); + win.dispatchEvent(focusEvent); + doc.close(); +}, "Standard event listeners are to be removed from Window for a non-active document that is the associated Document of a Window (frame is removed)"); + +test(t => { + let winHappened = 0; + const winListener = t.step_func(() => { winHappened++; }); + window.addEventListener("focus", winListener); + t.add_cleanup(() => { window.removeEventListener("focus", winListener); }); + + let bodyHappened = 0; + const bodyListener = t.step_func(() => { bodyHappened++; }); + document.body.onfocus = bodyListener; + t.add_cleanup(() => { document.body.onfocus = null; }); + + const doc = document.implementation.createHTMLDocument(); + doc.open(); + + const focusEvent = new FocusEvent("focus"); + window.dispatchEvent(focusEvent); + + assert_equals(winHappened, 1); + assert_equals(bodyHappened, 1); +}, "Standard event listeners are NOT to be removed from Window for a Window-less document (createHTMLDocument)"); + +test(t => { + let winHappened = 0; + const winListener = t.step_func(() => { winHappened++; }); + window.addEventListener("focus", winListener); + t.add_cleanup(() => { window.removeEventListener("focus", winListener); }); + + let bodyHappened = 0; + const bodyListener = t.step_func(() => { bodyHappened++; }); + document.body.onfocus = bodyListener; + t.add_cleanup(() => { document.body.onfocus = null; }); + + const doc = new DOMParser().parseFromString("", "text/html"); + doc.open(); + + const focusEvent = new FocusEvent("focus"); + window.dispatchEvent(focusEvent); + + assert_equals(winHappened, 1); + assert_equals(bodyHappened, 1); +}, "Standard event listeners are NOT to be removed from Window for a Window-less document (DOMParser)"); + +async_test(t => { + const xhr = new XMLHttpRequest(); + xhr.onload = t.step_func_done(() => { + assert_equals(xhr.status, 200); + const doc = xhr.responseXML; + + let winHappened = 0; + const winListener = t.step_func(() => { winHappened++; }); + window.addEventListener("focus", winListener); + t.add_cleanup(() => { window.removeEventListener("focus", winListener); }); + + let bodyHappened = 0; + const bodyListener = t.step_func(() => { bodyHappened++; }); + document.body.onfocus = bodyListener; + t.add_cleanup(() => { document.body.onfocus = null; }); + + doc.open(); + + const focusEvent = new FocusEvent("focus"); + window.dispatchEvent(focusEvent); + + assert_equals(winHappened, 1); + assert_equals(bodyHappened, 1); + }); + xhr.responseType = "document"; + xhr.open("GET", "resources/dummy.html"); + xhr.send(); +}, "Standard event listeners are NOT to be removed from Window for a Window-less document (XMLHttpRequest)"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.contentWindow.addEventListener("x", t.unreached_func("window event listener not removed")); + frame.contentDocument.open(); + frame.contentWindow.dispatchEvent(new Event("x")); + frame.contentDocument.close(); +}, "Custom event listeners are to be removed from Window"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + const childFrame = frame.contentDocument.querySelector("iframe"); + const childDoc = childFrame.contentDocument; + const childWin = childFrame.contentWindow; + + // Right now childDoc is still fully active. + + frame.onload = t.step_func_done(() => { + // Now childDoc is still active but no longer fully active. + childWin.addEventListener("x", t.unreached_func("window event listener not removed")); + childDoc.open(); + childWin.dispatchEvent(new Event("x")); + childDoc.close(); + }); + frame.src = "/common/blank.html"; + }); + frame.src = "resources/page-with-frame.html"; +}, "Custom event listeners are to be removed from Window for an active but not fully active document"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + const win = frame.contentWindow; + const doc = frame.contentDocument; + + // Right now the frame is connected and it has an active document. + frame.remove(); + + win.addEventListener("x", t.unreached_func("window event listener not removed")); + doc.open(); + win.dispatchEvent(new Event("x")); + doc.close(); +}, "Custom event listeners are to be removed from Window for a non-active document that is the associated Document of a Window (frame is removed)"); + +test(t => { + const doc = document.implementation.createHTMLDocument(); + let happened = false; + window.addEventListener("createHTMLDocumentTest", t.step_func(() => { happened = true; })); + doc.open(); + window.dispatchEvent(new Event("createHTMLDocumentTest")); + assert_true(happened); +}, "Custom event listeners are NOT to be removed from Window for a Window-less document (createHTMLDocument)"); + +test(t => { + const doc = new DOMParser().parseFromString("", "text/html"); + let happened = false; + window.addEventListener("DOMParserTest", t.step_func(() => { happened = true; })); + doc.open(); + window.dispatchEvent(new Event("DOMParserTest")); + assert_true(happened); +}, "Custom event listeners are NOT to be removed from Window for a Window-less document (DOMParser)"); + +async_test(t => { + const xhr = new XMLHttpRequest(); + xhr.onload = t.step_func_done(() => { + assert_equals(xhr.status, 200); + const doc = xhr.responseXML; + let happened = false; + window.addEventListener("XHRTest", t.step_func(() => { happened = true; })); + doc.open(); + window.dispatchEvent(new Event("XHRTest")); + assert_true(happened); + }); + xhr.responseType = "document"; + xhr.open("GET", "resources/dummy.html"); + xhr.send(); +}, "Custom event listeners are NOT to be removed from Window for a Window-less document (XMLHttpRequest)"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")), + body = frame.contentDocument.body; + t.add_cleanup(() => frame.remove()); + const div = body.appendChild(frame.contentDocument.createElement("div")); + div.onclick = t.unreached_func("element event listener not removed"); + frame.contentDocument.open(); + assert_equals(div.onclick, null); + const e = frame.contentDocument.createEvent("mouseevents") + e.initEvent("click", false, false); + div.dispatchEvent(e); + frame.contentDocument.close(); +}, "IDL attribute event handlers are to be deactivated"); + +var thrower; + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")), + body = frame.contentDocument.body; + t.add_cleanup(() => frame.remove()); + const div = body.appendChild(frame.contentDocument.createElement("div")); + thrower = t.step_func(() => { throw new Error('element event listener not removed'); }); + div.setAttribute("onclick", "parent.thrower()"); + assert_not_equals(div.onclick, null); + frame.contentDocument.open(); + assert_equals(div.getAttribute("onclick"), "parent.thrower()"); + assert_equals(div.onclick, null); + const e = frame.contentDocument.createEvent("mouseevents") + e.initEvent("click", false, false); + div.dispatchEvent(e); + frame.contentDocument.close(); +}, "Content attribute event handlers are to be deactivated"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + let once = false; + frame.contentDocument.addEventListener("x", () => { + frame.contentDocument.open(); + once = true; + }); + frame.contentDocument.addEventListener("x", t.unreached_func("second event listener not removed")); + frame.contentDocument.dispatchEvent(new Event("x")); + assert_true(once); + frame.contentDocument.close(); +}, "Event listeners are to be removed with immediate effect"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")), + shadow = frame.contentDocument.body.attachShadow({ mode: "closed" }), + shadowChild = shadow.appendChild(document.createElement("div")), + shadowShadow = shadowChild.attachShadow({ mode: "open" }), + nodes = [shadow, shadowChild, shadowShadow]; + t.add_cleanup(() => frame.remove()); + nodes.forEach(node => { + node.addEventListener("x", t.unreached_func(node + "'s event listener not removed")); + }); + frame.contentDocument.open(); + nodes.forEach(node => { + node.dispatchEvent(new Event("x")); + }); + frame.contentDocument.close(); +}, "Event listeners are to be removed from shadow trees as well"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/form-control-state.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/form-control-state.html new file mode 100644 index 0000000000..7d03a885f0 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/form-control-state.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<html> +<head> +<title>Writing out a document with form controls with values</title> +<link rel="author" href="mailto:bzbarsky@mit.edu"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<script> +function asyncHop(t, arg) { + return new Promise(res => t.step_timeout(res.bind(null, arg), 0)); +} + +function loadPromise(t, iframe) { + var p = new Promise(res => + iframe.addEventListener("load", res.bind(null, iframe), { once: true })); + // We need to do one trip through the event loop to make sure we're + // not still under the load event firing when we start doing our + // document.open bits. + return p.then(asyncHop.bind(null, t)); +} + +async function createIframe(t) { + var i = document.createElement("iframe"); + t.add_cleanup(() => i.remove()); + var p = loadPromise(t, i); + document.body.appendChild(i); + return p; +} + +async function replaceIframe(t, i, text) { + var p = loadPromise(t, i); + var doc = i.contentDocument; + doc.open(); + doc.write(text); + doc.close(); + return p; +} + +promise_test(async function(t) { + var i = await createIframe(t); + var str = "<textarea>123</textarea>"; + await replaceIframe(t, i, str); + i.contentDocument.querySelector("textarea").value = "abc"; + await replaceIframe(t, i, str); + assert_equals(i.contentDocument.querySelector("textarea").value, "123"); +}, "textarea state"); + +promise_test(async function(t) { + var i = await createIframe(t); + var str = "<input value='123'>"; + await replaceIframe(t, i, str); + i.contentDocument.querySelector("input").value = "abc"; + await replaceIframe(t, i, str); + assert_equals(i.contentDocument.querySelector("input").value, "123"); +}, "input state"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history-state.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history-state.window.js new file mode 100644 index 0000000000..7fb172a141 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history-state.window.js @@ -0,0 +1,29 @@ +async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => iframe.remove()); + iframe.src = "/common/blank.html"; + iframe.onload = t.step_func_done(() => { + const win = iframe.contentWindow; + const doc = iframe.contentDocument; + assert_equals(win.history.state, null); + win.history.replaceState("state", ""); + assert_equals(win.history.state, "state"); + assert_equals(doc.open(), doc); + assert_equals(win.history.state, "state"); + }); +}, "history.state is kept by document.open()"); + +async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => iframe.remove()); + iframe.src = "/common/blank.html"; + iframe.onload = t.step_func_done(() => { + const win = iframe.contentWindow; + const doc = iframe.contentDocument; + assert_equals(win.history.state, null); + win.history.replaceState("state", ""); + assert_equals(win.history.state, "state"); + assert_equals(doc.open("", "replace"), doc); + assert_equals(win.history.state, "state"); + }); +}, "history.state is kept by document.open() (with historical replace parameter set)"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history.window.js new file mode 100644 index 0000000000..0134da24f0 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history.window.js @@ -0,0 +1,29 @@ +// Historically, document.open() created an entry in the session history so +// that the original page could be seen by going back. Test that this behavior +// no longer occurs. +// +// This test uses window.open() for variety, as most other tests in this +// directory use document.open(). An <iframe> would probably work also. We can +// always add an <iframe>-based test later if it is deemed necessary. + +const t = async_test("document.open should not add an entry to the session history"); + +const frameURL = new URL("resources/history-frame.html", document.URL).href; + +let origLength; +window.onFrameLoaded = t.step_func(() => { + window.onFrameLoaded = t.unreached_func("onFrameLoaded should only be called once"); + assert_equals(win.document.URL, frameURL); + assert_true(win.document.body.textContent.includes("Old")); + origLength = win.history.length; +}); +window.onDocumentOpen = t.step_func_done(() => { + window.onDocumentOpen = t.unreached_func("onDocumentOpen should only be called once"); + assert_equals(win.document.URL, frameURL); + assert_true(win.document.body.textContent.includes("New")); + assert_not_equals(origLength, undefined); + assert_equals(win.history.length, origLength); +}); + +const win = window.open(frameURL); +t.add_cleanup(() => win.close()); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/ignore-opens-during-unload.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/ignore-opens-during-unload.window.js new file mode 100644 index 0000000000..43506a22a4 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/ignore-opens-during-unload.window.js @@ -0,0 +1,60 @@ +for (const [ev, target] of [ + ["beforeunload", iframe => iframe.contentWindow], + ["pagehide", iframe => iframe.contentWindow], + ["unload", iframe => iframe.contentWindow], + ["visibilitychange", iframe => iframe.contentDocument], +]) { + async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => iframe.remove()); + iframe.src = "/common/blank.html"; + iframe.onload = t.step_func(() => { + target(iframe).addEventListener(ev, t.step_func_done(() => { + assert_not_equals(iframe.contentDocument.childNodes.length, 0); + assert_equals(iframe.contentDocument.open(), iframe.contentDocument); + assert_not_equals(iframe.contentDocument.childNodes.length, 0); + })); + iframe.src = "about:blank"; + }); + }, `document.open should bail out when ignore-opens-during-unload is greater than 0 during ${ev} event (in top-level browsing context)`); + + async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => iframe.remove()); + iframe.src = "/common/blank.html?1"; + iframe.onload = t.step_func(() => { + const doc = iframe.contentDocument; + const innerIframe = doc.body.appendChild(doc.createElement("iframe")); + innerIframe.src = "/common/blank.html?2"; + innerIframe.onload = t.step_func(() => { + // Navigate the parent, listen on the child, and open() the parent. + target(innerIframe).addEventListener(ev, t.step_func_done(() => { + assert_not_equals(iframe.contentDocument.childNodes.length, 0); + iframe.contentDocument.open(); + assert_not_equals(iframe.contentDocument.childNodes.length, 0); + })); + iframe.src = "about:blank"; + }); + }); + }, `document.open should bail out when ignore-opens-during-unload is greater than 0 during ${ev} event (open(parent) while unloading parent and child)`); + + async_test(t => { + const iframe = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => iframe.remove()); + iframe.src = "/common/blank.html?1"; + iframe.onload = t.step_func(() => { + const doc = iframe.contentDocument; + const innerIframe = doc.body.appendChild(doc.createElement("iframe")); + innerIframe.src = "/common/blank.html?2"; + innerIframe.onload = t.step_func(() => { + // Navigate the child, listen on the child, and open() the parent. + target(innerIframe).addEventListener(ev, t.step_func_done(() => { + assert_not_equals(iframe.contentDocument.childNodes.length, 0); + iframe.contentDocument.open(); + assert_equals(iframe.contentDocument.childNodes.length, 0); + })); + innerIframe.src = "about:blank"; + }); + }); + }, `document.open should bail out when ignore-opens-during-unload is greater than 0 during ${ev} event (open(parent) while unloading child only)`); +} diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html new file mode 100644 index 0000000000..a3bdd86ee6 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html @@ -0,0 +1,31 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<body> + <script> + var t = async_test("Location sets should cancel current navigation and prevent later document.open() from doing anything"); + + var finishTest = t.step_func_done(function() { + assert_equals(frames[0].document.body.textContent, "PASS", + "Should not have FAIL in our textContent"); + }); + + t.step(function() { + var i = document.createElement("iframe"); + i.srcdoc = ` + <script> + var blob = new Blob(["PASS"], { type: "text/html" }); + var url = URL.createObjectURL(blob); + location.href = url; + frameElement.onload = parent.finishTest; + document.open(); + document.write("FAIL"); + document.close(); + <\/script>`; + document.body.appendChild(i); + }); + + </script> +</body> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-events.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-events.window.js new file mode 100644 index 0000000000..4efbb863c6 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-events.window.js @@ -0,0 +1,22 @@ +// In an ideal world this test would eventually be obsolete due to mutation events disappearing. Or +// would have to change to account for mutation events not firing synchronously. Neither seems +// realistic to the author though. + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + frame.contentWindow.addEventListener("DOMNodeInserted", t.unreached_func()); + frame.contentWindow.addEventListener("DOMNodeInserted", t.unreached_func(), true); + frame.contentWindow.addEventListener("DOMNodeInsertedIntoDocument", t.unreached_func(), true); + frame.contentWindow.addEventListener("DOMNodeRemoved", t.unreached_func()); + frame.contentWindow.addEventListener("DOMNodeRemoved", t.unreached_func(), true); + frame.contentWindow.addEventListener("DOMNodeRemovedFromDocument", t.unreached_func(), true); + frame.contentWindow.addEventListener("DOMSubtreeModified", t.unreached_func()); + frame.contentWindow.addEventListener("DOMSubtreeModified", t.unreached_func(), true); + assert_equals(frame.contentDocument.documentElement.localName, "html"); + assert_equals(frame.contentDocument.open(), frame.contentDocument); + assert_equals(frame.contentDocument.documentElement, null); + frame.contentDocument.write("<div>heya</div>"); + frame.contentDocument.close(); + assert_equals(frame.contentDocument.documentElement.localName, "html"); + frame.remove(); +}, "document.open(), the HTML parser, and mutation events"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-observer.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-observer.window.js new file mode 100644 index 0000000000..34e73146a9 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-observer.window.js @@ -0,0 +1,19 @@ +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => { frame.remove(); }); + const originalHTMLElement = frame.contentDocument.documentElement; + assert_equals(originalHTMLElement.localName, "html"); + const observer = new frame.contentWindow.MutationObserver(t.step_func_done(records => { + // Even though we passed `subtree: true` to observer.observe, due to the + // fact that "replace all" algorithm removes children with the "suppress + // observers flag" set, we still only get the html element as the sole + // removed node. + assert_equals(records.length, 1); + assert_equals(records[0].type, "childList"); + assert_equals(records[0].target, frame.contentDocument); + assert_array_equals(records[0].addedNodes, []); + assert_array_equals(records[0].removedNodes, [originalHTMLElement]); + })); + observer.observe(frame.contentDocument, { childList: true, subtree: true }); + assert_equals(frame.contentDocument.open(), frame.contentDocument); +}, "document.open() should inform mutation observer of node removal"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/no-new-global.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/no-new-global.window.js new file mode 100644 index 0000000000..d4a9296fca --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/no-new-global.window.js @@ -0,0 +1,57 @@ +// In an earlier version of the HTML Standard, document open steps created a +// new JavaScript realm and migrated the existing objects to use the new realm. +// Test that this no longer happens. + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + // Ensure a load event gets dispatched to unblock testharness + t.add_cleanup(() => frame.remove()); + frame.src = "resources/global-variables-frame.html"; + frame.onload = t.step_func_done(() => { + assert_equals(frame.contentWindow.hey, "You", "precondition"); + frame.contentDocument.open(); + assert_equals(frame.contentWindow.hey, "You", "actual check"); + }); +}, "Obtaining a variable from a global whose document had open() invoked"); + +function testIdentity(desc, frameToObject, frameToConstructor) { + async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + // Ensure a load event gets dispatched to unblock testharness + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func_done(() => { + const obj = frameToObject(frame); + frame.contentDocument.open(); + assert_equals(frameToObject(frame), obj); + }); + }, `${desc} maintains object identity through open()`); + + async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + // Ensure a load event gets dispatched to unblock testharness + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func_done(() => { + const obj = frameToObject(frame); + const origProto = Object.getPrototypeOf(obj); + const origCtor = frameToConstructor(frame); + const sym = Symbol(); + obj[sym] = "foo"; + frame.contentDocument.open(); + assert_equals(frameToObject(frame)[sym], "foo"); + assert_true(frameToObject(frame) instanceof origCtor); + assert_equals(Object.getPrototypeOf(frameToObject(frame)), origProto); + assert_equals(frameToConstructor(frame), origCtor); + }); + }, `${desc} maintains its prototype and properties through open()`); +} + +testIdentity("Document", frame => frame.contentDocument, frame => frame.contentWindow.Document); +testIdentity("WindowProxy", frame => frame.contentWindow, frame => frame.contentWindow.Window); +testIdentity("BarProp", frame => frame.contentWindow.locationbar, frame => frame.contentWindow.BarProp); +testIdentity("History", frame => frame.contentWindow.history, frame => frame.contentWindow.History); +testIdentity("localStorage", frame => frame.contentWindow.localStorage, frame => frame.contentWindow.Storage); +testIdentity("Location", frame => frame.contentWindow.location, frame => frame.contentWindow.Location); +testIdentity("sessionStorage", frame => frame.contentWindow.sessionStorage, frame => frame.contentWindow.Storage); +testIdentity("Navigator", frame => frame.contentWindow.navigator, frame => frame.contentWindow.Navigator); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-basic.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-basic.html new file mode 100644 index 0000000000..118be71af1 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-basic.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>Origin check in document.open() - Basic usage</title> +<link rel="author" title="Jochen Eisinger" href="mailto:jochen@chromium.org"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#opening-the-input-stream"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/resources/common.js"></script> +<body> +<script> +testInIFrame(undefined, (ctx) => { + try { + ctx.iframes[0].contentDocument.open(); + } catch (e) { + assert_unreached("Opening a same origin document throws"); + } +}, "It should be possible to open same origin documents."); + +testInIFrame(undefined, (ctx) => { + try { + ctx.iframes[0].contentDocument.write(""); + } catch (e) { + assert_unreached("Implicitly opening a same origin document throws"); + } +}, "It should be possible to implicitly open same origin documents."); +</script> +</body> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-same-origin-domain.sub.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-same-origin-domain.sub.html new file mode 100644 index 0000000000..ba4ef3bae8 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-same-origin-domain.sub.html @@ -0,0 +1,24 @@ +<!doctype html> +<title>Origin check in document.open() - same origin-domain (but not same origin) documents</title> +<link rel="author" title="Jochen Eisinger" href="mailto:jochen@chromium.org"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#opening-the-input-stream"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/html/resources/common.js"></script> +<body> +<script> +testInIFrame("http://{{host}}:{{ports[http][1]}}/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/set-document-domain.html", (ctx) => { + document.domain = document.domain; + let doc = ctx.iframes[0].contentDocument; + let constructor = ctx.iframes[0].contentWindow.DOMException; + assert_throws_dom("SecurityError", constructor, doc.open.bind(doc), "Opening a same origin-domain (but not same origin) document doesn't throw."); +}, "It should not be possible to open same origin-domain (but not same origin) documents."); + +testInIFrame("http://{{host}}:{{ports[http][1]}}/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/set-document-domain.html", (ctx) => { + document.domain = document.domain; + let doc = ctx.iframes[0].contentDocument; + let constructor = ctx.iframes[0].contentWindow.DOMException; + assert_throws_dom("SecurityError", constructor, doc.write.bind(doc, ""), "Implicitly opening a same origin-domain (but not same origin) document doesn't throw."); +}, "It should not be possible to implicitly open same origin-domain (but not same origin) documents."); +</script> +</body> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/quirks.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/quirks.window.js new file mode 100644 index 0000000000..0ff0bb9944 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/quirks.window.js @@ -0,0 +1,74 @@ +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.contentDocument.close()); + assert_equals(frame.contentDocument.compatMode, "BackCompat"); + frame.contentDocument.open(); + assert_equals(frame.contentDocument.compatMode, "CSS1Compat"); + frame.contentDocument.close(); + assert_equals(frame.contentDocument.compatMode, "BackCompat"); +}, "document.open() sets document to no-quirks mode (write no doctype)"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.contentDocument.close()); + assert_equals(frame.contentDocument.compatMode, "BackCompat"); + frame.contentDocument.open(); + assert_equals(frame.contentDocument.compatMode, "CSS1Compat"); + frame.contentDocument.write("<!doctype html public"); + assert_equals(frame.contentDocument.compatMode, "CSS1Compat"); + frame.contentDocument.write(" \"-//IETF//DTD HTML 3//\""); + assert_equals(frame.contentDocument.compatMode, "CSS1Compat"); + frame.contentDocument.write(">"); + assert_equals(frame.contentDocument.compatMode, "BackCompat"); + frame.contentDocument.close(); + assert_equals(frame.contentDocument.compatMode, "BackCompat"); +}, "document.open() sets document to no-quirks mode (write old doctype)"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.contentDocument.close()); + assert_equals(frame.contentDocument.compatMode, "BackCompat"); + frame.contentDocument.open(); + assert_equals(frame.contentDocument.compatMode, "CSS1Compat"); + frame.contentDocument.write("<!doctype html"); + assert_equals(frame.contentDocument.compatMode, "CSS1Compat"); + frame.contentDocument.write(">"); + assert_equals(frame.contentDocument.compatMode, "CSS1Compat"); + frame.contentDocument.close(); + assert_equals(frame.contentDocument.compatMode, "CSS1Compat"); +}, "document.open() sets document to no-quirks mode (write new doctype)"); + +// This tests the document.open() call in fact sets the document to no-quirks +// mode, not limited-quirks mode. It is derived from +// quirks/blocks-ignore-line-height.html in WPT, as there is no direct way to +// distinguish between a no-quirks document and a limited-quirks document. It +// assumes that the user agent passes the linked test, which at the time of +// writing is all major web browsers. +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.contentDocument.close()); + assert_equals(frame.contentDocument.compatMode, "BackCompat"); + frame.contentDocument.open(); + assert_equals(frame.contentDocument.compatMode, "CSS1Compat"); + + // Create the DOM tree manually rather than going through document.write() to + // bypass the parser, which resets the document mode. + const html = frame.contentDocument.appendChild(frame.contentDocument.createElement("html")); + const body = html.appendChild(frame.contentDocument.createElement("body")); + assert_equals(frame.contentDocument.body, body); + body.innerHTML = ` + <style>#ref { display:block }</style> + <div id=test><font size=1>x</font></div> + <font id=ref size=1>x</font> + <div id=s_ref>x</div> + `; + assert_equals(frame.contentDocument.compatMode, "CSS1Compat"); + + const idTest = frame.contentDocument.getElementById("test"); + const idRef = frame.contentDocument.getElementById("ref"); + const idSRef = frame.contentDocument.getElementById("s_ref"); + assert_equals(frame.contentWindow.getComputedStyle(idTest).height, + frame.contentWindow.getComputedStyle(idSRef).height); + assert_not_equals(frame.contentWindow.getComputedStyle(idTest).height, + frame.contentWindow.getComputedStyle(idRef).height); +}, "document.open() sets document to no-quirks mode, not limited-quirks mode"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/readiness.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/readiness.window.js new file mode 100644 index 0000000000..729a958700 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/readiness.window.js @@ -0,0 +1,25 @@ +// This tests the behavior of dynamic markup insertion APIs with a document's +// readiness. + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => { frame.remove(); }); + frame.src = "/common/blank.html"; + frame.onload = t.step_func_done(() => { + const states = []; + frame.contentDocument.onreadystatechange = t.step_func(() => { + states.push(frame.contentDocument.readyState); + }); + assert_equals(frame.contentDocument.readyState, "complete"); + assert_array_equals(states, []); + + // When open() is called, it first removes the event listeners and handlers + // from all nodes in the DOM tree. Then, after a new parser is created and + // initialized, it changes the current document readiness to "loading". + // However, because all event listeners are removed, we cannot observe the + // readystatechange event fired for "loading" inside open(). + frame.contentDocument.open(); + assert_equals(frame.contentDocument.readyState, "loading"); + assert_array_equals(states, []); + }); +}, "document.open() and readiness"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js new file mode 100644 index 0000000000..279020f64d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js @@ -0,0 +1,71 @@ +// This test tests for the nonexistence of a reload override buffer, which is +// used in a previous version of the HTML Standard to make reloads of a +// document.open()'d document load the written-to document rather than doing an +// actual reload of the document's URL. +// +// This test has a somewhat interesting structure compared to the other tests +// in this directory. It eschews the <iframe> structure used by other tests, +// since when the child frame is reloaded it would adopt the URL of the test +// page (the responsible document of the entry settings object), and the spec +// forbids navigation in nested browsing contexts to the same URL as their +// parent. To work around that, we use window.open() which does not suffer from +// that restriction. +// +// In any case, this test as the caller of `document.open()` would be used both +// as the test file and as part of the test file. The `if (window.name !== +// "opened-dummy-window")` condition controls what role this file plays. + +if (window.name !== "opened-dummy-window") { + async_test(t => { + const testURL = document.URL; + const dummyURL = new URL("resources/dummy.html", document.URL).href; + + // 1. Open an auxiliary window. + const win = window.open("resources/dummy.html", "opened-dummy-window"); + t.add_cleanup(() => { win.close(); }); + + win.addEventListener("load", t.step_func(() => { + // The timeout seems to be necessary for Firefox, which when `load` is + // called may still have an active parser. + t.step_timeout(() => { + const doc = win.document; + assert_true(doc.body.textContent.includes("Dummy"), "precondition"); + assert_equals(doc.URL, dummyURL, "precondition"); + + window.onChildLoad = t.step_func(message => { + // 3. The dynamically overwritten content will trigger this function, + // which puts in place the actual test. + + assert_equals(message, "Written", "script on written page is executed"); + assert_true(win.document.body.textContent.includes("Content"), "page is written to"); + assert_equals(win.document.URL, testURL, "postcondition: after document.write()"); + assert_equals(win.document, doc, "document.open should not change the document object"); + window.onChildLoad = t.step_func_done(message => { + // 6. This function should be called from the if (opener) branch of + // this file. It would throw an assertion error if the overwritten + // content was executed instead. + assert_equals(message, "Done!", "actual test"); + assert_true(win.document.body.textContent.includes("Back to the test"), "test is reloaded"); + assert_equals(win.document.URL, testURL, "postcondition: after reload"); + assert_not_equals(win.document, doc, "reload should change the document object"); + }); + + // 4. Reload the pop-up window. Because of the doc.open() call, this + // pop-up window will reload to the same URL as this test itself. + win.location.reload(); + }); + + // 2. When it is loaded, dynamically overwrite its content. + assert_equals(doc.open(), doc); + assert_equals(doc.URL, testURL, "postcondition: after document.open()"); + doc.write("<p>Content</p><script>opener.onChildLoad('Written');</script>"); + doc.close(); + }, 100); + }), { once: true }); + }, "Reloading a document.open()'d page should reload the URL of the entry realm's responsible document"); +} else { + document.write("<p>Back to the test</p>"); + // 5. Since this window is window.open()'d, opener refers to the test window. + // Inform the opener that reload succeeded. + opener.onChildLoad("Done!"); +} diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/remove-initial-about-blankness.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/remove-initial-about-blankness.window.js new file mode 100644 index 0000000000..7442bc4925 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/remove-initial-about-blankness.window.js @@ -0,0 +1,65 @@ +// This tests the issues discussed in https://github.com/whatwg/html/issues/4299 +// and fixed in https://github.com/whatwg/html/pull/6567. + +// Note: because browsers do not interoperate on the spec's notion of window reuse (see e.g. https://crbug.com/778318) +// we pick a specific interoperable test case, which is "currently on initial about:blank, but loading something". + +async_test(t => { + const iframe = document.createElement("iframe"); + + // We can't just leave it at the actual initial about:blank because of the interop issues mentioned above. + // So put it in the "currently on initial about:blank, but loading something" state which interoperably does Window + // reuse. + iframe.src = "/common/blank.html"; + + // Create the Window object. It will be for the initial about:blank since the load of /common/blank.html hasn't + // completed. + document.body.append(iframe); + + // Store a string on that Window object so we can later test if it's reused. + iframe.contentWindow.persistedString = "Hello world!"; + + // This will reset the initial about:blank-ness. But, it will also cancel any ongoing loads. + iframe.contentDocument.open(); + + // So, re-start the load of /common/blank.html. + iframe.src = "/common/blank.html"; + + // When the load finally happens, will it reuse the Window object or not? + // Because document.open() resets the initial about:blank-ness, it will *not* reuse the Window object. + // The point of the test is to assert that. + iframe.addEventListener("load", t.step_func_done(() => { + assert_equals( + iframe.contentDocument.URL, + iframe.src, + "Prerequisite check: we are getting the right load event" + ); + + assert_equals(iframe.contentWindow.persistedString, undefined); + }), { once: true }); +}, "document.open() removes the initial about:blank-ness of the document"); + +// This test is redundant with others in WPT but it's intended to make it clear that document.open() is the +// distinguishing factor. It does the same exact thing but without document.open() and with the resulting final assert +// flipped. +async_test(t => { + const iframe = document.createElement("iframe"); + iframe.src = "/common/blank.html"; + document.body.append(iframe); + + iframe.contentWindow.persistedString = "Hello world!"; + + // NO document.open() call. + + iframe.src = "/common/blank.html"; + + iframe.addEventListener("load", t.step_func_done(() => { + assert_equals( + iframe.contentDocument.URL, + iframe.src, + "Prerequisite check: we are getting the right load event" + ); + + assert_equals(iframe.contentWindow.persistedString, "Hello world!"); + }), { once: true }); +}, "Double-check: without document.open(), Window reuse indeed happens"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-async-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-async-frame.html new file mode 100644 index 0000000000..d5535630be --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-async-frame.html @@ -0,0 +1,9 @@ +<!doctype html> +<p>Text</p> +<script> +window.stop(); +parent.step_timeout(() => { + document.open(); + parent.handlers.afterOpenAsync(); +}, 10); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-frame.html new file mode 100644 index 0000000000..d9ec23590b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-frame.html @@ -0,0 +1,7 @@ +<!doctype html> +<p>Text</p> +<script> +window.stop(); +document.open(); +parent.handlers.afterOpen(); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-custom-element-with-domain-frame.sub.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-custom-element-with-domain-frame.sub.html new file mode 100644 index 0000000000..4de97e8ed1 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-custom-element-with-domain-frame.sub.html @@ -0,0 +1,13 @@ +<p>Text</p> +<script> +document.domain = "{{host}}"; + +class CustomElement extends HTMLElement { + constructor() { + super(); + parent.onCustomElementReady(); + } +} +customElements.define("custom-element", CustomElement); +</script> +<custom-element></custom-element> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-frame.html new file mode 100644 index 0000000000..632b2934ac --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-frame.html @@ -0,0 +1,4 @@ +<p>Text</p> +<script> +parent.testSynchronousScript(); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-with-domain-frame.sub.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-with-domain-frame.sub.html new file mode 100644 index 0000000000..7ca7b5f44c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-with-domain-frame.sub.html @@ -0,0 +1,5 @@ +<p>Text</p> +<script> +document.domain = "{{host}}"; +parent.testSynchronousScript(); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-domain-frame.sub.xhtml b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-domain-frame.sub.xhtml new file mode 100644 index 0000000000..b054c0fe3a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-domain-frame.sub.xhtml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><title>XHTML document with domain set</title></head> + <body> + <p>Text</p> + <script> + document.domain = "{{host}}"; + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-synchronous-script-frame.xhtml b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-synchronous-script-frame.xhtml new file mode 100644 index 0000000000..00fc71eccf --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-synchronous-script-frame.xhtml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><title>XHTML document with hook to run script from a script tag</title></head> + <body> + <p>Text</p> + <script> + parent.testSynchronousScript(); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/document-open-side-effects.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/document-open-side-effects.js new file mode 100644 index 0000000000..7cb86dcba0 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/document-open-side-effects.js @@ -0,0 +1,8 @@ +function assertDocumentIsReadyForSideEffectsTest(doc, description) { + assert_not_equals(doc.childNodes.length, 0, `document should not be empty before side effects test (${description})`); +} + +function assertOpenHasNoSideEffects(doc, originalURL, description) { + assert_not_equals(doc.childNodes.length, 0, `document nodes should not be cleared (${description})`); + assert_equals(doc.URL, originalURL, `The original URL should be kept (${description})`); +} diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/dummy.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/dummy.html new file mode 100644 index 0000000000..a092f4e2d7 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/dummy.html @@ -0,0 +1,2 @@ +<!-- Like /common/blank.html, but with some content in it. --> +<p>Dummy</p> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/encoding-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/encoding-frame.html new file mode 100644 index 0000000000..843c3a2c79 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/encoding-frame.html @@ -0,0 +1,3 @@ +<!doctype html> +<meta charset=ms932> +<p>Encoded in Shift_JIS.</p> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/global-variables-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/global-variables-frame.html new file mode 100644 index 0000000000..0fe189914c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/global-variables-frame.html @@ -0,0 +1,4 @@ +<!doctype html> +<script> +hey = "You"; +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/history-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/history-frame.html new file mode 100644 index 0000000000..2404105b09 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/history-frame.html @@ -0,0 +1,20 @@ +<script> +function queueTest() { + // The timeout is necessary to avoid the parser still being active when + // `document.open()` is called and becoming a no-op. + // + // We also cannot use setTimeout(..., 0), as the parser is terminated in a + // task with DOM manipulation task source while the timeout is run in a task + // on the timer task source. The order is therefore not guaranteed. Let's + // play it safer and use some actual timeout. + setTimeout(() => { + document.open(); + document.write("<p>New content</p>"); + document.close(); + opener.onDocumentOpen(); + }, 200); +} +</script> +<body onload="opener.onFrameLoaded(); queueTest();"> +<p>Old content</p> +</body> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/http-refresh.py b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/http-refresh.py new file mode 100644 index 0000000000..161a34b6b5 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/http-refresh.py @@ -0,0 +1,5 @@ +from wptserve.utils import isomorphic_encode + +def main(request, response): + time = isomorphic_encode(request.url_parts.query) if request.url_parts.query else b'0' + return 200, [(b'Refresh', time), (b'Content-Type', b"text/html")], b'' diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/meta-refresh.py b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/meta-refresh.py new file mode 100644 index 0000000000..2dfbab6e76 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/meta-refresh.py @@ -0,0 +1,3 @@ +def main(request, response): + time = request.url_parts.query if request.url_parts.query else u'0' + return 200, [[b'Content-Type', b'text/html']], u'<meta http-equiv=refresh content=%s>' % time diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/page-with-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/page-with-frame.html new file mode 100644 index 0000000000..a1ab01e072 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/page-with-frame.html @@ -0,0 +1 @@ +<iframe src="/common/blank.html"></iframe> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/set-document-domain.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/set-document-domain.html new file mode 100644 index 0000000000..a92a7ae39f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/set-document-domain.html @@ -0,0 +1,4 @@ +<!doctype html> +<script> +document.domain = document.domain; +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py new file mode 100644 index 0000000000..fced22aa26 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py @@ -0,0 +1,8 @@ +import time +from base64 import decodebytes + +png_response = decodebytes(b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg==') + +def main(request, response): + time.sleep(2) + return 200, [], png_response diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-incumbent-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-incumbent-frame.html new file mode 100644 index 0000000000..bd78d8ee52 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-incumbent-frame.html @@ -0,0 +1,4 @@ +<!doctype html> +<script> +window.callDocumentMethod = methodName => document[methodName](); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-timer-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-timer-frame.html new file mode 100644 index 0000000000..b2c050768c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-timer-frame.html @@ -0,0 +1,3 @@ +<script> +setTimeout(parent.timerTest, 10); +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-frame.html new file mode 100644 index 0000000000..be483ff0ae --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-frame.html @@ -0,0 +1,9 @@ +<script> +onload = () => { + const beforeURL = document.URL; + document.open(); + const afterURL = document.URL; + document.close(); + parent.testDone(beforeURL, afterURL); +} +</script> diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.js new file mode 100644 index 0000000000..887adcb739 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.js @@ -0,0 +1,106 @@ +// An older version of the HTML Standard mandated that document.open() remove +// all tasks associated with the document on which open() is called. This step +// has been proposed to be removed. This series of tests ensures that this step +// is no longer executed. +// +// This file comprehensively (but not exhaustively) tests for many queued tasks +// that may be observable. Each taskTest() call in fact runs two tests: the +// first one "tasks without document.open()" does not actually run +// document.open(), just to test that the tested task works ordinarily; the +// second actually calls document.open() to test if the method call removes +// that specific task from the queue. + +// This is necessary to allow the promise rejection test below. +setup({ + allow_uncaught_exception: true +}); + +function taskTest(description, testBody) { + async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + // The empty HTML seems to be necessary to cajole Chrome and Safari into + // firing a load event asynchronously, which is necessary to make sure the + // frame's document doesn't have a parser associated with it. + // See: https://crbug.com/569511 + frame.src = "/common/blank.html"; + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + // Make sure there is no parser. Firefox seems to have an additional + // non-spec-compliant readiness state "uninitialized", so test for the + // two known valid readiness states instead. + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1191683 + assert_in_array(frame.contentDocument.readyState, ["interactive", "complete"]); + testBody(t, frame, doc => {}); + }); + }, `tasks without document.open() (${description})`); + + async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + // The empty HTML seems to be necessary to cajole Chrome into firing a load + // event, which is necessary to make sure the frame's document doesn't have + // a parser associated with it. + // See: https://crbug.com/569511 + frame.src = "/common/blank.html"; + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + // Make sure there is no parser. Firefox seems to have an additional + // non-spec-compliant readiness state "uninitialized", so test for the + // two known valid readiness states instead. + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1191683 + assert_in_array(frame.contentDocument.readyState, ["interactive", "complete"]); + testBody(t, frame, doc => doc.open()); + }); + }, `document.open() and tasks (${description})`); +} + +taskTest("timeout", (t, frame, open) => { + frame.contentWindow.setTimeout(t.step_func_done(), 100); + open(frame.contentDocument); +}); + +taskTest("window message", (t, frame, open) => { + let counter = 0; + frame.contentWindow.postMessage(undefined, "*"); + open(frame.contentDocument); + frame.contentWindow.postMessage(undefined, "*"); + frame.contentWindow.onmessage = t.step_func(e => { + assert_equals(e.data, undefined); + counter++; + assert_less_than_equal(counter, 2); + if (counter == 2) { + t.done(); + } + }); +}); + +taskTest("canvas.toBlob()", (t, frame, open) => { + const canvas = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("canvas")); + canvas.toBlob(t.step_func_done()); + open(frame.contentDocument); +}); + +taskTest("MessagePort", (t, frame, open) => { + frame.contentWindow.eval(`({ port1, port2 } = new MessageChannel());`); + frame.contentWindow.port2.onmessage = t.step_func_done(ev => { + assert_equals(ev.data, "Hello world"); + }); + frame.contentWindow.port1.postMessage("Hello world"); + open(frame.contentDocument); +}); + +taskTest("Promise rejection", (t, frame, open) => { + // There is currently some ambiguity on which Window object the + // unhandledrejection event should be fired on. Here, let's account for that + // ambiguity and allow event fired on _any_ global to pass this test. + // See: + // - https://github.com/whatwg/html/issues/958, + // - https://bugs.webkit.org/show_bug.cgi?id=187822 + const promise = frame.contentWindow.eval("Promise.reject(42);"); + open(frame.contentDocument); + const listener = t.step_func_done(ev => { + assert_equals(ev.promise, promise); + assert_equals(ev.reason, 42); + }); + frame.contentWindow.onunhandledrejection = listener; + window.onunhandledrejection = listener; +}); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext-subframe.txt b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext-subframe.txt new file mode 100644 index 0000000000..3e715502b9 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext-subframe.txt @@ -0,0 +1 @@ +Some text. diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext.window.js new file mode 100644 index 0000000000..ab1d9706a4 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext.window.js @@ -0,0 +1,23 @@ +["replace", + "NOBODY", + "@ FD ;", + "it does not matter, you see \f", + "text/plain", + "text/xml", + "application/octet-stream", + "\0"].forEach(type => { + async_test(t => { + const frame = document.createElement("iframe"); + frame.src = "type-argument-plaintext-subframe.txt"; + document.body.appendChild(frame); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func_done(() => { + assert_equals(frame.contentDocument.open(type), frame.contentDocument); + frame.contentDocument.write("<B>heya</b>"); + frame.contentDocument.close(); + assert_equals(frame.contentDocument.body.firstChild.localName, "b"); + assert_equals(frame.contentDocument.body.textContent, "heya"); + assert_equals(frame.contentDocument.contentType, "text/plain"); + }); + }, "document.open() on plaintext document with type set to: " + type + " (type argument is supposed to be ignored)"); +}); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument.window.js new file mode 100644 index 0000000000..9174008da3 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument.window.js @@ -0,0 +1,20 @@ +["replace", + "NOBODY", + "@ FD ;", + "it does not matter, you see \f", + "text/plain", + "text/xml", + "application/octet-stream", + "\0"].forEach(type => { + async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + assert_equals(frame.contentDocument.open(type), frame.contentDocument); + frame.contentDocument.write("<B>heya</b>"); + frame.contentDocument.close(); + assert_equals(frame.contentDocument.body.firstChild.localName, "b"); + assert_equals(frame.contentDocument.body.textContent, "heya"); + assert_equals(frame.contentDocument.contentType, "text/html"); + t.done(); + }, "document.open() with type set to: " + type + " (type argument is supposed to be ignored)"); +}); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/unload.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/unload.window.js new file mode 100644 index 0000000000..e275a4987a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/unload.window.js @@ -0,0 +1,19 @@ +// In an earlier version of the HTML Standard, document open steps had "unload +// document" as a step. Test that this no longer happens. + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.contentWindow.onpagehide = t.unreached_func("onpagehide got called"); + frame.contentDocument.onvisibilitychange = t.unreached_func("onvisibilitychange got called"); + frame.contentWindow.onunload = t.unreached_func("onunload got called"); + frame.contentDocument.open(); + t.step_timeout(t.step_func_done(() => { + // If none of the three events have been fired by this point, we consider + // the test a success. `frame.remove()` above will allow the `load` event + // to be fired on the top-level Window, thus unblocking testharness. + }), 500); + }); +}, "document.open(): Do not fire pagehide, visibilitychange, or unload events"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document-sync-call.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document-sync-call.window.js new file mode 100644 index 0000000000..f20b4341e3 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document-sync-call.window.js @@ -0,0 +1,13 @@ +for (const methodName of ["open", "write", "writeln"]) { + async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => { frame.remove(); }); + const frameURL = new URL("resources/url-entry-document-incumbent-frame.html", document.URL).href; + frame.onload = t.step_func_done(() => { + assert_equals(frame.contentDocument.URL, frameURL); + frame.contentWindow.callDocumentMethod(methodName); + assert_equals(frame.contentDocument.URL, document.URL); + }); + frame.src = frameURL; + }, `document.${methodName}() changes document's URL to the entry global object's associate document's (sync call)`); +} diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document.window.js new file mode 100644 index 0000000000..c3a1c3a874 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document.window.js @@ -0,0 +1,18 @@ +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + const frameURL = new URL("resources/url-entry-document-timer-frame.html", document.URL).href; + window.timerTest = t.step_func_done(() => { + assert_equals(frame.contentDocument.URL, frameURL); + assert_equals(frame.contentWindow.location.href, frameURL); + + // In this case, the entry settings object was set when this function is + // executed in the timer task through Web IDL's "invoke a callback + // function" algorithm, to be the relevant settings object of this + // function. Therefore the URL of this document would be inherited. + assert_equals(frame.contentDocument.open(), frame.contentDocument); + assert_equals(frame.contentDocument.URL, document.URL); + assert_equals(frame.contentWindow.location.href, document.URL); + }); + frame.src = frameURL; +}, "document.open() changes document's URL to the entry settings object's responsible document's (through timeouts)"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-fragment.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-fragment.window.js new file mode 100644 index 0000000000..0c528935b5 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-fragment.window.js @@ -0,0 +1,26 @@ +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")), + urlSansHash = document.URL; + t.add_cleanup(() => { frame.remove(); }); + assert_equals(frame.contentDocument.URL, "about:blank"); + assert_equals(frame.contentWindow.location.href, "about:blank"); + self.onhashchange = t.step_func_done(() => { + frame.contentDocument.open(); + assert_equals(frame.contentDocument.URL, urlSansHash); + assert_equals(frame.contentWindow.location.href, urlSansHash); + }); + self.location.hash = "heya"; +}, "document.open() and document's URL containing a fragment (entry is not relevant)"); + +window.testDone = undefined; +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")) + t.add_cleanup(() => { frame.remove(); }); + frame.src = "resources/url-frame.html#heya"; + window.testDone = t.step_func_done((beforeURL, afterURL) => { + assert_equals(beforeURL, frame.src); + assert_equals(afterURL, frame.src); + assert_equals(frame.contentDocument.URL, frame.src); + assert_equals(frame.contentWindow.location.href, frame.src); + }); +}, "document.open() and document's URL containing a fragment (entry is relevant)"); diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url.window.js new file mode 100644 index 0000000000..4e7c649f45 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url.window.js @@ -0,0 +1,93 @@ +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + assert_equals(frame.contentDocument.URL, "about:blank"); + assert_equals(frame.contentWindow.location.href, "about:blank"); + assert_equals(frame.contentDocument.open(), frame.contentDocument); + assert_equals(frame.contentDocument.URL, document.URL); + assert_equals(frame.contentWindow.location.href, document.URL); +}, "document.open() changes document's URL (fully active document)"); + +async_test(t => { + const blankURL = new URL("/common/blank.html", document.URL).href; + const frameURL = new URL("resources/page-with-frame.html", document.URL).href; + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.onload = t.step_func(() => { + assert_equals(frame.contentDocument.URL, frameURL); + assert_equals(frame.contentWindow.location.href, frameURL); + const childFrame = frame.contentDocument.querySelector("iframe"); + const childDoc = childFrame.contentDocument; + const childWin = childFrame.contentWindow; + assert_equals(childDoc.URL, blankURL); + assert_equals(childWin.location.href, blankURL); + + // Right now childDoc is still fully active. + + frame.onload = t.step_func_done(() => { + // Now childDoc is still active but no longer fully active. + assert_equals(childDoc.open(), childDoc); + assert_equals(childDoc.URL, blankURL); + assert_equals(childWin.location.href, blankURL); + }); + frame.src = "/common/blank.html"; + }); + frame.src = frameURL; +}, "document.open() does not change document's URL (active but not fully active document)"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + const doc = frame.contentDocument; + + // We do not test for win.location.href in this test due to + // https://github.com/whatwg/html/issues/3959. + + // Right now the frame is connected and it has an active document. + assert_equals(doc.URL, "about:blank"); + + frame.remove(); + + // Now the frame is no longer connected. Its document is no longer active. + assert_equals(doc.URL, "about:blank"); + assert_equals(doc.open(), doc); + assert_equals(doc.URL, "about:blank"); +}, "document.open() does not change document's URL (non-active document with an associated Window object; frame is removed)"); + +async_test(t => { + const frame = document.createElement("iframe"); + t.add_cleanup(() => frame.remove()); + + // We do not test for win.location.href in this test due to + // https://github.com/whatwg/html/issues/3959. + + frame.onload = t.step_func(() => { + const doc = frame.contentDocument; + // Right now the frame is connected and it has an active document. + assert_equals(doc.URL, "about:blank"); + + frame.onload = t.step_func_done(() => { + // Now even though the frame is still connected, its document is no + // longer active. + assert_not_equals(frame.contentDocument, doc); + assert_equals(doc.URL, "about:blank"); + assert_equals(doc.open(), doc); + assert_equals(doc.URL, "about:blank"); + }); + + frame.src = "/common/blank.html"; + }); + + // We need to connect the frame after the load event is set up to mitigate + // against https://crbug.com/569511. + document.body.appendChild(frame); +}, "document.open() does not change document's URL (non-active document with an associated Window object; navigated away)"); + +test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + const doc = frame.contentDocument.implementation.createHTMLDocument(); + assert_equals(doc.URL, "about:blank"); + assert_equals(doc.open(), doc); + assert_equals(doc.URL, "about:blank"); +}, "document.open() does not change document's URL (non-active document without an associated Window object)"); |