| <!DOCTYPE html> |
| <title>Custom Elements: namespace prefix is set after construction per spec</title> |
| <link rel="help" content="https://dom.spec.whatwg.org/#concept-create-element"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <body> |
| <script> |
| // Step 5.1.3.9 of https://dom.spec.whatwg.org/#concept-create-element sets |
| // the namespace prefix AFTER the constructor returns. These tests verify that |
| // the prefix is not observable during construction but is correct afterwards. |
| |
| test(() => { |
| let prefixDuringConstructor; |
| let tagNameDuringConstructor; |
| |
| class PrefixEl extends HTMLElement { |
| constructor() { |
| super(); |
| prefixDuringConstructor = this.prefix; |
| tagNameDuringConstructor = this.tagName; |
| } |
| } |
| customElements.define('prefix-timing-el', PrefixEl); |
| |
| const el = document.createElementNS('http://www.w3.org/1999/xhtml', 'p:prefix-timing-el'); |
| |
| assert_equals(prefixDuringConstructor, null, |
| 'prefix should be null during constructor (set after construction per step 5.1.3.9)'); |
| assert_equals(tagNameDuringConstructor, 'PREFIX-TIMING-EL', |
| 'tagName during constructor should not include prefix'); |
| |
| assert_equals(el.prefix, 'p', |
| 'prefix should be set after construction'); |
| assert_equals(el.tagName, 'P:PREFIX-TIMING-EL', |
| 'tagName after construction should include prefix'); |
| }, 'Autonomous custom element prefix is set after constructor returns'); |
| |
| test(() => { |
| let innerPrefix; |
| let outerPrefixDuringConstructor; |
| |
| class ReentrantEl extends HTMLElement { |
| static callCount = 0; |
| constructor() { |
| super(); |
| if (ReentrantEl.callCount++ === 0) { |
| // Create another instance via direct construction re-entrantly |
| // during outer (createElementNS-initiated) construction. |
| const inner = new ReentrantEl(); |
| innerPrefix = inner.prefix; |
| } |
| outerPrefixDuringConstructor = this.prefix; |
| } |
| } |
| customElements.define('reentrant-prefix-el', ReentrantEl); |
| |
| const el = document.createElementNS('http://www.w3.org/1999/xhtml', 'r:reentrant-prefix-el'); |
| |
| assert_equals(outerPrefixDuringConstructor, null, |
| 'outer prefix should be null during constructor'); |
| assert_equals(innerPrefix, null, |
| 'directly-constructed inner element should not inherit outer prefix'); |
| assert_equals(el.prefix, 'r', |
| 'outer element prefix should be set after construction'); |
| }, 'Reentrant construction does not leak prefix between instances'); |
| |
| test(() => { |
| let prefixDuringConstructor; |
| let outerElement; |
| |
| class ReentrantNSEl extends HTMLElement { |
| static callCount = 0; |
| constructor() { |
| super(); |
| if (ReentrantNSEl.callCount++ === 0) { |
| outerElement = this; |
| // Create another instance via createElementNS re-entrantly. |
| const inner = document.createElementNS('http://www.w3.org/1999/xhtml', 'q:reentrant-ns-el'); |
| assert_equals(inner.prefix, 'q', 'inner element created during outer constructor should have its own prefix'); |
| } |
| prefixDuringConstructor = this.prefix; |
| } |
| } |
| customElements.define('reentrant-ns-el', ReentrantNSEl); |
| |
| const el = document.createElementNS('http://www.w3.org/1999/xhtml', 'p:reentrant-ns-el'); |
| |
| assert_equals(el.prefix, 'p', |
| 'outer element should have its own prefix'); |
| assert_equals(outerElement, el, |
| 'outerElement reference should match returned element'); |
| }, 'Nested createElementNS calls do not corrupt prefix state'); |
| </script> |
| </body> |