Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /dom/nodes/Node-properties.html - WPT Dashboard Interop Dashboard
<!doctype html>
<title>Node assorted property tests</title>
<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name>
<meta charset=utf-8>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=../common.js></script>
<script>
"use strict";
/**
* First we define a data structure to tell us what tests to run. The keys
* will be eval()ed, and are mostly global variables defined in common.js. The
* values are objects, which maps properties to expected values. So
*
* foo: {
* bar: "baz",
* quz: 7,
* },
*
* will test that eval("foo.bar") === "baz" and eval("foo.quz") === 7. "foo"
* and "bar" could thus be expressions, like "document.documentElement" and
* "childNodes[4]" respectively.
*
* To avoid repetition, some values are automatically added based on others.
* For instance, if we specify nodeType: Node.TEXT_NODE, we'll automatically
* also test nodeName: "#text". This is handled by code after this variable is
* defined.
*/
var expected = {
testDiv: {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: document,
parentNode: document.body,
parentElement: document.body,
"childNodes.length": 7,
"childNodes[0]": paras[0],
"childNodes[1]": paras[1],
"childNodes[2]": paras[2],
"childNodes[3]": paras[3],
"childNodes[4]": paras[4],
"childNodes[5]": paras[5],
"childNodes[6]": comment,
previousSibling: null,
nextSibling: document.getElementById("log"),
textContent: "A\u0308b\u0308c\u0308d\u0308e\u0308f\u0308g\u0308h\u0308\nIjklmnop\nQrstuvwxYzabcdefGhijklmn123456789012",
// Element
prefix: null,
localName: "div",
tagName: "DIV",
id: "test",
"children[0]": paras[0],
"children[1]": paras[1],
"children[2]": paras[2],
"children[3]": paras[3],
"children[4]": paras[4],
"children[5]": paras[5],
previousElementSibling: null,
// nextSibling isn't explicitly set
//nextElementSibling: ,
childElementCount: 6,
},
detachedDiv: {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: document,
parentNode: null,
parentElement: null,
"childNodes.length": 2,
"childNodes[0]": detachedPara1,
"childNodes[1]": detachedPara2,
previousSibling: null,
nextSibling: null,
textContent: "OpqrstuvWxyzabcd",
// Element
prefix: null,
localName: "div",
tagName: "DIV",
"children[0]": detachedPara1,
"children[1]": detachedPara2,
previousElementSibling: null,
nextElementSibling: null,
childElementCount: 2,
},
detachedPara1: {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: document,
parentNode: detachedDiv,
parentElement: detachedDiv,
"childNodes.length": 1,
previousSibling: null,
nextSibling: detachedPara2,
textContent: "Opqrstuv",
// Element
prefix: null,
localName: "p",
tagName: "P",
previousElementSibling: null,
nextElementSibling: detachedPara2,
childElementCount: 0,
},
detachedPara2: {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: document,
parentNode: detachedDiv,
parentElement: detachedDiv,
"childNodes.length": 1,
previousSibling: detachedPara1,
nextSibling: null,
textContent: "Wxyzabcd",
// Element
prefix: null,
localName: "p",
tagName: "P",
previousElementSibling: detachedPara1,
nextElementSibling: null,
childElementCount: 0,
},
document: {
// Node
nodeType: Node.DOCUMENT_NODE,
"childNodes.length": 2,
"childNodes[0]": document.doctype,
"childNodes[1]": document.documentElement,
// Document
URL: String(location),
compatMode: "CSS1Compat",
characterSet: "UTF-8",
contentType: "text/html",
doctype: doctype,
//documentElement: ,
},
foreignDoc: {
// Node
nodeType: Node.DOCUMENT_NODE,
"childNodes.length": 3,
"childNodes[0]": foreignDoc.doctype,
"childNodes[1]": foreignDoc.documentElement,
"childNodes[2]": foreignComment,
// Document
URL: "about:blank",
compatMode: "CSS1Compat",
characterSet: "UTF-8",
contentType: "text/html",
//doctype: ,
//documentElement: ,
},
foreignPara1: {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: foreignDoc,
parentNode: foreignDoc.body,
parentElement: foreignDoc.body,
"childNodes.length": 1,
previousSibling: null,
nextSibling: foreignPara2,
textContent: "Efghijkl",
// Element
prefix: null,
localName: "p",
tagName: "P",
previousElementSibling: null,
nextElementSibling: foreignPara2,
childElementCount: 0,
},
foreignPara2: {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: foreignDoc,
parentNode: foreignDoc.body,
parentElement: foreignDoc.body,
"childNodes.length": 1,
previousSibling: foreignPara1,
nextSibling: foreignTextNode,
textContent: "Mnopqrst",
// Element
prefix: null,
localName: "p",
tagName: "P",
previousElementSibling: foreignPara1,
nextElementSibling: null,
childElementCount: 0,
},
xmlDoc: {
// Node
nodeType: Node.DOCUMENT_NODE,
"childNodes.length": 4,
"childNodes[0]": xmlDoctype,
"childNodes[1]": xmlElement,
"childNodes[2]": processingInstruction,
"childNodes[3]": xmlComment,
// Document
URL: "about:blank",
compatMode: "CSS1Compat",
characterSet: "UTF-8",
contentType: "application/xml",
//doctype: ,
//documentElement: ,
},
xmlElement: {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: xmlDoc,
parentNode: xmlDoc,
parentElement: null,
"childNodes.length": 1,
"childNodes[0]": xmlTextNode,
previousSibling: xmlDoctype,
nextSibling: processingInstruction,
textContent: "do re mi fa so la ti",
// Element
namespaceURI: null,
prefix: null,
localName: "igiveuponcreativenames",
tagName: "igiveuponcreativenames",
previousElementSibling: null,
nextElementSibling: null,
childElementCount: 0,
},
detachedXmlElement: {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: xmlDoc,
parentNode: null,
parentElement: null,
"childNodes.length": 0,
previousSibling: null,
nextSibling: null,
textContent: "",
// Element
namespaceURI: null,
prefix: null,
localName: "everyone-hates-hyphenated-element-names",
tagName: "everyone-hates-hyphenated-element-names",
previousElementSibling: null,
nextElementSibling: null,
childElementCount: 0,
},
detachedTextNode: {
// Node
nodeType: Node.TEXT_NODE,
ownerDocument: document,
parentNode: null,
parentElement: null,
previousSibling: null,
nextSibling: null,
nodeValue: "Uvwxyzab",
// Text
wholeText: "Uvwxyzab",
},
foreignTextNode: {
// Node
nodeType: Node.TEXT_NODE,
ownerDocument: foreignDoc,
parentNode: foreignDoc.body,
parentElement: foreignDoc.body,
previousSibling: foreignPara2,
nextSibling: null,
nodeValue: "I admit that I harbor doubts about whether we really need so many things to test, but it's too late to stop now.",
// Text
wholeText: "I admit that I harbor doubts about whether we really need so many things to test, but it's too late to stop now.",
},
detachedForeignTextNode: {
// Node
nodeType: Node.TEXT_NODE,
ownerDocument: foreignDoc,
parentNode: null,
parentElement: null,
previousSibling: null,
nextSibling: null,
nodeValue: "Cdefghij",
// Text
wholeText: "Cdefghij",
},
xmlTextNode: {
// Node
nodeType: Node.TEXT_NODE,
ownerDocument: xmlDoc,
parentNode: xmlElement,
parentElement: xmlElement,
previousSibling: null,
nextSibling: null,
nodeValue: "do re mi fa so la ti",
// Text
wholeText: "do re mi fa so la ti",
},
detachedXmlTextNode: {
// Node
nodeType: Node.TEXT_NODE,
ownerDocument: xmlDoc,
parentNode: null,
parentElement: null,
previousSibling: null,
nextSibling: null,
nodeValue: "Klmnopqr",
// Text
wholeText: "Klmnopqr",
},
processingInstruction: {
// Node
nodeType: Node.PROCESSING_INSTRUCTION_NODE,
ownerDocument: xmlDoc,
parentNode: xmlDoc,
parentElement: null,
previousSibling: xmlElement,
nextSibling: xmlComment,
nodeValue: 'Did you know that ":syn sync fromstart" is very useful when using vim to edit large amounts of JavaScript embedded in HTML?',
// ProcessingInstruction
target: "somePI",
},
detachedProcessingInstruction: {
// Node
nodeType: Node.PROCESSING_INSTRUCTION_NODE,
ownerDocument: xmlDoc,
parentNode: null,
parentElement: null,
previousSibling: null,
nextSibling: null,
nodeValue: "chirp chirp chirp",
// ProcessingInstruction
target: "whippoorwill",
},
comment: {
// Node
nodeType: Node.COMMENT_NODE,
ownerDocument: document,
parentNode: testDiv,
parentElement: testDiv,
previousSibling: paras[5],
nextSibling: null,
nodeValue: "Alphabet soup?",
},
detachedComment: {
// Node
nodeType: Node.COMMENT_NODE,
ownerDocument: document,
parentNode: null,
parentElement: null,
previousSibling: null,
nextSibling: null,
nodeValue: "Stuvwxyz",
},
foreignComment: {
// Node
nodeType: Node.COMMENT_NODE,
ownerDocument: foreignDoc,
parentNode: foreignDoc,
parentElement: null,
previousSibling: foreignDoc.documentElement,
nextSibling: null,
nodeValue: '"Commenter" and "commentator" mean different things. I\'ve seen non-native speakers trip up on this.',
},
detachedForeignComment: {
// Node
nodeType: Node.COMMENT_NODE,
ownerDocument: foreignDoc,
parentNode: null,
parentElement: null,
previousSibling: null,
nextSibling: null,
nodeValue: "אריה יהודה",
},
xmlComment: {
// Node
nodeType: Node.COMMENT_NODE,
ownerDocument: xmlDoc,
parentNode: xmlDoc,
parentElement: null,
previousSibling: processingInstruction,
nextSibling: null,
nodeValue: "I maliciously created a comment that will break incautious XML serializers, but Firefox threw an exception, so all I got was this lousy T-shirt",
},
detachedXmlComment: {
// Node
nodeType: Node.COMMENT_NODE,
ownerDocument: xmlDoc,
parentNode: null,
parentElement: null,
previousSibling: null,
nextSibling: null,
nodeValue: "בן חיים אליעזר",
},
docfrag: {
// Node
nodeType: Node.DOCUMENT_FRAGMENT_NODE,
ownerDocument: document,
"childNodes.length": 0,
textContent: "",
},
foreignDocfrag: {
// Node
nodeType: Node.DOCUMENT_FRAGMENT_NODE,
ownerDocument: foreignDoc,
"childNodes.length": 0,
textContent: "",
},
xmlDocfrag: {
// Node
nodeType: Node.DOCUMENT_FRAGMENT_NODE,
ownerDocument: xmlDoc,
"childNodes.length": 0,
textContent: "",
},
doctype: {
// Node
nodeType: Node.DOCUMENT_TYPE_NODE,
ownerDocument: document,
parentNode: document,
previousSibling: null,
nextSibling: document.documentElement,
// DocumentType
name: "html",
publicId: "",
systemId: "",
},
foreignDoctype: {
// Node
nodeType: Node.DOCUMENT_TYPE_NODE,
ownerDocument: foreignDoc,
parentNode: foreignDoc,
previousSibling: null,
nextSibling: foreignDoc.documentElement,
// DocumentType
name: "html",
publicId: "",
systemId: "",
},
xmlDoctype: {
// Node
nodeType: Node.DOCUMENT_TYPE_NODE,
ownerDocument: xmlDoc,
parentNode: xmlDoc,
previousSibling: null,
nextSibling: xmlElement,
// DocumentType
name: "qorflesnorf",
publicId: "abcde",
systemId: "x\"'y",
},
"paras[0]": {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: document,
parentNode: testDiv,
parentElement: testDiv,
"childNodes.length": 1,
previousSibling: null,
nextSibling: paras[1],
textContent: "A\u0308b\u0308c\u0308d\u0308e\u0308f\u0308g\u0308h\u0308\n",
// Element
prefix: null,
localName: "p",
tagName: "P",
id: "a",
previousElementSibling: null,
nextElementSibling: paras[1],
childElementCount: 0,
},
"paras[1]": {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: document,
parentNode: testDiv,
parentElement: testDiv,
"childNodes.length": 1,
previousSibling: paras[0],
nextSibling: paras[2],
textContent: "Ijklmnop\n",
// Element
prefix: null,
localName: "p",
tagName: "P",
id: "b",
previousElementSibling: paras[0],
nextElementSibling: paras[2],
childElementCount: 0,
},
"paras[2]": {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: document,
parentNode: testDiv,
parentElement: testDiv,
"childNodes.length": 1,
previousSibling: paras[1],
nextSibling: paras[3],
textContent: "Qrstuvwx",
// Element
prefix: null,
localName: "p",
tagName: "P",
id: "c",
previousElementSibling: paras[1],
nextElementSibling: paras[3],
childElementCount: 0,
},
"paras[3]": {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: document,
parentNode: testDiv,
parentElement: testDiv,
"childNodes.length": 1,
previousSibling: paras[2],
nextSibling: paras[4],
textContent: "Yzabcdef",
// Element
prefix: null,
localName: "p",
tagName: "P",
id: "d",
previousElementSibling: paras[2],
nextElementSibling: paras[4],
childElementCount: 0,
},
"paras[4]": {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: document,
parentNode: testDiv,
parentElement: testDiv,
"childNodes.length": 1,
previousSibling: paras[3],
nextSibling: paras[5],
textContent: "Ghijklmn",
// Element
prefix: null,
localName: "p",
tagName: "P",
id: "e",
previousElementSibling: paras[3],
nextElementSibling: paras[5],
childElementCount: 0,
},
"paras[5]": {
// Node
nodeType: Node.ELEMENT_NODE,
ownerDocument: document,
parentNode: testDiv,
parentElement: testDiv,
"childNodes.length": 3,
previousSibling: paras[4],
nextSibling: comment,
textContent: "123456789012",
// Element
prefix: null,
localName: "p",
tagName: "P",
previousElementSibling: paras[4],
nextElementSibling: null,
childElementCount: 0,
}
};
for (var node in expected) {
// Now we set various default values by node type.
switch (expected[node].nodeType) {
case Node.ELEMENT_NODE:
expected[node].nodeName = expected[node].tagName;
expected[node].nodeValue = null;
expected[node]["children.length"] = expected[node].childElementCount;
if (expected[node].id === undefined) {
expected[node].id = "";
}
if (expected[node].className === undefined) {
expected[node].className = "";
}
var len = expected[node].childElementCount;
if (len === 0) {
expected[node].firstElementChild =
expected[node].lastElementChild = null;
} else {
// If we have expectations for the first/last child in children,
// use those. Otherwise, at least check that .firstElementChild ==
// .children[0] and .lastElementChild == .children[len - 1], even
// if we aren't sure what they should be.
expected[node].firstElementChild = expected[node]["children[0]"]
? expected[node]["children[0]"]
: eval(node).children[0];
expected[node].lastElementChild =
expected[node]["children[" + (len - 1) + "]"]
? expected[node]["children[" + (len - 1) + "]"]
: eval(node).children[len - 1];
}
break;
case Node.TEXT_NODE:
expected[node].nodeName = "#text";
expected[node]["childNodes.length"] = 0;
expected[node].textContent = expected[node].data =
expected[node].nodeValue;
expected[node].length = expected[node].nodeValue.length;
break;
case Node.PROCESSING_INSTRUCTION_NODE:
expected[node].nodeName = expected[node].target;
expected[node]["childNodes.length"] = 0;
expected[node].textContent = expected[node].data =
expected[node].nodeValue;
expected[node].length = expected[node].nodeValue.length;
break;
case Node.COMMENT_NODE:
expected[node].nodeName = "#comment";
expected[node]["childNodes.length"] = 0;
expected[node].textContent = expected[node].data =
expected[node].nodeValue;
expected[node].length = expected[node].nodeValue.length;
break;
case Node.DOCUMENT_NODE:
expected[node].nodeName = "#document";
expected[node].ownerDocument = expected[node].parentNode =
expected[node].parentElement = expected[node].previousSibling =
expected[node].nextSibling = expected[node].nodeValue =
expected[node].textContent = null;
expected[node].documentURI = expected[node].URL;
expected[node].charset = expected[node].inputEncoding =
expected[node].characterSet;
break;
case Node.DOCUMENT_TYPE_NODE:
expected[node].nodeName = expected[node].name;
expected[node]["childNodes.length"] = 0;
expected[node].parentElement = expected[node].nodeValue =
expected[node].textContent = null;
break;
case Node.DOCUMENT_FRAGMENT_NODE:
expected[node].nodeName = "#document-fragment";
expected[node].parentNode = expected[node].parentElement =
expected[node].previousSibling = expected[node].nextSibling =
expected[node].nodeValue = null;
break;
}
// Now we set some further default values that are independent of node
// type.
var len = expected[node]["childNodes.length"];
if (len === 0) {
expected[node].firstChild = expected[node].lastChild = null;
} else {
// If we have expectations for the first/last child in childNodes, use
// those. Otherwise, at least check that .firstChild == .childNodes[0]
// and .lastChild == .childNodes[len - 1], even if we aren't sure what
// they should be.
expected[node].firstChild = expected[node]["childNodes[0]"]
? expected[node]["childNodes[0]"]
: eval(node).childNodes[0];
expected[node].lastChild =
expected[node]["childNodes[" + (len - 1) + "]"]
? expected[node]["childNodes[" + (len - 1) + "]"]
: eval(node).childNodes[len - 1];
}
expected[node]["hasChildNodes()"] = !!expected[node]["childNodes.length"];
// Finally, we test!
for (var prop in expected[node]) {
test(function() {
assert_equals(eval(node + "." + prop), expected[node][prop]);
}, node + "." + prop);
}
}
testDiv.parentNode.removeChild(testDiv);
</script>