OLD | NEW |
(Empty) | |
| 1 <!DOCTYPE html> |
| 2 <html> |
| 3 <head> |
| 4 <title>Custom Elements: Upgrading</title> |
| 5 <meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> |
| 6 <meta name="assert" content="Node.prototype.cloneNode should upgrade a custom el
ement"> |
| 7 <link rel="help" href="https://html.spec.whatwg.org/#upgrades"> |
| 8 <script src="/resources/testharness.js"></script> |
| 9 <script src="/resources/testharnessreport.js"></script> |
| 10 <script src="../resources/custom-elements-helpers.js"></script> |
| 11 </head> |
| 12 <body> |
| 13 <div id="log"></div> |
| 14 <script> |
| 15 |
| 16 test(function () { |
| 17 class MyCustomElement extends HTMLElement {} |
| 18 customElements.define('my-custom-element', MyCustomElement); |
| 19 |
| 20 var instance = document.createElement('my-custom-element'); |
| 21 assert_true(instance instanceof HTMLElement); |
| 22 assert_true(instance instanceof MyCustomElement); |
| 23 |
| 24 var clone = instance.cloneNode(false); |
| 25 assert_not_equals(instance, clone); |
| 26 assert_true(clone instanceof HTMLElement, |
| 27 'A cloned custom element must be an instance of HTMLElement'); |
| 28 assert_true(clone instanceof MyCustomElement, |
| 29 'A cloned custom element must be an instance of the custom element'); |
| 30 }, 'Node.prototype.cloneNode(false) must be able to clone a custom element'); |
| 31 |
| 32 test_with_window(function (contentWindow) { |
| 33 var contentDocument = contentWindow.document; |
| 34 class MyCustomElement extends contentWindow.HTMLElement {} |
| 35 contentWindow.customElements.define('my-custom-element', MyCustomElement); |
| 36 |
| 37 var instance = contentDocument.createElement('my-custom-element'); |
| 38 assert_true(instance instanceof contentWindow.HTMLElement); |
| 39 assert_true(instance instanceof MyCustomElement); |
| 40 |
| 41 var clone = instance.cloneNode(false); |
| 42 assert_not_equals(instance, clone); |
| 43 assert_true(clone instanceof contentWindow.HTMLElement, |
| 44 'A cloned custom element must be an instance of HTMLElement'); |
| 45 assert_true(clone instanceof MyCustomElement, |
| 46 'A cloned custom element must be an instance of the custom element'); |
| 47 }, 'Node.prototype.cloneNode(false) must be able to clone a custom element insid
e an iframe'); |
| 48 |
| 49 test_with_window(function (contentWindow) { |
| 50 var contentDocument = contentWindow.document; |
| 51 class MyCustomElement extends contentWindow.HTMLElement { } |
| 52 contentWindow.customElements.define('my-custom-element', MyCustomElement); |
| 53 |
| 54 var instance = contentDocument.createElement('my-custom-element'); |
| 55 var container = contentDocument.createElement('div'); |
| 56 container.appendChild(instance); |
| 57 |
| 58 var containerClone = container.cloneNode(true); |
| 59 assert_true(containerClone instanceof contentWindow.HTMLDivElement); |
| 60 |
| 61 var clone = containerClone.firstChild; |
| 62 assert_not_equals(instance, clone); |
| 63 assert_true(clone instanceof contentWindow.HTMLElement, |
| 64 'A cloned custom element must be an instance of HTMLElement'); |
| 65 assert_true(clone instanceof MyCustomElement, |
| 66 'A cloned custom element must be an instance of the custom element'); |
| 67 }, 'Node.prototype.cloneNode(true) must be able to clone a descendent custom ele
ment'); |
| 68 |
| 69 test_with_window(function (contentWindow) { |
| 70 var parentNodeInConstructor; |
| 71 var previousSiblingInConstructor; |
| 72 var nextSiblingInConstructor; |
| 73 class MyCustomElement extends contentWindow.HTMLElement { |
| 74 constructor() { |
| 75 super(); |
| 76 parentNodeInConstructor = this.parentNode; |
| 77 previousSiblingInConstructor = this.previousSibling; |
| 78 nextSiblingInConstructor = this.nextSibling; |
| 79 } |
| 80 } |
| 81 contentWindow.customElements.define('my-custom-element', MyCustomElement); |
| 82 |
| 83 var contentDocument = contentWindow.document; |
| 84 var instance = contentDocument.createElement('my-custom-element'); |
| 85 var siblingBeforeInstance = contentDocument.createElement('b'); |
| 86 var siblingAfterInstance = contentDocument.createElement('a'); |
| 87 var container = contentDocument.createElement('div'); |
| 88 container.appendChild(siblingBeforeInstance); |
| 89 container.appendChild(instance); |
| 90 container.appendChild(siblingAfterInstance); |
| 91 |
| 92 var containerClone = container.cloneNode(true); |
| 93 |
| 94 assert_equals(parentNodeInConstructor, containerClone, |
| 95 'An upgraded element must have its parentNode set before the custom elem
ent constructor is called'); |
| 96 assert_equals(previousSiblingInConstructor, containerClone.firstChild, |
| 97 'An upgraded element must have its previousSibling set before the custom
element constructor is called'); |
| 98 assert_equals(nextSiblingInConstructor, containerClone.lastChild, |
| 99 'An upgraded element must have its nextSibling set before the custom ele
ment constructor is called'); |
| 100 }, 'Node.prototype.cloneNode(true) must set parentNode, previousSibling, and nex
tSibling before upgrading custom elements'); |
| 101 |
| 102 test_with_window(function (contentWindow) { |
| 103 class MyCustomElement extends contentWindow.HTMLElement { |
| 104 constructor(doNotCreateItself) { |
| 105 super(); |
| 106 if (!doNotCreateItself) |
| 107 new MyCustomElement(true); |
| 108 } |
| 109 } |
| 110 contentWindow.customElements.define('my-custom-element', MyCustomElement); |
| 111 |
| 112 var instance = new MyCustomElement(false); |
| 113 var uncaughtError; |
| 114 contentWindow.onerror = function (message, url, lineNumber, columnNumber, er
ror) { uncaughtError = error; return true; } |
| 115 instance.cloneNode(false); |
| 116 assert_equals(uncaughtError.name, 'InvalidStateError'); |
| 117 }, 'HTMLElement constructor must throw an InvalidStateError when the top of the
construction stack is marked AlreadyConstructed' |
| 118 + ' due to a custom element constructor constructing itself after super() ca
ll'); |
| 119 |
| 120 test_with_window(function (contentWindow) { |
| 121 class MyCustomElement extends contentWindow.HTMLElement { |
| 122 constructor(doNotCreateItself) { |
| 123 if (!doNotCreateItself) |
| 124 new MyCustomElement(true); |
| 125 super(); |
| 126 } |
| 127 } |
| 128 contentWindow.customElements.define('my-custom-element', MyCustomElement); |
| 129 |
| 130 var instance = new MyCustomElement(false); |
| 131 var uncaughtError; |
| 132 contentWindow.onerror = function (message, url, lineNumber, columnNumber, er
ror) { uncaughtError = error; return true; } |
| 133 instance.cloneNode(false); |
| 134 assert_equals(uncaughtError.name, 'InvalidStateError'); |
| 135 }, 'HTMLElement constructor must throw an InvalidStateError when the top of the
construction stack is marked AlreadyConstructed' |
| 136 + ' due to a custom element constructor constructing itself before super() c
all'); |
| 137 |
| 138 test_with_window(function (contentWindow) { |
| 139 var contentDocument = contentWindow.document; |
| 140 var returnSpan = false; |
| 141 class MyCustomElement extends contentWindow.HTMLElement { |
| 142 constructor() { |
| 143 super(); |
| 144 if (returnSpan) |
| 145 return contentDocument.createElement('span'); |
| 146 } |
| 147 } |
| 148 contentWindow.customElements.define('my-custom-element', MyCustomElement); |
| 149 |
| 150 var instance = new MyCustomElement(false); |
| 151 returnSpan = true; |
| 152 var uncaughtError; |
| 153 contentWindow.onerror = function (message, url, lineNumber, columnNumber, er
ror) { uncaughtError = error; return true; } |
| 154 instance.cloneNode(false); |
| 155 assert_equals(uncaughtError.name, 'InvalidStateError'); |
| 156 }, 'Upgrading a custom element must throw InvalidStateError when the custom elem
ent\'s constructor returns another element'); |
| 157 |
| 158 test_with_window(function (contentWindow) { |
| 159 var contentDocument = contentWindow.document; |
| 160 var instance = contentDocument.createElement('my-custom-element'); |
| 161 contentDocument.body.appendChild(instance); |
| 162 |
| 163 var calls = []; |
| 164 class MyCustomElement extends contentWindow.HTMLElement { |
| 165 constructor() { |
| 166 super(); |
| 167 calls.push(this); |
| 168 throw 'bad'; |
| 169 } |
| 170 } |
| 171 |
| 172 var uncaughtError; |
| 173 contentWindow.onerror = function (message, url, lineNumber, columnNumber, er
ror) { uncaughtError = error; return true; } |
| 174 contentWindow.customElements.define('my-custom-element', MyCustomElement); |
| 175 assert_equals(uncaughtError, 'bad'); |
| 176 |
| 177 assert_array_equals(calls, [instance]); |
| 178 contentDocument.body.removeChild(instance); |
| 179 contentDocument.body.appendChild(instance); |
| 180 assert_array_equals(calls, [instance]); |
| 181 }, 'Inserting an element must not try to upgrade a custom element when it had al
ready failed to upgrade once'); |
| 182 |
| 183 </script> |
| 184 </body> |
| 185 </html> |
OLD | NEW |