-
Notifications
You must be signed in to change notification settings - Fork 295
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
replaceChild() has odd mutation observer behavior after #754 #814
Comments
The thing I don't understand is that previousSibling goes away as we do store that in a variable upfront before any mutations have happened. So how could it disappear? |
child's previous sibling is saved, but not node's. The first mutation event results from step 13 of replace
which eventually goes to step 7.1 of insert
which goes to step 2 of adopt
which fires a mutation event. At that time, node's previous sibling has already been removed (in step 11.2 of replace), so the fired mutation event does not contain a previousSibling. The second mutation event in the array is a result of "queue a tree mutation record" in replace itself. That works fine. |
Thanks. Sigh this is hard. So would reverting work, but then changing "adopt" in two ways:
Then in the cc @smaug---- @rniwa |
@TimothyGu thoughts on the above? Does jsdom also have all the relevant tests imported? In that case I suppose I could play around with that too, it'd be nice to find a solution here. |
@annevk Yes, definitely feel free to play around. Tests are all there, and you can change test exceptions in the to-run.yml file (look for 754 and 813) for a list. Here's the patch for what you described above: diff --git a/lib/jsdom/living/nodes/Document-impl.js b/lib/jsdom/living/nodes/Document-impl.js
index 94f8d484..ad642df5 100644
--- a/lib/jsdom/living/nodes/Document-impl.js
+++ b/lib/jsdom/living/nodes/Document-impl.js
@@ -816,7 +816,7 @@ class DocumentImpl extends NodeImpl {
}
// https://dom.spec.whatwg.org/#concept-node-adopt
- _adoptNode(node) {
+ _adoptNode(node, doItAnyway = false) {
const newDocument = this;
const oldDocument = node._ownerDocument;
@@ -827,6 +827,9 @@ class DocumentImpl extends NodeImpl {
if (oldDocument !== newDocument) {
for (const inclusiveDescendant of shadowIncludingInclusiveDescendantsIterator(node)) {
+ if (!doItAnyway && DocumentFragment.isImpl(inclusiveDescendant)) {
+ continue;
+ }
inclusiveDescendant._ownerDocument = newDocument;
}
diff --git a/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js b/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js
index b0a2405b..1f829e49 100644
--- a/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js
+++ b/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js
@@ -43,7 +43,7 @@ class HTMLTemplateElementImpl extends HTMLElementImpl {
// https://html.spec.whatwg.org/multipage/scripting.html#template-adopting-steps
_adoptingSteps() {
const doc = this._appropriateTemplateContentsOwnerDocument(this._ownerDocument);
- doc._adoptNode(this._templateContents);
+ doc._adoptNode(this._templateContents, /* doItAnyway= */ true);
}
get content() { You could apply it and run tests through Edit: It looks like this change made For
(but the "moving the For
|
Sorry, it looks like I have gotten myself confused. The correct patch should be the following: diff --git a/lib/jsdom/living/nodes/Document-impl.js b/lib/jsdom/living/nodes/Document-impl.js
index 94f8d484..3b486d84 100644
--- a/lib/jsdom/living/nodes/Document-impl.js
+++ b/lib/jsdom/living/nodes/Document-impl.js
@@ -816,7 +816,7 @@ class DocumentImpl extends NodeImpl {
}
// https://dom.spec.whatwg.org/#concept-node-adopt
- _adoptNode(node) {
+ _adoptNode(node, doItAnyway = false) {
const newDocument = this;
const oldDocument = node._ownerDocument;
@@ -827,6 +827,9 @@ class DocumentImpl extends NodeImpl {
if (oldDocument !== newDocument) {
for (const inclusiveDescendant of shadowIncludingInclusiveDescendantsIterator(node)) {
+ if (!doItAnyway && DocumentFragment.isImpl(node) && node._host) {
+ continue;
+ }
inclusiveDescendant._ownerDocument = newDocument;
}
diff --git a/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js b/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js
index b0a2405b..1f829e49 100644
--- a/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js
+++ b/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js
@@ -43,7 +43,7 @@ class HTMLTemplateElementImpl extends HTMLElementImpl {
// https://html.spec.whatwg.org/multipage/scripting.html#template-adopting-steps
_adoptingSteps() {
const doc = this._appropriateTemplateContentsOwnerDocument(this._ownerDocument);
- doc._adoptNode(this._templateContents);
+ doc._adoptNode(this._templateContents, /* doItAnyway= */ true);
}
get content() { In terms of tests,
|
I worked a bit more on this and put up jsdom/jsdom#2925, #819, and web-platform-tests/wpt#22504. I'll clean that all up for wider review soonish, but early feedback appreciated. |
Tests: web-platform-tests/wpt#22504. Corresponding HTML PR: whatwg/html#5413. Closes #813 and closes #814.
After implementing #754 in jsdom, we are no longer passing wpt/dom/nodes/MutatioObserver-childList.html due to the following test:
(
-
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 aspreviousSibling
in the record.After #754, however, the explicit adoption process was removed. So
n52.firstChild
first gets removed silently at step 11, and thenn52.lastChild
is removed as part of the adoption process in insert in step 13, leading to a mutation record – whenn52.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 ofn52.firstChild
had already happened – and all this is observable throughpreviousSibling
. 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.The text was updated successfully, but these errors were encountered: