Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE html>
<meta charset=utf-8>
<title>ParentNode.replaceChildren</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="pre-insertion-validation-hierarchy.js"></script>
<script>
preInsertionValidateHierarchy("replaceChildren");
function test_replacechildren(node, nodeName) {
test(() => {
const parent = node.cloneNode();
parent.replaceChildren();
assert_array_equals(parent.childNodes, []);
}, `${nodeName}.replaceChildren() without any argument, on a parent having no child.`);
test(() => {
const parent = node.cloneNode();
parent.replaceChildren(null);
assert_equals(parent.childNodes[0].textContent, 'null');
}, `${nodeName}.replaceChildren() with null as an argument, on a parent having no child.`);
test(() => {
const parent = node.cloneNode();
parent.replaceChildren(undefined);
assert_equals(parent.childNodes[0].textContent, 'undefined');
}, `${nodeName}.replaceChildren() with undefined as an argument, on a parent having no child.`);
test(() => {
const parent = node.cloneNode();
parent.replaceChildren('text');
assert_equals(parent.childNodes[0].textContent, 'text');
}, `${nodeName}.replaceChildren() with only text as an argument, on a parent having no child.`);
test(() => {
const parent = node.cloneNode();
const x = document.createElement('x');
parent.replaceChildren(x);
assert_array_equals(parent.childNodes, [x]);
}, `${nodeName}.replaceChildren() with only one element as an argument, on a parent having no child.`);
test(() => {
const parent = node.cloneNode();
const child = document.createElement('test');
parent.appendChild(child);
parent.replaceChildren();
assert_array_equals(parent.childNodes, []);
}, `${nodeName}.replaceChildren() without any argument, on a parent having a child.`);
test(() => {
const parent = node.cloneNode();
const child = document.createElement('test');
parent.appendChild(child);
parent.replaceChildren(null);
assert_equals(parent.childNodes.length, 1);
assert_equals(parent.childNodes[0].textContent, 'null');
}, `${nodeName}.replaceChildren() with null as an argument, on a parent having a child.`);
test(() => {
const parent = node.cloneNode();
const x = document.createElement('x');
const child = document.createElement('test');
parent.appendChild(child);
parent.replaceChildren(x, 'text');
assert_equals(parent.childNodes.length, 2);
assert_equals(parent.childNodes[0], x);
assert_equals(parent.childNodes[1].textContent, 'text');
}, `${nodeName}.replaceChildren() with one element and text as argument, on a parent having a child.`);
async_test(t => {
let phase = 0;
const previousParent = node.cloneNode();
const insertions = [
document.createElement("test1"),
document.createElement("test2")
];
previousParent.append(...insertions);
const parent = node.cloneNode();
const children = [
document.createElement("test3"),
document.createElement("test4")
];
parent.append(...children);
const previousObserver = new MutationObserver(mutations => {
t.step(() => {
assert_equals(phase, 0);
assert_equals(mutations.length, 2);
for (const [i, mutation] of Object.entries(mutations)) {
assert_equals(mutation.type, "childList");
assert_equals(mutation.addedNodes.length, 0);
assert_equals(mutation.removedNodes.length, 1);
assert_equals(mutation.removedNodes[0], insertions[i]);
}
phase = 1;
});
});
previousObserver.observe(previousParent, { childList: true });
const observer = new MutationObserver(mutations => {
t.step(() => {
assert_equals(phase, 1, "phase");
assert_equals(mutations.length, 1, "mutations.length");
const mutation = mutations[0];
assert_equals(mutation.type, "childList", "mutation.type");
assert_equals(mutation.addedNodes.length, 2, "added nodes length");
assert_array_equals([...mutation.addedNodes], insertions, "added nodes");
assert_equals(mutation.removedNodes.length, 2, "removed nodes length");
assert_array_equals([...mutation.removedNodes], children, "removed nodes");
});
t.done();
});
observer.observe(parent, { childList: true });
parent.replaceChildren(...previousParent.children);
}, `${nodeName}.replaceChildren() should move nodes in the right order`);
}
test_replacechildren(document.createElement('div'), 'Element');
test_replacechildren(document.createDocumentFragment(), 'DocumentFragment');
async_test(t => {
let root = document.createElement("div");
root.innerHTML = "<div id='a'>text<div id='b'>text2</div></div>";
const a = root.firstChild;
const b = a.lastChild;
const txt = b.previousSibling;
const txt2 = b.firstChild;
const observer = new MutationObserver((mutations) => {
assert_equals(mutations.length, 2, "mutations.length");
assert_equals(mutations[0].target.id, "a", "Target of the removal");
assert_equals(mutations[0].addedNodes.length, 0, "Should not have added nodes");
assert_equals(mutations[0].removedNodes.length, 1, "Should have 1 removed node");
assert_equals(mutations[0].removedNodes[0], txt, "Should have removed txt node");
assert_equals(mutations[1].target.id, "b", "Target of the replaceChildren");
assert_equals(mutations[1].removedNodes.length, 1, "Should have removed 1 node");
assert_equals(mutations[1].removedNodes[0], txt2, "Should have removed txt2 node");
assert_equals(mutations[1].addedNodes.length, 1, "Should have added a node");
assert_equals(mutations[1].addedNodes[0], txt, "Should have added txt node");
observer.disconnect();
t.done();
});
observer.observe(a, {
subtree: true,
childList: true
});
b.replaceChildren(txt);
}, "There should be a MutationRecord for the node removed from another parent node.");
async_test(t => {
// This is almost the same test as above, but passes two nodes to replaceChildren.
let root = document.createElement("div");
root.innerHTML = "<div id='a'><div id='c'></div>text<div id='b'>text2</div></div>";
const a = root.firstChild;
const b = a.lastChild;
const c = a.firstChild;
const txt = b.previousSibling;
const txt2 = b.firstChild;
const observer = new MutationObserver((mutations) => {
assert_equals(mutations.length, 3, "mutations.length");
assert_equals(mutations[0].target.id, "a", "Target of the removal");
assert_equals(mutations[0].addedNodes.length, 0, "Should not have added nodes");
assert_equals(mutations[0].removedNodes.length, 1, "Should have 1 removed node");
assert_equals(mutations[0].removedNodes[0], c, "Should have removed c node");
assert_equals(mutations[1].target.id, "a", "Target of the removal");
assert_equals(mutations[1].addedNodes.length, 0, "Should not have added nodes");
assert_equals(mutations[1].removedNodes.length, 1, "Should have 1 removed node");
assert_equals(mutations[1].removedNodes[0], txt, "Should have removed txt node");
assert_equals(mutations[2].target.id, "b", "Target of the replaceChildren");
assert_equals(mutations[2].removedNodes.length, 1, "Should have removed 1 node");
assert_equals(mutations[2].removedNodes[0], txt2, "Should have removed txt2 node");
assert_equals(mutations[2].addedNodes.length, 2, "Should have added a node");
assert_equals(mutations[2].addedNodes[0], c, "Should have added c node");
assert_equals(mutations[2].addedNodes[1], txt, "Should have added txt node");
observer.disconnect();
t.done();
});
observer.observe(a, {
subtree: true,
childList: true
});
b.replaceChildren(c, txt);
}, "There should be MutationRecords for the nodes removed from another parent node.");
</script>
</html>