Skip to content

replaceChild() has odd mutation observer behavior after #754 #814

Open
@TimothyGu

Description

@TimothyGu

After implementing #754 in jsdom, we are no longer passing wpt/dom/nodes/MutatioObserver-childList.html due to the following test:

<p id='n52'><span>NO </span><span>CHANGED</span></p>
<p id='n53'><span>text content</span></p>
   var n52 = document.getElementById('n52');
   runMutationTest(n52,
                   {"childList":true},
                   [{type: "childList",
-                    removedNodes: [n52.lastChild],
-                    previousSibling: n52.firstChild},
+                    removedNodes: [n52.lastChild]},
                    {type: "childList",
                     removedNodes: [n52.firstChild],
                     addedNodes: [n52.lastChild]}],
                   function() { n52.replaceChild(n52.lastChild, n52.firstChild); },
                   "childList Node.replaceChild: internal replacement mutation");
 
   var n53 = document.getElementById('n53');
   runMutationTest(n53,
                   {"childList":true},
                   [{type: "childList",
-                    removedNodes: [n53.firstChild]},
-                   {type: "childList",
-                    addedNodes: [n53.firstChild]}],
+                    addedNodes: [n53.firstChild],
+                    removedNodes: [n53.firstChild]}],
                   function() { n53.replaceChild(n53.firstChild, n53.firstChild); },
                   "childList Node.replaceChild: self internal replacement mutation");

(- is the previous expected result; + is what #754 gives.)

While the n53 change looks fine if in need of an update, n52 is perhaps more problematic.

Prior to #754, n52.lastChild first gets removed as part of adoption process in replace, between steps 9 and 10, leading to a mutation record. At the time of its removal, n52.firstChild is still in place, so it's recorded as previousSibling in the record.

After #754, however, the explicit adoption process was removed. So n52.firstChild first gets removed silently at step 11, and then n52.lastChild is removed as part of the adoption process in insert in step 13, leading to a mutation record – when n52.firstChild is no longer present in the document.

Looking only at the list of mutation records, the post-#754 flow of event is weird. Even though the removal of n52.lastChild is shown as the first event, the silent removal of n52.firstChild had already happened – and all this is observable through previousSibling. Another way to put this is that the events seem to no longer be atomic, as the second event happens both before and after the first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions