Document-importNode.html (9452B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> 5 <link rel="help" href="https://github.com/whatwg/html/issues/10854"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 </head> 9 <body> 10 <div id="host"> 11 <template shadowrootmode="open" shadowrootclonable="true" shadowrootcustomelementregistry> 12 <div> 13 <some-element></some-element> 14 <other-element></other-element> 15 </div> 16 </template> 17 </div> 18 <template id="template"> 19 <some-element> 20 <template shadowrootmode="closed" shadowrootclonable="true" shadowrootcustomelementregistry> 21 <div> 22 <some-element></some-element> 23 <other-element></other-element> 24 </div> 25 </template> 26 </some-element> 27 </template> 28 <div id="root"> 29 <span></span> 30 </div> 31 <script> 32 33 const scopedRegistry = new CustomElementRegistry(); 34 const emptyRegistry = new CustomElementRegistry(); 35 class GlobalSomeElement extends HTMLElement { 36 elementInternals; 37 38 constructor() { 39 super(); 40 this.elementInternals = this.attachInternals(); 41 if (this.elementInternals.shadowRoot) 42 scopedRegistry.initialize(this.elementInternals.shadowRoot); 43 } 44 }; 45 class GlobalOtherElement extends HTMLElement {}; 46 class ScopedSomeElement extends HTMLElement {}; 47 customElements.define('some-element', GlobalSomeElement); 48 customElements.define('other-element', GlobalOtherElement); 49 scopedRegistry.define('some-element', ScopedSomeElement); 50 51 test(() => { 52 assert_true(document.importNode(document.createElement('some-element')) instanceof GlobalSomeElement); 53 }, 'importNode should clone using the global regsitry by default'); 54 55 test(() => { 56 assert_true(document.importNode(document.createElement('some-element'), {customElementRegistry: scopedRegistry}) instanceof GlobalSomeElement); 57 }, 'importNode should clone using target\'s registry if non-null'); 58 59 test(() => { 60 assert_true(document.importNode(document.implementation.createHTMLDocument().createElement('some-element'), {customElementRegistry: scopedRegistry}) instanceof ScopedSomeElement); 61 }, 'importNode should clone using the specified registry if target\'s registry is null'); 62 63 test(() => { 64 const clone = document.importNode(host, {selfOnly: false, customElementRegistry: scopedRegistry}); 65 assert_equals(clone.shadowRoot.querySelector('some-element').__proto__.constructor.name, 'HTMLElement'); 66 assert_false(clone.shadowRoot.querySelector('some-element') instanceof GlobalSomeElement); 67 assert_false(clone.shadowRoot.querySelector('some-element') instanceof ScopedSomeElement); 68 assert_true(clone.shadowRoot.querySelector('other-element') instanceof HTMLElement); 69 assert_false(clone.shadowRoot.querySelector('other-element') instanceof GlobalOtherElement); 70 }, 'importNode should preserve null-ness of custom element registry'); 71 72 test(() => { 73 const clone = document.importNode(host.shadowRoot.querySelector('div'), {selfOnly: false}); 74 assert_equals(clone.customElementRegistry, window.customElements); 75 assert_true(clone.querySelector('some-element') instanceof GlobalSomeElement); 76 assert_true(clone.querySelector('other-element') instanceof GlobalOtherElement); 77 }, 'importNode should clone a shadow host with a declarative shadow DOM using the global registry by default'); 78 79 test(() => { 80 const clone = document.importNode(host.shadowRoot.querySelector('div'), {selfOnly: false, customElementRegistry: scopedRegistry}); 81 assert_equals(clone.customElementRegistry, scopedRegistry); 82 assert_true(clone.querySelector('some-element') instanceof ScopedSomeElement); 83 assert_false(clone.querySelector('other-element') instanceof GlobalOtherElement); 84 }, 'importNode should clone a shadow host with a declarative shadow DOM using a specified scoped registry'); 85 86 test(() => { 87 const element = document.createElement('div', {customElementRegistry: emptyRegistry}); 88 element.innerHTML = '<some-element></some-element><other-element></other-element>'; 89 const clone = document.importNode(element, {selfOnly: false, customElementRegistry: scopedRegistry}); 90 assert_equals(clone.customElementRegistry, emptyRegistry); 91 assert_true(clone.querySelector('some-element') instanceof HTMLElement); 92 assert_false(clone.querySelector('some-element') instanceof GlobalSomeElement); 93 assert_false(clone.querySelector('some-element') instanceof ScopedSomeElement); 94 assert_true(clone.querySelector('other-element') instanceof HTMLElement); 95 assert_false(clone.querySelector('other-element') instanceof GlobalOtherElement); 96 }, 'importNode should clone using target\'s registry if non-null, including when it\'s not the global registry'); 97 98 test(() => { 99 const template = document.createElement('template'); 100 template.innerHTML = '<div><some-element>hello</some-element><other-element>world</other-element></div>'; 101 assert_equals(template.content.querySelector('some-element').__proto__.constructor.name, 'HTMLElement'); 102 assert_equals(template.content.querySelector('other-element').__proto__.constructor.name, 'HTMLElement'); 103 const clone = document.importNode(template.content, {selfOnly: false}); 104 assert_equals(clone.querySelector('some-element').customElementRegistry, window.customElements); 105 assert_equals(clone.querySelector('some-element').__proto__.constructor.name, 'GlobalSomeElement'); 106 assert_equals(clone.querySelector('other-element').__proto__.constructor.name, 'GlobalOtherElement'); 107 }, 'importNode should clone a template content using the global registry by default'); 108 109 test(() => { 110 const template = document.createElement('template'); 111 template.innerHTML = '<div><some-element>hello</some-element><other-element>world</other-element></div>'; 112 assert_equals(template.content.querySelector('some-element').__proto__.constructor.name, 'HTMLElement'); 113 assert_equals(template.content.querySelector('other-element').__proto__.constructor.name, 'HTMLElement'); 114 const clone = document.importNode(template.content, {selfOnly: false, customElementRegistry: scopedRegistry}); 115 assert_equals(clone.querySelector('some-element').customElementRegistry, scopedRegistry); 116 assert_equals(clone.querySelector('some-element').__proto__.constructor.name, 'ScopedSomeElement'); 117 assert_equals(clone.querySelector('other-element').__proto__.constructor.name, 'HTMLElement'); 118 }, 'importNode should clone a template content using a specified scoped registry'); 119 120 test(() => { 121 const template = document.createElement('template'); 122 template.innerHTML = ` 123 <div> 124 <some-element> 125 <template> 126 <other-element> 127 hello 128 </other-element> 129 </template> 130 </some-element> 131 <other-element> 132 world 133 </other-element> 134 </div>`; 135 assert_equals(template.content.querySelector('some-element').__proto__.constructor.name, 'HTMLElement'); 136 assert_equals(template.content.querySelector('other-element').__proto__.constructor.name, 'HTMLElement'); 137 const clone = document.importNode(template.content, {selfOnly: false}); 138 assert_equals(clone.querySelector('some-element').customElementRegistry, window.customElements); 139 assert_equals(clone.querySelector('some-element').__proto__.constructor.name, 'GlobalSomeElement'); 140 const otherElementInTemplate = clone.querySelector('template').content.querySelector('other-element'); 141 assert_equals(otherElementInTemplate.__proto__.constructor.name, 'HTMLElement'); 142 assert_equals(clone.querySelector('other-element').__proto__.constructor.name, 'GlobalOtherElement'); 143 }, 'importNode should clone a template content with a nested template element using a scoped registry'); 144 145 test(() => { 146 const clone = document.importNode(root); 147 assert_false(clone.hasChildNodes()); 148 }, "importNode: don't pass options argument"); 149 150 test(() => { 151 const clone = document.importNode(root, false); 152 assert_false(clone.hasChildNodes()); 153 }, "importNode: pass options argument with value false"); 154 155 test(() => { 156 const clone = document.importNode(root, true); 157 assert_true(clone.hasChildNodes()); 158 }, "importNode: pass options argument with value true"); 159 160 test(() => { 161 const clone = document.importNode(root, undefined); 162 assert_false(clone.hasChildNodes()); 163 }, "importNode: pass options argument with value undefined"); 164 165 test(() => { 166 const clone = document.importNode(root, { }); 167 assert_true(clone.hasChildNodes()); 168 }, "importNode: pass options argument with value { }"); 169 170 test(() => { 171 const clone = document.importNode(root, { selfOnly: false }); 172 assert_true(clone.hasChildNodes()); 173 }, "importNode: pass options argument with value { selfOnly: false }"); 174 175 test(() => { 176 const clone = document.importNode(root, { selfOnly: true }); 177 assert_false(clone.hasChildNodes()); 178 }, "importNode: pass options argument with value { selfOnly: true }"); 179 180 test(() => { 181 const clone = document.importNode(root, { customElementRegistry: scopedRegistry }); 182 assert_true(clone.hasChildNodes()); 183 }, "importNode: pass options argument with value { customElementRegistry: scopedRegistry }"); 184 185 test(() => { 186 assert_throws_js(TypeError, () => document.importNode(root, { customElementRegistry: null })); 187 }, "importNode: pass options argument with value { customElementRegistry: null }"); 188 189 </script> 190 </body> 191 </html>