Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test has a WPT meta file that expects 24 subtest issues.
- This WPT test may be referenced by the following Test IDs:
- /dom/nodes/moveBefore/tentative/Node-moveBefore.html - WPT Dashboard Interop Dashboard
<!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-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") })
// Pre-move validity, step 1:
// "If either parent or node are not connected, then throw a
// "HierarchyRequestError" DOMException."
//
test(t => {
const connectedTarget = document.body.appendChild(document.createElement('div'));
const disconnectedDestination = document.createElement('div');
t.add_cleanup(() => connectedTarget.remove());
assert_throws_dom("HIERARCHY_REQUEST_ERR", () => {
disconnectedDestination.moveBefore(connectedTarget, null);
});
}, "moveBefore() on disconnected parent throws a HierarchyRequestError");
test(t => {
const connectedDestination = document.body.appendChild(document.createElement('div'));
const disconnectedTarget = document.createElement('div');
t.add_cleanup(() => connectedDestination.remove());
assert_throws_dom("HIERARCHY_REQUEST_ERR", () => {
connectedDestination.moveBefore(disconnectedTarget, null);
});
}, "moveBefore() with disconnected target node throws a HierarchyRequestError");
// Pre-move validity, step 2:
// "If parent’s shadow-including root is not the same as node’s shadow-including
// "root, then throw a "HierarchyRequestError" DOMException."
//
test(t => {
const iframe = document.createElement('iframe');
document.body.append(iframe);
const connectedCrossDocChild = iframe.contentDocument.createElement('div');
const connectedLocalParent = document.querySelector('div');
t.add_cleanup(() => iframe.remove());
assert_throws_dom("HIERARCHY_REQUEST_ERR", () => {
connectedLocalParent.moveBefore(connectedCrossDocChild, null);
});
}, "moveBefore() on a cross-document target node throws a HierarchyRequestError");
// Pre-move validity, step 3:
// "If parent is not an Element node, then throw a "HierarchyRequestError"
// DOMException."
//
test(t => {
const iframe = document.body.appendChild(document.createElement('iframe'));
const innerBody = iframe.contentDocument.querySelector('body');
assert_throws_dom("HIERARCHY_REQUEST_ERR", iframe.contentWindow.DOMException, () => {
// Moving the body into the same place that it already is, which is a valid
// action in the normal case, when moving a node into an Element.
iframe.contentDocument.moveBefore(innerBody, null);
});
}, "moveBefore() into a Document throws a HierarchyRequestError");
test(t => {
const comment = document.body.appendChild(document.createComment("comment"));
const child = document.body.appendChild(document.createElement('p'));
assert_throws_dom("HIERARCHY_REQUEST_ERR", () => {
comment.moveBefore(child, null);
});
}, "moveBefore() into a CharacterData throws a HierarchyRequestError");
// Pre-move validity, step 4:
// "If node is a host-including inclusive ancestor of parent, then throw a
// "HierarchyRequestError" DOMException."
//
test(t => {
const parentDiv = document.body.appendChild(document.createElement('div'));
const childDiv = parentDiv.appendChild(document.createElement('div'));
t.add_cleanup(() => {
parentDiv.remove();
childDiv.remove();
});
assert_throws_dom("HIERARCHY_REQUEST_ERR", () => {
parentDiv.moveBefore(parentDiv, null);
}, "parent moving itself");
assert_throws_dom("HIERARCHY_REQUEST_ERR", () => {
childDiv.moveBefore(parentDiv, null);
}, "Moving parent into immediate child");
assert_throws_dom("HIERARCHY_REQUEST_ERR", () => {
childDiv.moveBefore(document.body, null);
}, "Moving grandparent into grandchild");
assert_throws_dom("HIERARCHY_REQUEST_ERR", () => {
document.body.moveBefore(document.documentElement, childDiv);
}, "Moving documentElement (<html>) into a deeper child");
}, "moveBefore() with node being an inclusive ancestor of parent throws a " +
"HierarchyRequestError");
// Pre-move validity, step 5:
// "If node is not an Element or a CharacterData node, then throw a
// "HierarchyRequestError" DOMException."
//
test(t => {
assert_true(document.doctype.isConnected);
assert_throws_dom("HIERARCHY_REQUEST_ERR", () => {
document.body.moveBefore(document.doctype, null);
}, "DocumentType throws");
assert_throws_dom("HIERARCHY_REQUEST_ERR", () => {
document.body.moveBefore(new DocumentFragment(), null);
}, "DocumentFragment throws");
const doc = document.implementation.createHTMLDocument("title");
assert_true(doc.isConnected);
assert_throws_dom("HIERARCHY_REQUEST_ERR", () => {
document.body.moveBefore(doc, null);
});
}, "moveBefore() with a non-{Element, CharacterData} throws a HierarchyRequestError");
test(t => {
const text = new Text("child text");
document.body.prepend(text);
const childElement = document.createElement('p');
document.body.prepend(childElement);
t.add_cleanup(() => {
text.remove();
childElement.remove();
});
document.body.moveBefore(text, null);
assert_equals(document.body.lastChild, text);
document.body.moveBefore(childElement, null);
assert_equals(document.body.lastChild, childElement);
document.body.moveBefore(text, null);
assert_equals(document.body.lastChild, text);
}, "moveBefore with an Element or CharacterData succeeds");
test(t => {
const p = document.createElement('p');
p.textContent = "Some content";
document.body.prepend(p);
const text_node = p.firstChild;
// The Text node is *inside* the paragraph.
assert_equals(text_node.textContent, "Some content");
assert_not_equals(document.body.lastChild, text_node);
t.add_cleanup(() => {
text_node.remove();
p.remove();
});
document.body.moveBefore(p.firstChild, null);
assert_equals(document.body.lastChild, text_node);
}, "moveBefore on a paragraph's Text node child");
// Pre-move validity, step 6:
// "If child is non-null and its parent is not parent, then throw a
// "NotFoundError" DOMException."
//
test(t => {
const a = document.body.appendChild(document.createElement("div"));
const b = document.body.appendChild(document.createElement("div"));
const c = document.body.appendChild(document.createElement("div"));
t.add_cleanup(() => {
a.remove();
b.remove();
c.remove();
});
assert_throws_dom("NotFoundError", () => {
a.moveBefore(b, c);
});
}, "moveBefore with reference child whose parent is NOT the destination " +
"parent (context node) throws a NotFoundError.")
test(() => {
const a = document.body.appendChild(document.createElement("div"));
const b = document.createElement("div");
const c = document.createElement("div");
a.append(b);
a.append(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>