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