Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!DOCTYPE html>
<meta name="author" title="Xiaocheng Hu" href="mailto:xiaochengh@chromium.org">
<meta name="assert" content="Custom element constructors can re-enter with different definitions">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id='test-container-1'></div>
<div id='test-container-2'></div>
<script>
setup({allow_uncaught_exception : true});
function createShadowForTest(t, registry) {
const host = document.createElement('div');
const shadow = host.attachShadow({mode: 'open', registry});
document.body.appendChild(host);
t.add_cleanup(() => host.remove());
return shadow;
}
test(t => {
let needsTest = true;
class ReentryBeforeSuper extends HTMLElement {
constructor() {
if (needsTest) {
needsTest = false;
document.getElementById('test-container-1').innerHTML =
'<test-element-1></test-element-1>';
}
super();
}
};
window.customElements.define('test-element-1', ReentryBeforeSuper);
let registry = new CustomElementRegistry;
registry.define('shadow-test-element-1', ReentryBeforeSuper);
let shadow = createShadowForTest(t, registry);
shadow.innerHTML = '<shadow-test-element-1></shadow-test-element-1>';
let shadowElement = shadow.firstChild;
assert_true(shadowElement instanceof ReentryBeforeSuper);
assert_equals(shadowElement.localName, 'shadow-test-element-1');
let mainDocElement = document.getElementById('test-container-1').firstChild;
assert_true(mainDocElement instanceof ReentryBeforeSuper);
assert_equals(mainDocElement.localName, 'test-element-1');
}, 'Re-entry via upgrade before calling super()');
test(t => {
let needsTest = true;
class ReentryAfterSuper extends HTMLElement {
constructor() {
super();
if (needsTest) {
needsTest = false;
document.getElementById('test-container-2').innerHTML =
'<test-element-2></test-element-2>';
}
}
};
window.customElements.define('test-element-2', ReentryAfterSuper);
let registry = new CustomElementRegistry;
registry.define('shadow-test-element-2', ReentryAfterSuper);
let shadow = createShadowForTest(t, registry);
shadow.innerHTML = '<shadow-test-element-2></shadow-test-element-2>';
let shadowElement = shadow.firstChild;
assert_true(shadowElement instanceof ReentryAfterSuper);
assert_equals(shadowElement.localName, 'shadow-test-element-2');
let mainDocElement = document.getElementById('test-container-2').firstChild;
assert_true(mainDocElement instanceof ReentryAfterSuper);
assert_equals(mainDocElement.localName, 'test-element-2');
}, 'Re-entry via upgrade after calling super()');
test(t => {
let needsTest = true;
let elementByNestedCall;
class ReentryByDirectCall extends HTMLElement {
constructor() {
if (needsTest) {
needsTest = false;
elementByNestedCall = new ReentryByDirectCall;
}
super();
}
}
window.customElements.define('test-element-3', ReentryByDirectCall);
let registry = new CustomElementRegistry;
registry.define('shadow-test-element-3', ReentryByDirectCall);
let shadow = createShadowForTest(t, registry);
shadow.innerHTML = '<shadow-test-element-3></shadow-test-element-3>';
let shadowElement = shadow.firstChild;
assert_true(shadowElement instanceof ReentryByDirectCall);
assert_equals(shadowElement.localName, 'shadow-test-element-3');
// Nested constructor call makes the following `super()` fail, and we should
// end up creating only one element.
assert_equals(elementByNestedCall, shadowElement);
}, 'Re-entry via direct constructor call before calling super()');
test(t => {
let needsTest = true;
let elementByNestedCall;
class ReentryByDirectCall extends HTMLElement {
constructor() {
super();
if (needsTest) {
needsTest = false;
elementByNestedCall = new ReentryByDirectCall;
}
}
}
window.customElements.define('test-element-4', ReentryByDirectCall);
let registry = new CustomElementRegistry;
registry.define('shadow-test-element-4', ReentryByDirectCall);
let shadow = createShadowForTest(t, registry);
shadow.innerHTML = '<shadow-test-element-4></shadow-test-element-4>';
let shadowElement = shadow.firstChild;
assert_true(shadowElement instanceof ReentryByDirectCall);
assert_equals(shadowElement.localName, 'shadow-test-element-4');
// Nested constructor call should be blocked.
assert_false(elementByNestedCall instanceof ReentryByDirectCall);
}, 'Re-entry via direct constructor call after calling super()');
</script>