summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/dom/nodes
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:35:37 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:35:37 +0000
commita90a5cba08fdf6c0ceb95101c275108a152a3aed (patch)
tree532507288f3defd7f4dcf1af49698bcb76034855 /testing/web-platform/tests/dom/nodes
parentAdding debian version 126.0.1-1. (diff)
downloadfirefox-a90a5cba08fdf6c0ceb95101c275108a152a3aed.tar.xz
firefox-a90a5cba08fdf6c0ceb95101c275108a152a3aed.zip
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/dom/nodes')
-rw-r--r--testing/web-platform/tests/dom/nodes/insertion-removing-steps/Node-append-meta-referrer-and-script-from-fragment.tentative.html54
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/Node-moveBefore.html297
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/chrome-338071841-crash.html6
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-animation-left.html51
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-animation-transform.html48
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-left-pseudo.html54
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-left.html41
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-transform-pseudo.html54
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-transform.html36
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-animation-commit-styles.html45
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-cross-document.html45
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-cross-shadow.html64
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-to-disconnected-document.html43
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-trigger.html43
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/focus-preserve.html85
-rw-r--r--testing/web-platform/tests/dom/nodes/moveBefore/tentative/fullscreen-preserve.html49
16 files changed, 994 insertions, 21 deletions
diff --git a/testing/web-platform/tests/dom/nodes/insertion-removing-steps/Node-append-meta-referrer-and-script-from-fragment.tentative.html b/testing/web-platform/tests/dom/nodes/insertion-removing-steps/Node-append-meta-referrer-and-script-from-fragment.tentative.html
index d247797603..e80e3b45b6 100644
--- a/testing/web-platform/tests/dom/nodes/insertion-removing-steps/Node-append-meta-referrer-and-script-from-fragment.tentative.html
+++ b/testing/web-platform/tests/dom/nodes/insertion-removing-steps/Node-append-meta-referrer-and-script-from-fragment.tentative.html
@@ -5,25 +5,37 @@
<script src=/resources/testharnessreport.js></script>
<script>
promise_test(async t => {
- const script = document.createElement("script");
- const meta = document.createElement("meta");
- meta.name = "referrer";
- meta.content = "no-referrer";
- const fragment = new DocumentFragment();
- const done = new Promise(resolve => {
- window.didFetch = resolve;
- });
- script.textContent = `
- (async function() {
- const response = await fetch("/html/infrastructure/urls/terminology-0/resources/echo-referrer-text.py")
- const text = await response.text();
- window.didFetch(text);
- })();
- `;
- fragment.append(script, meta);
- document.head.append(fragment);
- const result = await done;
- assert_equals(result, "");
-}, "<meta name=referrer> should apply before script, as it is an insertion step " +
- "and not a post-insertion step");
+ const preMetaScript = document.createElement("script");
+ preMetaScript.textContent = `
+ window.preMetaScriptPromise = fetch('/html/infrastructure/urls/terminology-0/resources/echo-referrer-text.py')
+ .then(response => response.text());
+ `;
+
+ const meta = document.createElement("meta");
+ meta.name = "referrer";
+ meta.content = "no-referrer";
+
+ const postMetaScript = document.createElement("script");
+ postMetaScript.textContent = `
+ window.postMetaScriptPromise = fetch('/html/infrastructure/urls/terminology-0/resources/echo-referrer-text.py')
+ .then(response => response.text());
+ `;
+
+ const fragment = new DocumentFragment();
+ fragment.append(preMetaScript, meta, postMetaScript);
+ document.head.append(fragment);
+
+ const preMetaReferrer = await window.preMetaScriptPromise;
+ assert_equals(preMetaReferrer, location.href,
+ "preMetaReferrer is the full URL; by the time the first script runs in " +
+ "its post-insertion steps, the later-inserted meta tag has not run its " +
+ "post-insertion steps, which is where meta tags are processed");
+
+ const postMetaReferrer = await window.postMetaScriptPromise;
+ assert_equals(postMetaReferrer, "",
+ "postMetaReferrer is empty; by the time the second script runs in " +
+ "its post-insertion steps, the later-inserted meta tag has run its " +
+ "post-insertion steps, and observes the meta tag's effect");
+}, "<meta name=referrer> gets processed and applied in the post-insertion " +
+ "steps");
</script>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/Node-moveBefore.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/Node-moveBefore.html
new file mode 100644
index 0000000000..8a1db6f93b
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/Node-moveBefore.html
@@ -0,0 +1,297 @@
+<!DOCTYPE html>
+<title>Node.moveBefore</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<!-- First test shared pre-insertion checks that work similarly for replaceChild
+ and moveBefore -->
+<script>
+ var insertFunc = Node.prototype.moveBefore;
+</script>
+<script src="../../pre-insertion-validation-notfound.js"></script>
+<script src="../../pre-insertion-validation-hierarchy.js"></script>
+<script>
+preInsertionValidateHierarchy("moveBefore");
+
+function testLeafNode(nodeName, createNodeFunction) {
+ test(function() {
+ var node = createNodeFunction();
+ assert_throws_js(TypeError, function() { node.moveBefore(null, null) })
+ }, "Calling moveBefore with a non-Node first argument on a leaf node " + nodeName + " must throw TypeError.")
+ test(function() {
+ var node = createNodeFunction();
+ assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { node.moveBefore(document.createTextNode("fail"), null) })
+ // Would be step 2.
+ assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { node.moveBefore(node, null) })
+ // Would be step 3.
+ assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { node.moveBefore(node, document.createTextNode("child")) })
+ }, "Calling moveBefore an a leaf node " + nodeName + " must throw HIERARCHY_REQUEST_ERR.")
+}
+
+test(function() {
+ // WebIDL: first argument.
+ assert_throws_js(TypeError, function() { document.body.moveBefore(null, null) })
+ assert_throws_js(TypeError, function() { document.body.moveBefore(null, document.body.firstChild) })
+ assert_throws_js(TypeError, function() { document.body.moveBefore({'a':'b'}, document.body.firstChild) })
+}, "Calling moveBefore with a non-Node first argument must throw TypeError.")
+
+test(function() {
+ // WebIDL: second argument.
+ assert_throws_js(TypeError, function() { document.body.moveBefore(document.createTextNode("child")) })
+ assert_throws_js(TypeError, function() { document.body.moveBefore(document.createTextNode("child"), {'a':'b'}) })
+}, "Calling moveBefore with second argument missing, or other than Node, null, or undefined, must throw TypeError.")
+
+testLeafNode("DocumentType", function () { return document.doctype; } )
+testLeafNode("Text", function () { return document.createTextNode("Foo") })
+testLeafNode("Comment", function () { return document.createComment("Foo") })
+testLeafNode("ProcessingInstruction", function () { return document.createProcessingInstruction("foo", "bar") })
+
+test(function() {
+ // Step 2.
+ assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { document.body.moveBefore(document.body, document.getElementById("log")) })
+ assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { document.body.moveBefore(document.documentElement, document.getElementById("log")) })
+}, "Calling moveBefore with an inclusive ancestor of the context object must throw HIERARCHY_REQUEST_ERR.")
+
+// Step 3.
+test(function() {
+ var a = document.createElement("div");
+ var b = document.createElement("div");
+ var c = document.createElement("div");
+ assert_throws_dom("NotFoundError", function() {
+ a.moveBefore(b, c);
+ });
+}, "Calling moveBefore with a reference child whose parent is not the context node must throw a NotFoundError.")
+
+// Step 4.1.
+test(function() {
+ var doc = document.implementation.createHTMLDocument("title");
+ var doc2 = document.implementation.createHTMLDocument("title2");
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(doc2, doc.documentElement);
+ });
+
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(doc.createTextNode("text"), doc.documentElement);
+ });
+}, "If the context node is a document, inserting a document or text node should throw a HierarchyRequestError.")
+
+// Step 4.2.1.
+test(function() {
+ var doc = document.implementation.createHTMLDocument("title");
+ doc.removeChild(doc.documentElement);
+
+ var df = doc.createDocumentFragment();
+ df.appendChild(doc.createElement("a"));
+ df.appendChild(doc.createElement("b"));
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(df, doc.firstChild);
+ });
+
+ df = doc.createDocumentFragment();
+ df.appendChild(doc.createTextNode("text"));
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(df, doc.firstChild);
+ });
+
+ df = doc.createDocumentFragment();
+ df.appendChild(doc.createComment("comment"));
+ df.appendChild(doc.createTextNode("text"));
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(df, doc.firstChild);
+ });
+}, "If the context node is a document, inserting a DocumentFragment that contains a text node or too many elements should throw a HierarchyRequestError.")
+
+// Step 4.2.2.
+test(function() {
+ // The context node has an element child.
+ var doc = document.implementation.createHTMLDocument("title");
+ var comment = doc.appendChild(doc.createComment("foo"));
+ assert_array_equals(doc.childNodes, [doc.doctype, doc.documentElement, comment]);
+
+ var df = doc.createDocumentFragment();
+ df.appendChild(doc.createElement("a"));
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(df, doc.doctype);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(df, doc.documentElement);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(df, comment);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(df, null);
+ });
+}, "If the context node is a document, inserting a DocumentFragment with an element if there already is an element child should throw a HierarchyRequestError.")
+test(function() {
+ // /child/ is a doctype.
+ var doc = document.implementation.createHTMLDocument("title");
+ var comment = doc.moveBefore(doc.createComment("foo"), doc.firstChild);
+ doc.removeChild(doc.documentElement);
+ assert_array_equals(doc.childNodes, [comment, doc.doctype]);
+
+ var df = doc.createDocumentFragment();
+ df.appendChild(doc.createElement("a"));
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(df, doc.doctype);
+ });
+}, "If the context node is a document and a doctype is following the reference child, inserting a DocumentFragment with an element should throw a HierarchyRequestError.")
+test(function() {
+ // /child/ is not null and a doctype is following /child/.
+ var doc = document.implementation.createHTMLDocument("title");
+ var comment = doc.moveBefore(doc.createComment("foo"), doc.firstChild);
+ doc.removeChild(doc.documentElement);
+ assert_array_equals(doc.childNodes, [comment, doc.doctype]);
+
+ var df = doc.createDocumentFragment();
+ df.appendChild(doc.createElement("a"));
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(df, comment);
+ });
+}, "If the context node is a document, inserting a DocumentFragment with an element before the doctype should throw a HierarchyRequestError.")
+
+// Step 4.3.
+test(function() {
+ // The context node has an element child.
+ var doc = document.implementation.createHTMLDocument("title");
+ var comment = doc.appendChild(doc.createComment("foo"));
+ assert_array_equals(doc.childNodes, [doc.doctype, doc.documentElement, comment]);
+
+ var a = doc.createElement("a");
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(a, doc.doctype);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(a, doc.documentElement);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(a, comment);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(a, null);
+ });
+}, "If the context node is a document, inserting an element if there already is an element child should throw a HierarchyRequestError.")
+test(function() {
+ // /child/ is a doctype.
+ var doc = document.implementation.createHTMLDocument("title");
+ var comment = doc.moveBefore(doc.createComment("foo"), doc.firstChild);
+ doc.removeChild(doc.documentElement);
+ assert_array_equals(doc.childNodes, [comment, doc.doctype]);
+
+ var a = doc.createElement("a");
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(a, doc.doctype);
+ });
+}, "If the context node is a document, inserting an element before the doctype should throw a HierarchyRequestError.")
+test(function() {
+ // /child/ is not null and a doctype is following /child/.
+ var doc = document.implementation.createHTMLDocument("title");
+ var comment = doc.moveBefore(doc.createComment("foo"), doc.firstChild);
+ doc.removeChild(doc.documentElement);
+ assert_array_equals(doc.childNodes, [comment, doc.doctype]);
+
+ var a = doc.createElement("a");
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(a, comment);
+ });
+}, "If the context node is a document and a doctype is following the reference child, inserting an element should throw a HierarchyRequestError.")
+
+// Step 4.4.
+test(function() {
+ var doc = document.implementation.createHTMLDocument("title");
+ var comment = doc.moveBefore(doc.createComment("foo"), doc.firstChild);
+ assert_array_equals(doc.childNodes, [comment, doc.doctype, doc.documentElement]);
+
+ var doctype = document.implementation.createDocumentType("html", "", "");
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(doctype, comment);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(doctype, doc.doctype);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(doctype, doc.documentElement);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(doctype, null);
+ });
+}, "If the context node is a document, inserting a doctype if there already is a doctype child should throw a HierarchyRequestError.")
+test(function() {
+ var doc = document.implementation.createHTMLDocument("title");
+ var comment = doc.appendChild(doc.createComment("foo"));
+ doc.removeChild(doc.doctype);
+ assert_array_equals(doc.childNodes, [doc.documentElement, comment]);
+
+ var doctype = document.implementation.createDocumentType("html", "", "");
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(doctype, comment);
+ });
+}, "If the context node is a document, inserting a doctype after the document element should throw a HierarchyRequestError.")
+test(function() {
+ var doc = document.implementation.createHTMLDocument("title");
+ var comment = doc.appendChild(doc.createComment("foo"));
+ doc.removeChild(doc.doctype);
+ assert_array_equals(doc.childNodes, [doc.documentElement, comment]);
+
+ var doctype = document.implementation.createDocumentType("html", "", "");
+ assert_throws_dom("HierarchyRequestError", function() {
+ doc.moveBefore(doctype, null);
+ });
+}, "If the context node is a document with and element child, appending a doctype should throw a HierarchyRequestError.")
+
+// Step 5.
+test(function() {
+ var df = document.createDocumentFragment();
+ var a = df.appendChild(document.createElement("a"));
+
+ var doc = document.implementation.createHTMLDocument("title");
+ assert_throws_dom("HierarchyRequestError", function() {
+ df.moveBefore(doc, a);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ df.moveBefore(doc, null);
+ });
+
+ var doctype = document.implementation.createDocumentType("html", "", "");
+ assert_throws_dom("HierarchyRequestError", function() {
+ df.moveBefore(doctype, a);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ df.moveBefore(doctype, null);
+ });
+}, "If the context node is a DocumentFragment, inserting a document or a doctype should throw a HierarchyRequestError.")
+test(function() {
+ var el = document.createElement("div");
+ var a = el.appendChild(document.createElement("a"));
+
+ var doc = document.implementation.createHTMLDocument("title");
+ assert_throws_dom("HierarchyRequestError", function() {
+ el.moveBefore(doc, a);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ el.moveBefore(doc, null);
+ });
+
+ var doctype = document.implementation.createDocumentType("html", "", "");
+ assert_throws_dom("HierarchyRequestError", function() {
+ el.moveBefore(doctype, a);
+ });
+ assert_throws_dom("HierarchyRequestError", function() {
+ el.moveBefore(doctype, null);
+ });
+}, "If the context node is an element, inserting a document or a doctype should throw a HierarchyRequestError.")
+
+// Step 7.
+test(function() {
+ var a = document.createElement("div");
+ var b = document.createElement("div");
+ var c = document.createElement("div");
+ a.appendChild(b);
+ a.appendChild(c);
+ assert_array_equals(a.childNodes, [b, c]);
+ assert_equals(a.moveBefore(b, b), b);
+ assert_array_equals(a.childNodes, [b, c]);
+ assert_equals(a.moveBefore(c, c), c);
+ assert_array_equals(a.childNodes, [b, c]);
+}, "Inserting a node before itself should not move the node");
+</script>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/chrome-338071841-crash.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/chrome-338071841-crash.html
new file mode 100644
index 0000000000..26adfb1cbf
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/chrome-338071841-crash.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/338071841">
+<div id="p"><span></span><!-- comment --></div>
+<script>
+ p.moveBefore(p.lastChild, p.firstChild);
+</script>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-animation-left.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-animation-left.html
new file mode 100644
index 0000000000..8c7f73e3c9
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-animation-left.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<title>Node.moveBefore should preserve CSS animation state (left)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+ <section id="old-parent">
+ <div id="item"></div>
+ </section>
+ <section id="new-parent">
+ </section>
+ <style>
+ @keyframes anim {
+ from {
+ left: 100px;
+ }
+
+ to {
+ left: 400px;
+ }
+ }
+
+ section {
+ position: absolute;
+ }
+
+ #item {
+ position: relative;
+ width: 100px;
+ height: 100px;
+ background: green;
+ animation: 1s linear infinite alternate anim;
+ animation-delay: 100ms;
+ }
+ </style>
+ <script>
+ promise_test(async t => {
+ const item = document.querySelector("#item");
+ let num_events = 0;
+ await new Promise(resolve => addEventListener("animationstart", () => {
+ num_events++;
+ resolve();
+ }));
+
+ // Reparent item
+ document.body.querySelector("#new-parent").moveBefore(item, null);
+ await new Promise(resolve => requestAnimationFrame(() => resolve()));
+ assert_equals(num_events, 1);
+ assert_not_equals(getComputedStyle(item).left, "0px");
+ });
+ </script>
+</body>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-animation-transform.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-animation-transform.html
new file mode 100644
index 0000000000..e7a285893a
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-animation-transform.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title>Node.moveBefore should preserve CSS animation state (transform)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+ <section id="old-parent">
+ <div id="item"></div>
+ </section>
+ <section id="new-parent">
+ </section>
+ <style>
+ @keyframes anim {
+ from {
+ transform: translateX(100px);
+ }
+
+ to {
+ transform: translateX(400px);
+ }
+ }
+
+ #item {
+ position: relative;
+ width: 100px;
+ height: 100px;
+ background: green;
+ animation: 1s linear infinite alternate anim;
+ animation-delay: 100ms;
+ }
+ </style>
+ <script>
+ promise_test(async t => {
+ const item = document.querySelector("#item");
+ let num_events = 0;
+ await new Promise(resolve => addEventListener("animationstart", () => {
+ num_events++;
+ resolve();
+ }));
+
+ // Reparent item
+ document.body.querySelector("#new-parent").moveBefore(item, null);
+ await new Promise(resolve => requestAnimationFrame(() => resolve()));
+ assert_equals(num_events, 1);
+ assert_not_equals(getComputedStyle(item).transform, "none");
+ });
+ </script>
+</body>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-left-pseudo.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-left-pseudo.html
new file mode 100644
index 0000000000..fa51b16887
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-left-pseudo.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<title>Node.moveBefore should preserve CSS transition state on pseudo-elements (left)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+ <section id="old-parent">
+ <div id="item"></div>
+ </section>
+ <section id="new-parent">
+ </section>
+ <style>
+ #item {
+ width: 100px;
+ height: 100px;
+ background: green;
+ position: absolute;
+ left: 0;
+ }
+
+ #item::before {
+ content: "Foo";
+ width: 100px;
+ height: 100px;
+ background: green;
+ transition: left 60s steps(1, jump-both);
+ left: 0px;
+ position: absolute;
+ }
+
+ #item.big::before {
+ left: 400px;
+ }
+
+ section {
+ position: relative;
+ }
+
+ body {
+ margin-left: 0;
+ }
+ </style>
+ <script>
+ promise_test(async t => {
+ const item = document.querySelector("#item");
+ assert_equals(item.getBoundingClientRect().x, 0);
+ item.classList.add("big");
+ await new Promise(resolve => item.addEventListener("transitionstart", resolve));
+ document.querySelector("#new-parent").moveBefore(item, null);
+ await new Promise(resolve => requestAnimationFrame(() => resolve()));
+ assert_equals(getComputedStyle(item, "::before").left, "200px");
+ });
+ </script>
+</body>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-left.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-left.html
new file mode 100644
index 0000000000..2b8e04b26e
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-left.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>Node.moveBefore should preserve CSS transition state (left)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+ <section id="old-parent">
+ <div id="item"></div>
+ </section>
+ <section id="new-parent">
+ </section>
+ <style>
+ #item {
+ width: 100px;
+ height: 100px;
+ background: green;
+ transition: left 10s;
+ position: absolute;
+ left: 0;
+ }
+
+ section {
+ position: relative;
+ }
+
+ body {
+ margin-left: 0;
+ }
+ </style>
+ <script>
+ promise_test(async t => {
+ const item = document.querySelector("#item");
+ assert_equals(item.getBoundingClientRect().x, 0);
+ item.style.left = "400px";
+ await new Promise(resolve => item.addEventListener("transitionstart", resolve));
+ document.querySelector("#new-parent").moveBefore(item, null);
+ await new Promise(resolve => requestAnimationFrame(() => resolve()));
+ assert_less_than(item.getBoundingClientRect().x, 399);
+ });
+ </script>
+</body>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-transform-pseudo.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-transform-pseudo.html
new file mode 100644
index 0000000000..d02c72561c
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-transform-pseudo.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<title>Node.moveBefore should preserve CSS transition state on pseudo-elements (transform)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+ <section id="old-parent">
+ <div id="item"></div>
+ </section>
+ <section id="new-parent">
+ </section>
+ <style>
+ #item {
+ width: 100px;
+ height: 100px;
+ background: green;
+ position: absolute;
+ left: 0;
+ }
+
+ #item::before {
+ content: "Foo";
+ width: 100px;
+ height: 100px;
+ background: green;
+ transition: transform 60s steps(1, jump-both);
+ transform: none;
+ position: absolute;
+ }
+
+ #item.big::before {
+ transform: translateX(400px);
+ }
+
+ section {
+ position: relative;
+ }
+
+ body {
+ margin-left: 0;
+ }
+ </style>
+ <script>
+ promise_test(async t => {
+ const item = document.querySelector("#item");
+ assert_equals(item.getBoundingClientRect().x, 0);
+ item.classList.add("big");
+ await new Promise(resolve => item.addEventListener("transitionstart", resolve));
+ document.querySelector("#new-parent").moveBefore(item, null);
+ await new Promise(resolve => requestAnimationFrame(() => resolve()));
+ assert_not_equals(getComputedStyle(item, "::before").transform, "none");
+ });
+ </script>
+</body>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-transform.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-transform.html
new file mode 100644
index 0000000000..f09edca144
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/continue-css-transition-transform.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Node.moveBefore should preserve CSS transition state (transform)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+ <section id="old-parent">
+ <div id="item"></div>
+ </section>
+ <section id="new-parent">
+ </section>
+ <style>
+ #item {
+ width: 100px;
+ height: 100px;
+ background: green;
+ transition: transform 60s steps(1, jump-both);
+ }
+
+ body {
+ margin-left: 0;
+ }
+ </style>
+ <script>
+ promise_test(async t => {
+ const item = document.querySelector("#item");
+ assert_equals(item.getBoundingClientRect().x, 0);
+ item.style.transform = "translateX(400px)";
+ await new Promise(resolve => item.addEventListener("transitionstart", resolve));
+ document.querySelector("#new-parent").moveBefore(item, null);
+ await new Promise(resolve => requestAnimationFrame(() => resolve()));
+ assert_equals(item.getBoundingClientRect().x, 200);
+ assert_equals(item.getAnimations().length, 1);
+ });
+ </script>
+</body>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-animation-commit-styles.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-animation-commit-styles.html
new file mode 100644
index 0000000000..86bb7c33e4
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-animation-commit-styles.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<title>Calling commitStyles after Node.moveBefore should commit mid-transition value</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+ <section id="old-parent">
+ <div id="item"></div>
+ </section>
+ <section id="new-parent">
+ </section>
+ <style>
+ @keyframes anim {
+ from {
+ transform: translateX(100px);
+ }
+
+ to {
+ transform: translateX(400px);
+ }
+ }
+
+ #item {
+ position: relative;
+ width: 100px;
+ height: 100px;
+ background: green;
+ animation: 1s linear infinite alternate anim;
+ animation-delay: 100ms;
+ }
+ </style>
+ <script>
+ promise_test(async t => {
+ const item = document.querySelector("#item");
+ await new Promise(resolve => item.addEventListener("animationstart", resolve));
+
+ // Reparent item
+ document.body.querySelector("#new-parent").moveBefore(item, null);
+
+ item.getAnimations()[0].commitStyles();
+ assert_true("transform" in item.style);
+ assert_not_equals(item.style.transform, "none");
+ });
+ </script>
+</body>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-cross-document.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-cross-document.html
new file mode 100644
index 0000000000..f3c8fafbfa
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-cross-document.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<title>Node.moveBefore should not preserve CSS transition state when crossing document boundaries</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+ <iframe id="iframe">
+ </iframe>
+ <section id="new-parent">
+ </section>
+ <style id="style">
+ #item {
+ width: 100px;
+ height: 100px;
+ background: green;
+ transition: left 10s;
+ position: absolute;
+ left: 0;
+ }
+
+ section {
+ position: relative;
+ }
+
+ body {
+ margin-left: 0;
+ }
+ </style>
+ <script>
+ promise_test(async t => {
+ const iframe = document.querySelector("#iframe");
+ const style = document.querySelector("#style");
+ iframe.contentDocument.head.append(style.cloneNode(true));
+ const item = iframe.contentDocument.createElement("div");
+ item.id = "item";
+ iframe.contentDocument.body.append(item);
+ assert_equals(item.getBoundingClientRect().x, 0);
+ item.style.left = "400px";
+ await new Promise(resolve => item.addEventListener("transitionstart", resolve));
+ document.querySelector("#new-parent").moveBefore(item, null);
+ await new Promise(resolve => requestAnimationFrame(() => resolve()));
+ assert_greater_than(item.getBoundingClientRect().x, 399);
+ }, "Moving a transition across documents should reset its state");
+ </script>
+</body>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-cross-shadow.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-cross-shadow.html
new file mode 100644
index 0000000000..145f40ba50
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-cross-shadow.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<title>Node.moveBefore should not preserve CSS transition state when crossing shadow boundaries</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+ <section id="old-parent">
+ <div id="item"></div>
+ </section>
+ <div id="shadow-container">
+ <template shadowrootmode="open">
+ <style>
+ #item {
+ width: 100px;
+ height: 100px;
+ background: green;
+ transition: left 10s;
+ position: absolute;
+ left: 0;
+ }
+
+ section {
+ position: relative;
+ }
+
+ body {
+ margin-left: 0;
+ }
+ </style>
+ <section id="new-parent">
+ </section>
+ </template>
+ </div>
+ <style>
+ #item {
+ width: 100px;
+ height: 100px;
+ background: green;
+ transition: left 10s;
+ position: absolute;
+ left: 0;
+ }
+
+ section {
+ position: relative;
+ }
+
+ body {
+ margin-left: 0;
+ }
+ </style>
+ <script>
+ promise_test(async t => {
+ const item = document.querySelector("#item");
+ assert_equals(item.getBoundingClientRect().x, 0);
+ item.style.left = "400px";
+ await new Promise(resolve => item.addEventListener("transitionstart", resolve));
+ const shadowContainer = document.querySelector("#shadow-container");
+ shadowContainer.shadowRoot.querySelector("#new-parent").moveBefore(item, null);
+ await new Promise(resolve => requestAnimationFrame(() => resolve()));
+ assert_greater_than(item.getBoundingClientRect().x, 399);
+ }, "Moving an element with a transition across shadow boundaries should reset the transition");
+ </script>
+</body>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-to-disconnected-document.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-to-disconnected-document.html
new file mode 100644
index 0000000000..537edfe9b6
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-to-disconnected-document.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>Node.moveBefore should act like insertBefore when moving to a disconnected document</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+ <section id="old-parent">
+ <div id="item"></div>
+ </section>
+ <section id="new-parent">
+ </section>
+ <style>
+ #item {
+ width: 100px;
+ height: 100px;
+ background: green;
+ transition: left 10s;
+ position: absolute;
+ left: 0;
+ }
+
+ section {
+ position: relative;
+ }
+
+ body {
+ margin-left: 0;
+ }
+ </style>
+
+ <script>
+ promise_test(async t => {
+ const item = document.querySelector("#item");
+ assert_equals(item.getBoundingClientRect().x, 0);
+ item.style.left = "400px";
+ await new Promise(resolve => item.addEventListener("transitionstart", resolve));
+ const doc = document.implementation.createHTMLDocument();
+ doc.body.moveBefore(item, null);
+ await new Promise(resolve => requestAnimationFrame(() => resolve()));
+ assert_equals(item.getBoundingClientRect().x, 0);
+ }, "Moving an element with a transition to a disconnected document should reset the transitionm state");
+ </script>
+</body>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-trigger.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-trigger.html
new file mode 100644
index 0000000000..0cb5608a69
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/css-transition-trigger.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>Node.moveBefore should trigger CSS transition state (left) if needed</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+ <section id="old-parent">
+ <div id="item"></div>
+ </section>
+ <section id="new-parent">
+ </section>
+ <style>
+ #item {
+ width: 100px;
+ height: 100px;
+ background: green;
+ transition: left 10s steps(1, jump-both);
+ position: absolute;
+ left: 0;
+ }
+
+ #new-parent #item {
+ left: 400px;
+ }
+
+ section {
+ position: relative;
+ }
+
+ body {
+ margin-left: 0;
+ }
+ </style>
+ <script>
+ promise_test(async t => {
+ const item = document.querySelector("#item");
+ assert_equals(item.getBoundingClientRect().x, 0);
+ document.querySelector("#new-parent").moveBefore(item, null);
+ await new Promise(resolve => item.addEventListener("transitionstart", resolve));
+ assert_equals(item.getBoundingClientRect().x, 200);
+ });
+ </script>
+</body>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/focus-preserve.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/focus-preserve.html
new file mode 100644
index 0000000000..a00e8b7788
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/focus-preserve.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<title>moveBefore should not automatically clear focus</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<section id="old_parent">
+<button id="button" tabindex="1">Button</button>
+</section>
+<section id="new_parent">
+</section>
+<section id="inert_parent" inert>
+</section>
+<section id="hidden_parent" hidden>
+</section>
+<script>
+
+function eventually_blurred(t, item, timeout = 1000) {
+ return new Promise((resolve, reject) => {
+ function onblur() {
+ resolve();
+ item.removeEventListener("blur", onblur);
+ }
+ item.addEventListener("blur", onblur);
+ t.step_timeout(reject, timeout);
+ });
+}
+
+test(t => {
+ const old_parent = document.querySelector("#old_parent");
+ const button = document.querySelector("#button");
+ t.add_cleanup(() => old_parent.append(button));
+ button.focus();
+ assert_equals(document.activeElement, button);
+ new_parent.moveBefore(button, null);
+ assert_equals(document.activeElement, button);
+}, "when reparenting an element, don't automatically reset the document focus");
+
+promise_test(async t => {
+ const old_parent = document.querySelector("#old_parent");
+ const button = document.querySelector("#button");
+ t.add_cleanup(() => old_parent.append(button));
+ const inert_parent = document.querySelector("#inert_parent");
+ button.focus();
+ assert_equals(document.activeElement, button);
+ inert_parent.moveBefore(button, null);
+
+ // The button will still be considered the active element. It will blur asynchronously.
+ assert_equals(document.activeElement, button);
+ await eventually_blurred(t, button);
+ assert_equals(document.activeElement, document.body);
+}, "when reparenting a focused element into an inert parent, reset the document focus");
+
+
+promise_test(async t => {
+ const old_parent = document.querySelector("#old_parent");
+ const button = document.querySelector("#button");
+ t.add_cleanup(() => old_parent.append(button));
+ const hidden_parent = document.querySelector("#hidden_parent");
+ button.focus();
+ assert_equals(document.activeElement, button);
+ hidden_parent.moveBefore(button, null);
+
+ // The button will still be considered the active element. It will blur asynchronously.
+ // This is similar to other operations that can cause a blur due to change in inert trees,
+ // e.g. a style change that makes an ancestor `display: none`.
+ assert_equals(document.activeElement, button);
+ await eventually_blurred(t, button);
+ assert_equals(document.activeElement, document.body);
+}, "when reparenting a focused element into a hidden parent, reset the document focus");
+
+promise_test(async t => {
+ const old_parent = document.querySelector("#old_parent");
+ const button = document.querySelector("#button");
+ t.add_cleanup(() => document.body.append(old_parent));
+ const hidden_parent = document.querySelector("#hidden_parent");
+ button.focus();
+ assert_equals(document.activeElement, button);
+ hidden_parent.moveBefore(old_parent, null);
+
+ // The button will still be considered the active element. It will blur asynchronously.
+ assert_equals(document.activeElement, button);
+ await eventually_blurred(t, button);
+ assert_equals(document.activeElement, document.body);
+}, "when reparenting an ancestor of an focused element into a hidden parent, reset the document focus");
+</script>
diff --git a/testing/web-platform/tests/dom/nodes/moveBefore/tentative/fullscreen-preserve.html b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/fullscreen-preserve.html
new file mode 100644
index 0000000000..810eeac9af
--- /dev/null
+++ b/testing/web-platform/tests/dom/nodes/moveBefore/tentative/fullscreen-preserve.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>Document#fullscreenElement</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/fullscreen/trusted-click.js"></script>
+<section id="old_parent">
+ <div id="item"></div>
+</section>
+<section id="new_parent">
+ <div id="item"></div>
+</section>
+<script>
+ promise_test(async function (t) {
+ const item = document.querySelector("#item");
+
+ await trusted_click();
+
+ assert_equals(
+ document.fullscreenElement,
+ null,
+ "fullscreenElement before requestFullscreen()"
+ );
+
+ await item.requestFullscreen();
+ assert_equals(
+ document.fullscreenElement,
+ item,
+ "fullscreenElement before moveBefore()"
+ );
+
+ document.querySelector("#new_parent").moveBefore(item, null);
+
+ assert_equals(
+ document.fullscreenElement,
+ item,
+ "fullscreenElement after moveBefore()"
+ );
+
+ await Promise.all([document.exitFullscreen(), fullScreenChange()]);
+
+ assert_equals(
+ document.fullscreenElement,
+ null,
+ "fullscreenElement after exiting fullscreen"
+ );
+ });
+</script>