Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
| 2 <title>Custom Elements: defineElement</title> | 2 <title>Custom Elements: defineElement</title> |
| 3 <link rel="help" href="https://html.spec.whatwg.org/multipage/scripting.html#cus tomelementsregistry"> | 3 <link rel="help" href="https://html.spec.whatwg.org/multipage/scripting.html#cus tomelementsregistry"> |
| 4 <meta name="author" title="Dominic Cooney" href="mailto:dominicc@chromium.org"> | 4 <meta name="author" title="Dominic Cooney" href="mailto:dominicc@chromium.org"> |
| 5 <script src="../../resources/testharness.js"></script> | 5 <script src="../../resources/testharness.js"></script> |
| 6 <script src="../../resources/testharness-helpers.js"></script> | 6 <script src="../../resources/testharness-helpers.js"></script> |
| 7 <script src="../../resources/testharnessreport.js"></script> | 7 <script src="../../resources/testharnessreport.js"></script> |
| 8 <script src="resources/custom-elements-helpers.js"></script> | 8 <script src="resources/custom-elements-helpers.js"></script> |
| 9 <body> | 9 <body> |
| 10 <script> | 10 <script> |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 57 test_with_window((w) => { | 57 test_with_window((w) => { |
| 58 class X extends w.HTMLElement {} | 58 class X extends w.HTMLElement {} |
| 59 class Y extends w.HTMLElement {} | 59 class Y extends w.HTMLElement {} |
| 60 w.customElements.define('a-a', X); | 60 w.customElements.define('a-a', X); |
| 61 assert_throws('NotSupportedError', () => { | 61 assert_throws('NotSupportedError', () => { |
| 62 w.customElements.define('a-a', Y); | 62 w.customElements.define('a-a', Y); |
| 63 }, 'defining an element with a name that is already defined should throw ' + | 63 }, 'defining an element with a name that is already defined should throw ' + |
| 64 'a NotSupportedError'); | 64 'a NotSupportedError'); |
| 65 }, 'Duplicate name'); | 65 }, 'Duplicate name'); |
| 66 | 66 |
| 67 // TODO(dominicc): Update this (perhaps by removing this comment) when | 67 |
|
dominicc (has gone to gerrit)
2016/06/23 04:13:10
Delete this blank line; put just one blank line be
| |
| 68 // https://github.com/whatwg/html/pull/1333 lands/issue | |
| 69 // https://github.com/whatwg/html/issues/1329 is closed. | |
| 70 test_with_window((w) => { | 68 test_with_window((w) => { |
| 71 class Y extends w.HTMLElement {} | 69 class Y extends w.HTMLElement {} |
| 72 let X = (function () {}).bind({}); | 70 let X = (function () {}).bind({}); |
| 73 Object.defineProperty(X, 'prototype', { | 71 Object.defineProperty(X, 'prototype', { |
| 74 get() { | 72 get() { |
| 75 assert_throws('NotSupportedError', () => { | 73 assert_throws('NotSupportedError', () => { |
| 76 w.customElements.define('a-a', Y); | 74 w.customElements.define('a-a', Y); |
| 77 }, 'defining an element with a name that is being defined should ' + | 75 }, 'defining an element with a name that is being defined should ' + |
| 78 'throw a NotSupportedError'); | 76 'throw a NotSupportedError'); |
| 79 return new Object(); | 77 return new Object(); |
| 80 } | 78 } |
| 81 }); | 79 }); |
| 82 // TODO(dominicc): When callback retrieval is implemented, change this | |
| 83 // to pass a valid constructor and recursively call define when retrieving | |
| 84 // callbacks instead; then it is possible to assert the first definition | |
| 85 // worked: | |
| 86 // let element = Reflect.construct(HTMLElement, [], X); | |
| 87 // assert_equals(element.localName, 'a-a'); | |
| 88 w.customElements.define('a-a', X); | 80 w.customElements.define('a-a', X); |
| 81 assert_true(w.customElements.get('a-a') === X, 'asserting that the first defin ition worked'); | |
|
dominicc (has gone to gerrit)
2016/06/23 04:13:10
Don't put "asserting" in the message because that'
| |
| 82 assert_false(w.customElements.get('a-a') === Y, 'asserting that the first defi nition worked'); | |
|
dominicc (has gone to gerrit)
2016/06/23 04:13:10
You can probably omit this assertion; it is not ve
| |
| 89 }, 'Duplicate name defined recursively'); | 83 }, 'Duplicate name defined recursively'); |
| 90 | 84 |
| 91 test_with_window((w) => { | 85 test_with_window((w) => { |
| 92 class X extends w.HTMLElement {} | 86 class X extends w.HTMLElement {} |
| 93 w.customElements.define('a-a', X); | 87 w.customElements.define('a-a', X); |
| 94 assert_throws('NotSupportedError', () => { | 88 assert_throws('NotSupportedError', () => { |
| 95 w.customElements.define('a-b', X); | 89 w.customElements.define('a-b', X); |
| 96 }, 'defining an element with a constructor that is already in the ' + | 90 }, 'defining an element with a constructor that is already in the ' + |
| 97 'registry should throw a NotSupportedError'); | 91 'registry should throw a NotSupportedError'); |
| 98 }, 'Reused constructor'); | 92 }, 'Reused constructor'); |
| 99 | 93 |
| 100 // TODO(dominicc): Update this (perhaps by removing this comment) when | |
| 101 // https://github.com/whatwg/html/pull/1333 lands/issue | |
| 102 // https://github.com/whatwg/html/issues/1329 is closed. | |
| 103 test_with_window((w) => { | 94 test_with_window((w) => { |
| 104 let X = (function () {}).bind({}); | 95 let X = (function () {}).bind({}); |
| 105 Object.defineProperty(X, 'prototype', { | 96 Object.defineProperty(X, 'prototype', { |
| 106 get() { | 97 get() { |
| 107 assert_throws('NotSupportedError', () => { | 98 assert_throws('NotSupportedError', () => { |
| 108 w.customElements.define('second-name', X); | 99 w.customElements.define('second-name', X); |
| 109 }, 'defining an element with a constructor that is being defined ' + | 100 }, 'defining an element with a constructor that is being defined ' + |
| 110 'should throw a NotSupportedError'); | 101 'should throw a NotSupportedError'); |
| 111 return new Object(); | 102 return new Object(); |
| 112 } | 103 } |
| 113 }); | 104 }); |
| 114 // TODO(dominicc): When callback retrieval is implemented, change this | |
| 115 // to pass a valid constructor and recursively call define when retrieving | |
| 116 // callbacks instead; then it is possible to assert the first definition | |
| 117 // worked: | |
| 118 // let element = Reflect.construct(HTMLElement, [], X); | |
| 119 // assert_equals(element.localName, 'a-a'); | |
| 120 w.customElements.define('first-name', X); | 105 w.customElements.define('first-name', X); |
| 106 assert_true(w.customElements.get('first-name') === X, 'asserting that the firs t definition worked'); | |
| 107 assert_false(w.customElements.get('second-name') === X, 'asserting that the fi rst definition worked'); | |
| 121 }, 'Reused constructor recursively'); | 108 }, 'Reused constructor recursively'); |
| 122 | 109 |
| 123 test_with_window((w) => { | 110 test_with_window((w) => { |
| 124 function F() {} | 111 function F() {} |
| 125 F.prototype = 42; | 112 F.prototype = 42; |
| 126 assert_throws(TypeError.prototype, () => { | 113 assert_throws(TypeError.prototype, () => { |
| 127 w.customElements.define('a-a', F); | 114 w.customElements.define('a-a', F); |
| 128 }, 'defining an element with a constructor with a prototype that is not an ' + | 115 }, 'defining an element with a constructor with a prototype that is not an ' + |
| 129 'object should throw a TypeError'); | 116 'object should throw a TypeError'); |
| 130 }, 'Retrieved prototype is a non-object'); | 117 }, 'Retrieved prototype is a non-object'); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 185 'to the defined prototype'); | 172 'to the defined prototype'); |
| 186 invocations.push(this); | 173 invocations.push(this); |
| 187 } | 174 } |
| 188 } | 175 } |
| 189 w.customElements.define('a-a', C); | 176 w.customElements.define('a-a', C); |
| 190 assert_array_equals([a], invocations, | 177 assert_array_equals([a], invocations, |
| 191 'the constructor should have been invoked for the in-' + | 178 'the constructor should have been invoked for the in-' + |
| 192 'document element'); | 179 'document element'); |
| 193 }, 'Upgrade: sets prototype of existing elements'); | 180 }, 'Upgrade: sets prototype of existing elements'); |
| 194 | 181 |
| 182 | |
| 195 test_with_window((w) => { | 183 test_with_window((w) => { |
| 196 let doc = w.document; | 184 let doc = w.document; |
| 197 var shadow = doc.body.attachShadow({mode: 'open'}); | 185 var shadow = doc.body.attachShadow({mode: 'open'}); |
| 198 let a = doc.createElement('a-a'); | 186 let a = doc.createElement('a-a'); |
| 199 shadow.appendChild(a); | 187 shadow.appendChild(a); |
| 200 let invocations = []; | 188 let invocations = []; |
| 201 class C extends w.HTMLElement { | 189 class C extends w.HTMLElement { |
| 202 constructor() { | 190 constructor() { |
| 203 super(); | 191 super(); |
| 204 invocations.push(this); | 192 invocations.push(this); |
| 205 } | 193 } |
| 206 } | 194 } |
| 207 w.customElements.define('a-a', C); | 195 w.customElements.define('a-a', C); |
| 208 assert_array_equals([a], invocations, | 196 assert_array_equals([a], invocations, |
| 209 'the constructor should have been invoked once for the ' + | 197 'the constructor should have been invoked once for the ' + |
| 210 'elements in the shadow tree'); | 198 'elements in the shadow tree'); |
| 211 }, 'Upgrade: shadow tree'); | 199 }, 'Upgrade: shadow tree'); |
| 200 | |
| 201 test_with_window((w) => { | |
| 202 let invocations = []; | |
|
dominicc (has gone to gerrit)
2016/06/23 04:13:10
There's only one thing going into invocations, so
| |
| 203 class Y extends w.HTMLElement {} | |
| 204 let X = (function () {}).bind({}); | |
| 205 Object.defineProperty(X, 'prototype', { | |
| 206 get() { throw 42; } | |
| 207 }); | |
| 208 try { | |
| 209 w.customElements.define('a-a', X); | |
| 210 } catch(e) { | |
| 211 invocations.push(e); | |
| 212 } | |
| 213 assert_equals(invocations[0], 42, 'rethrows Get(constructor, "prototype") exce ption'); | |
| 214 w.customElements.define('a-a', Y); | |
| 215 assert_true(w.customElements.get('a-a') === Y, 'algorithm terminates when the first set of steps threw an exception'); | |
|
dominicc (has gone to gerrit)
2016/06/23 04:13:10
"the first set of steps" is a bit vague. This desc
| |
| 216 }, 'If an exception is thrown, rethrow that exception and terminate the algorith m'); | |
| 217 | |
| 218 test_with_window((w) => { | |
|
dominicc (has gone to gerrit)
2016/06/23 04:13:10
Tests from here vvv
| |
| 219 function F() {} | |
| 220 F.prototype = new Object(); | |
| 221 Object.defineProperty(F.prototype, 'connectedCallback', { | |
| 222 get() { return new Object(); } | |
| 223 }); | |
| 224 assert_throws(TypeError.prototype, () => { | |
| 225 w.customElements.define('a-a', F); | |
| 226 }, 'defining an element with a constructor with a connectedCallback that is ' + | |
| 227 'not undefined and not callable should throw a TypeError'); | |
| 228 }, 'Retrieved connectedCallback is not undefined and not callable'); | |
| 229 | |
| 230 test_with_window((w) => { | |
| 231 function F() {} | |
| 232 F.prototype = new Object(); | |
| 233 Object.defineProperty(F.prototype, 'disconnectedCallback', { | |
| 234 get() { return new Object(); } | |
| 235 }); | |
| 236 assert_throws(TypeError.prototype, () => { | |
| 237 w.customElements.define('a-a', F); | |
| 238 }, 'defining an element with a constructor with a disconnectedCallback that is ' + | |
| 239 'not undefined and not callable should throw a TypeError'); | |
| 240 }, 'Retrieved disconnectedCallback is not undefined and not callable'); | |
| 241 | |
| 242 test_with_window((w) => { | |
| 243 function F() {} | |
| 244 F.prototype = new Object(); | |
| 245 Object.defineProperty(F.prototype, 'attributeChangedCallback', { | |
| 246 get() {return new Object(); } | |
| 247 }); | |
| 248 assert_throws(TypeError.prototype, () => { | |
| 249 w.customElements.define('a-a', F); | |
| 250 }, 'defining an element with a constructor with a attribiteChangedCallback tha t is ' + | |
| 251 'not undefined and not callable should throw a TypeError'); | |
| 252 }, 'Retrieved attrbuteChangedCallback is not undefined and not callable'); | |
|
dominicc (has gone to gerrit)
2016/06/23 04:13:10
... to here ^^^
are perfect. Good work.
| |
| 253 | |
| 254 // should be TypeError | |
| 255 test_with_window((w) => { | |
| 256 let invalid_name = 'annotation-xml'; | |
| 257 assert_throws('SYNTAX_ERR', () => { | |
|
dominicc (has gone to gerrit)
2016/06/23 04:13:10
The implementation has a bug you found--awesome. W
| |
| 258 w.customElements.define(invalid_name, HTMLElement); | |
| 259 }, 'defining a constructor that is an interface object whose interface is HT MLElement' + | |
| 260 'should throw TypeError not SyntaxError'); | |
|
dominicc (has gone to gerrit)
2016/06/23 04:13:09
Let's put a comment mentioning the exact step.
Th
| |
| 261 }, 'Invalid constructor'); | |
| 262 | |
| 263 // should be TypeError | |
| 264 test_with_window((w) => { | |
| 265 let invalid_name = 'annotation-xml'; | |
| 266 assert_throws('SYNTAX_ERR', () => { | |
| 267 w.customElements.define(invalid_name, HTMLButtonElement); | |
| 268 }, 'defining a constructor that is an interface object who has HTMLElement i n its set of inhertied interfaces' + | |
| 269 'should throw TypeError not SyntaxError'); | |
| 270 }, 'Invalid constructor'); | |
| 271 | |
| 272 | |
| 273 test_with_window((w) => { | |
| 274 let invalid_name = 'annotation-xml'; | |
| 275 assert_throws('SYNTAX_ERR', () => { | |
| 276 w.customElements.define(invalid_name, class extends HTMLElement {}); | |
| 277 }, 'defining author-defined custom element constructor' + | |
| 278 'should pass this step without throwing TypeError'); | |
| 279 }, 'Invalid constructor'); | |
| 280 | |
| 281 | |
| 282 test_with_window((w) => { | |
| 283 let element = w.document.createElement('a-a'); | |
| 284 w.document.body.appendChild(element); | |
| 285 w.customElements.define('a-a', Set); | |
| 286 assert_true(w.customElements.get('a-a') === Set, 'definition is added to Custo mElementRegistry'); | |
| 287 assert_equals(element.matches(':defined'), false, 'fails during upgrade'); | |
| 288 assert_equals(element.matches(':not(:defined)'), true, 'fails during upgrade') ; | |
| 289 }, 'Invalid constructor'); | |
| 290 | |
| 291 | |
| 212 </script> | 292 </script> |
| OLD | NEW |