diff options
Diffstat (limited to 'testing/web-platform/tests/custom-elements/parser')
11 files changed, 700 insertions, 0 deletions
diff --git a/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-element-in-document-write.html b/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-element-in-document-write.html new file mode 100644 index 0000000000..14c830b9ba --- /dev/null +++ b/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-element-in-document-write.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html> +<head> +<title>Custom Elements: Changes to the HTML parser</title> +<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> +<meta name="assert" content="HTML parser must construct custom elements inside document.write"> +<link rel="help" href="https://html.spec.whatwg.org/#create-an-element-for-the-token"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-create-element"> +<link rel="help" href="https://html.spec.whatwg.org/#document.write()"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<script> + +var numberOfChildNodesInConnectedCallback = 0; + +class MyCustomElement extends HTMLElement { + connectedCallback() { + numberOfChildNodesInConnectedCallback = this.childNodes.length; + } +} +customElements.define('my-custom-element', MyCustomElement); + +document.write('<my-custom-element>hello <b>world</b></my-custom-element>'); + +test(function () { + var instance = document.querySelector('my-custom-element'); + + assert_true(instance instanceof HTMLElement); + assert_true(instance instanceof MyCustomElement); + +}, 'HTML parser must instantiate custom elements inside document.write'); + +test(function () { + assert_equals(numberOfChildNodesInConnectedCallback, 0); + +}, 'HTML parser should call connectedCallback before appending child nodes inside document.write'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-element-synchronously.html b/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-element-synchronously.html new file mode 100644 index 0000000000..206aa17f20 --- /dev/null +++ b/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-element-synchronously.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<html> +<head> +<title>Custom Elements: Changes to the HTML parser</title> +<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> +<meta name="assert" content="HTML parser must construct a custom element synchronously"> +<link rel="help" href="https://html.spec.whatwg.org/#create-an-element-for-the-token"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-create-element"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<script> + +var childElementCountInConstructor; +var containerChildNodesInConstructor = []; +var containerNextSiblingInConstructor; +class MyCustomElement extends HTMLElement { + constructor() { + super(); + var container = document.getElementById('custom-element-container'); + for (var i = 0; i < container.childNodes.length; i++) + containerChildNodesInConstructor.push(container.childNodes[i]); + containerNextSiblingInConstructor = container.nextSibling; + } +}; +customElements.define('my-custom-element', MyCustomElement); + +</script> +<div id="custom-element-container"> + <span id="custom-element-previous-element"></span> + <my-custom-element></my-custom-element> + <div id="custom-element-next-element"></div> +</div> +<script> + +test(function () { + var instance = document.querySelector('my-custom-element'); + + assert_equals(containerChildNodesInConstructor.length, 3); + assert_equals(containerChildNodesInConstructor[0], instance.parentNode.firstChild); + assert_equals(containerChildNodesInConstructor[1], document.getElementById('custom-element-previous-element')); + assert_equals(containerChildNodesInConstructor[2], instance.previousSibling); + assert_equals(containerNextSiblingInConstructor, null); + +}, 'HTML parser must only append nodes that appear before a custom element before instantiating the custom element'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-elements-with-is.html b/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-elements-with-is.html new file mode 100644 index 0000000000..96c00278a3 --- /dev/null +++ b/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-elements-with-is.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<html> +<head> +<title>Custom Elements: Changes to the HTML parser</title> +<meta name="author" title="John Dai" href="mailto:jdai@mozilla.com"> +<meta name="assert" content="HTML parser creates a custom element which contains is attribute"> +<link rel="help" href="https://html.spec.whatwg.org/#create-an-element-for-the-token"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-create-element"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<autonomous-custom-element id="instance1" is="is-custom-element"></autonomous-custom-element> +<script> + +class AutonomousCustomElement extends HTMLElement { }; +class IsCustomElement extends HTMLElement { }; + +customElements.define('autonomous-custom-element', AutonomousCustomElement); +customElements.define('is-custom-element', IsCustomElement); + +test(function () { + var customElement = document.getElementById('instance1'); + + assert_true(customElement instanceof HTMLElement, 'A resolved custom element must be an instance of HTMLElement'); + assert_false(customElement instanceof HTMLUnknownElement, 'A resolved custom element must NOT be an instance of HTMLUnknownElement'); + assert_true(customElement instanceof AutonomousCustomElement, 'A resolved custom element must be an instance of that custom element'); + assert_equals(customElement.localName, 'autonomous-custom-element'); + assert_equals(customElement.namespaceURI, 'http://www.w3.org/1999/xhtml', 'A custom element HTML must use HTML namespace'); + +}, 'HTML parser must create a defined autonomous custom element when customElements.define comes after HTML parser creation'); + +</script> +<autonomous-custom-element id="instance2" is="is-custom-element"></autonomous-custom-element> +<script> + +test(function () { + var customElement = document.getElementById('instance2'); + + assert_true(customElement instanceof HTMLElement, 'A resolved custom element must be an instance of HTMLElement'); + assert_false(customElement instanceof HTMLUnknownElement, 'A resolved custom element must NOT be an instance of HTMLUnknownElement'); + assert_true(customElement instanceof AutonomousCustomElement, 'A resolved custom element must be an instance of that custom element'); + assert_equals(customElement.localName, 'autonomous-custom-element'); + assert_equals(customElement.namespaceURI, 'http://www.w3.org/1999/xhtml', 'A custom element HTML must use HTML namespace'); + +}, 'HTML parser must create a defined autonomous custom element when customElements.define comes before HTML parser creation'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-elements.html b/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-elements.html new file mode 100644 index 0000000000..3f13c50a0e --- /dev/null +++ b/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-elements.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<html> +<head> +<title>Custom Elements: Changes to the HTML parser</title> +<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> +<meta name="assert" content="HTML parser creates a custom element"> +<link rel="help" href="https://html.spec.whatwg.org/#create-an-element-for-the-token"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-create-element"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<my-custom-element id="instance1"></my-custom-element> +<script> + +class MyCustomElement extends HTMLElement { }; + +test(function () { + var customElement = document.getElementById('instance1'); + + assert_true(customElement instanceof HTMLElement, 'An unresolved custom element must be an instance of HTMLElement'); + assert_false(customElement instanceof MyCustomElement, 'An unresolved custom element must NOT be an instance of that custom element'); + assert_equals(customElement.localName, 'my-custom-element'); + assert_equals(customElement.namespaceURI, 'http://www.w3.org/1999/xhtml', 'A custom element HTML must use HTML namespace'); + +}, 'HTML parser must NOT create a custom element before customElements.define is called'); + +customElements.define('my-custom-element', MyCustomElement); + +</script> +<my-custom-element id="instance2"></my-custom-element> +<script> + +test(function () { + var customElement = document.getElementById('instance2'); + + assert_true(customElement instanceof HTMLElement, 'A resolved custom element must be an instance of HTMLElement'); + assert_false(customElement instanceof HTMLUnknownElement, 'A resolved custom element must NOT be an instance of HTMLUnknownElement'); + assert_true(customElement instanceof MyCustomElement, 'A resolved custom element must be an instance of that custom element'); + assert_equals(customElement.localName, 'my-custom-element'); + assert_equals(customElement.namespaceURI, 'http://www.w3.org/1999/xhtml', 'A custom element HTML must use HTML namespace'); + +}, 'HTML parser must create a defined custom element before executing inline scripts'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/custom-elements/parser/parser-custom-element-in-foreign-content.html b/testing/web-platform/tests/custom-elements/parser/parser-custom-element-in-foreign-content.html new file mode 100644 index 0000000000..2ae0f1309c --- /dev/null +++ b/testing/web-platform/tests/custom-elements/parser/parser-custom-element-in-foreign-content.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>Custom Elements: Custom element in foreign content</title> +<meta name="assert" content="HTML parser should not create non-HTML namespace custom elements"> +<link rel="help" href="https://html.spec.whatwg.org/#create-an-element-for-the-token"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-create-element"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +class ThrowsException extends HTMLElement { + constructor() { + throw 'Bad'; + } +}; +customElements.define('throws-exception', ThrowsException); +</script> +<svg> + <throws-exception/> +</svg> +<script> +test(function () { + var instance = document.querySelector('throws-exception'); + assert_false(instance instanceof ThrowsException, + 'The HTML parser must NOT instantiate a custom element in non-HTML namespaces'); + assert_false(instance instanceof HTMLUnknownElement, 'The HTML parser should not fallback'); + assert_true(instance instanceof SVGElement, + 'The element created by the HTML parser must be an instance of SVGElement'); +}, 'HTML parser should not create custom elements in non-HTML namespaces'); +</script> diff --git a/testing/web-platform/tests/custom-elements/parser/parser-fallsback-to-unknown-element.html b/testing/web-platform/tests/custom-elements/parser/parser-fallsback-to-unknown-element.html new file mode 100644 index 0000000000..82e970f1ae --- /dev/null +++ b/testing/web-platform/tests/custom-elements/parser/parser-fallsback-to-unknown-element.html @@ -0,0 +1,91 @@ +<!DOCTYPE html> +<html> +<head> +<title>Custom Elements: Changes to the HTML parser</title> +<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> +<meta name="assert" content="HTML parser must fallback to creating a HTMLUnknownElement when a custom element construction fails"> +<link rel="help" href="https://html.spec.whatwg.org/#create-an-element-for-the-token"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-create-element"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<script> + +setup({allow_uncaught_exception:true}); + +class ReturnsTextNode extends HTMLElement { + constructor() { + super(); + return document.createTextNode('some text'); + } +}; +customElements.define('returns-text', ReturnsTextNode); + +class ReturnsNonElementObject extends HTMLElement { + constructor() { + super(); + return {}; + } +}; +customElements.define('returns-non-element-object', ReturnsNonElementObject); + +class LacksSuperCall extends HTMLElement { + constructor() { } +}; +customElements.define('lacks-super-call', LacksSuperCall); + +class ThrowsException extends HTMLElement { + constructor() { + throw 'Bad'; + } +}; +customElements.define('throws-exception', ThrowsException); + +</script> +<returns-text></returns-text> +<returns-non-element-object></returns-non-element-object> +<lacks-super-call></lacks-super-call> +<throws-exception></throws-exception> +<script> + +test(function () { + var instance = document.querySelector('returns-text'); + + assert_false(instance instanceof ReturnsTextNode, 'HTML parser must NOT instantiate a custom element when the constructor returns a Text node'); + assert_true(instance instanceof HTMLElement, 'The fallback element created by HTML parser must be an instance of HTMLElement'); + assert_true(instance instanceof HTMLUnknownElement, 'The fallback element created by HTML parser must be an instance of HTMLUnknownElement'); + +}, 'HTML parser must create a fallback HTMLUnknownElement when a custom element constructor returns a Text node'); + +test(function () { + var instance = document.querySelector('returns-non-element-object'); + + assert_false(instance instanceof ReturnsNonElementObject, 'HTML parser must NOT instantiate a custom element when the constructor returns a non-Element object'); + assert_true(instance instanceof HTMLElement, 'The fallback element created by HTML parser must be an instance of HTMLElement'); + assert_true(instance instanceof HTMLUnknownElement, 'The fallback element created by HTML parser must be an instance of HTMLUnknownElement'); + +}, 'HTML parser must create a fallback HTMLUnknownElement when a custom element constructor returns non-Element object'); + +test(function () { + var instance = document.querySelector('lacks-super-call'); + + assert_false(instance instanceof LacksSuperCall, 'HTML parser must NOT instantiate a custom element when the constructor does not call super()'); + assert_true(instance instanceof HTMLElement, 'The fallback element created by HTML parser must be an instance of HTMLElement'); + assert_true(instance instanceof HTMLUnknownElement, 'The fallback element created by HTML parser must be an instance of HTMLUnknownElement'); + +}, 'HTML parser must create a fallback HTMLUnknownElement when a custom element constructor does not call super()'); + +test(function () { + var instance = document.querySelector('throws-exception'); + + assert_false(instance instanceof ThrowsException, 'HTML parser must NOT instantiate a custom element when the constructor throws an exception'); + assert_true(instance instanceof HTMLElement, 'The fallback element created by HTML parser must be an instance of HTMLElement'); + assert_true(instance instanceof HTMLUnknownElement, 'The fallback element created by HTML parser must be an instance of HTMLUnknownElement'); + +}, 'HTML parser must create a fallback HTMLUnknownElement when a custom element constructor throws an exception'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/custom-elements/parser/parser-sets-attributes-and-children.html b/testing/web-platform/tests/custom-elements/parser/parser-sets-attributes-and-children.html new file mode 100644 index 0000000000..987bf8525f --- /dev/null +++ b/testing/web-platform/tests/custom-elements/parser/parser-sets-attributes-and-children.html @@ -0,0 +1,95 @@ +<!DOCTYPE html> +<html> +<head> +<title>Custom Elements: Changes to the HTML parser</title> +<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> +<meta name="assert" content="HTML parser must set the attributes and append the children on a custom element"> +<link rel="help" href="https://html.spec.whatwg.org/#create-an-element-for-the-token"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/parsing.html#insert-a-foreign-element"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-create-element"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/custom-elements-helpers.js"></script> +</head> +<body> +<div id="log"></div> +<script> + +var numberOfAttributesInConstructor = 0; +var numberOfChildNodesInConstructor = 0; +var numberOfChildNodesInAttributeChangedCallback = 0; +var numberOfChildNodesInConnectedCallback = 0; +var attributesChangedCalls = []; + +class MyCustomElement extends HTMLElement { + constructor(...args) { + super(...args); + numberOfAttributesInConstructor = this.attributes.length; + numberOfChildNodesInConstructor = this.childNodes.length; + } + + attributeChangedCallback(...args) { + attributesChangedCalls.push(create_attribute_changed_callback_log(this, ...args)); + numberOfChildNodesInAttributeChangedCallback = this.childNodes.length; + } + + static get observedAttributes() { + return ['id', 'class']; + } + + connectedCallback() { + numberOfChildNodesInConnectedCallback = this.childNodes.length; + } +}; +customElements.define('my-custom-element', MyCustomElement); + +</script> +<my-custom-element id="custom-element-id" class="class1 class2">hello <b>world</b></my-custom-element> +<script> + +var customElement = document.querySelector('my-custom-element'); + +test(function () { + assert_equals(customElement.getAttribute('id'), 'custom-element-id', 'HTML parser must preserve the id attribute'); + assert_equals(customElement.id, 'custom-element-id', 'HTML parser must preserve the semantics of reflect for the id attribute'); + assert_equals(customElement.getAttribute('class'), 'class1 class2', 'HTML parser must preserve the class attribute'); + assert_equals(customElement.classList.length, 2, 'HTML parser must initialize classList on custom elements'); + assert_equals(customElement.classList[0], 'class1', 'HTML parser must initialize classList on custom elements'); + assert_equals(customElement.classList[1], 'class2', 'HTML parser must initialize classList on custom elements'); +}, 'HTML parser must set the attributes'); + +test(function () { + assert_equals(customElement.childNodes.length, 2, 'HTML parser must append child nodes'); + assert_true(customElement.firstChild instanceof Text, 'HTML parser must append Text node child to a custom element'); + assert_equals(customElement.firstChild.data, 'hello ', 'HTML parser must append Text node child to a custom element'); + assert_true(customElement.lastChild instanceof HTMLElement, 'HTML parser must append a builtin element child to a custom element'); + assert_true(customElement.lastChild.firstChild instanceof Text, 'HTML parser must preserve grandchild nodes of a custom element'); + assert_equals(customElement.lastChild.firstChild.data, 'world', 'HTML parser must preserve grandchild nodes of a custom element'); +}, 'HTML parser must append child nodes'); + +test(function () { + assert_equals(numberOfAttributesInConstructor, 0, 'HTML parser must not set attributes on a custom element before invoking the constructor'); + assert_equals(numberOfChildNodesInConstructor, 0, 'HTML parser must not append child nodes to a custom element before invoking the constructor'); +}, 'HTML parser must set the attributes or append children before calling constructor'); + +test(function () { + // https://html.spec.whatwg.org/multipage/parsing.html#insert-a-foreign-element + // 3.3. Pop the element queue from the custom element reactions + // stack, and invoke custom element reactions in that queue. + assert_equals(numberOfChildNodesInConnectedCallback, 0); +}, 'HTML parser should call connectedCallback before appending child nodes.'); + +test(function () { + assert_equals(attributesChangedCalls.length, 2); + assert_attribute_log_entry(attributesChangedCalls[0], {name: 'id', oldValue: null, newValue: 'custom-element-id', namespace: null}); + assert_attribute_log_entry(attributesChangedCalls[1], {name: 'class', oldValue: null, newValue: 'class1 class2', namespace: null}); + // https://html.spec.whatwg.org/multipage/parsing.html#create-an-element-for-the-token + // 9.2. Invoke custom element reactions in queue. + assert_equals(numberOfChildNodesInAttributeChangedCallback, 0, + 'attributeChangedCallback should be called ' + + 'before appending a child'); +}, 'HTML parser must enqueue attributeChanged reactions'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/custom-elements/parser/parser-uses-constructed-element.html b/testing/web-platform/tests/custom-elements/parser/parser-uses-constructed-element.html new file mode 100644 index 0000000000..dd98f15cd9 --- /dev/null +++ b/testing/web-platform/tests/custom-elements/parser/parser-uses-constructed-element.html @@ -0,0 +1,75 @@ +<!DOCTYPE html> +<html> +<head> +<title>Custom Elements: HTML parser must construct a custom element instead of upgrading</title> +<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> +<meta name="assert" content="HTML parser must construct a custom element instead of upgrading"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/#create-an-element-for-the-token"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-create-element"> +</head> +<body> +<div id="log"></div> +<script> + +let anotherElementCreatedBeforeSuperCall = undefined; +let elementCreatedBySuperCall = undefined; +let shouldCreateElementBeforeSuperCall = true; +class InstantiatesItselfBeforeSuper extends HTMLElement { + constructor() { + if (shouldCreateElementBeforeSuperCall) { + shouldCreateElementBeforeSuperCall = false; + anotherElementCreatedBeforeSuperCall = new InstantiatesItselfBeforeSuper(); + } + super(); + elementCreatedBySuperCall = this; + } +}; +customElements.define('instantiates-itself-before-super', InstantiatesItselfBeforeSuper); + +let shouldCreateAnotherInstance = true; +let anotherInstance = undefined; +let firstInstance = undefined; +class ReturnsAnotherInstance extends HTMLElement { + constructor() { + super(); + if (shouldCreateAnotherInstance) { + shouldCreateAnotherInstance = false; + firstInstance = this; + anotherInstance = new ReturnsAnotherInstance; + return anotherInstance; + } else + return this; + } +}; +customElements.define('returns-another-instance', ReturnsAnotherInstance); + +</script> +<instantiates-itself-before-super></instantiates-itself-before-super> +<returns-another-instance></returns-another-instance> +<script> + +test(function () { + var instance = document.querySelector('instantiates-itself-before-super'); + + assert_true(instance instanceof InstantiatesItselfBeforeSuper, 'HTML parser must insert the synchronously constructed custom element'); + assert_equals(instance, elementCreatedBySuperCall, 'HTML parser must insert the element returned by the custom element constructor'); + assert_not_equals(instance, anotherElementCreatedBeforeSuperCall, 'HTML parser must not insert another instance of the custom element created before super() call'); + assert_equals(anotherElementCreatedBeforeSuperCall.parentNode, null, 'HTML parser must not insert another instance of the custom element created before super() call'); + +}, 'HTML parser must use the returned value of the custom element constructor instead of the one created before super() call'); + +test(function () { + var instance = document.querySelector('returns-another-instance'); + + assert_true(instance instanceof ReturnsAnotherInstance, 'HTML parser must insert the synchronously constructed custom element'); + assert_equals(instance, anotherInstance, 'HTML parser must insert the element returned by the custom element constructor'); + assert_not_equals(instance, firstInstance, 'HTML parser must not insert the element created by super() call if the constructor returned another element'); + assert_equals(firstInstance.parentNode, null, 'HTML parser must not insert the element created by super() call if the constructor returned another element'); + +}, 'HTML parser must use the returned value of the custom element constructor instead using the one created in super() call'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/custom-elements/parser/parser-uses-create-an-element-for-a-token-svg.svg b/testing/web-platform/tests/custom-elements/parser/parser-uses-create-an-element-for-a-token-svg.svg new file mode 100644 index 0000000000..526de0f63f --- /dev/null +++ b/testing/web-platform/tests/custom-elements/parser/parser-uses-create-an-element-for-a-token-svg.svg @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg:svg xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/1999/xhtml" + width="100%" height="100%" viewBox="0 0 800 600"> +<svg:title>XML parser should use "create an element for a token"</svg:title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/xhtml.html#parsing-xhtml-documents:create-an-element-for-the-token"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script><![CDATA[ +class MyElement1 extends HTMLElement {} +customElements.define('my-element', MyElement1); +class MyElement2 extends HTMLDivElement {} +customElements.define('my-div', MyElement2, { extends: 'div' }); + +var test1 = async_test('XML parser should create autonomous custom elements.'); +window.addEventListener('load', test1.step_func_done(() => { + assert_true(document.getElementById('me1') instanceof MyElement1); +})); + +var test2 = async_test('XML parser should create custom built-in elements.'); +window.addEventListener('load', test2.step_func_done(() => { + assert_true(document.getElementById('me2') instanceof MyElement2); +})); +]]></script> +<my-element id="me1"></my-element> +<div is="my-div" id="me2"></div> +</svg:svg> diff --git a/testing/web-platform/tests/custom-elements/parser/parser-uses-registry-of-owner-document.html b/testing/web-platform/tests/custom-elements/parser/parser-uses-registry-of-owner-document.html new file mode 100644 index 0000000000..bb256da295 --- /dev/null +++ b/testing/web-platform/tests/custom-elements/parser/parser-uses-registry-of-owner-document.html @@ -0,0 +1,154 @@ +<!DOCTYPE html> +<html> +<head> +<title>Custom Elements: HTML parser must use the owner document's custom element registry</title> +<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> +<meta name="assert" content="HTML parser must use the owner document's custom element registry"> +<link rel="help" href="https://html.spec.whatwg.org/#create-an-element-for-the-token"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-create-element"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/custom-elements-helpers.js"></script> +</head> +<body> +<div id="log"></div> +<script> + +class MyCustomElement extends HTMLElement { }; +customElements.define('my-custom-element', MyCustomElement); + +document.write('<template><my-custom-element></my-custom-element></template>'); + +test(function () { + var template = document.querySelector('template'); + var instance = template.content.firstChild; + + assert_true(instance instanceof HTMLElement, + 'A custom element inside a template element must be an instance of HTMLElement'); + assert_false(instance instanceof MyCustomElement, + 'A custom element must not be instantiated inside a template element using the registry of the template element\'s owner document'); + assert_equals(instance.ownerDocument, template.content.ownerDocument, + 'Custom elements inside a template must use the appropriate template contents owner document as the owner document'); + +}, 'HTML parser must not instantiate custom elements inside template elements'); + +var iframe = document.createElement('iframe'); +document.body.appendChild(iframe); +iframe.contentDocument.body.innerHTML = '<my-custom-element></my-custom-element>'; + +test(function () { + var instance = iframe.contentDocument.querySelector('my-custom-element'); + + assert_true(instance instanceof iframe.contentWindow.HTMLElement); + assert_false(instance instanceof MyCustomElement); + +}, 'HTML parser must not use the registry of the owner element\'s document inside an iframe'); + +class ElementInIFrame extends iframe.contentWindow.HTMLElement { }; +iframe.contentWindow.customElements.define('element-in-iframe', ElementInIFrame); +iframe.contentDocument.body.innerHTML = '<element-in-iframe></element-in-iframe>'; + +test(function () { + var instance = iframe.contentDocument.querySelector('element-in-iframe'); + + assert_true(instance instanceof iframe.contentWindow.HTMLElement, 'A custom element inside an iframe must be an instance of HTMLElement'); + assert_true(instance instanceof ElementInIFrame, + 'A custom element must be instantiated inside an iframe using the registry of the content document'); + assert_equals(instance.ownerDocument, iframe.contentDocument, + 'The owner document of custom elements inside an iframe must be the content document of the iframe'); + +}, 'HTML parser must use the registry of the content document inside an iframe'); + +document.write('<element-in-iframe></element-in-iframe>'); + +test(function () { + var instance = document.querySelector('element-in-iframe'); + + assert_true(instance instanceof HTMLElement); + assert_false(instance instanceof ElementInIFrame); + +}, 'HTML parser must not instantiate a custom element defined inside an frame in frame element\'s owner document'); + +document.body.removeChild(iframe); + +test(function () { + var windowlessDocument = (new DOMParser()).parseFromString('<my-custom-element></my-custom-element>', "text/html"); + + var instance = windowlessDocument.querySelector('my-custom-element'); + + assert_true(instance instanceof HTMLElement); + assert_false(instance instanceof MyCustomElement); + +}, 'HTML parser must use the registry of window.document in a document created by DOMParser'); + +test(function () { + var windowlessDocument = document.implementation.createDocument ('http://www.w3.org/1999/xhtml', 'html', null); + windowlessDocument.documentElement.innerHTML = '<my-custom-element></my-custom-element>'; + + var instance = windowlessDocument.querySelector('my-custom-element'); + assert_true(instance instanceof HTMLElement); + assert_false(instance instanceof MyCustomElement); + +}, 'HTML parser must use the registry of window.document in a document created by document.implementation.createXHTMLDocument()'); + +test(function () { + var windowlessDocument = new Document; + windowlessDocument.appendChild(windowlessDocument.createElement('html')); + windowlessDocument.documentElement.innerHTML = '<my-custom-element></my-custom-element>'; + + var instance = windowlessDocument.querySelector('my-custom-element'); + + assert_true(instance instanceof Element); + assert_false(instance instanceof MyCustomElement); + +}, 'HTML parser must use the registry of window.document in a document created by new Document'); + +promise_test(function () { + return new Promise(function (resolve, reject) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', '../resources/my-custom-element-html-document.html'); + xhr.overrideMimeType('text/xml'); + xhr.onload = function () { resolve(xhr.responseXML); } + xhr.onerror = function () { reject('Failed to fetch the document'); } + xhr.send(); + }).then(function (doc) { + var instance = doc.querySelector('my-custom-element'); + assert_true(instance instanceof Element); + assert_false(instance instanceof MyCustomElement); + + doc.documentElement.innerHTML = '<my-custom-element></my-custom-element>'; + var instance2 = doc.querySelector('my-custom-element'); + assert_true(instance2 instanceof Element); + assert_false(instance2 instanceof MyCustomElement); + }); +}, 'HTML parser must use the registry of window.document in a document created by XMLHttpRequest'); + +test_with_window(function (contentWindow, contentDocument) { + const element = define_custom_element_in_window(contentWindow, 'my-custom-element', []); + // document-open-steps spec doesn't do anything with the custom element + // registry, so it should just stick around. + contentDocument.write('<my-custom-element></my-custom-element>'); + + var instance = contentDocument.querySelector('my-custom-element'); + + assert_true(instance instanceof contentWindow.HTMLElement); + assert_true(instance instanceof element.class); + +}, 'document.write() must not instantiate a custom element without a defined insertion point'); + +test_with_window(function (contentWindow, contentDocument) { + const element = define_custom_element_in_window(contentWindow, 'my-custom-element', []); + // document-open-steps spec doesn't do anything with the custom element + // registry, so it should just stick around. + contentDocument.writeln('<my-custom-element></my-custom-element>'); + + var instance = contentDocument.querySelector('my-custom-element'); + + assert_true(instance instanceof contentWindow.HTMLElement); + assert_true(instance instanceof element.class); + +}, 'document.writeln() must not instantiate a custom element without a defined insertion point'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/custom-elements/parser/serializing-html-fragments-customized-builtins.html b/testing/web-platform/tests/custom-elements/parser/serializing-html-fragments-customized-builtins.html new file mode 100644 index 0000000000..6992dd6df6 --- /dev/null +++ b/testing/web-platform/tests/custom-elements/parser/serializing-html-fragments-customized-builtins.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<link rel="help" href="https://html.spec.whatwg.org/multipage/parsing.html#serialising-html-fragments"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<div id="container"></div> +<script> +test(() => { + class MyParagraph extends HTMLParagraphElement {} + customElements.define('my-p', MyParagraph, { extends: 'p' }); + + let p = new MyParagraph(); + p.setAttribute('class', 'foo'); + assert_equals(p.outerHTML, '<p is="my-p" class="foo"></p>'); + + let container = document.querySelector('#container'); + container.appendChild(p); + container.innerHTML = container.innerHTML; + assert_not_equals(container.firstChild, p); + assert_true(container.firstChild instanceof MyParagraph); +}, '"is" value should be serialized if the custom element has no "is" content attribute'); + +test(() => { + let p = document.createElement('p', { is: 'your-p' }); + assert_equals(p.outerHTML, '<p is="your-p"></p>'); +}, '"is" value should be serialized even for an undefined element'); + +test(() => { + class MyDiv extends HTMLDivElement {} + customElements.define('my-div', MyDiv, { extends: 'div' }); + + let div = document.createElement('div', { is: 'my-div' }); + div.setAttribute('is', 'foo"bar\n'); + assert_equals(div.outerHTML, '<div is="foo"bar\n"></div>'); +}, '"is" content attribute should be serialized even if the element is a customized built-in element'); +</script> +</body> |