summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/domparsing
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/domparsing')
-rw-r--r--testing/web-platform/tests/domparsing/DOMParser-parseFromString-encoding.html47
-rw-r--r--testing/web-platform/tests/domparsing/DOMParser-parseFromString-html.html86
-rw-r--r--testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base-pushstate.html13
-rw-r--r--testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base.html8
-rw-r--r--testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-moretests.html66
-rw-r--r--testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-pushstate.html12
-rw-r--r--testing/web-platform/tests/domparsing/DOMParser-parseFromString-url.html7
-rw-r--r--testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-doctype.html27
-rw-r--r--testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-internal-subset.html24
-rw-r--r--testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-parsererror.html50
-rw-r--r--testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml.html77
-rw-r--r--testing/web-platform/tests/domparsing/META.yml4
-rw-r--r--testing/web-platform/tests/domparsing/XMLSerializer-serializeToString.html231
-rw-r--r--testing/web-platform/tests/domparsing/createContextualFragment.html179
-rw-r--r--testing/web-platform/tests/domparsing/idlharness.window.js18
-rw-r--r--testing/web-platform/tests/domparsing/innerhtml-01.xhtml28
-rw-r--r--testing/web-platform/tests/domparsing/innerhtml-03.xhtml59
-rw-r--r--testing/web-platform/tests/domparsing/innerhtml-04.html24
-rw-r--r--testing/web-platform/tests/domparsing/innerhtml-05.xhtml26
-rw-r--r--testing/web-platform/tests/domparsing/innerhtml-06.html19
-rw-r--r--testing/web-platform/tests/domparsing/innerhtml-07.html49
-rw-r--r--testing/web-platform/tests/domparsing/innerhtml-mxss.sub.html49
-rw-r--r--testing/web-platform/tests/domparsing/insert-adjacent.html38
-rw-r--r--testing/web-platform/tests/domparsing/insert_adjacent_html-xhtml.xhtml91
-rw-r--r--testing/web-platform/tests/domparsing/insert_adjacent_html.html94
-rw-r--r--testing/web-platform/tests/domparsing/insert_adjacent_html.js33
-rw-r--r--testing/web-platform/tests/domparsing/outerhtml-01.html15
-rw-r--r--testing/web-platform/tests/domparsing/outerhtml-02.html54
-rw-r--r--testing/web-platform/tests/domparsing/resources/domparser-iframe-base-pushstate.html10
-rw-r--r--testing/web-platform/tests/domparsing/resources/domparser-iframe-base.html6
-rw-r--r--testing/web-platform/tests/domparsing/resources/domparser-iframe-pushstate.html9
-rw-r--r--testing/web-platform/tests/domparsing/resources/domparser-iframe.html4
-rw-r--r--testing/web-platform/tests/domparsing/resources/domparser-iframe.js4
-rw-r--r--testing/web-platform/tests/domparsing/resources/domparser-url-tests.js72
-rw-r--r--testing/web-platform/tests/domparsing/style_attribute_html.html52
-rw-r--r--testing/web-platform/tests/domparsing/xml-serialization.xhtml103
-rw-r--r--testing/web-platform/tests/domparsing/xmldomparser.html13
37 files changed, 1701 insertions, 0 deletions
diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-encoding.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-encoding.html
new file mode 100644
index 0000000000..0dd4468cf2
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-encoding.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<title>DOMParser encoding test</title>
+<meta charset="windows-1252"> <!-- intentional to make sure the results are UTF-8 anyway -->
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+"use strict";
+
+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 parser = new DOMParser();
+ const doc = parser.parseFromString("", "text/html");
+
+ assertEncoding(doc);
+}, "HTML: empty");
+
+test(() => {
+ const parser = new DOMParser();
+ const doc = parser.parseFromString("", "text/xml");
+
+ assertEncoding(doc);
+}, "XML: empty");
+
+test(() => {
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(`<meta charset="latin2">`, "text/html");
+
+ assertEncoding(doc);
+}, "HTML: meta charset");
+
+test(() => {
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(`<?xml version="1.0" encoding="latin2"?><x/>`, "text/xml");
+
+ assertEncoding(doc);
+}, "XML: XML declaration");
+</script>
diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-html.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-html.html
new file mode 100644
index 0000000000..86e516d618
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-html.html
@@ -0,0 +1,86 @@
+<!doctype html>
+<title>DOMParser 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() {
+ var parser = new DOMParser();
+ var input = '<html id="root"><head></head><body></body></html>';
+ doc = parser.parseFromString(input, 'text/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() {
+ var parser = new DOMParser();
+ var input = '<!DOCTYPE html><html id="root"><head></head><body></body></html>';
+ doc = parser.parseFromString(input, 'text/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 soup = "<!DOCTYPE foo></><foo></multiple></>";
+ var htmldoc = new DOMParser().parseFromString(soup, "text/html");
+ assert_equals(htmldoc.documentElement.localName, "html");
+ assert_equals(htmldoc.documentElement.namespaceURI, "http://www.w3.org/1999/xhtml");
+}, "DOMParser parses HTML tag soup with no problems");
+
+test(function() {
+ const doc = new DOMParser().parseFromString('<noembed>&lt;a&gt;</noembed>', 'text/html');
+ assert_equals(doc.querySelector('noembed').textContent, '&lt;a&gt;');
+}, 'DOMParser should handle the content of <noembed> as raw text');
+
+test(function() {
+ assert_throws_js(TypeError, function() {
+ new DOMParser().parseFromString("", "text/foo-this-is-invalid");
+ })
+}, "DOMParser throws on an invalid enum value")
+
+test(() => {
+ const doc = new DOMParser().parseFromString(`
+<html><body>
+<style>
+ @import url(/dummy.css)
+</style>
+<script>document.x = 8<\/script>
+</body></html>`, 'text/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 = new DOMParser().parseFromString(`<body><noscript><p id="test1">test1<p id="test2">test2</noscript>`, 'text/html');
+ 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/domparsing/DOMParser-parseFromString-url-base-pushstate.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base-pushstate.html
new file mode 100644
index 0000000000..41d7344a64
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base-pushstate.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>DOMParser 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="/domparsing/resources/domparser-iframe-base-pushstate.html" onload="window.resolveLoadPromise();"></iframe>
+
+<script>
+"use strict";
+history.pushState(null, "", "/fake/push-state-from-outer-frame");
+</script>
+<script src="/domparsing/resources/domparser-url-tests.js"></script>
diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base.html
new file mode 100644
index 0000000000..5af1cee1c5
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>DOMParser 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="/domparsing/resources/domparser-iframe-base.html" onload="window.resolveLoadPromise();"></iframe>
+<script src="/domparsing/resources/domparser-url-tests.js"></script>
diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-moretests.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-moretests.html
new file mode 100644
index 0000000000..e7599f306e
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-moretests.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>DOMParser: 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;
+ var supportedTypes = [
+ "text/html",
+ "text/xml",
+ "application/xml",
+ "application/xhtml+xml",
+ "image/svg+xml",
+ ];
+
+ supportedTypes.forEach(function(type) {
+ test(function() {
+ var dp = new DOMParser();
+ var doc = dp.parseFromString("<html></html>", type);
+ assert_equals(doc.URL, document.URL);
+ }, "Parent window (" + type + ")");
+
+ test(function() {
+ var dp = new child.DOMParser();
+ var doc = dp.parseFromString("<html></html>", type);
+ assert_equals(doc.URL, child.document.URL);
+ }, "Child window (" + type + ")");
+
+ test(function() {
+ var dp = new DOMParser();
+ var doc = child.DOMParser.prototype.parseFromString.call(dp, "<html></html>", type);
+ assert_equals(doc.URL, document.URL);
+ }, "Parent window with child method (" + type + ")");
+
+ test(function() {
+ var dp = new child.DOMParser();
+ var doc = DOMParser.prototype.parseFromString.call(dp, "<html></html>", type);
+ assert_equals(doc.URL, child.document.URL);
+ }, "Child window with parent method (" + type + ")");
+ });
+
+ var dpBeforeNavigation = new child.DOMParser(), urlBeforeNavigation = child.document.URL;
+ iframe.onload = this.step_func_done(function() {
+ supportedTypes.forEach(function(type) {
+ test(function() {
+ var doc = dpBeforeNavigation.parseFromString("<html></html>", type);
+ assert_equals(doc.URL, urlBeforeNavigation);
+ }, "Child window crossing navigation (" + type + ")");
+
+ test(function() {
+ var dp = new child.DOMParser();
+ var doc = dp.parseFromString("<html></html>", type);
+ assert_equals(doc.URL, child.document.URL);
+ }, "Child window after navigation (" + type + ")");
+ });
+ });
+ iframe.src = "/common/blank.html?2";
+ });
+ iframe.src = "/common/blank.html?1";
+ document.body.appendChild(iframe);
+});
+</script>
diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-pushstate.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-pushstate.html
new file mode 100644
index 0000000000..ecb89bc741
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-pushstate.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>DOMParser 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="/domparsing/resources/domparser-iframe-pushstate.html" onload="window.resolveLoadPromise();"></iframe>
+
+<script>
+"use strict";
+history.pushState(null, "", "/fake/push-state-from-outer-frame");
+</script>
+<script src="/domparsing/resources/domparser-url-tests.js"></script>
diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url.html
new file mode 100644
index 0000000000..9b9a672c48
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<title>DOMParser 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="/domparsing/resources/domparser-iframe.html" onload="window.resolveLoadPromise();"></iframe>
+<script src="/domparsing/resources/domparser-url-tests.js"></script>
diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-doctype.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-doctype.html
new file mode 100644
index 0000000000..cd655acf93
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-doctype.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>HTML entities for various XHTML Doctype variants</title>
+<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ test(function () {
+ var doc = new DOMParser().parseFromString('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"><html><div id="test"/></html>', 'application/xhtml+xml');
+ var div = doc.getElementById('test');
+ assert_equals(div, null); // If null, then this was a an error document (didn't parse the input successfully)
+ }, "Doctype parsing of System Id must fail on ommitted value");
+
+ test(function () {
+ var doc = new DOMParser().parseFromString('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ""><html><div id="test"/></html>', 'application/xhtml+xml');
+ var div = doc.getElementById('test');
+ assert_not_equals(div, null); // If found, then the DOMParser didn't generate an error document
+ }, "Doctype parsing of System Id can handle empty string");
+
+ test(function () {
+ var doc = new DOMParser().parseFromString('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "x"><html><div id="test"/></html>', 'application/xhtml+xml');
+ var div = doc.getElementById('test');
+ assert_not_equals(div, null);
+ }, "Doctype parsing of System Id can handle a quoted value");
+
+</script>
diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-internal-subset.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-internal-subset.html
new file mode 100644
index 0000000000..26b5fa99f1
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-internal-subset.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>Parsing and serialization of doctype internal subset</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function () {
+ // https://www.w3.org/TR/xml11/#sec-prolog-dtd has intSubset as part of the
+ // syntax, which is not represented in the DocumentType interface. Check that
+ // publicId and systemId are not affected.
+ var doc = new DOMParser().parseFromString('<!DOCTYPE foo [ <!ENTITY x "y"> ]><foo>&x;</foo>', 'text/xml');
+ var doctype = doc.doctype;
+ assert_equals(doctype.name, 'foo', 'doctype name');
+ assert_equals(doctype.publicId, '', 'doctype publicId');
+ assert_equals(doctype.systemId, '', 'doctype systemId');
+ // Check that document itself was parsed correctly.
+ var documentElementString = new XMLSerializer().serializeToString(doc.documentElement);
+ assert_equals(documentElementString, '<foo>y</foo>', 'serialized document element');
+ // https://w3c.github.io/DOM-Parsing/#xml-serializing-a-documenttype-node also
+ // does not have any notion of the internal subset, so also check that it
+ // isn't serialized by XMLSerializer.
+ var doctypeString = new XMLSerializer().serializeToString(doctype);
+ assert_equals(doctypeString, '<!DOCTYPE foo>', 'serialized doctype');
+});
+</script>
diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-parsererror.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-parsererror.html
new file mode 100644
index 0000000000..f6985aa20a
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-parsererror.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<title>DOMParser: &lt;parsererror> element added on error</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+const xhtml_prologue = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' +
+ ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n' +
+ '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n' +
+ '<body>\n',
+ xhtml_epilogue = '</body>\n</html>\n';
+
+[
+ '<span x:test="testing">1</span>', // undeclared 'x' namespace prefix
+ '< span>2</span>', // bad start tag
+ '<span :test="testing">3</span>', // empty namespace prefix
+ '<span><em>4</span></em>', // staggered tags
+ '<span>5', // missing end </span> tag
+ '6</span>', // missing start <span> tag
+ '<span>7< /span>', // bad end tag
+ '<span>8</ span>', // bad end tag
+ '<span novalue>9</span>', // missing attribute value
+ '<span ="noattr">10</span>', // missing attribute name
+ '<span ::="test">11</span>', // bad namespace prefix
+ '<span xmlns:="urn:x-test:test">12</span>', // missing namespace prefix
+ '<span xmlns:xmlns="">13</span>', // invalid namespace prefix
+ '<span data-test=testing>14</span>', // unquoted attribute value
+ '15<span', // bad start tag
+ '<8:test xmlns:8="urn:x-test:test">16</8:test>', // invalid namespace prefix
+ '<span xmlns:p1 xmlns:p2="urn:x-test:test"/>17', // missing namespace URI
+].forEach(fragment => {
+ test(() => {
+ var document_string = xhtml_prologue + fragment + xhtml_epilogue;
+ var doc = (new DOMParser).parseFromString(document_string, "application/xhtml+xml");
+ var parsererrors = doc.getElementsByTagName("parsererror");
+ assert_equals(parsererrors.length, 1, 'expecting one parsererror');
+ }, document.title + ', ' + fragment);
+});
+
+[
+ 'text/xml',
+ 'application/xml',
+ 'application/xhtml+xml',
+ 'image/svg+xml'
+].forEach(mimeType => {
+ test(() => {
+ const doc = (new DOMParser()).parseFromString('<span x:test="testing">1</span>', mimeType);
+ assert_equals(doc.contentType, mimeType);
+ }, `${mimeType} is preserved in the error document`);
+})
+</script>
diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml.html
new file mode 100644
index 0000000000..b07bb3d87c
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<title>DOMParser</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+function checkMetadata(doc, contentType) {
+ assert_true(doc instanceof Document, "Should be Document");
+ assert_equals(doc.URL, document.URL, "URL");
+ assert_equals(doc.documentURI, document.URL, "documentURI");
+ assert_equals(doc.baseURI, document.URL, "baseURI");
+ assert_equals(doc.characterSet, "UTF-8", "characterSet");
+ assert_equals(doc.charset, "UTF-8", "charset");
+ assert_equals(doc.inputEncoding, "UTF-8", "inputEncoding");
+ assert_equals(doc.contentType, contentType, "contentType");
+ assert_equals(doc.location, null, "location");
+}
+
+var allowedTypes = ["text/xml", "application/xml", "application/xhtml+xml", "image/svg+xml"];
+
+allowedTypes.forEach(function(type) {
+ test(function() {
+ var p = new DOMParser();
+ var doc = p.parseFromString("<foo/>", type);
+ assert_true(doc instanceof Document, "Should be Document");
+ checkMetadata(doc, type);
+ assert_equals(doc.documentElement.namespaceURI, null);
+ assert_equals(doc.documentElement.localName, "foo");
+ assert_equals(doc.documentElement.tagName, "foo");
+ }, "Should parse correctly in type " + type);
+
+ test(function() {
+ var p = new DOMParser();
+ var doc = p.parseFromString("<foo/>", type);
+ assert_false(doc instanceof XMLDocument, "Should not be XMLDocument");
+ }, "XMLDocument interface for correctly parsed document with type " + type);
+
+ test(function() {
+ var p = new DOMParser();
+ var doc = p.parseFromString("<foo>", type);
+ checkMetadata(doc, type);
+ assert_equals(doc.documentElement.namespaceURI, "http://www.mozilla.org/newlayout/xml/parsererror.xml");
+ assert_equals(doc.documentElement.localName, "parsererror");
+ assert_equals(doc.documentElement.tagName, "parsererror");
+ }, "Should return an error document for XML wellformedness errors in type " + type);
+
+ test(function() {
+ var p = new DOMParser();
+ var doc = p.parseFromString("<foo>", type);
+ assert_false(doc instanceof XMLDocument, "Should not be XMLDocument");
+ }, "XMLDocument interface for incorrectly parsed document with type " + type);
+
+ test(function() {
+ var p = new DOMParser();
+ var doc = p.parseFromString(`
+ <html>
+ <head></head>
+ <body>
+ <script>document.x = 5;<\/script>
+ <noscript><p>test1</p><p>test2</p></noscript>
+ </body>
+ </html>`
+ , type);
+
+ 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");
+
+ const body = doc.documentElement.children[1];
+ assert_equals(body.localName, "body");
+ assert_equals(body.children[1].localName, "noscript");
+ assert_equals(body.children[1].children.length, 2);
+ assert_equals(body.children[1].children[0].localName, "p");
+ assert_equals(body.children[1].children[1].localName, "p");
+ }, "scripting must be disabled with type " + type);
+});
+</script>
diff --git a/testing/web-platform/tests/domparsing/META.yml b/testing/web-platform/tests/domparsing/META.yml
new file mode 100644
index 0000000000..72f66c4301
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/META.yml
@@ -0,0 +1,4 @@
+spec: https://w3c.github.io/DOM-Parsing/
+suggested_reviewers:
+ - ChrisParis
+ - jdm
diff --git a/testing/web-platform/tests/domparsing/XMLSerializer-serializeToString.html b/testing/web-platform/tests/domparsing/XMLSerializer-serializeToString.html
new file mode 100644
index 0000000000..17280af7b8
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/XMLSerializer-serializeToString.html
@@ -0,0 +1,231 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<html>
+ <head>
+ <title>domparsing Test: XMLSerializer.serializeToString</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>domparsing_XMLSerializer_serializeToString</h1>
+ <script>
+const XMLNS_URI = 'http://www.w3.org/2000/xmlns/';
+
+function createXmlDoc(){
+ var input = '<?xml version="1.0" encoding="UTF-8"?><root><child1>value1</child1></root>';
+ var parser = new DOMParser();
+ return parser.parseFromString(input, 'text/xml');
+}
+
+// Returns the root element.
+function parse(xmlString) {
+ return (new DOMParser()).parseFromString(xmlString, 'text/xml').documentElement;
+}
+
+function serialize(node) {
+ return (new XMLSerializer()).serializeToString(node);
+}
+
+test(function() {
+ var root = createXmlDoc().documentElement;
+ assert_equals(serialize(root), '<root><child1>value1</child1></root>');
+}, 'check XMLSerializer.serializeToString method could parsing xmldoc to string');
+
+test(function() {
+ var root = parse('<html><head></head><body><div></div><span></span></body></html>');
+ assert_equals(serialize(root.ownerDocument), '<html><head/><body><div/><span/></body></html>');
+}, 'check XMLSerializer.serializeToString method could parsing document to string');
+
+test(function() {
+ var root = createXmlDoc().documentElement;
+ var element = root.ownerDocument.createElementNS('urn:foo', 'another');
+ var child1 = root.firstChild;
+ root.replaceChild(element, child1);
+ element.appendChild(child1);
+ assert_equals(serialize(root), '<root><another xmlns="urn:foo"><child1 xmlns="">value1</child1></another></root>');
+}, 'Check if the default namespace is correctly reset.');
+
+test(function() {
+ var root = parse('<root xmlns="urn:bar"><outer xmlns=""><inner>value1</inner></outer></root>');
+ assert_equals(serialize(root), '<root xmlns="urn:bar"><outer xmlns=""><inner>value1</inner></outer></root>');
+}, 'Check if there is no redundant empty namespace declaration.');
+
+// https://github.com/w3c/DOM-Parsing/issues/47
+test(function() {
+ assert_equals(serialize(parse('<root><child xmlns=""/></root>')),
+ '<root><child/></root>');
+ assert_equals(serialize(parse('<root xmlns=""><child xmlns=""/></root>')),
+ '<root><child/></root>');
+ assert_equals(serialize(parse('<root xmlns="u1"><child xmlns="u1"/></root>')),
+ '<root xmlns="u1"><child/></root>');
+}, 'Check if redundant xmlns="..." is dropped.');
+
+test(function() {
+ const root = parse('<root xmlns="uri1"/>');
+ const child = root.ownerDocument.createElement('child');
+ child.setAttributeNS(XMLNS_URI, 'xmlns', 'FAIL1');
+ root.appendChild(child);
+ const child2 = root.ownerDocument.createElementNS('uri2', 'child2');
+ child2.setAttributeNS(XMLNS_URI, 'xmlns', 'FAIL2');
+ root.appendChild(child2);
+ const child3 = root.ownerDocument.createElementNS('uri1', 'child3');
+ child3.setAttributeNS(XMLNS_URI, 'xmlns', 'FAIL3');
+ root.appendChild(child3);
+ const child4 = root.ownerDocument.createElementNS('uri4', 'child4');
+ child4.setAttributeNS(XMLNS_URI, 'xmlns', 'uri4');
+ root.appendChild(child4);
+ const child5 = root.ownerDocument.createElement('child5');
+ child5.setAttributeNS(XMLNS_URI, 'xmlns', '');
+ root.appendChild(child5);
+ assert_equals(serialize(root), '<root xmlns="uri1"><child xmlns=""/><child2 xmlns="uri2"/><child3/><child4 xmlns="uri4"/><child5 xmlns=""/></root>');
+}, 'Check if inconsistent xmlns="..." is dropped.');
+
+test(function() {
+ let root = parse('<r xmlns:xx="uri"></r>');
+ root.setAttributeNS('uri', 'name', 'v');
+ assert_equals(serialize(root), '<r xmlns:xx="uri" xx:name="v"/>');
+
+ let root2 = parse('<r xmlns:xx="uri"><b/></r>');
+ let child = root2.firstChild;
+ child.setAttributeNS('uri', 'name', 'v');
+ assert_equals(serialize(root2), '<r xmlns:xx="uri"><b xx:name="v"/></r>');
+
+ let root3 = parse('<r xmlns:x0="uri" xmlns:x2="uri"><b xmlns:x1="uri"/></r>');
+ let child3 = root3.firstChild;
+ child3.setAttributeNS('uri', 'name', 'v');
+ assert_equals(serialize(root3),
+ '<r xmlns:x0="uri" xmlns:x2="uri"><b xmlns:x1="uri" x1:name="v"/></r>',
+ 'Should choose the nearest prefix');
+}, 'Check if an attribute with namespace and no prefix is serialized with the nearest-declared prefix');
+
+// https://github.com/w3c/DOM-Parsing/issues/45
+test(function() {
+ let root = parse('<el1 xmlns:p="u1" xmlns:q="u1"><el2 xmlns:q="u2"/></el1>');
+ root.firstChild.setAttributeNS('u1', 'name', 'v');
+ assert_equals(serialize(root),
+ '<el1 xmlns:p="u1" xmlns:q="u1"><el2 xmlns:q="u2" q:name="v"/></el1>');
+}, 'Check if an attribute with namespace and no prefix is serialized with the nearest-declared prefix even if the prefix is assigned to another namespace.');
+
+test(function() {
+ let root = parse('<r xmlns:xx="uri"></r>');
+ root.setAttributeNS('uri', 'p:name', 'v');
+ assert_equals(serialize(root), '<r xmlns:xx="uri" xx:name="v"/>');
+
+ let root2 = parse('<r xmlns:xx="uri"><b/></r>');
+ let child = root2.firstChild;
+ child.setAttributeNS('uri', 'p:name', 'value');
+ assert_equals(serialize(root2),
+ '<r xmlns:xx="uri"><b xx:name="value"/></r>');
+}, 'Check if the prefix of an attribute is replaced with another existing prefix mapped to the same namespace URI.');
+
+// https://github.com/w3c/DOM-Parsing/issues/29
+test(function() {
+ let root = parse('<r xmlns:xx="uri"></r>');
+ root.setAttributeNS('uri2', 'p:name', 'value');
+ assert_equals(serialize(root),
+ '<r xmlns:xx="uri" xmlns:ns1="uri2" ns1:name="value"/>');
+}, 'Check if the prefix of an attribute is NOT preserved in a case where neither its prefix nor its namespace URI is not already used.');
+
+test(function() {
+ let root = parse('<r xmlns:xx="uri"></r>');
+ root.setAttributeNS('uri2', 'xx:name', 'value');
+ assert_equals(serialize(root),
+ '<r xmlns:xx="uri" xmlns:ns1="uri2" ns1:name="value"/>');
+}, 'Check if the prefix of an attribute is replaced with a generated one in a case where the prefix is already mapped to a different namespace URI.');
+
+test(function() {
+ var root = parse('<root />');
+ root.setAttribute('attr', '\t');
+ assert_in_array(serialize(root), [
+ '<root attr="&#9;"/>', '<root attr="&#x9;"/>']);
+ root.setAttribute('attr', '\n');
+ assert_in_array(serialize(root), [
+ '<root attr="&#xA;"/>', '<root attr="&#10;"/>']);
+ root.setAttribute('attr', '\r');
+ assert_in_array(serialize(root), [
+ '<root attr="&#xD;"/>', '<root attr="&#13;"/>']);
+}, 'check XMLSerializer.serializeToString escapes attribute values for roundtripping');
+
+test(function() {
+ const root = (new Document()).createElement('root');
+ root.setAttributeNS('uri1', 'p:foobar', 'value1');
+ root.setAttributeNS(XMLNS_URI, 'xmlns:p', 'uri2');
+ assert_equals(serialize(root), '<root xmlns:ns1="uri1" ns1:foobar="value1" xmlns:p="uri2"/>');
+}, 'Check if attribute serialization takes into account of following xmlns:* attributes');
+
+test(function() {
+ const root = parse('<root xmlns:p="uri1"><child/></root>');
+ root.firstChild.setAttributeNS('uri2', 'p:foobar', 'v');
+ assert_equals(serialize(root), '<root xmlns:p="uri1"><child xmlns:ns1="uri2" ns1:foobar="v"/></root>');
+}, 'Check if attribute serialization takes into account of the same prefix declared in an ancestor element');
+
+test(function() {
+ assert_equals(serialize(parse('<root><child/></root>')), '<root><child/></root>');
+ assert_equals(serialize(parse('<root xmlns="u1"><p:child xmlns:p="u1"/></root>')), '<root xmlns="u1"><child xmlns:p="u1"/></root>');
+}, 'Check if start tag serialization drops element prefix if the namespace is same as inherited default namespace.');
+
+test(function() {
+ const root = parse('<root xmlns:p1="u1"><child xmlns:p2="u1"/></root>');
+ const child2 = root.ownerDocument.createElementNS('u1', 'child2');
+ root.firstChild.appendChild(child2);
+ assert_equals(serialize(root), '<root xmlns:p1="u1"><child xmlns:p2="u1"><p2:child2/></child></root>');
+}, 'Check if start tag serialization finds an appropriate prefix.');
+
+test(function() {
+ const root = (new Document()).createElementNS('uri1', 'p:root');
+ root.setAttributeNS(XMLNS_URI, 'xmlns:p', 'uri2');
+ assert_equals(serialize(root), '<ns1:root xmlns:ns1="uri1" xmlns:p="uri2"/>');
+}, 'Check if start tag serialization takes into account of its xmlns:* attributes');
+
+test(function() {
+ const root = (new Document()).createElement('root');
+ root.setAttributeNS(XMLNS_URI, 'xmlns:p', 'uri2');
+ const child = root.ownerDocument.createElementNS('uri1', 'p:child');
+ root.appendChild(child);
+ assert_equals(serialize(root), '<root xmlns:p="uri2"><p:child xmlns:p="uri1"/></root>');
+}, 'Check if start tag serialization applied the original prefix even if it is declared in an ancestor element.');
+
+// https://github.com/w3c/DOM-Parsing/issues/52
+test(function() {
+ assert_equals(serialize(parse('<root xmlns:x="uri1"><table xmlns="uri1"></table></root>')),
+ '<root xmlns:x="uri1"><x:table xmlns="uri1"/></root>');
+}, 'Check if start tag serialization does NOT apply the default namespace if its namespace is declared in an ancestor.');
+
+test(function() {
+ const root = parse('<root><child1/><child2/></root>');
+ root.firstChild.setAttributeNS('uri1', 'attr1', 'value1');
+ root.firstChild.setAttributeNS('uri2', 'attr2', 'value2');
+ root.lastChild.setAttributeNS('uri3', 'attr3', 'value3');
+ assert_equals(serialize(root), '<root><child1 xmlns:ns1="uri1" ns1:attr1="value1" xmlns:ns2="uri2" ns2:attr2="value2"/><child2 xmlns:ns3="uri3" ns3:attr3="value3"/></root>');
+}, 'Check if generated prefixes match to "ns${index}".');
+
+// https://github.com/w3c/DOM-Parsing/issues/44
+// According to 'DOM Parsing and Serialization' draft as of 2018-12-11,
+// 'generate a prefix' result can conflict with an existing xmlns:ns* declaration.
+test(function() {
+ const root = parse('<root xmlns:ns2="uri2"><child xmlns:ns1="uri1"/></root>');
+ root.firstChild.setAttributeNS('uri3', 'attr1', 'value1');
+ assert_equals(serialize(root), '<root xmlns:ns2="uri2"><child xmlns:ns1="uri1" xmlns:ns1="uri3" ns1:attr1="value1"/></root>');
+}, 'Check if "ns1" is generated even if the element already has xmlns:ns1.');
+
+test(function() {
+ const root = (new Document()).createElement('root');
+ root.setAttributeNS('http://www.w3.org/1999/xlink', 'href', 'v');
+ assert_equals(serialize(root), '<root xmlns:ns1="http://www.w3.org/1999/xlink" ns1:href="v"/>');
+
+ const root2 = (new Document()).createElement('root');
+ root2.setAttributeNS('http://www.w3.org/1999/xlink', 'xl:type', 'v');
+ assert_equals(serialize(root2), '<root xmlns:xl="http://www.w3.org/1999/xlink" xl:type="v"/>');
+}, 'Check if no special handling for XLink namespace unlike HTML serializer.');
+
+test(function() {
+ var root = new DocumentFragment;
+ root.append(document.createElement('div'));
+ root.append(document.createElement('span'));
+ assert_equals(serialize(root), '<div xmlns="http://www.w3.org/1999/xhtml"></div><span xmlns="http://www.w3.org/1999/xhtml"></span>');
+}, 'Check if document fragment serializes.');
+
+
+</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/domparsing/createContextualFragment.html b/testing/web-platform/tests/domparsing/createContextualFragment.html
new file mode 100644
index 0000000000..170c0c464d
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/createContextualFragment.html
@@ -0,0 +1,179 @@
+<!doctype html>
+<title>createContextualFragment() tests</title>
+<div id=log></div>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+// We are not testing XML documents here, because apparently it's not clear
+// what we want to happen there. We also aren't testing the HTML parser in any
+// depth, just some basic sanity checks.
+
+// Exception-throwing
+test(function() {
+ var range = document.createRange();
+ range.detach();
+ range.createContextualFragment("");
+}, "Must not throw INVALID_STATE_ERR for a detached node.");
+
+test(function() {
+ var range = document.createRange();
+ assert_throws_js(TypeError, function() {
+ range.createContextualFragment();
+ });
+}, "Must throw TypeError when calling without arguments");
+
+test(function() {
+ // Simple test
+ var range = document.createRange();
+ range.selectNodeContents(document.body);
+
+ var fragment = "<p CLaSs=testclass> Hi! <p>Hi!";
+ var expected = document.createDocumentFragment();
+ var tmpNode = document.createElement("p");
+ tmpNode.setAttribute("class", "testclass");
+ tmpNode.appendChild(document.createTextNode(" Hi! "));
+ expected.appendChild(tmpNode);
+
+ tmpNode = document.createElement("p");
+ tmpNode.appendChild(document.createTextNode("Hi!"));
+ expected.appendChild(tmpNode);
+
+ var result = range.createContextualFragment(fragment);
+ assert_true(expected.isEqualNode(result),
+ "Unexpected result (collapsed Range)");
+
+ // Token test that the end node makes no difference
+ range.setEnd(document.body.getElementsByTagName("script")[0], 0);
+ result = range.createContextualFragment(fragment);
+ assert_true(expected.isEqualNode(result),
+ "Unexpected result (Range ends in <script>)");
+}, "Simple test with paragraphs");
+
+test(function() {
+ // This test based on https://bugzilla.mozilla.org/show_bug.cgi?id=585819,
+ // from a real-world compat bug
+ var range = document.createRange();
+ range.selectNodeContents(document.documentElement);
+ var fragment = "<span>Hello world</span>";
+ var expected = document.createDocumentFragment();
+ var tmpNode = document.createElement("span");
+ tmpNode.appendChild(document.createTextNode("Hello world"));
+ expected.appendChild(tmpNode);
+
+ var result = range.createContextualFragment(fragment);
+ assert_true(expected.isEqualNode(result),
+ "Unexpected result (collapsed Range)");
+
+ // Another token test that the end node makes no difference
+ range.setEnd(document.head, 0);
+ result = range.createContextualFragment(fragment);
+ assert_true(expected.isEqualNode(result),
+ "Unexpected result (Range ends in <head>)");
+}, "Don't auto-create <body> when applied to <html>");
+
+// Scripts should be run if inserted (that's what the "Unmark all scripts
+// . . ." line means, I'm told)
+var passed = false;
+test(function() {
+ assert_false(passed, "Sanity check");
+ var range = document.createRange();
+ range.selectNodeContents(document.documentElement);
+ var fragment = range.createContextualFragment("<script>passed = true</s" + "cript>");
+ assert_false(passed, "Fragment created but not yet added to document, should not have run");
+ document.body.appendChild(fragment);
+ assert_true(passed, "Fragment created and added to document, should run");
+}, "<script>s should be run when appended to the document (but not before)");
+
+// Historical bugs in browsers; see https://github.com/whatwg/html/issues/2222
+
+[
+ // Void
+ "area",
+ "base",
+ "basefont",
+ "bgsound",
+ "br",
+ "col",
+ "embed",
+ "frame",
+ "hr",
+ "img",
+ "input",
+ "keygen",
+ "link",
+ "meta",
+ "param",
+ "source",
+ "track",
+ "wbr",
+
+ // Historical
+ "menuitem",
+ "image"
+].forEach(name => {
+ test(() => {
+ const range = document.createRange();
+ const contextNode = document.createElement(name);
+ const selectedNode = document.createElement("div");
+ contextNode.appendChild(selectedNode);
+ range.selectNode(selectedNode);
+
+ range.createContextualFragment("some text");
+ }, `createContextualFragment should work even when the context is <${name}>`);
+});
+
+
+// Now that we've established basic sanity, let's do equivalence tests. Those
+// are easier to write anyway.
+function testEquivalence(element1, fragment1, element2, fragment2) {
+ var range1 = element1.ownerDocument.createRange();
+ range1.selectNodeContents(element1);
+ var range2 = element2.ownerDocument.createRange();
+ range2.selectNodeContents(element2);
+
+ var result1 = range1.createContextualFragment(fragment1);
+ var result2 = range2.createContextualFragment(fragment2);
+
+ assert_true(result1.isEqualNode(result2), "Results are supposed to be equivalent");
+
+ // Throw in partial ownerDocument tests on the side, since the algorithm
+ // does specify that and we don't want to completely not test it.
+ if (result1.firstChild != null) {
+ assert_equals(result1.firstChild.ownerDocument, element1.ownerDocument,
+ "ownerDocument must be set to that of the reference node");
+ }
+ if (result2.firstChild != null) {
+ assert_equals(result2.firstChild.ownerDocument, element2.ownerDocument,
+ "ownerDocument must be set to that of the reference node");
+ }
+}
+
+var doc_fragment = document.createDocumentFragment();
+var comment = document.createComment("~o~");
+doc_fragment.appendChild(comment);
+
+var tests = [
+ ["<html> and <body> must work the same, 1", document.documentElement, "<span>Hello world</span>", document.body, "<span>Hello world</span>"],
+ ["<html> and <body> must work the same, 2", document.documentElement, "<body><p>Hello world", document.body, "<body><p>Hello world"],
+ ["Implicit <body> creation", document.documentElement, "<body><p>", document.documentElement, "<p>"],
+ ["Namespace generally shouldn't matter",
+ document.createElementNS("http://fake-namespace", "div"), "<body><p><span>Foo",
+ document.createElement("div"), "<body><p><span>Foo"],
+ ["<html> in a different namespace shouldn't be special",
+ document.createElementNS("http://fake-namespace", "html"), "<body><p>",
+ document.createElement("div"), "<body><p>"],
+ ["SVG namespace shouldn't be special",
+ document.createElementNS("http://www.w3.org/2000/svg", "div"), "<body><p>",
+ document.createElement("div"), "<body><p>"],
+ ["null should be stringified", document.createElement("span"), null, document.createElement("span"), "null"],
+ ["undefined should be stringified", document.createElement("span"), undefined, document.createElement("span"), "undefined"],
+ ["Text nodes shouldn't be special",
+ document.createTextNode("?"), "<body><p>",
+ document.createElement("div"), "<body><p>"],
+ ["Non-Element parent should not be special",
+ comment, "<body><p>",
+ document.createElement("div"), "<body><p>"]
+];
+
+generate_tests(testEquivalence, tests);
+</script>
diff --git a/testing/web-platform/tests/domparsing/idlharness.window.js b/testing/web-platform/tests/domparsing/idlharness.window.js
new file mode 100644
index 0000000000..f5f32b3bb5
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/idlharness.window.js
@@ -0,0 +1,18 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+'use strict';
+
+// https://w3c.github.io/DOM-Parsing/
+
+idl_test(
+ ['DOM-Parsing'],
+ ['dom'],
+ idlArray => {
+ idlArray.add_objects({
+ Element: ['document.createElement("div")'],
+ Range: ['new Range()'],
+ XMLSerializer: ['new XMLSerializer()'],
+ })
+ }
+);
diff --git a/testing/web-platform/tests/domparsing/innerhtml-01.xhtml b/testing/web-platform/tests/domparsing/innerhtml-01.xhtml
new file mode 100644
index 0000000000..08345ac58b
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/innerhtml-01.xhtml
@@ -0,0 +1,28 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>innerHTML in XHTML: getting while the document is in an invalid state</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/>
+<link rel="help" href="https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML"/>
+<link rel="help" href="http://www.whatwg.org/html5/#xml-fragment-serialization-algorithm"/>
+<link rel="help" href="http://www.whatwg.org/html5/#document.title"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function() {
+ document.documentElement.appendChild(document.createElement("test:test"));
+ assert_throws_dom("INVALID_STATE_ERR", function() {
+ document.documentElement.innerHTML;
+ }, "getting element with \":\" in its local name");
+});
+test(function() {
+ document.title = "\f";
+ assert_throws_dom("INVALID_STATE_ERR", function() {
+ document.getElementsByTagName("title")[0].innerHTML;
+ }, "Getting a Text node whose data contains characters that are not matched by the XML Char production");
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/domparsing/innerhtml-03.xhtml b/testing/web-platform/tests/domparsing/innerhtml-03.xhtml
new file mode 100644
index 0000000000..313531e49c
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/innerhtml-03.xhtml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>innerHTML in XHTML</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/>
+<link rel="help" href="http://html5.org/specs/dom-parsing.html#dom-innerhtml"/>
+<link rel="help" href="http://www.whatwg.org/html5/#xml-fragment-serialization-algorithm"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script><![CDATA[
+test(function() {
+ var el = document.createElement("div");
+ el.appendChild(document.createElement("xmp"))
+ .appendChild(document.createElement("span"))
+ .appendChild(document.createTextNode("<"));
+ assert_equals(el.innerHTML, "<xmp xmlns=\"http://www.w3.org/1999/xhtml\"><span>&lt;<\/span><\/xmp>");
+})
+test(function() {
+ var el = document.createElement("xmp");
+ el.appendChild(document.createElement("span"))
+ .appendChild(document.createTextNode("<"));
+ assert_equals(el.innerHTML, "<span xmlns=\"http://www.w3.org/1999/xhtml\">&lt;<\/span>");
+})
+test(function() {
+ var el = document.createElement("xmp");
+ el.appendChild(document.createTextNode("<"));
+ assert_equals(el.innerHTML, "&lt;");
+})
+test(function() {
+ var el = document.createElement("div");
+ el.appendChild(document.createElement("br"));
+ assert_equals(el.innerHTML, "<br xmlns=\"http://www.w3.org/1999/xhtml\" />");
+})
+test(function() {
+ var el = document.createElement("div");
+ el.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "html:br"));
+ assert_equals(el.innerHTML, "<html:br xmlns:html=\"http://www.w3.org/1999/xhtml\" />");
+})
+test(function() {
+ var el = document.createElement("div");
+ el.appendChild(document.createTextNode("<>\"'&"));
+ assert_equals(el.innerHTML, "&lt;&gt;\"'&amp;");
+})
+test(function() {
+ var el = document.createElement("div");
+ el.appendChild(document.createTextNode("&lt;&gt;&quot;&apos;&amp;"));
+ assert_equals(el.innerHTML, "&amp;lt;&amp;gt;&amp;quot;&amp;apos;&amp;amp;");
+})
+test(function() {
+ var el = document.createElement("div");
+ el.appendChild(document.createTextNode("àו…\u00A0"));
+ assert_equals(el.innerHTML, "àו…\u00A0");
+})
+]]></script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/domparsing/innerhtml-04.html b/testing/web-platform/tests/domparsing/innerhtml-04.html
new file mode 100644
index 0000000000..32c921d235
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/innerhtml-04.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>innerHTML in HTML</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel="help" href="https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML">
+<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.innerHTML = "";
+ testIsChild(b, t);
+ assert_equals(t.data, "foo");
+}, "innerHTML should leave the removed children alone.")
+</script>
diff --git a/testing/web-platform/tests/domparsing/innerhtml-05.xhtml b/testing/web-platform/tests/domparsing/innerhtml-05.xhtml
new file mode 100644
index 0000000000..3afb681523
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/innerhtml-05.xhtml
@@ -0,0 +1,26 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>innerHTML in XHTML</title>
+<link rel="author" title="Simon Pieters" href="mailto:simonp@opera.com"/>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/>
+<link rel="help" href="http://html5.org/specs/dom-parsing.html#dom-innerhtml"/>
+<link rel="help" href="http://www.whatwg.org/html5/#xml-fragment-serialization-algorithm"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<iframe src="data:text/xml,&lt;html xmlns='http://www.w3.org/1999/xhtml'>&lt;foo--/>&lt;/html>"></iframe>
+<script><![CDATA[
+var t = async_test();
+window.onload = t.step_func(function() {
+ var foo = window[0].document.documentElement.firstChild;
+ assert_throws_dom('SyntaxError', function() {
+ foo.innerHTML = 'x<\/foo--><\!--y';
+ // This is ridiculous.
+ });
+ t.done();
+});
+]]></script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/domparsing/innerhtml-06.html b/testing/web-platform/tests/domparsing/innerhtml-06.html
new file mode 100644
index 0000000000..81e9c57b5c
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/innerhtml-06.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>math in html: innerHTML</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<h1>math in html: innerHTML</h1>
+<div id="log"></div>
+<div style="display:none">
+<div id="d1"><math><mi>x</mi></math></div>
+</div>
+<script>
+test(function() {
+ var math = document.getElementById("d1").firstChild;
+ assert_equals(math.innerHTML, "<mi>x</mi>");
+},"innerHTML defined on math.");
+</script>
diff --git a/testing/web-platform/tests/domparsing/innerhtml-07.html b/testing/web-platform/tests/domparsing/innerhtml-07.html
new file mode 100644
index 0000000000..b48b421eff
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/innerhtml-07.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>innerHTML and string conversion</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel="help" href="https://w3c.github.io/DOM-Parsing/#extensions-to-the-element-interface">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ var p = document.createElement("p");
+ p.innerHTML = null;
+ assert_equals(p.innerHTML, "");
+ assert_equals(p.textContent, "");
+}, "innerHTML and string conversion: null.")
+
+test(function() {
+ var p = document.createElement("p");
+ p.innerHTML = undefined;
+ assert_equals(p.innerHTML, "undefined");
+ assert_equals(p.textContent, "undefined");
+}, "innerHTML and string conversion: undefined.")
+
+test(function() {
+ var p = document.createElement("p");
+ p.innerHTML = 42;
+ assert_equals(p.innerHTML, "42");
+ assert_equals(p.textContent, "42");
+}, "innerHTML and string conversion: number.")
+
+test(function() {
+ var p = document.createElement("p");
+ p.innerHTML = {
+ toString: function() { return "pass"; },
+ valueOf: function() { return "fail"; }
+ };
+ assert_equals(p.innerHTML, "pass");
+ assert_equals(p.textContent, "pass");
+}, "innerHTML and string conversion: toString.")
+
+test(function() {
+ var p = document.createElement("p");
+ p.innerHTML = {
+ toString: undefined,
+ valueOf: function() { return "pass"; }
+ };
+ assert_equals(p.innerHTML, "pass");
+ assert_equals(p.textContent, "pass");
+}, "innerHTML and string conversion: valueOf.")
+</script>
diff --git a/testing/web-platform/tests/domparsing/innerhtml-mxss.sub.html b/testing/web-platform/tests/domparsing/innerhtml-mxss.sub.html
new file mode 100644
index 0000000000..7563d892d9
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/innerhtml-mxss.sub.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <div><a></a></div>
+ <script>
+ var whitespaces = [
+ "1680", "2000", "2001", "2002", "2003", "2004", "2005", "2006", "2007",
+ "2008", "2009", "200a", "2028", "205f", "3000"
+ ];
+
+ for (var i = 0; i < whitespaces.length; i++) {
+ var container = document.querySelector('a').parentNode;
+ var entity = `&#x${whitespaces[i]};`;
+ var character = String.fromCharCode(parseInt(whitespaces[i], 16));
+ var url = encodeURIComponent(character);
+ container.innerHTML = `<a href="${entity}javascript:alert(1)">Link</a>`;
+
+ var a = document.querySelector('a');
+
+ test(_ => {
+ assert_equals(
+ container.innerHTML,
+ `<a href="${character}javascript:alert(1)">Link</a>`);
+ }, `innerHTML before setter: ${whitespaces[i]}`);
+ test(_ => {
+ assert_equals(
+ a.href,
+ `http://{{host}}:{{ports[http][0]}}/domparsing/${url}javascript:alert(1)`);
+ }, `href before setter: ${whitespaces[i]}`);
+
+ a.parentNode.innerHTML += 'foo';
+ a = document.querySelector('a');
+
+ test(_ => {
+ assert_equals(
+ container.innerHTML,
+ `<a href="${character}javascript:alert(1)">Link</a>foo`);
+ }, `innerHTML after setter: ${whitespaces[i]}`);
+ test(_ => {
+ assert_equals(
+ a.href,
+ `http://{{host}}:{{ports[http][0]}}/domparsing/${url}javascript:alert(1)`);
+ }, `href after setter: ${whitespaces[i]}`);
+ }
+ </script>
+</body>
diff --git a/testing/web-platform/tests/domparsing/insert-adjacent.html b/testing/web-platform/tests/domparsing/insert-adjacent.html
new file mode 100644
index 0000000000..f43ec406e4
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/insert-adjacent.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>insertAdjacentHTML</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+#element {
+ display: none;
+}
+</style>
+
+<div id="element"></div>
+<div id="log"></div>
+
+<script>
+function wrap(text) {
+ return '<h3>' + text + '</h3>';
+}
+
+var possiblePositions = {
+ 'beforebegin': 'previousSibling'
+ , 'afterbegin': 'firstChild'
+ , 'beforeend': 'lastChild'
+ , 'afterend': 'nextSibling'
+}
+
+var el = document.querySelector('#element');
+
+Object.keys(possiblePositions).forEach(function(position) {
+ var html = wrap(position);
+ test(function() {
+ el.insertAdjacentHTML(position, html);
+ var heading = document.createElement('h3');
+ heading.innerHTML = position;
+ assert_equals(el[possiblePositions[position]].nodeName, "H3");
+ assert_equals(el[possiblePositions[position]].firstChild.nodeType, Node.TEXT_NODE);
+ }, 'insertAdjacentHTML(' + position + ', ' + html + ' )');
+});
+</script>
diff --git a/testing/web-platform/tests/domparsing/insert_adjacent_html-xhtml.xhtml b/testing/web-platform/tests/domparsing/insert_adjacent_html-xhtml.xhtml
new file mode 100644
index 0000000000..f02f425c47
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/insert_adjacent_html-xhtml.xhtml
@@ -0,0 +1,91 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>insertAdjacentHTML in HTML</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="insert_adjacent_html.js"></script>
+</head>
+<body>
+<p id="display"></p><div id="content" style="display: none"></div><div id="content2" style="display: none"></div>
+<script><![CDATA[
+var script_ran = false;
+
+function testPositions(node, testDesc) {
+ test(function() {
+ script_ran = false;
+ node.insertAdjacentHTML("beforeBegin", "\u003Cscript>script_ran = true;\u003C/script><i></i>");
+ assert_equals(node.previousSibling.localName, "i", "Should have had <i> as previous sibling");
+ assert_equals(node.previousSibling.previousSibling.localName, "script", "Should have had <script> as second previous child");
+ assert_false(script_ran, "script should not have run");
+ }, "beforeBegin " + node.id + " " + testDesc)
+
+ test(function() {
+ script_ran = false;
+ node.insertAdjacentHTML("Afterbegin", "<b></b>\u003Cscript>script_ran = true;\u003C/script>");
+ assert_equals(node.firstChild.localName, "b", "Should have had <b> as first child");
+ assert_equals(node.firstChild.nextSibling.localName, "script", "Should have had <script> as second child");
+ assert_false(script_ran, "script should not have run");
+ }, "Afterbegin " + node.id + " " + testDesc);
+
+ test(function() {
+ script_ran = false;
+ node.insertAdjacentHTML("BeforeEnd", "\u003Cscript>script_ran = true;\u003C/script><u></u>");
+ assert_equals(node.lastChild.localName, "u", "Should have had <u> as last child");
+ assert_equals(node.lastChild.previousSibling.localName, "script", "Should have had <script> as penultimate child");
+ assert_false(script_ran, "script should not have run");
+ }, "BeforeEnd " + node.id + " " + testDesc)
+
+ test(function() {
+ script_ran = false;
+ node.insertAdjacentHTML("afterend", "<a></a>\u003Cscript>script_ran = true;\u003C/script>");
+ assert_equals(node.nextSibling.localName, "a", "Should have had <a> as next sibling");
+ assert_equals(node.nextSibling.nextSibling.localName, "script", "Should have had <script> as second next sibling");
+ assert_false(script_ran, "script should not have run");
+ }, "afterend " + node.id + " " + testDesc)
+}
+
+var content = document.getElementById("content");
+testPositions(content, "without next sibling");
+testPositions(content, "again, with next sibling");
+
+test(function() {
+ assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("bar", "foo")});
+ assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("beforebegİn", "foo")});
+ assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("beforebegın", "foo")});
+}, "Should throw when inserting with invalid position string");
+
+var parentElement = document.createElement("div");
+var child = document.createElement("div");
+child.id = "child";
+
+testThrowingNoParent(child, "null");
+testThrowingNoParent(document.documentElement, "a document");
+
+test(function() {
+ child.insertAdjacentHTML("afterBegin", "foo");
+ child.insertAdjacentHTML("beforeend", "bar");
+ assert_equals(child.textContent, "foobar");
+ parentElement.appendChild(child);
+}, "Inserting after being and before end should order things correctly");
+
+testPositions(child, "node not in tree but has parent");
+
+test(function() {
+ script_ran = false;
+ content.appendChild(parentElement); // must not run scripts
+ assert_false(script_ran, "script should not have run");
+}, "Should not run script when appending things which have descendant <script> inserted via insertAdjacentHTML");
+
+var content2 = document.getElementById("content2");
+testPositions(content2, "without next sibling");
+testPositions(content2, "test again, now that there's a next sibling");
+
+// XML-only:
+test(function() {
+ assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("beforeend", "<p>")});
+});
+
+]]></script>
+<div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/domparsing/insert_adjacent_html.html b/testing/web-platform/tests/domparsing/insert_adjacent_html.html
new file mode 100644
index 0000000000..d8b3874819
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/insert_adjacent_html.html
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>insertAdjacentHTML in HTML</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="insert_adjacent_html.js"></script>
+</head>
+<body>
+<p id="display"></p><div id="content" style="display: none"></div><div id="content2" style="display: none"></div>
+<script>
+var script_ran = false;
+
+function testPositions(node, testDesc) {
+ test(function() {
+ script_ran = false;
+ node.insertAdjacentHTML("beforeBegin", "\u003Cscript>script_ran = true;\u003C/script><i></i>");
+ assert_equals(node.previousSibling.localName, "i", "Should have had <i> as previous sibling");
+ assert_equals(node.previousSibling.previousSibling.localName, "script", "Should have had <script> as second previous child");
+ assert_false(script_ran, "script should not have run");
+ }, "beforeBegin " + node.id + " " + testDesc)
+
+ test(function() {
+ script_ran = false;
+ node.insertAdjacentHTML("Afterbegin", "<b></b>\u003Cscript>script_ran = true;\u003C/script>");
+ assert_equals(node.firstChild.localName, "b", "Should have had <b> as first child");
+ assert_equals(node.firstChild.nextSibling.localName, "script", "Should have had <script> as second child");
+ assert_false(script_ran, "script should not have run");
+ }, "Afterbegin " + node.id + " " + testDesc);
+
+ test(function() {
+ script_ran = false;
+ node.insertAdjacentHTML("BeforeEnd", "\u003Cscript>script_ran = true;\u003C/script><u></u>");
+ assert_equals(node.lastChild.localName, "u", "Should have had <u> as last child");
+ assert_equals(node.lastChild.previousSibling.localName, "script", "Should have had <script> as penultimate child");
+ assert_false(script_ran, "script should not have run");
+ }, "BeforeEnd " + node.id + " " + testDesc)
+
+ test(function() {
+ script_ran = false;
+ node.insertAdjacentHTML("afterend", "<a></a>\u003Cscript>script_ran = true;\u003C/script>");
+ assert_equals(node.nextSibling.localName, "a", "Should have had <a> as next sibling");
+ assert_equals(node.nextSibling.nextSibling.localName, "script", "Should have had <script> as second next sibling");
+ assert_false(script_ran, "script should not have run");
+ }, "afterend " + node.id + " " + testDesc)
+}
+
+var content = document.getElementById("content");
+testPositions(content, "without next sibling");
+testPositions(content, "again, with next sibling");
+
+test(function() {
+ assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("bar", "foo")});
+ assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("beforebegİn", "foo")});
+ assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("beforebegın", "foo")});
+}, "Should throw when inserting with invalid position string");
+
+var parentElement = document.createElement("div");
+var child = document.createElement("div");
+child.id = "child";
+
+testThrowingNoParent(child, "null");
+testThrowingNoParent(document.documentElement, "a document");
+
+test(function() {
+ child.insertAdjacentHTML("afterBegin", "foo");
+ child.insertAdjacentHTML("beforeend", "bar");
+ assert_equals(child.textContent, "foobar");
+ parentElement.appendChild(child);
+}, "Inserting after being and before end should order things correctly");
+
+testPositions(child, "node not in tree but has parent");
+
+test(function() {
+ script_ran = false;
+ content.appendChild(parentElement); // must not run scripts
+ assert_false(script_ran, "script should not have run");
+}, "Should not run script when appending things which have descendant <script> inserted via insertAdjacentHTML");
+
+var content2 = document.getElementById("content2");
+testPositions(content2, "without next sibling");
+testPositions(content2, "test again, now that there's a next sibling");
+
+// HTML only
+test(function() {
+ document.body.insertAdjacentHTML("afterend", "<p>");
+ document.head.insertAdjacentHTML("beforebegin", "<p>");
+ assert_equals(document.getElementsByTagName("head").length, 1, "Should still have one head");
+ assert_equals(document.getElementsByTagName("body").length, 1, "Should still have one body");
+}, "Inserting kids of the <html> element should not do weird things with implied <body>/<head> tags")
+</script>
+<div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/domparsing/insert_adjacent_html.js b/testing/web-platform/tests/domparsing/insert_adjacent_html.js
new file mode 100644
index 0000000000..2980037433
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/insert_adjacent_html.js
@@ -0,0 +1,33 @@
+function testThrowingNoParent(element, desc) {
+ test(function() {
+ assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR",
+ function() { element.insertAdjacentHTML("afterend", "") }
+ );
+ assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR",
+ function() { element.insertAdjacentHTML("beforebegin", "") }
+ );
+ assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR",
+ function() { element.insertAdjacentHTML("afterend", "foo") }
+ );
+ assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR",
+ function() { element.insertAdjacentHTML("beforebegin", "foo") }
+ );
+ }, "When the parent node is " + desc + ", insertAdjacentHTML should throw for beforebegin and afterend (text)");
+ test(function() {
+ assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR",
+ function() { element.insertAdjacentHTML("afterend", "<!-- fail -->") }
+ );
+ assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR",
+ function() { element.insertAdjacentHTML("beforebegin", "<!-- fail -->") }
+ );
+ }, "When the parent node is " + desc + ", insertAdjacentHTML should throw for beforebegin and afterend (comments)");
+ test(function() {
+ assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR",
+ function() { element.insertAdjacentHTML("afterend", "<div></div>") }
+ );
+ assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR",
+ function() { element.insertAdjacentHTML("beforebegin", "<div></div>") }
+ );
+ }, "When the parent node is " + desc + ", insertAdjacentHTML should throw for beforebegin and afterend (elements)");
+}
+
diff --git a/testing/web-platform/tests/domparsing/outerhtml-01.html b/testing/web-platform/tests/domparsing/outerhtml-01.html
new file mode 100644
index 0000000000..d9a38b7045
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/outerhtml-01.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>outerHTML: child of #document</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel="help" href="http://html5.org/specs/dom-parsing.html#outerhtml">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR", function() {
+ document.documentElement.outerHTML = "<html><p>FAIL: Should have thrown an error<\/p><\/html>";
+ })
+});
+</script>
+
diff --git a/testing/web-platform/tests/domparsing/outerhtml-02.html b/testing/web-platform/tests/domparsing/outerhtml-02.html
new file mode 100644
index 0000000000..1ce5df03e4
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/outerhtml-02.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<title>outerHTML and string conversion</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel="help" href="https://w3c.github.io/DOM-Parsing/#extensions-to-the-element-interface">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ var div = document.createElement("div");
+ var p = div.appendChild(document.createElement("p"));
+ p.outerHTML = null;
+ assert_equals(div.innerHTML, "");
+ assert_equals(div.textContent, "");
+}, "outerHTML and string conversion: null.")
+
+test(function() {
+ var div = document.createElement("div");
+ var p = div.appendChild(document.createElement("p"));
+ p.outerHTML = undefined;
+ assert_equals(div.innerHTML, "undefined");
+ assert_equals(div.textContent, "undefined");
+}, "outerHTML and string conversion: undefined.")
+
+test(function() {
+ var div = document.createElement("div");
+ var p = div.appendChild(document.createElement("p"));
+ p.outerHTML = 42;
+ assert_equals(div.innerHTML, "42");
+ assert_equals(div.textContent, "42");
+}, "outerHTML and string conversion: number.")
+
+test(function() {
+ var div = document.createElement("div");
+ var p = div.appendChild(document.createElement("p"));
+ p.outerHTML = {
+ toString: function() { return "pass"; },
+ valueOf: function() { return "fail"; }
+ };
+ assert_equals(div.innerHTML, "pass");
+ assert_equals(div.textContent, "pass");
+}, "outerHTML and string conversion: toString.")
+
+test(function() {
+ var div = document.createElement("div");
+ var p = div.appendChild(document.createElement("p"));
+ p.outerHTML = {
+ toString: undefined,
+ valueOf: function() { return "pass"; }
+ };
+ assert_equals(div.innerHTML, "pass");
+ assert_equals(div.textContent, "pass");
+}, "outerHTML and string conversion: valueOf.")
+</script>
diff --git a/testing/web-platform/tests/domparsing/resources/domparser-iframe-base-pushstate.html b/testing/web-platform/tests/domparsing/resources/domparser-iframe-base-pushstate.html
new file mode 100644
index 0000000000..9c4a1bd07a
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/resources/domparser-iframe-base-pushstate.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>An iframe that does DOMParser 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="/domparsing/resources/domparser-iframe.js"></script>
diff --git a/testing/web-platform/tests/domparsing/resources/domparser-iframe-base.html b/testing/web-platform/tests/domparsing/resources/domparser-iframe-base.html
new file mode 100644
index 0000000000..e8a084b7dc
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/resources/domparser-iframe-base.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>An iframe that does DOMParser stuff with base</title>
+<base href="/fake/base-from-iframe">
+
+<script src="/domparsing/resources/domparser-iframe.js"></script>
diff --git a/testing/web-platform/tests/domparsing/resources/domparser-iframe-pushstate.html b/testing/web-platform/tests/domparsing/resources/domparser-iframe-pushstate.html
new file mode 100644
index 0000000000..b2821c6994
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/resources/domparser-iframe-pushstate.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>An iframe that does DOMParser stuff and pushstates itself</title>
+
+<script>
+"use strict";
+history.pushState(null, "", "/fake/push-state-from-iframe");
+</script>
+<script src="/domparsing/resources/domparser-iframe.js"></script>
diff --git a/testing/web-platform/tests/domparsing/resources/domparser-iframe.html b/testing/web-platform/tests/domparsing/resources/domparser-iframe.html
new file mode 100644
index 0000000000..710f141bb9
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/resources/domparser-iframe.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>An iframe that does DOMParser stuff</title>
+<script src="/domparsing/resources/domparser-iframe.js"></script>
diff --git a/testing/web-platform/tests/domparsing/resources/domparser-iframe.js b/testing/web-platform/tests/domparsing/resources/domparser-iframe.js
new file mode 100644
index 0000000000..a62d2f293b
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/resources/domparser-iframe.js
@@ -0,0 +1,4 @@
+window.doParse = (html, mimeType) => {
+ const parser = new DOMParser();
+ return parser.parseFromString(html, mimeType);
+};
diff --git a/testing/web-platform/tests/domparsing/resources/domparser-url-tests.js b/testing/web-platform/tests/domparsing/resources/domparser-url-tests.js
new file mode 100644
index 0000000000..7b02fab1c3
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/resources/domparser-url-tests.js
@@ -0,0 +1,72 @@
+const loadPromise = new Promise(resolve => { window.resolveLoadPromise = resolve; });
+
+function assertURL(doc, expectedURL) {
+ assert_equals(doc.URL, expectedURL, "document.URL");
+ assert_equals(doc.documentURI, expectedURL, "document.documentURI");
+ assert_equals(doc.baseURI, expectedURL, "document.baseURI");
+}
+
+const supportedTypes = [
+ "text/html",
+ "text/xml",
+ "application/xml",
+ "application/xhtml+xml",
+ "image/svg+xml",
+];
+
+const invalidXML = `<span x:test="testing">1</span>`;
+const inputs = {
+ valid: "<html></html>",
+ "invalid XML": invalidXML
+};
+
+for (const mimeType of supportedTypes) {
+ for (const [inputName, input] of Object.entries(inputs)) {
+ if (mimeType === "text/html" && input === invalidXML) {
+ continue;
+ }
+
+ test(() => {
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(input, mimeType);
+
+ assertURL(doc, document.URL);
+ }, `${mimeType} ${inputName}: created normally`);
+
+ promise_test(async () => {
+ await loadPromise;
+
+ const parser = new frames[0].DOMParser();
+ const doc = parser.parseFromString(input, mimeType);
+
+ assertURL(doc, frames[0].document.URL);
+ }, `${mimeType} ${inputName}: created using another iframe's DOMParser from this frame`);
+
+ promise_test(async () => {
+ await loadPromise;
+
+ const parser = new frames[0].DOMParser();
+ const doc = frames[0].doParse(input, mimeType);
+
+ assertURL(doc, frames[0].document.URL);
+ }, `${mimeType} ${inputName}: created using another iframe's DOMParser from that frame`);
+
+ promise_test(async () => {
+ await loadPromise;
+
+ const parser = new DOMParser();
+ const doc = frames[0].DOMParser.prototype.parseFromString.call(parser, input, mimeType);
+
+ assertURL(doc, document.URL);
+ }, `${mimeType} ${inputName}: created using a parser from this frame and the method from the iframe`);
+
+ promise_test(async () => {
+ await loadPromise;
+
+ const parser = new frames[0].DOMParser();
+ const doc = DOMParser.prototype.parseFromString.call(parser, input, mimeType);
+
+ assertURL(doc, frames[0].document.URL);
+ }, `${mimeType} ${inputName}: created using a parser from the iframe and the method from this frame`);
+ }
+}
diff --git a/testing/web-platform/tests/domparsing/style_attribute_html.html b/testing/web-platform/tests/domparsing/style_attribute_html.html
new file mode 100644
index 0000000000..f7f057d2d8
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/style_attribute_html.html
@@ -0,0 +1,52 @@
+<!doctype 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 = (new DOMParser()).parseFromString(input, 'text/html');
+ 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/domparsing/xml-serialization.xhtml b/testing/web-platform/tests/domparsing/xml-serialization.xhtml
new file mode 100644
index 0000000000..852bbcc9fd
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/xml-serialization.xhtml
@@ -0,0 +1,103 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>XML serialization</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script><![CDATA[
+function serialize(node) {
+ var serializer = new XMLSerializer();
+ return serializer.serializeToString(node);
+}
+
+test(function() {
+ var dt = document.createComment("--");
+ assert_equals(serialize(dt), '<!------>');
+}, "Comment: containing --");
+
+test(function() {
+ var dt = document.createComment("- x");
+ assert_equals(serialize(dt), '<!--- x-->');
+}, "Comment: starting with -");
+
+test(function() {
+ var dt = document.createComment("x -");
+ assert_equals(serialize(dt), '<!--x --->');
+}, "Comment: ending with -");
+
+test(function() {
+ var dt = document.createComment("-->");
+ assert_equals(serialize(dt), '<!---->-->');
+}, "Comment: containing -->");
+
+test(function() {
+ var dt = document.implementation.createDocumentType("html", "", "");
+ assert_equals(serialize(dt), '<!DOCTYPE html>');
+}, "DocumentType: empty public and system id");
+
+test(function() {
+ var dt = document.implementation.createDocumentType("html", "a", "");
+ assert_equals(serialize(dt), '<!DOCTYPE html PUBLIC "a">');
+}, "DocumentType: empty system id");
+
+test(function() {
+ var dt = document.implementation.createDocumentType("html", "", "a");
+ assert_equals(serialize(dt), '<!DOCTYPE html SYSTEM "a">');
+}, "DocumentType: empty public id");
+
+test(function() {
+ var dt = document.implementation.createDocumentType("html", "a", "b");
+ assert_equals(serialize(dt), '<!DOCTYPE html PUBLIC "a" "b">');
+}, "DocumentType: non-empty public and system id");
+
+test(function() {
+ var dt = document.implementation.createDocumentType("html", "'", "'");
+ assert_equals(serialize(dt), "<!DOCTYPE html PUBLIC \"'\" \"'\">");
+}, "DocumentType: 'APOSTROPHE' (U+0027)");
+
+test(function() {
+ var dt = document.implementation.createDocumentType("html", '"', '"');
+ assert_equals(serialize(dt), '<!DOCTYPE html PUBLIC """ """>');
+}, "DocumentType: 'QUOTATION MARK' (U+0022)");
+
+test(function() {
+ var dt = document.implementation.createDocumentType("html", '"\'', '\'"');
+ assert_equals(serialize(dt), '<!DOCTYPE html PUBLIC ""\'" "\'"">');
+}, "DocumentType: 'APOSTROPHE' (U+0027) and 'QUOTATION MARK' (U+0022)");
+
+test(function() {
+ var el = document.createElement("a");
+ el.setAttribute("href", "\u3042\u3044\u3046 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~");
+ assert_equals(serialize(el), "<a xmlns=\"http://www.w3.org/1999/xhtml\" href=\"\u3042\u3044\u3046 !&quot;#$%&amp;'()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"></a>");
+}, "Element: href attributes are not percent-encoded");
+
+test(function() {
+ var el = document.createElement("a");
+ el.setAttribute("href", "?\u3042\u3044\u3046 !\"$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~");
+ assert_equals(serialize(el), "<a xmlns=\"http://www.w3.org/1999/xhtml\" href=\"?\u3042\u3044\u3046 !&quot;$%&amp;'()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"></a>");
+}, "Element: query parts in href attributes are not percent-encoded");
+
+test(function() {
+ var pi = document.createProcessingInstruction("a", "");
+ assert_equals(serialize(pi), "<?a ?>");
+}, "ProcessingInstruction: empty data");
+
+test(function() {
+ var pi = document.createProcessingInstruction("a", "b");
+ assert_equals(serialize(pi), "<?a b?>");
+}, "ProcessingInstruction: non-empty data");
+
+test(function() {
+ var pi = document.createProcessingInstruction("xml", "b");
+ assert_equals(serialize(pi), "<?xml b?>");
+}, "ProcessingInstruction: target contains xml");
+
+test(function() {
+ var pi = document.createProcessingInstruction("x:y", "b");
+ assert_equals(serialize(pi), "<?x:y b?>");
+}, "ProcessingInstruction: target contains a 'COLON' (U+003A)");
+]]></script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/domparsing/xmldomparser.html b/testing/web-platform/tests/domparsing/xmldomparser.html
new file mode 100644
index 0000000000..9dac65d305
--- /dev/null
+++ b/testing/web-platform/tests/domparsing/xmldomparser.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>XML Dom Parse readyState Test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ test(function () {
+ assert_equals(
+ (new DOMParser()).parseFromString("<html></html>", "text/xml").readyState,
+ "complete"
+ );
+ });
+</script>