Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /custom-elements/enqueue-custom-element-callback-reactions-inside-another-callback.html - WPT Dashboard Interop Dashboard
<!DOCTYPE html>
<html>
<head>
<title>Custom Elements: must enqueue an element on the appropriate element queue after checking callback is null and the attribute name</title>
<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
<meta name="assert" content="To enqueue a custom element callback reaction, the callback must be checked of being null and whether the attribute name is observed or not">
<link rel="help" content="https://html.spec.whatwg.org/multipage/custom-elements.html#enqueue-a-custom-element-callback-reaction">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/custom-elements-helpers.js"></script>
</head>
<body>
<script>
test_with_window((contentWindow, contentDocument) => {
class ParentElement extends contentWindow.HTMLElement {
connectedCallback()
{
logs.push('begin');
const child = this.firstChild;
child.remove();
logs.push('end');
}
}
contentWindow.customElements.define('parent-element', ParentElement);
const logs = [];
class ChildElement extends contentWindow.HTMLElement {
connectedCallback() { logs.push('connected'); }
disconnectedCallback() { logs.push('disconnected'); }
}
contentWindow.customElements.define('child-element', ChildElement);
const parent = new ParentElement;
const child = new ChildElement;
parent.appendChild(child);
contentDocument.body.appendChild(parent);
assert_array_equals(logs, ['begin', 'connected', 'disconnected', 'end']);
}, 'Disconnecting an element with disconnectedCallback while it has a connectedCallback in its custom element reaction queue must result in connectedCallback getting invoked before the removal completes');
test_with_window((contentWindow, contentDocument) => {
class ParentElement extends contentWindow.HTMLElement {
connectedCallback()
{
logs.push('begin');
const child = this.firstChild;
child.remove();
logs.push('end');
}
}
contentWindow.customElements.define('parent-element', ParentElement);
const logs = [];
class ChildElement extends contentWindow.HTMLElement {
connectedCallback() { logs.push('connected'); }
}
contentWindow.customElements.define('child-element', ChildElement);
const parent = new ParentElement;
const child = new ChildElement;
parent.appendChild(child);
contentDocument.body.appendChild(parent);
assert_array_equals(logs, ['begin', 'end', 'connected']);
}, 'Disconnecting an element without disconnectedCallback while it has a connectedCallback in its custom element reaction queue must not result in connectedCallback getting invoked before the removal completes');
test_with_window((contentWindow, contentDocument) => {
class ParentElement extends contentWindow.HTMLElement {
disconnectedCallback()
{
logs.push('begin');
contentDocument.body.appendChild(this.firstChild);
logs.push('end');
}
}
contentWindow.customElements.define('parent-element', ParentElement);
const logs = [];
class ChildElement extends contentWindow.HTMLElement {
connectedCallback() { logs.push('connected'); }
disconnectedCallback() { logs.push('disconnected'); }
}
contentWindow.customElements.define('child-element', ChildElement);
const parent = new ParentElement;
const child = new ChildElement;
parent.appendChild(child);
contentDocument.body.appendChild(parent);
parent.remove();
assert_array_equals(logs, ['connected', 'begin', 'disconnected', 'connected', 'end']);
}, 'Connecting a element with connectedCallback while it has a disconnectedCallback in its custom element reaction queue must result in disconnectedCallback getting invoked before the insertion completes');
test_with_window((contentWindow, contentDocument) => {
class ParentElement extends contentWindow.HTMLElement {
disconnectedCallback()
{
logs.push('begin');
contentDocument.body.appendChild(this.firstChild);
logs.push('end');
}
}
contentWindow.customElements.define('parent-element', ParentElement);
const logs = [];
class ChildElement extends contentWindow.HTMLElement {
disconnectedCallback() { logs.push('disconnected'); }
}
contentWindow.customElements.define('child-element', ChildElement);
const parent = new ParentElement;
const child = new ChildElement;
parent.appendChild(child);
contentDocument.body.appendChild(parent);
parent.remove();
assert_array_equals(logs, ['begin', 'end', 'disconnected']);
}, 'Connecting an element without connectedCallback while it has a disconnectedCallback in its custom element reaction queue must not result in disconnectedCallback getting invoked before the insertion completes');
test_with_window((contentWindow, contentDocument) => {
class ParentElement extends contentWindow.HTMLElement {
connectedCallback()
{
logs.push('begin');
document.adoptNode(this.firstChild);
logs.push('end');
}
}
contentWindow.customElements.define('parent-element', ParentElement);
const logs = [];
class ChildElement extends contentWindow.HTMLElement {
adoptedCallback() { logs.push('adopted'); }
connectedCallback() { logs.push('connected'); }
}
contentWindow.customElements.define('child-element', ChildElement);
const parent = new ParentElement;
const child = new ChildElement;
parent.appendChild(child);
contentDocument.body.appendChild(parent);
assert_array_equals(logs, ['begin', 'connected', 'adopted', 'end']);
}, 'Adopting an element with adoptingCallback while it has a connectedCallback in its custom element reaction queue must result in connectedCallback getting invoked before the adoption completes');
test_with_window((contentWindow, contentDocument) => {
class ParentElement extends contentWindow.HTMLElement {
connectedCallback()
{
logs.push('begin');
document.adoptNode(this.firstChild);
logs.push('end');
}
}
contentWindow.customElements.define('parent-element', ParentElement);
const logs = [];
class ChildElement extends contentWindow.HTMLElement {
connectedCallback() { logs.push('connected'); }
}
contentWindow.customElements.define('child-element', ChildElement);
const parent = new ParentElement;
const child = new ChildElement;
parent.appendChild(child);
contentDocument.body.appendChild(parent);
assert_array_equals(logs, ['begin', 'end', 'connected']);
}, 'Adopting an element without adoptingCallback while it has a connectedCallback in its custom element reaction queue must not result in connectedCallback getting invoked before the adoption completes');
test_with_window((contentWindow, contentDocument) => {
class ParentElement extends contentWindow.HTMLElement {
connectedCallback()
{
logs.push('begin');
this.firstChild.setAttribute('title', 'foo');
logs.push('end');
}
}
contentWindow.customElements.define('parent-element', ParentElement);
const logs = [];
class ChildElement extends contentWindow.HTMLElement {
attributeChangedCallback() { logs.push('attributeChanged'); }
connectedCallback() { logs.push('connected'); }
static get observedAttributes() { return ['title']; }
}
contentWindow.customElements.define('child-element', ChildElement);
const parent = new ParentElement;
const child = new ChildElement;
parent.appendChild(child);
contentDocument.body.appendChild(parent);
assert_array_equals(logs, ['begin', 'connected', 'attributeChanged', 'end']);
}, 'Setting an observed attribute on an element with attributeChangedCallback while it has a connectedCallback in its custom element reaction queue must result in connectedCallback getting invoked before the attribute change completes');
test_with_window((contentWindow, contentDocument) => {
class ParentElement extends contentWindow.HTMLElement {
connectedCallback()
{
logs.push('begin');
this.firstChild.setAttribute('lang', 'en');
logs.push('end');
}
}
contentWindow.customElements.define('parent-element', ParentElement);
const logs = [];
class ChildElement extends contentWindow.HTMLElement {
attributeChangedCallback() { logs.push('attributeChanged'); }
connectedCallback() { logs.push('connected'); }
static get observedAttributes() { return ['title']; }
}
contentWindow.customElements.define('child-element', ChildElement);
const parent = new ParentElement;
const child = new ChildElement;
parent.appendChild(child);
contentDocument.body.appendChild(parent);
assert_array_equals(logs, ['begin', 'end', 'connected']);
}, 'Setting an observed attribute on an element with attributeChangedCallback while it has a connectedCallback in its custom element reaction queue must not result in connectedCallback getting invoked before the attribute change completes');
</script>
</body>
</html>