| <!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": 6, |
| "childNodes[0]": paras[0], |
| "childNodes[1]": paras[1], |
| "childNodes[2]": paras[2], |
| "childNodes[3]": paras[3], |
| "childNodes[4]": paras[4], |
| "childNodes[5]": comment, |
| previousSibling: null, |
| nextSibling: document.getElementById("log"), |
| textContent: "A\u0308b\u0308c\u0308d\u0308e\u0308f\u0308g\u0308h\u0308\nIjklmnop\nQrstuvwxYzabcdefGhijklmn", |
| |
| // 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], |
| previousElementSibling: null, |
| // nextSibling isn't explicitly set |
| //nextElementSibling: , |
| childElementCount: 5, |
| }, |
| 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: "http://www.w3.org/1999/xhtml", |
| 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: "http://www.w3.org/1999/xhtml", |
| 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[4], |
| 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: comment, |
| textContent: "Ghijklmn", |
| |
| // Element |
| namespaceURI: "http://www.w3.org/1999/xhtml", |
| prefix: null, |
| localName: "p", |
| tagName: "P", |
| id: "e", |
| previousElementSibling: paras[3], |
| 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> |