summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/custom-elements/upgrading.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/custom-elements/upgrading.html')
-rw-r--r--testing/web-platform/tests/custom-elements/upgrading.html258
1 files changed, 258 insertions, 0 deletions
diff --git a/testing/web-platform/tests/custom-elements/upgrading.html b/testing/web-platform/tests/custom-elements/upgrading.html
new file mode 100644
index 0000000000..9a28fcbe12
--- /dev/null
+++ b/testing/web-platform/tests/custom-elements/upgrading.html
@@ -0,0 +1,258 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Custom Elements: Enqueue a custom element upgrade reaction</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="Enqueue a custom element upgrade reaction must upgrade a custom element">
+<link rel="help" href="https://dom.spec.whatwg.org/#concept-create-element">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/scripting.html#concept-try-upgrade">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-upgrade-reaction">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/custom-elements-helpers.js"></script>
+</head>
+<body>
+<infinite-cloning-element-1></infinite-cloning-element-1>
+<infinite-cloning-element-2 id="a"></infinite-cloning-element-2>
+<infinite-cloning-element-2 id="b"></infinite-cloning-element-2>
+<div id="log"></div>
+<script>
+setup({allow_uncaught_exception:true});
+
+class PredefinedCustomElement extends HTMLElement {}
+customElements.define('predefined-custom-element', PredefinedCustomElement);
+
+var customElementNumber = 1;
+function generateNextCustomElementName() { return 'custom-' + customElementNumber++; }
+
+// Tests for documents without a browsing context.
+document_types().filter(function (entry) { return !entry.isOwner && !entry.hasBrowsingContext; }).forEach(function (entry) {
+ var documentName = entry.name;
+ var getDocument = entry.create;
+
+ promise_test(function () {
+ return getDocument().then(function (doc) {
+ assert_false(doc.createElement('predefined-custom-element') instanceof PredefinedCustomElement);
+ });
+ }, 'Creating an element in ' + documentName + ' must not enqueue a custom element upgrade reaction'
+ + ' because the document does not have a browsing context');
+
+ promise_test(function () {
+ var name = generateNextCustomElementName();
+ var unresolvedElement = document.createElement(name);
+
+ assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype,
+ '[[Prototype]] internal slot of the unresolved custom element must be the HTMLElement prototype');
+
+ return getDocument().then(function (doc) {
+ var unresolvedElementInDoc = doc.createElement(name);
+ var prototype = (unresolvedElementInDoc.namespaceURI == 'http://www.w3.org/1999/xhtml' ? HTMLElement : Element).prototype;
+
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), prototype,
+ '[[Prototype]] internal slot of the unresolved custom element must be the ' + prototype.toString() + ' prototype');
+ var someCustomElement = class extends HTMLElement {};
+ customElements.define(name, someCustomElement);
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), prototype, '"define" must not upgrade a disconnected unresolved custom elements');
+ doc.documentElement.appendChild(unresolvedElementInDoc);
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), prototype,
+ 'Inserting an element into a document without a browsing context must not enqueue a custom element upgrade reaction');
+ });
+ }, 'Creating an element in ' + documentName + ' and inserting into the document must not enqueue a custom element upgrade reaction');
+
+ promise_test(function () {
+ var name = generateNextCustomElementName();
+ var unresolvedElement = document.createElement(name);
+
+ assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype,
+ '[[Prototype]] internal slot of the unresolved custom element must be the HTMLElement prototype');
+
+ return getDocument().then(function (doc) {
+ var unresolvedElementInDoc = doc.createElement(name);
+ var prototype = (unresolvedElementInDoc.namespaceURI == 'http://www.w3.org/1999/xhtml' ? HTMLElement : Element).prototype;
+
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), prototype,
+ '[[Prototype]] internal slot of the unresolved custom element must be the ' + prototype.toString() + ' prototype');
+ var someCustomElement = class extends HTMLElement {};
+ customElements.define(name, someCustomElement);
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), prototype, '"define" must not upgrade a disconnected unresolved custom elements');
+ document.body.appendChild(unresolvedElementInDoc);
+
+ if (unresolvedElementInDoc.namespaceURI == 'http://www.w3.org/1999/xhtml') {
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), someCustomElement.prototype,
+ 'Inserting an element into a document with a browsing context must enqueue a custom element upgrade reaction');
+ } else {
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), prototype,
+ 'Looking up a custom element definition must return null if the element is not in the HTML namespace');
+ }
+ });
+ }, 'Creating an element in ' + documentName + ' and adopting back to a document with browsing context must enqueue a custom element upgrade reaction');
+
+});
+
+// Tests for documents with a browsing context.
+document_types().filter(function (entry) { return !entry.isOwner && entry.hasBrowsingContext; }).forEach(function (entry) {
+ var documentName = entry.name;
+ var getDocument = entry.create;
+
+ promise_test(function () {
+ return getDocument().then(function (doc) {
+ assert_false(doc.createElement('predefined-custom-element') instanceof PredefinedCustomElement);
+ });
+ }, 'Creating an element in ' + documentName + ' must not enqueue a custom element upgrade reaction if there is no matching definition');
+
+ promise_test(function () {
+ return getDocument().then(function (doc) {
+ var docWindow = doc.defaultView;
+ class DistinctPredefinedCustomElement extends docWindow.HTMLElement { };
+ docWindow.customElements.define('predefined-custom-element', DistinctPredefinedCustomElement);
+ assert_true(doc.createElement('predefined-custom-element') instanceof DistinctPredefinedCustomElement);
+ });
+ }, 'Creating an element in ' + documentName + ' must enqueue a custom element upgrade reaction if there is a matching definition');
+
+ promise_test(function () {
+ var unresolvedElement = document.createElement('unresolved-element');
+ return getDocument().then(function (doc) {
+ var docWindow = doc.defaultView;
+ class UnresolvedElement extends docWindow.HTMLElement { };
+ var unresolvedElementInDoc = doc.createElement('unresolved-element');
+
+ assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype);
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), docWindow.HTMLElement.prototype);
+
+ docWindow.customElements.define('unresolved-element', UnresolvedElement);
+
+ assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype);
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), docWindow.HTMLElement.prototype);
+
+ });
+ }, '"define" in ' + documentName + ' must not enqueue a custom element upgrade reaction on a disconnected unresolved custom element');
+
+ promise_test(function () {
+ var unresolvedElement = document.createElement('unresolved-element');
+ return getDocument().then(function (doc) {
+ var docWindow = doc.defaultView;
+ class UnresolvedElement extends docWindow.HTMLElement { };
+ var unresolvedElementInDoc = doc.createElement('unresolved-element');
+
+ assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype);
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), docWindow.HTMLElement.prototype);
+
+ docWindow.customElements.define('unresolved-element', UnresolvedElement);
+ doc.documentElement.appendChild(unresolvedElementInDoc);
+
+ assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype);
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), UnresolvedElement.prototype);
+ });
+ }, 'Inserting an unresolved custom element into ' + documentName + ' must enqueue a custom element upgrade reaction');
+
+ promise_test(function () {
+ var unresolvedElement = document.createElement('unresolved-element');
+ return getDocument().then(function (doc) {
+ var docWindow = doc.defaultView;
+ class UnresolvedElement extends docWindow.HTMLElement { };
+ var unresolvedElementInDoc = doc.createElement('unresolved-element');
+ doc.documentElement.appendChild(unresolvedElementInDoc);
+
+ assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype);
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), docWindow.HTMLElement.prototype);
+
+ docWindow.customElements.define('unresolved-element', UnresolvedElement);
+
+ assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype);
+ assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), UnresolvedElement.prototype);
+ });
+ }, '"define" in ' + documentName + ' must enqueue a custom element upgrade reaction on a connected unresolved custom element');
+
+ promise_test(function () {
+ var unresolvedElement = document.createElement('unresolved-element');
+ return getDocument().then(function (doc) {
+ var docWindow = doc.defaultView;
+ class UnresolvedElement extends docWindow.HTMLElement { };
+ assert_false(unresolvedElement instanceof UnresolvedElement);
+ docWindow.customElements.define('unresolved-element', UnresolvedElement);
+ doc.adoptNode(unresolvedElement);
+ assert_false(unresolvedElement instanceof UnresolvedElement);
+ });
+ }, 'Adopting (and leaving disconnceted) an unresolved custom element into ' + documentName + ' must not enqueue a custom element upgrade reaction');
+
+ promise_test(function () {
+ var unresolvedElement = document.createElement('unresolved-element');
+ return getDocument().then(function (doc) {
+ var docWindow = doc.defaultView;
+ class UnresolvedElement extends docWindow.HTMLElement { };
+ assert_false(unresolvedElement instanceof UnresolvedElement);
+ docWindow.customElements.define('unresolved-element', UnresolvedElement);
+ doc.documentElement.appendChild(unresolvedElement);
+ assert_true(unresolvedElement instanceof UnresolvedElement);
+ });
+ }, 'Adopting and inserting an unresolved custom element into ' + documentName + ' must enqueue a custom element upgrade reaction');
+
+});
+
+test(() => {
+ class ShadowDisabledElement extends HTMLElement {
+ static get disabledFeatures() { return ['shadow']; }
+ }
+ let error = null;
+ window.addEventListener('error', e => { error = e.error; }, {once: true});
+ let element = document.createElement('shadow-disabled');
+ element.attachShadow({mode: 'open'});
+ customElements.define('shadow-disabled', ShadowDisabledElement);
+ customElements.upgrade(element);
+ assert_false(element instanceof ShadowDisabledElement,
+ 'Upgrading should fail.');
+ assert_true(error instanceof DOMException);
+ assert_equals(error.name, 'NotSupportedError');
+}, 'If definition\'s disable shadow is true and element\'s shadow root is ' +
+ 'non-null, then throw a "NotSupportedError" DOMException.');
+
+test(() => {
+ var log = [];
+
+ customElements.define('infinite-cloning-element-1',class extends HTMLElement {
+ constructor() {
+ super();
+ log.push([this, 'begin']);
+ // Potential infinite recursion:
+ customElements.upgrade(this);
+ log.push([this, 'end']);
+ }
+ });
+
+ assert_equals(log.length, 2);
+ const instance = document.querySelector("infinite-cloning-element-1");
+ assert_array_equals(log[0], [instance, 'begin']);
+ assert_array_equals(log[1], [instance, 'end']);
+}, 'Infinite constructor recursion with upgrade(this) should not be possible');
+
+test(() => {
+ var log = [];
+
+ customElements.define('infinite-cloning-element-2',class extends HTMLElement {
+ constructor() {
+ super();
+ log.push([this, 'begin']);
+ const b = document.querySelector("#b");
+ b.remove();
+ // While this constructor is running for "a", "b" is still
+ // undefined, and so inserting it into the document will enqueue a
+ // second upgrade reaction for "b" in addition to the one enqueued
+ // by defining x-foo.
+ document.body.appendChild(b);
+ log.push([this, 'end']);
+ }
+ });
+
+ assert_equals(log.length, 4);
+ const instanceA = document.querySelector("#a");
+ const instanceB = document.querySelector("#b");
+ assert_array_equals(log[0], [instanceA, 'begin']);
+ assert_array_equals(log[1], [instanceB, 'begin']);
+ assert_array_equals(log[2], [instanceB, 'end']);
+ assert_array_equals(log[3], [instanceA, 'end']);
+}, 'Infinite constructor recursion with appendChild should not be possible');
+
+
+</script>
+</body>
+</html>