Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOM: Test 'slotchange' event firing during move #49810

Merged
merged 1 commit into from
Dec 20, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions dom/nodes/moveBefore/tentative/slotchange-events.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<!DOCTYPE html>
<title>slotchanged event</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>

<script>
customElements.define(
"custom-element",
class extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: "open"});
const slot = document.createElement('slot');
slot.name = 'content';
shadowRoot.append(slot);
}
},
);

promise_test(async t => {
const customElement = document.body.appendChild(document.createElement('custom-element'));
t.add_cleanup(() => customElement.remove());

const slot = customElement.shadowRoot.children[0];
const slotChangePromise = new Promise((resolve, reject) => {
slot.addEventListener('slotchange', e => resolve(), {once: true});
t.step_timeout(() => reject('Timeout; slotchange was not fired'), 1500);
});

const defaultContentP = customElement.shadowRoot.appendChild(document.createElement('p'));
slot.moveBefore(defaultContentP, null);
await slotChangePromise;
}, "Moving default content into a slot fires 'slotchange' event");

promise_test(async t => {
const customElement = document.body.appendChild(document.createElement('custom-element'));
t.add_cleanup(() => customElement.remove());

const slot = customElement.shadowRoot.children[0];
const defaultContentP = slot.appendChild(document.createElement('p'));

// Wait for "signal a slot change" to asynchronously settle. This should fire
// the 'slotchange' event for the insertion above, but we will not assert that,
// since this test is only testing that 'slotchange' is fired on removal. We
// separate this out in case an implementation fires one but not the other
// (i.e., Chromium, at the time of writing this).
await new Promise(resolve => t.step_timeout(() => resolve()));

const slotChangePromise = new Promise((resolve, reject) => {
slot.addEventListener('slotchange', e => resolve(), {once: true});
t.step_timeout(() => reject('Timeout; slotchange was not fired'), 1500);
});

// Move `defaultContentP` OUT of the slot, and into the ShadowRoot. This
// triggers "signal a slot change" on `defaultContentP`'s old parent, which is
// the slot.
customElement.shadowRoot.moveBefore(defaultContentP, null);
await slotChangePromise;
}, "Moving default content out of a slot fires 'slotchange' event");

promise_test(async t => {
const customElement = document.body.appendChild(document.createElement('custom-element'));
t.add_cleanup(() => customElement.remove());

const slot = customElement.shadowRoot.children[0];
const slottable = document.body.appendChild(document.createElement('p'));
slottable.slot = 'content';

{
const slotChangePromise = new Promise((resolve, reject) => {
slot.addEventListener('slotchange', e => {
if (slot.assignedNodes().includes(slottable)) {
resolve();
} else {
reject('slot.assignedNodes() did not include the slottable after move');
}
}, {once: true});

t.step_timeout(() => reject('Timeout; slotchange (whiling moving an element in) was not fired'), 1500);
});

// Move the slottable INTO the custom element, thus slotting it.
customElement.moveBefore(slottable, null);
await slotChangePromise;
}

{
const slotChangePromise = new Promise((resolve, reject) => {
slot.addEventListener('slotchange', e => {
if (slot.assignedNodes().length === 0) {
resolve();
} else {
reject('slot.assignedNodes() not empty after the slottable moved out');
}
}, {once: true});

t.step_timeout(() => reject('Timeout; slotchange (whiling moving an element out) was not fired'), 1500);
});

// Move the slottable OUT of the custom element, thus unslotting it.
document.body.moveBefore(slottable, null);
await slotChangePromise;
}
}, "Moving a slottable into and out out of a custom element fires 'slotchange' event");
</script>