<!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 namespaceURI: "http://www.w3.org/1999/xhtml", 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 namespaceURI: "http://www.w3.org/1999/xhtml", 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 namespaceURI: "http://www.w3.org/1999/xhtml", 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 namespaceURI: "http://www.w3.org/1999/xhtml", 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 namespaceURI: "http://www.w3.org/1999/xhtml", 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 namespaceURI: "http://www.w3.org/1999/xhtml", 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 namespaceURI: "http://www.w3.org/1999/xhtml", 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 namespaceURI: "http://www.w3.org/1999/xhtml", 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 namespaceURI: "http://www.w3.org/1999/xhtml", 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 namespaceURI: "http://www.w3.org/1999/xhtml", 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 namespaceURI: "http://www.w3.org/1999/xhtml", 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 namespaceURI: "http://www.w3.org/1999/xhtml", 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>