Node-properties.html (21882B)
1 <!doctype html> 2 <title>Node assorted property tests</title> 3 <link rel=author title="Aryeh Gregor" href=ayg@aryeh.name> 4 <meta charset=utf-8> 5 <div id=log></div> 6 <script src=/resources/testharness.js></script> 7 <script src=/resources/testharnessreport.js></script> 8 <script src=../common.js></script> 9 <script> 10 "use strict"; 11 /** 12 * First we define a data structure to tell us what tests to run. The keys 13 * will be eval()ed, and are mostly global variables defined in common.js. The 14 * values are objects, which maps properties to expected values. So 15 * 16 * foo: { 17 * bar: "baz", 18 * quz: 7, 19 * }, 20 * 21 * will test that eval("foo.bar") === "baz" and eval("foo.quz") === 7. "foo" 22 * and "bar" could thus be expressions, like "document.documentElement" and 23 * "childNodes[4]" respectively. 24 * 25 * To avoid repetition, some values are automatically added based on others. 26 * For instance, if we specify nodeType: Node.TEXT_NODE, we'll automatically 27 * also test nodeName: "#text". This is handled by code after this variable is 28 * defined. 29 */ 30 var expected = { 31 testDiv: { 32 // Node 33 nodeType: Node.ELEMENT_NODE, 34 ownerDocument: document, 35 parentNode: document.body, 36 parentElement: document.body, 37 "childNodes.length": 7, 38 "childNodes[0]": paras[0], 39 "childNodes[1]": paras[1], 40 "childNodes[2]": paras[2], 41 "childNodes[3]": paras[3], 42 "childNodes[4]": paras[4], 43 "childNodes[5]": paras[5], 44 "childNodes[6]": comment, 45 previousSibling: null, 46 nextSibling: document.getElementById("log"), 47 textContent: "A\u0308b\u0308c\u0308d\u0308e\u0308f\u0308g\u0308h\u0308\nIjklmnop\nQrstuvwxYzabcdefGhijklmn123456789012", 48 49 // Element 50 namespaceURI: "http://www.w3.org/1999/xhtml", 51 prefix: null, 52 localName: "div", 53 tagName: "DIV", 54 id: "test", 55 "children[0]": paras[0], 56 "children[1]": paras[1], 57 "children[2]": paras[2], 58 "children[3]": paras[3], 59 "children[4]": paras[4], 60 "children[5]": paras[5], 61 previousElementSibling: null, 62 // nextSibling isn't explicitly set 63 //nextElementSibling: , 64 childElementCount: 6, 65 }, 66 detachedDiv: { 67 // Node 68 nodeType: Node.ELEMENT_NODE, 69 ownerDocument: document, 70 parentNode: null, 71 parentElement: null, 72 "childNodes.length": 2, 73 "childNodes[0]": detachedPara1, 74 "childNodes[1]": detachedPara2, 75 previousSibling: null, 76 nextSibling: null, 77 textContent: "OpqrstuvWxyzabcd", 78 79 // Element 80 namespaceURI: "http://www.w3.org/1999/xhtml", 81 prefix: null, 82 localName: "div", 83 tagName: "DIV", 84 "children[0]": detachedPara1, 85 "children[1]": detachedPara2, 86 previousElementSibling: null, 87 nextElementSibling: null, 88 childElementCount: 2, 89 }, 90 detachedPara1: { 91 // Node 92 nodeType: Node.ELEMENT_NODE, 93 ownerDocument: document, 94 parentNode: detachedDiv, 95 parentElement: detachedDiv, 96 "childNodes.length": 1, 97 previousSibling: null, 98 nextSibling: detachedPara2, 99 textContent: "Opqrstuv", 100 101 // Element 102 namespaceURI: "http://www.w3.org/1999/xhtml", 103 prefix: null, 104 localName: "p", 105 tagName: "P", 106 previousElementSibling: null, 107 nextElementSibling: detachedPara2, 108 childElementCount: 0, 109 }, 110 detachedPara2: { 111 // Node 112 nodeType: Node.ELEMENT_NODE, 113 ownerDocument: document, 114 parentNode: detachedDiv, 115 parentElement: detachedDiv, 116 "childNodes.length": 1, 117 previousSibling: detachedPara1, 118 nextSibling: null, 119 textContent: "Wxyzabcd", 120 121 // Element 122 namespaceURI: "http://www.w3.org/1999/xhtml", 123 prefix: null, 124 localName: "p", 125 tagName: "P", 126 previousElementSibling: detachedPara1, 127 nextElementSibling: null, 128 childElementCount: 0, 129 }, 130 document: { 131 // Node 132 nodeType: Node.DOCUMENT_NODE, 133 "childNodes.length": 2, 134 "childNodes[0]": document.doctype, 135 "childNodes[1]": document.documentElement, 136 137 // Document 138 URL: String(location), 139 compatMode: "CSS1Compat", 140 characterSet: "UTF-8", 141 contentType: "text/html", 142 doctype: doctype, 143 //documentElement: , 144 }, 145 foreignDoc: { 146 // Node 147 nodeType: Node.DOCUMENT_NODE, 148 "childNodes.length": 3, 149 "childNodes[0]": foreignDoc.doctype, 150 "childNodes[1]": foreignDoc.documentElement, 151 "childNodes[2]": foreignComment, 152 153 // Document 154 URL: "about:blank", 155 compatMode: "CSS1Compat", 156 characterSet: "UTF-8", 157 contentType: "text/html", 158 //doctype: , 159 //documentElement: , 160 }, 161 foreignPara1: { 162 // Node 163 nodeType: Node.ELEMENT_NODE, 164 ownerDocument: foreignDoc, 165 parentNode: foreignDoc.body, 166 parentElement: foreignDoc.body, 167 "childNodes.length": 1, 168 previousSibling: null, 169 nextSibling: foreignPara2, 170 textContent: "Efghijkl", 171 172 // Element 173 namespaceURI: "http://www.w3.org/1999/xhtml", 174 prefix: null, 175 localName: "p", 176 tagName: "P", 177 previousElementSibling: null, 178 nextElementSibling: foreignPara2, 179 childElementCount: 0, 180 }, 181 foreignPara2: { 182 // Node 183 nodeType: Node.ELEMENT_NODE, 184 ownerDocument: foreignDoc, 185 parentNode: foreignDoc.body, 186 parentElement: foreignDoc.body, 187 "childNodes.length": 1, 188 previousSibling: foreignPara1, 189 nextSibling: foreignTextNode, 190 textContent: "Mnopqrst", 191 192 // Element 193 namespaceURI: "http://www.w3.org/1999/xhtml", 194 prefix: null, 195 localName: "p", 196 tagName: "P", 197 previousElementSibling: foreignPara1, 198 nextElementSibling: null, 199 childElementCount: 0, 200 }, 201 xmlDoc: { 202 // Node 203 nodeType: Node.DOCUMENT_NODE, 204 "childNodes.length": 4, 205 "childNodes[0]": xmlDoctype, 206 "childNodes[1]": xmlElement, 207 "childNodes[2]": processingInstruction, 208 "childNodes[3]": xmlComment, 209 210 // Document 211 URL: "about:blank", 212 compatMode: "CSS1Compat", 213 characterSet: "UTF-8", 214 contentType: "application/xml", 215 //doctype: , 216 //documentElement: , 217 }, 218 xmlElement: { 219 // Node 220 nodeType: Node.ELEMENT_NODE, 221 ownerDocument: xmlDoc, 222 parentNode: xmlDoc, 223 parentElement: null, 224 "childNodes.length": 1, 225 "childNodes[0]": xmlTextNode, 226 previousSibling: xmlDoctype, 227 nextSibling: processingInstruction, 228 textContent: "do re mi fa so la ti", 229 230 // Element 231 namespaceURI: null, 232 prefix: null, 233 localName: "igiveuponcreativenames", 234 tagName: "igiveuponcreativenames", 235 previousElementSibling: null, 236 nextElementSibling: null, 237 childElementCount: 0, 238 }, 239 detachedXmlElement: { 240 // Node 241 nodeType: Node.ELEMENT_NODE, 242 ownerDocument: xmlDoc, 243 parentNode: null, 244 parentElement: null, 245 "childNodes.length": 0, 246 previousSibling: null, 247 nextSibling: null, 248 textContent: "", 249 250 // Element 251 namespaceURI: null, 252 prefix: null, 253 localName: "everyone-hates-hyphenated-element-names", 254 tagName: "everyone-hates-hyphenated-element-names", 255 previousElementSibling: null, 256 nextElementSibling: null, 257 childElementCount: 0, 258 }, 259 detachedTextNode: { 260 // Node 261 nodeType: Node.TEXT_NODE, 262 ownerDocument: document, 263 parentNode: null, 264 parentElement: null, 265 previousSibling: null, 266 nextSibling: null, 267 nodeValue: "Uvwxyzab", 268 269 // Text 270 wholeText: "Uvwxyzab", 271 }, 272 foreignTextNode: { 273 // Node 274 nodeType: Node.TEXT_NODE, 275 ownerDocument: foreignDoc, 276 parentNode: foreignDoc.body, 277 parentElement: foreignDoc.body, 278 previousSibling: foreignPara2, 279 nextSibling: null, 280 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.", 281 282 // Text 283 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.", 284 }, 285 detachedForeignTextNode: { 286 // Node 287 nodeType: Node.TEXT_NODE, 288 ownerDocument: foreignDoc, 289 parentNode: null, 290 parentElement: null, 291 previousSibling: null, 292 nextSibling: null, 293 nodeValue: "Cdefghij", 294 295 // Text 296 wholeText: "Cdefghij", 297 }, 298 xmlTextNode: { 299 // Node 300 nodeType: Node.TEXT_NODE, 301 ownerDocument: xmlDoc, 302 parentNode: xmlElement, 303 parentElement: xmlElement, 304 previousSibling: null, 305 nextSibling: null, 306 nodeValue: "do re mi fa so la ti", 307 308 // Text 309 wholeText: "do re mi fa so la ti", 310 }, 311 detachedXmlTextNode: { 312 // Node 313 nodeType: Node.TEXT_NODE, 314 ownerDocument: xmlDoc, 315 parentNode: null, 316 parentElement: null, 317 previousSibling: null, 318 nextSibling: null, 319 nodeValue: "Klmnopqr", 320 321 // Text 322 wholeText: "Klmnopqr", 323 }, 324 processingInstruction: { 325 // Node 326 nodeType: Node.PROCESSING_INSTRUCTION_NODE, 327 ownerDocument: xmlDoc, 328 parentNode: xmlDoc, 329 parentElement: null, 330 previousSibling: xmlElement, 331 nextSibling: xmlComment, 332 nodeValue: 'Did you know that ":syn sync fromstart" is very useful when using vim to edit large amounts of JavaScript embedded in HTML?', 333 334 // ProcessingInstruction 335 target: "somePI", 336 }, 337 detachedProcessingInstruction: { 338 // Node 339 nodeType: Node.PROCESSING_INSTRUCTION_NODE, 340 ownerDocument: xmlDoc, 341 parentNode: null, 342 parentElement: null, 343 previousSibling: null, 344 nextSibling: null, 345 nodeValue: "chirp chirp chirp", 346 347 // ProcessingInstruction 348 target: "whippoorwill", 349 }, 350 comment: { 351 // Node 352 nodeType: Node.COMMENT_NODE, 353 ownerDocument: document, 354 parentNode: testDiv, 355 parentElement: testDiv, 356 previousSibling: paras[5], 357 nextSibling: null, 358 nodeValue: "Alphabet soup?", 359 }, 360 detachedComment: { 361 // Node 362 nodeType: Node.COMMENT_NODE, 363 ownerDocument: document, 364 parentNode: null, 365 parentElement: null, 366 previousSibling: null, 367 nextSibling: null, 368 nodeValue: "Stuvwxyz", 369 }, 370 foreignComment: { 371 // Node 372 nodeType: Node.COMMENT_NODE, 373 ownerDocument: foreignDoc, 374 parentNode: foreignDoc, 375 parentElement: null, 376 previousSibling: foreignDoc.documentElement, 377 nextSibling: null, 378 nodeValue: '"Commenter" and "commentator" mean different things. I\'ve seen non-native speakers trip up on this.', 379 }, 380 detachedForeignComment: { 381 // Node 382 nodeType: Node.COMMENT_NODE, 383 ownerDocument: foreignDoc, 384 parentNode: null, 385 parentElement: null, 386 previousSibling: null, 387 nextSibling: null, 388 nodeValue: "אריה יהודה", 389 }, 390 xmlComment: { 391 // Node 392 nodeType: Node.COMMENT_NODE, 393 ownerDocument: xmlDoc, 394 parentNode: xmlDoc, 395 parentElement: null, 396 previousSibling: processingInstruction, 397 nextSibling: null, 398 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", 399 }, 400 detachedXmlComment: { 401 // Node 402 nodeType: Node.COMMENT_NODE, 403 ownerDocument: xmlDoc, 404 parentNode: null, 405 parentElement: null, 406 previousSibling: null, 407 nextSibling: null, 408 nodeValue: "בן חיים אליעזר", 409 }, 410 docfrag: { 411 // Node 412 nodeType: Node.DOCUMENT_FRAGMENT_NODE, 413 ownerDocument: document, 414 "childNodes.length": 0, 415 textContent: "", 416 }, 417 foreignDocfrag: { 418 // Node 419 nodeType: Node.DOCUMENT_FRAGMENT_NODE, 420 ownerDocument: foreignDoc, 421 "childNodes.length": 0, 422 textContent: "", 423 }, 424 xmlDocfrag: { 425 // Node 426 nodeType: Node.DOCUMENT_FRAGMENT_NODE, 427 ownerDocument: xmlDoc, 428 "childNodes.length": 0, 429 textContent: "", 430 }, 431 doctype: { 432 // Node 433 nodeType: Node.DOCUMENT_TYPE_NODE, 434 ownerDocument: document, 435 parentNode: document, 436 previousSibling: null, 437 nextSibling: document.documentElement, 438 439 // DocumentType 440 name: "html", 441 publicId: "", 442 systemId: "", 443 }, 444 foreignDoctype: { 445 // Node 446 nodeType: Node.DOCUMENT_TYPE_NODE, 447 ownerDocument: foreignDoc, 448 parentNode: foreignDoc, 449 previousSibling: null, 450 nextSibling: foreignDoc.documentElement, 451 452 // DocumentType 453 name: "html", 454 publicId: "", 455 systemId: "", 456 }, 457 xmlDoctype: { 458 // Node 459 nodeType: Node.DOCUMENT_TYPE_NODE, 460 ownerDocument: xmlDoc, 461 parentNode: xmlDoc, 462 previousSibling: null, 463 nextSibling: xmlElement, 464 465 // DocumentType 466 name: "qorflesnorf", 467 publicId: "abcde", 468 systemId: "x\"'y", 469 }, 470 "paras[0]": { 471 // Node 472 nodeType: Node.ELEMENT_NODE, 473 ownerDocument: document, 474 parentNode: testDiv, 475 parentElement: testDiv, 476 "childNodes.length": 1, 477 previousSibling: null, 478 nextSibling: paras[1], 479 textContent: "A\u0308b\u0308c\u0308d\u0308e\u0308f\u0308g\u0308h\u0308\n", 480 481 // Element 482 namespaceURI: "http://www.w3.org/1999/xhtml", 483 prefix: null, 484 localName: "p", 485 tagName: "P", 486 id: "a", 487 previousElementSibling: null, 488 nextElementSibling: paras[1], 489 childElementCount: 0, 490 }, 491 "paras[1]": { 492 // Node 493 nodeType: Node.ELEMENT_NODE, 494 ownerDocument: document, 495 parentNode: testDiv, 496 parentElement: testDiv, 497 "childNodes.length": 1, 498 previousSibling: paras[0], 499 nextSibling: paras[2], 500 textContent: "Ijklmnop\n", 501 502 // Element 503 namespaceURI: "http://www.w3.org/1999/xhtml", 504 prefix: null, 505 localName: "p", 506 tagName: "P", 507 id: "b", 508 previousElementSibling: paras[0], 509 nextElementSibling: paras[2], 510 childElementCount: 0, 511 }, 512 "paras[2]": { 513 // Node 514 nodeType: Node.ELEMENT_NODE, 515 ownerDocument: document, 516 parentNode: testDiv, 517 parentElement: testDiv, 518 "childNodes.length": 1, 519 previousSibling: paras[1], 520 nextSibling: paras[3], 521 textContent: "Qrstuvwx", 522 523 // Element 524 namespaceURI: "http://www.w3.org/1999/xhtml", 525 prefix: null, 526 localName: "p", 527 tagName: "P", 528 id: "c", 529 previousElementSibling: paras[1], 530 nextElementSibling: paras[3], 531 childElementCount: 0, 532 }, 533 "paras[3]": { 534 // Node 535 nodeType: Node.ELEMENT_NODE, 536 ownerDocument: document, 537 parentNode: testDiv, 538 parentElement: testDiv, 539 "childNodes.length": 1, 540 previousSibling: paras[2], 541 nextSibling: paras[4], 542 textContent: "Yzabcdef", 543 544 // Element 545 namespaceURI: "http://www.w3.org/1999/xhtml", 546 prefix: null, 547 localName: "p", 548 tagName: "P", 549 id: "d", 550 previousElementSibling: paras[2], 551 nextElementSibling: paras[4], 552 childElementCount: 0, 553 }, 554 "paras[4]": { 555 // Node 556 nodeType: Node.ELEMENT_NODE, 557 ownerDocument: document, 558 parentNode: testDiv, 559 parentElement: testDiv, 560 "childNodes.length": 1, 561 previousSibling: paras[3], 562 nextSibling: paras[5], 563 textContent: "Ghijklmn", 564 565 // Element 566 namespaceURI: "http://www.w3.org/1999/xhtml", 567 prefix: null, 568 localName: "p", 569 tagName: "P", 570 id: "e", 571 previousElementSibling: paras[3], 572 nextElementSibling: paras[5], 573 childElementCount: 0, 574 }, 575 "paras[5]": { 576 // Node 577 nodeType: Node.ELEMENT_NODE, 578 ownerDocument: document, 579 parentNode: testDiv, 580 parentElement: testDiv, 581 "childNodes.length": 3, 582 previousSibling: paras[4], 583 nextSibling: comment, 584 textContent: "123456789012", 585 586 // Element 587 namespaceURI: "http://www.w3.org/1999/xhtml", 588 prefix: null, 589 localName: "p", 590 tagName: "P", 591 previousElementSibling: paras[4], 592 nextElementSibling: null, 593 childElementCount: 0, 594 } 595 }; 596 597 for (var node in expected) { 598 // Now we set various default values by node type. 599 switch (expected[node].nodeType) { 600 case Node.ELEMENT_NODE: 601 expected[node].nodeName = expected[node].tagName; 602 expected[node].nodeValue = null; 603 expected[node]["children.length"] = expected[node].childElementCount; 604 605 if (expected[node].id === undefined) { 606 expected[node].id = ""; 607 } 608 if (expected[node].className === undefined) { 609 expected[node].className = ""; 610 } 611 612 var len = expected[node].childElementCount; 613 if (len === 0) { 614 expected[node].firstElementChild = 615 expected[node].lastElementChild = null; 616 } else { 617 // If we have expectations for the first/last child in children, 618 // use those. Otherwise, at least check that .firstElementChild == 619 // .children[0] and .lastElementChild == .children[len - 1], even 620 // if we aren't sure what they should be. 621 expected[node].firstElementChild = expected[node]["children[0]"] 622 ? expected[node]["children[0]"] 623 : eval(node).children[0]; 624 expected[node].lastElementChild = 625 expected[node]["children[" + (len - 1) + "]"] 626 ? expected[node]["children[" + (len - 1) + "]"] 627 : eval(node).children[len - 1]; 628 } 629 break; 630 631 case Node.TEXT_NODE: 632 expected[node].nodeName = "#text"; 633 expected[node]["childNodes.length"] = 0; 634 expected[node].textContent = expected[node].data = 635 expected[node].nodeValue; 636 expected[node].length = expected[node].nodeValue.length; 637 break; 638 639 case Node.PROCESSING_INSTRUCTION_NODE: 640 expected[node].nodeName = expected[node].target; 641 expected[node]["childNodes.length"] = 0; 642 expected[node].textContent = expected[node].data = 643 expected[node].nodeValue; 644 expected[node].length = expected[node].nodeValue.length; 645 break; 646 647 case Node.COMMENT_NODE: 648 expected[node].nodeName = "#comment"; 649 expected[node]["childNodes.length"] = 0; 650 expected[node].textContent = expected[node].data = 651 expected[node].nodeValue; 652 expected[node].length = expected[node].nodeValue.length; 653 break; 654 655 case Node.DOCUMENT_NODE: 656 expected[node].nodeName = "#document"; 657 expected[node].ownerDocument = expected[node].parentNode = 658 expected[node].parentElement = expected[node].previousSibling = 659 expected[node].nextSibling = expected[node].nodeValue = 660 expected[node].textContent = null; 661 expected[node].documentURI = expected[node].URL; 662 expected[node].charset = expected[node].inputEncoding = 663 expected[node].characterSet; 664 break; 665 666 case Node.DOCUMENT_TYPE_NODE: 667 expected[node].nodeName = expected[node].name; 668 expected[node]["childNodes.length"] = 0; 669 expected[node].parentElement = expected[node].nodeValue = 670 expected[node].textContent = null; 671 break; 672 673 case Node.DOCUMENT_FRAGMENT_NODE: 674 expected[node].nodeName = "#document-fragment"; 675 expected[node].parentNode = expected[node].parentElement = 676 expected[node].previousSibling = expected[node].nextSibling = 677 expected[node].nodeValue = null; 678 break; 679 } 680 681 // Now we set some further default values that are independent of node 682 // type. 683 var len = expected[node]["childNodes.length"]; 684 if (len === 0) { 685 expected[node].firstChild = expected[node].lastChild = null; 686 } else { 687 // If we have expectations for the first/last child in childNodes, use 688 // those. Otherwise, at least check that .firstChild == .childNodes[0] 689 // and .lastChild == .childNodes[len - 1], even if we aren't sure what 690 // they should be. 691 expected[node].firstChild = expected[node]["childNodes[0]"] 692 ? expected[node]["childNodes[0]"] 693 : eval(node).childNodes[0]; 694 expected[node].lastChild = 695 expected[node]["childNodes[" + (len - 1) + "]"] 696 ? expected[node]["childNodes[" + (len - 1) + "]"] 697 : eval(node).childNodes[len - 1]; 698 } 699 expected[node]["hasChildNodes()"] = !!expected[node]["childNodes.length"]; 700 701 // Finally, we test! 702 for (var prop in expected[node]) { 703 test(function() { 704 assert_equals(eval(node + "." + prop), expected[node][prop]); 705 }, node + "." + prop); 706 } 707 } 708 709 testDiv.parentNode.removeChild(testDiv); 710 </script>