diff options
Diffstat (limited to '')
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><a></noembed>', 'text/html'); + assert_equals(doc.querySelector('noembed').textContent, '<a>'); +}, '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: <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="	"/>', '<root attr="	"/>']); + root.setAttribute('attr', '\n'); + assert_in_array(serialize(root), [ + '<root attr="
"/>', '<root attr=" "/>']); + root.setAttribute('attr', '\r'); + assert_in_array(serialize(root), [ + '<root attr="
"/>', '<root attr=" "/>']); +}, '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><<\/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\"><<\/span>"); +}) +test(function() { + var el = document.createElement("xmp"); + el.appendChild(document.createTextNode("<")); + assert_equals(el.innerHTML, "<"); +}) +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, "<>\"'&"); +}) +test(function() { + var el = document.createElement("div"); + el.appendChild(document.createTextNode("<>"'&")); + assert_equals(el.innerHTML, "&lt;&gt;&quot;&apos;&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,<html xmlns='http://www.w3.org/1999/xhtml'><foo--/></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 !"#$%&'()*+,-./0123456789:;<=>?@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 !"$%&'()*+,-./0123456789:;<=>?@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> |