ParentNode-replaceChildren.html (8379B)
1 <!DOCTYPE html> 2 <meta charset=utf-8> 3 <title>ParentNode.replaceChildren</title> 4 <link rel=help href="https://dom.spec.whatwg.org/#dom-parentnode-replacechildren"> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="pre-insertion-validation-hierarchy.js"></script> 8 <script> 9 preInsertionValidateHierarchy("replaceChildren"); 10 11 function test_replacechildren(node, nodeName) { 12 test(() => { 13 const parent = node.cloneNode(); 14 parent.replaceChildren(); 15 assert_array_equals(parent.childNodes, []); 16 }, `${nodeName}.replaceChildren() without any argument, on a parent having no child.`); 17 18 test(() => { 19 const parent = node.cloneNode(); 20 parent.replaceChildren(null); 21 assert_equals(parent.childNodes[0].textContent, 'null'); 22 }, `${nodeName}.replaceChildren() with null as an argument, on a parent having no child.`); 23 24 test(() => { 25 const parent = node.cloneNode(); 26 parent.replaceChildren(undefined); 27 assert_equals(parent.childNodes[0].textContent, 'undefined'); 28 }, `${nodeName}.replaceChildren() with undefined as an argument, on a parent having no child.`); 29 30 test(() => { 31 const parent = node.cloneNode(); 32 parent.replaceChildren('text'); 33 assert_equals(parent.childNodes[0].textContent, 'text'); 34 }, `${nodeName}.replaceChildren() with only text as an argument, on a parent having no child.`); 35 36 test(() => { 37 const parent = node.cloneNode(); 38 const x = document.createElement('x'); 39 parent.replaceChildren(x); 40 assert_array_equals(parent.childNodes, [x]); 41 }, `${nodeName}.replaceChildren() with only one element as an argument, on a parent having no child.`); 42 43 test(() => { 44 const parent = node.cloneNode(); 45 const child = document.createElement('test'); 46 parent.appendChild(child); 47 parent.replaceChildren(); 48 assert_array_equals(parent.childNodes, []); 49 }, `${nodeName}.replaceChildren() without any argument, on a parent having a child.`); 50 51 test(() => { 52 const parent = node.cloneNode(); 53 const child = document.createElement('test'); 54 parent.appendChild(child); 55 parent.replaceChildren(null); 56 assert_equals(parent.childNodes.length, 1); 57 assert_equals(parent.childNodes[0].textContent, 'null'); 58 }, `${nodeName}.replaceChildren() with null as an argument, on a parent having a child.`); 59 60 test(() => { 61 const parent = node.cloneNode(); 62 const x = document.createElement('x'); 63 const child = document.createElement('test'); 64 parent.appendChild(child); 65 parent.replaceChildren(x, 'text'); 66 assert_equals(parent.childNodes.length, 2); 67 assert_equals(parent.childNodes[0], x); 68 assert_equals(parent.childNodes[1].textContent, 'text'); 69 }, `${nodeName}.replaceChildren() with one element and text as argument, on a parent having a child.`); 70 71 async_test(t => { 72 let phase = 0; 73 74 const previousParent = node.cloneNode(); 75 const insertions = [ 76 document.createElement("test1"), 77 document.createElement("test2") 78 ]; 79 previousParent.append(...insertions); 80 81 const parent = node.cloneNode(); 82 const children = [ 83 document.createElement("test3"), 84 document.createElement("test4") 85 ]; 86 parent.append(...children); 87 88 const previousObserver = new MutationObserver(mutations => { 89 t.step(() => { 90 assert_equals(phase, 0); 91 assert_equals(mutations.length, 2); 92 for (const [i, mutation] of Object.entries(mutations)) { 93 assert_equals(mutation.type, "childList"); 94 assert_equals(mutation.addedNodes.length, 0); 95 assert_equals(mutation.removedNodes.length, 1); 96 assert_equals(mutation.removedNodes[0], insertions[i]); 97 } 98 phase = 1; 99 }); 100 }); 101 previousObserver.observe(previousParent, { childList: true }); 102 103 const observer = new MutationObserver(mutations => { 104 t.step(() => { 105 assert_equals(phase, 1, "phase"); 106 assert_equals(mutations.length, 1, "mutations.length"); 107 const mutation = mutations[0]; 108 assert_equals(mutation.type, "childList", "mutation.type"); 109 assert_equals(mutation.addedNodes.length, 2, "added nodes length"); 110 assert_array_equals([...mutation.addedNodes], insertions, "added nodes"); 111 assert_equals(mutation.removedNodes.length, 2, "removed nodes length"); 112 assert_array_equals([...mutation.removedNodes], children, "removed nodes"); 113 }); 114 t.done(); 115 }); 116 observer.observe(parent, { childList: true }); 117 118 parent.replaceChildren(...previousParent.children); 119 }, `${nodeName}.replaceChildren() should move nodes in the right order`); 120 } 121 122 test_replacechildren(document.createElement('div'), 'Element'); 123 test_replacechildren(document.createDocumentFragment(), 'DocumentFragment'); 124 125 async_test(t => { 126 let root = document.createElement("div"); 127 root.innerHTML = "<div id='a'>text<div id='b'>text2</div></div>"; 128 const a = root.firstChild; 129 const b = a.lastChild; 130 const txt = b.previousSibling; 131 const txt2 = b.firstChild; 132 133 const observer = new MutationObserver((mutations) => { 134 135 assert_equals(mutations.length, 2, "mutations.length"); 136 137 assert_equals(mutations[0].target.id, "a", "Target of the removal"); 138 assert_equals(mutations[0].addedNodes.length, 0, "Should not have added nodes"); 139 assert_equals(mutations[0].removedNodes.length, 1, "Should have 1 removed node"); 140 assert_equals(mutations[0].removedNodes[0], txt, "Should have removed txt node"); 141 142 assert_equals(mutations[1].target.id, "b", "Target of the replaceChildren"); 143 assert_equals(mutations[1].removedNodes.length, 1, "Should have removed 1 node"); 144 assert_equals(mutations[1].removedNodes[0], txt2, "Should have removed txt2 node"); 145 assert_equals(mutations[1].addedNodes.length, 1, "Should have added a node"); 146 assert_equals(mutations[1].addedNodes[0], txt, "Should have added txt node"); 147 148 observer.disconnect(); 149 t.done(); 150 }); 151 152 observer.observe(a, { 153 subtree: true, 154 childList: true 155 }); 156 157 b.replaceChildren(txt); 158 }, "There should be a MutationRecord for the node removed from another parent node."); 159 160 async_test(t => { 161 // This is almost the same test as above, but passes two nodes to replaceChildren. 162 163 let root = document.createElement("div"); 164 root.innerHTML = "<div id='a'><div id='c'></div>text<div id='b'>text2</div></div>"; 165 const a = root.firstChild; 166 const b = a.lastChild; 167 const c = a.firstChild; 168 const txt = b.previousSibling; 169 const txt2 = b.firstChild; 170 171 const observer = new MutationObserver((mutations) => { 172 173 assert_equals(mutations.length, 3, "mutations.length"); 174 175 assert_equals(mutations[0].target.id, "a", "Target of the removal"); 176 assert_equals(mutations[0].addedNodes.length, 0, "Should not have added nodes"); 177 assert_equals(mutations[0].removedNodes.length, 1, "Should have 1 removed node"); 178 assert_equals(mutations[0].removedNodes[0], c, "Should have removed c node"); 179 180 assert_equals(mutations[1].target.id, "a", "Target of the removal"); 181 assert_equals(mutations[1].addedNodes.length, 0, "Should not have added nodes"); 182 assert_equals(mutations[1].removedNodes.length, 1, "Should have 1 removed node"); 183 assert_equals(mutations[1].removedNodes[0], txt, "Should have removed txt node"); 184 185 assert_equals(mutations[2].target.id, "b", "Target of the replaceChildren"); 186 assert_equals(mutations[2].removedNodes.length, 1, "Should have removed 1 node"); 187 assert_equals(mutations[2].removedNodes[0], txt2, "Should have removed txt2 node"); 188 assert_equals(mutations[2].addedNodes.length, 2, "Should have added a node"); 189 assert_equals(mutations[2].addedNodes[0], c, "Should have added c node"); 190 assert_equals(mutations[2].addedNodes[1], txt, "Should have added txt node"); 191 192 observer.disconnect(); 193 t.done(); 194 }); 195 196 observer.observe(a, { 197 subtree: true, 198 childList: true 199 }); 200 201 b.replaceChildren(c, txt); 202 }, "There should be MutationRecords for the nodes removed from another parent node."); 203 </script> 204 205 </html>