test_ariaowns.html (25639B)
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <title>@aria-owns attribute testing</title> 6 7 <link rel="stylesheet" type="text/css" 8 href="chrome://mochikit/content/tests/SimpleTest/test.css" /> 9 10 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> 11 12 <script type="application/javascript" 13 src="../common.js"></script> 14 <script type="application/javascript" 15 src="../role.js"></script> 16 <script type="application/javascript" 17 src="../events.js"></script> 18 19 <script type="application/javascript"> 20 21 // ////////////////////////////////////////////////////////////////////////// 22 // Invokers 23 // ////////////////////////////////////////////////////////////////////////// 24 25 function changeARIAOwns() { 26 this.eventSeq = [ 27 new invokerChecker(EVENT_HIDE, getNode("t1_button")), 28 // no hide for t1_subdiv because it is contained by hidden t1_checkbox 29 new invokerChecker(EVENT_HIDE, getNode("t1_checkbox")), 30 new invokerChecker(EVENT_SHOW, getNode("t1_checkbox")), 31 new invokerChecker(EVENT_SHOW, getNode("t1_button")), 32 new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")), 33 new invokerChecker(EVENT_REORDER, getNode("t1_container")), 34 ]; 35 36 this.invoke = function setARIAOwns_invoke() { 37 // children are swapped by ARIA owns 38 var tree = 39 { SECTION: [ 40 { CHECKBUTTON: [ 41 { SECTION: [] }, 42 ] }, 43 { PUSHBUTTON: [ ] }, 44 ] }; 45 testAccessibleTree("t1_container", tree); 46 47 getNode("t1_container"). 48 setAttribute("aria-owns", "t1_button t1_subdiv"); 49 }; 50 51 this.finalCheck = function setARIAOwns_finalCheck() { 52 // children are swapped again, button and subdiv are appended to 53 // the children. 54 var tree = 55 { SECTION: [ 56 { CHECKBUTTON: [ ] }, // checkbox, native order 57 { PUSHBUTTON: [ ] }, // button, rearranged by ARIA own 58 { SECTION: [ ] }, // subdiv from the subtree, ARIA owned 59 ] }; 60 testAccessibleTree("t1_container", tree); 61 }; 62 63 this.getID = function setARIAOwns_getID() { 64 return "Change @aria-owns attribute"; 65 }; 66 } 67 68 function removeARIAOwns() { 69 this.eventSeq = [ 70 new invokerChecker(EVENT_HIDE, getNode("t1_button")), 71 new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")), 72 new orderChecker(), 73 new asyncInvokerChecker(EVENT_SHOW, getNode("t1_button")), 74 new asyncInvokerChecker(EVENT_SHOW, getNode("t1_subdiv")), 75 new orderChecker(), 76 new invokerChecker(EVENT_REORDER, getNode("t1_container")), 77 new unexpectedInvokerChecker(EVENT_REORDER, getNode("t1_checkbox")), 78 ]; 79 80 this.invoke = function removeARIAOwns_invoke() { 81 getNode("t1_container").removeAttribute("aria-owns"); 82 }; 83 84 this.finalCheck = function removeARIAOwns_finalCheck() { 85 // children follow the DOM order 86 var tree = 87 { SECTION: [ 88 { PUSHBUTTON: [ ] }, 89 { CHECKBUTTON: [ 90 { SECTION: [] }, 91 ] }, 92 ] }; 93 testAccessibleTree("t1_container", tree); 94 }; 95 96 this.getID = function removeARIAOwns_getID() { 97 return "Remove @aria-owns attribute"; 98 }; 99 } 100 101 function setARIAOwns() { 102 this.eventSeq = [ 103 new invokerChecker(EVENT_HIDE, getNode("t1_button")), 104 new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")), 105 new invokerChecker(EVENT_SHOW, getNode("t1_button")), 106 new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")), 107 new invokerChecker(EVENT_REORDER, getNode("t1_container")), 108 ]; 109 110 this.invoke = function setARIAOwns_invoke() { 111 getNode("t1_container"). 112 setAttribute("aria-owns", "t1_button t1_subdiv"); 113 }; 114 115 this.finalCheck = function setARIAOwns_finalCheck() { 116 // children are swapped again, button and subdiv are appended to 117 // the children. 118 var tree = 119 { SECTION: [ 120 { CHECKBUTTON: [ ] }, // checkbox 121 { PUSHBUTTON: [ ] }, // button, rearranged by ARIA own 122 { SECTION: [ ] }, // subdiv from the subtree, ARIA owned 123 ] }; 124 testAccessibleTree("t1_container", tree); 125 }; 126 127 this.getID = function setARIAOwns_getID() { 128 return "Set @aria-owns attribute"; 129 }; 130 } 131 132 function addIdToARIAOwns() { 133 this.eventSeq = [ 134 new invokerChecker(EVENT_HIDE, getNode("t1_group")), 135 new invokerChecker(EVENT_SHOW, getNode("t1_group")), 136 new invokerChecker(EVENT_REORDER, document), 137 ]; 138 139 this.invoke = function addIdToARIAOwns_invoke() { 140 getNode("t1_container"). 141 setAttribute("aria-owns", "t1_button t1_subdiv t1_group"); 142 }; 143 144 this.finalCheck = function addIdToARIAOwns_finalCheck() { 145 // children are swapped again, button and subdiv are appended to 146 // the children. 147 var tree = 148 { SECTION: [ 149 { CHECKBUTTON: [ ] }, // t1_checkbox 150 { PUSHBUTTON: [ ] }, // button, t1_button 151 { SECTION: [ ] }, // subdiv from the subtree, t1_subdiv 152 { GROUPING: [ ] }, // group from outside, t1_group 153 ] }; 154 testAccessibleTree("t1_container", tree); 155 }; 156 157 this.getID = function addIdToARIAOwns_getID() { 158 return "Add id to @aria-owns attribute value"; 159 }; 160 } 161 162 function appendEl() { 163 this.eventSeq = [ 164 new invokerChecker(EVENT_SHOW, getNode, "t1_child3"), 165 new invokerChecker(EVENT_REORDER, getNode("t1_container")), 166 ]; 167 168 this.invoke = function appendEl_invoke() { 169 var div = document.createElement("div"); 170 div.setAttribute("id", "t1_child3"); 171 div.setAttribute("role", "radio"); 172 getNode("t1_container").appendChild(div); 173 }; 174 175 this.finalCheck = function appendEl_finalCheck() { 176 // children are invalidated, they includes aria-owns swapped kids and 177 // newly inserted child. 178 var tree = 179 { SECTION: [ 180 { CHECKBUTTON: [ ] }, // existing explicit, t1_checkbox 181 { RADIOBUTTON: [ ] }, // new explicit, t1_child3 182 { PUSHBUTTON: [ ] }, // ARIA owned, t1_button 183 { SECTION: [ ] }, // ARIA owned, t1_subdiv 184 { GROUPING: [ ] }, // ARIA owned, t1_group 185 ] }; 186 testAccessibleTree("t1_container", tree); 187 }; 188 189 this.getID = function appendEl_getID() { 190 return "Append child under @aria-owns element"; 191 }; 192 } 193 194 function removeEl() { 195 this.eventSeq = [ 196 new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")), 197 new invokerChecker(EVENT_REORDER, getNode("t1_container")), 198 ]; 199 200 this.invoke = function removeEl_invoke() { 201 // remove a container of t1_subdiv 202 getNode("t1_span").remove(); 203 }; 204 205 this.finalCheck = function removeEl_finalCheck() { 206 // subdiv should go away 207 var tree = 208 { SECTION: [ 209 { CHECKBUTTON: [ ] }, // explicit, t1_checkbox 210 { RADIOBUTTON: [ ] }, // explicit, t1_child3 211 { PUSHBUTTON: [ ] }, // ARIA owned, t1_button 212 { GROUPING: [ ] }, // ARIA owned, t1_group 213 ] }; 214 testAccessibleTree("t1_container", tree); 215 }; 216 217 this.getID = function removeEl_getID() { 218 return "Remove a container of ARIA owned element"; 219 }; 220 } 221 222 function removeId() { 223 this.eventSeq = [ 224 new invokerChecker(EVENT_HIDE, getNode("t1_group")), 225 new invokerChecker(EVENT_SHOW, getNode("t1_group")), 226 new invokerChecker(EVENT_REORDER, document), 227 ]; 228 229 this.invoke = function removeId_invoke() { 230 getNode("t1_group").removeAttribute("id"); 231 }; 232 233 this.finalCheck = function removeId_finalCheck() { 234 var tree = 235 { SECTION: [ 236 { CHECKBUTTON: [ ] }, 237 { RADIOBUTTON: [ ] }, 238 { PUSHBUTTON: [ ] }, // ARIA owned, t1_button 239 ] }; 240 testAccessibleTree("t1_container", tree); 241 }; 242 243 this.getID = function removeId_getID() { 244 return "Remove ID from ARIA owned element"; 245 }; 246 } 247 248 function setId() { 249 this.eventSeq = [ 250 new invokerChecker(EVENT_HIDE, getNode("t1_grouptmp")), 251 new invokerChecker(EVENT_SHOW, getNode("t1_grouptmp")), 252 new invokerChecker(EVENT_REORDER, document), 253 ]; 254 255 this.invoke = function setId_invoke() { 256 getNode("t1_grouptmp").setAttribute("id", "t1_group"); 257 }; 258 259 this.finalCheck = function setId_finalCheck() { 260 var tree = 261 { SECTION: [ 262 { CHECKBUTTON: [ ] }, 263 { RADIOBUTTON: [ ] }, 264 { PUSHBUTTON: [ ] }, // ARIA owned, t1_button 265 { GROUPING: [ ] }, // ARIA owned, t1_group, previously t1_grouptmp 266 ] }; 267 testAccessibleTree("t1_container", tree); 268 }; 269 270 this.getID = function setId_getID() { 271 return "Set ID that is referred by ARIA owns"; 272 }; 273 } 274 275 /** 276 * Remove an accessible DOM element containing an element referred by 277 * ARIA owns. 278 */ 279 function removeA11eteiner() { 280 this.eventSeq = [ 281 new invokerChecker(EVENT_REORDER, getNode("t2_container1")), 282 ]; 283 284 this.invoke = function removeA11eteiner_invoke() { 285 var tree = 286 { SECTION: [ 287 { CHECKBUTTON: [ ] }, // ARIA owned, 't2_owned' 288 ] }; 289 testAccessibleTree("t2_container1", tree); 290 291 getNode("t2_container2").removeChild(getNode("t2_container3")); 292 }; 293 294 this.finalCheck = function removeA11eteiner_finalCheck() { 295 var tree = 296 { SECTION: [ 297 ] }; 298 testAccessibleTree("t2_container1", tree); 299 }; 300 301 this.getID = function removeA11eteiner_getID() { 302 return "Remove an accessible DOM element containing an element referred by ARIA owns"; 303 }; 304 } 305 306 /** 307 * Attempt to steal an element from other ARIA owns element. This should 308 * not be possible. The only child that will get owned into this 309 * container is a previously not aria-owned one. 310 */ 311 function stealFromOtherARIAOwns() { 312 this.eventSeq = [ 313 new invokerChecker(EVENT_REORDER, getNode("t3_container3")), 314 ]; 315 316 this.invoke = function stealFromOtherARIAOwns_invoke() { 317 getNode("t3_container3").setAttribute("aria-owns", "t3_child t3_child2"); 318 }; 319 320 this.finalCheck = function stealFromOtherARIAOwns_finalCheck() { 321 var tree = 322 { SECTION: [ 323 { CHECKBUTTON: [ 324 ] }, 325 ] }; 326 testAccessibleTree("t3_container1", tree); 327 328 tree = 329 { SECTION: [ 330 ] }; 331 testAccessibleTree("t3_container2", tree); 332 333 tree = 334 { SECTION: [ 335 { CHECKBUTTON: [ 336 ] }, 337 ] }; 338 testAccessibleTree("t3_container3", tree); 339 }; 340 341 this.getID = function stealFromOtherARIAOwns_getID() { 342 return "Steal an element from other ARIA owns element"; 343 }; 344 } 345 346 function appendElToRecacheChildren() { 347 this.eventSeq = [ 348 new invokerChecker(EVENT_REORDER, getNode("t3_container3")), 349 ]; 350 351 this.invoke = function appendElToRecacheChildren_invoke() { 352 var div = document.createElement("div"); 353 div.setAttribute("role", "radio"); 354 getNode("t3_container3").appendChild(div); 355 }; 356 357 this.finalCheck = function appendElToRecacheChildren_finalCheck() { 358 var tree = 359 { SECTION: [ 360 ] }; 361 testAccessibleTree("t3_container2", tree); 362 363 tree = 364 { SECTION: [ 365 { RADIOBUTTON: [ ] }, 366 { CHECKBUTTON: [ ] }, // ARIA owned 367 ] }; 368 testAccessibleTree("t3_container3", tree); 369 }; 370 371 this.getID = function appendElToRecacheChildren_getID() { 372 return "Append a child under @aria-owns element to trigger children recache"; 373 }; 374 } 375 376 function showHiddenElement() { 377 this.eventSeq = [ 378 new invokerChecker(EVENT_REORDER, getNode("t4_container1")), 379 ]; 380 381 this.invoke = function showHiddenElement_invoke() { 382 var tree = 383 { SECTION: [ 384 { RADIOBUTTON: [] }, 385 ] }; 386 testAccessibleTree("t4_container1", tree); 387 388 getNode("t4_child1").style.display = "block"; 389 }; 390 391 this.finalCheck = function showHiddenElement_finalCheck() { 392 var tree = 393 { SECTION: [ 394 { CHECKBUTTON: [] }, 395 { RADIOBUTTON: [] }, 396 ] }; 397 testAccessibleTree("t4_container1", tree); 398 }; 399 400 this.getID = function showHiddenElement_getID() { 401 return "Show hidden ARIA owns referred element"; 402 }; 403 } 404 405 function rearrangeARIAOwns(aContainer, aAttr, aIdList, aRoleList) { 406 this.eventSeq = []; 407 for (let id of aIdList) { 408 this.eventSeq.push(new invokerChecker(EVENT_HIDE, getNode(id))); 409 } 410 411 for (let id of aIdList) { 412 this.eventSeq.push(new invokerChecker(EVENT_SHOW, getNode(id))); 413 } 414 this.eventSeq.push(new invokerChecker(EVENT_REORDER, getNode(aContainer))); 415 416 this.invoke = function rearrangeARIAOwns_invoke() { 417 getNode(aContainer).setAttribute("aria-owns", aAttr); 418 }; 419 420 this.finalCheck = function rearrangeARIAOwns_finalCheck() { 421 var tree = { SECTION: [ ] }; 422 for (var role of aRoleList) { 423 var ch = {}; 424 ch[role] = []; 425 tree.SECTION.push(ch); 426 } 427 testAccessibleTree(aContainer, tree); 428 }; 429 430 this.getID = function rearrangeARIAOwns_getID() { 431 return `Rearrange @aria-owns attribute to '${aAttr}'`; 432 }; 433 } 434 435 function removeNotARIAOwnedEl(aContainer, aChild) { 436 this.eventSeq = [ 437 new invokerChecker(EVENT_REORDER, aContainer), 438 ]; 439 440 this.invoke = function removeNotARIAOwnedEl_invoke() { 441 var tree = { 442 SECTION: [ 443 { TEXT_LEAF: [ ] }, 444 { GROUPING: [ ] }, 445 ], 446 }; 447 testAccessibleTree(aContainer, tree); 448 449 getNode(aContainer).removeChild(getNode(aChild)); 450 }; 451 452 this.finalCheck = function removeNotARIAOwnedEl_finalCheck() { 453 var tree = { 454 SECTION: [ 455 { GROUPING: [ ] }, 456 ], 457 }; 458 testAccessibleTree(aContainer, tree); 459 }; 460 461 this.getID = function removeNotARIAOwnedEl_getID() { 462 return `remove not ARIA owned child`; 463 }; 464 } 465 466 function setARIAOwnsOnElToRemove(aParent, aChild) { 467 this.eventSeq = [ 468 new invokerChecker(EVENT_HIDE, getAccessible(aParent)), 469 ]; 470 471 this.invoke = function setARIAOwnsOnElToRemove_invoke() { 472 getNode(aChild).setAttribute("aria-owns", "no_id"); 473 getNode(aParent).removeChild(getNode(aChild)); 474 getNode(aParent).remove(); 475 }; 476 477 this.getID = function setARIAOwnsOnElToRemove_getID() { 478 return `set ARIA owns on an element, and then remove it, and then remove its parent`; 479 }; 480 } 481 482 /** 483 * Set ARIA owns on inaccessible span element that contains 484 * accessible children. This will move children from the container for 485 * the span. 486 */ 487 function test8() { 488 this.eventSeq = [ 489 new invokerChecker(EVENT_REORDER, "t8_container"), 490 ]; 491 492 this.invoke = function test8_invoke() { 493 var tree = 494 { SECTION: [ 495 { PUSHBUTTON: [] }, 496 { ENTRY: [] }, 497 { ENTRY: [] }, 498 { ENTRY: [] }, 499 ] }; 500 testAccessibleTree("t8_container", tree); 501 502 getNode(t8_container).setAttribute("aria-owns", "t8_span t8_button"); 503 }; 504 505 this.finalCheck = function test8_finalCheck() { 506 var tree = 507 { SECTION: [ 508 { TEXT: [ 509 { ENTRY: [] }, 510 { ENTRY: [] }, 511 { ENTRY: [] }, 512 ] }, 513 { PUSHBUTTON: [] }, 514 ] }; 515 testAccessibleTree("t8_container", tree); 516 }; 517 518 this.getID = function test8_getID() { 519 return `Set ARIA owns on inaccessible span element that contains accessible children`; 520 }; 521 } 522 523 function test9_prepare() { 524 this.eventSeq = [ 525 new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, () => { 526 return getNode("t9_container").contentDocument; 527 }), 528 ]; 529 530 this.invoke = () => { 531 // The \ before the final /script avoids the script from being terminated 532 // by the html parser. 533 getNode("t9_container").src = `data:text/html, 534 <html><body></body> 535 <script> 536 let el = document.createElement('div'); 537 el.id = 'container'; 538 el.innerHTML = "<input id='input'>"; 539 document.documentElement.appendChild(el); 540 <\/script></html>`; 541 }; 542 543 this.finalCheck = () => { 544 var tree = 545 { INTERNAL_FRAME: [ 546 { DOCUMENT: [ 547 { SECTION: [ 548 { ENTRY: [] }, 549 ] }, 550 ] }, 551 ] }; 552 testAccessibleTree("t9_container", tree); 553 }; 554 555 this.getID = () => { 556 return `Set ARIA owns on a document (part1)`; 557 }; 558 } 559 560 function test9_setARIAOwns() { 561 this.eventSeq = [ 562 new invokerChecker(EVENT_SHOW, () => { 563 let doc = getNode("t9_container").contentDocument; 564 return doc && doc.getElementById("input"); 565 }), 566 ]; 567 568 this.invoke = () => { 569 let doc = getNode("t9_container").contentDocument; 570 doc.body.setAttribute("aria-owns", "input"); 571 }; 572 573 this.finalCheck = () => { 574 var tree = 575 { INTERNAL_FRAME: [ 576 { DOCUMENT: [ 577 { SECTION: [] }, 578 { ENTRY: [] }, 579 ] }, 580 ] }; 581 testAccessibleTree("t9_container", tree); 582 }; 583 584 this.getID = () => { 585 return `Set ARIA owns on a document (part2)`; 586 }; 587 } 588 589 function test9_finish() { 590 this.eventSeq = [ 591 new invokerChecker(EVENT_REORDER, () => { 592 return getNode("t9_container").contentDocument; 593 }), 594 ]; 595 596 this.invoke = () => { 597 // trigger a tree update. 598 let doc = getNode("t9_container").contentDocument; 599 doc.body.appendChild(doc.createElement("p")); 600 }; 601 602 this.finalCheck = () => { 603 var tree = 604 { INTERNAL_FRAME: [ 605 { DOCUMENT: [ 606 { PARAGRAPH: [] }, 607 { SECTION: [] }, 608 { ENTRY: [] }, 609 ] }, 610 ] }; 611 testAccessibleTree("t9_container", tree); 612 }; 613 614 this.getID = () => { 615 return `Set ARIA owns on a document (part3)`; 616 }; 617 } 618 619 /** 620 * Put ARIA owned child back when ARIA owner removed. 621 */ 622 function test10_removeARIAOwner() { 623 this.eventSeq = [ 624 new invokerChecker(EVENT_HIDE, getAccessible("t10_owner")), 625 ]; 626 627 this.invoke = () => { 628 let tree = 629 { SECTION: [ // t10_container 630 { SECTION: [ // t10_owner 631 { ENTRY: [] }, // t10_child 632 ] }, 633 ] }; 634 testAccessibleTree("t10_container", tree); 635 636 getNode("t10_owner").remove(); 637 }; 638 639 this.getID = () => { 640 return "Put aria owned child back when aria owner removed"; 641 }; 642 } 643 644 function test10_finishTest() { 645 this.eventSeq = [ 646 new invokerChecker(EVENT_REORDER, "t10_container"), 647 ]; 648 649 this.invoke = () => { 650 // trigger a tree update. 651 getNode("t10_container").append(document.createElement("p")); 652 }; 653 654 this.finalCheck = () => { 655 let tree = 656 { SECTION: [ // t10_container 657 { ENTRY: [] }, // t10_child 658 { PARAGRAPH: [] }, 659 ] }; 660 testAccessibleTree("t10_container", tree); 661 todo(false, "Input accessible has be moved back in the tree"); 662 }; 663 664 this.getID = () => { 665 return `Put aria owned child back when aria owner removed (finish test)`; 666 }; 667 } 668 669 // ////////////////////////////////////////////////////////////////////////// 670 // Test 671 // ////////////////////////////////////////////////////////////////////////// 672 673 // gA11yEventDumpToConsole = true; 674 // enableLogging("tree,eventTree,verbose"); // debug stuff 675 676 var gQueue = null; 677 678 async function doTest() { 679 let PromEvents = {}; 680 Services.scriptloader.loadSubScript( 681 "chrome://mochitests/content/a11y/accessible/tests/mochitest/promisified-events.js", 682 PromEvents); 683 684 gQueue = new eventQueue(); 685 let queueFinished = new Promise(resolve => { 686 gQueue.onFinish = function() { 687 resolve(); 688 return DO_NOT_FINISH_TEST; 689 }; 690 }); 691 692 // test1 693 gQueue.push(new changeARIAOwns()); 694 gQueue.push(new removeARIAOwns()); 695 gQueue.push(new setARIAOwns()); 696 gQueue.push(new addIdToARIAOwns()); 697 gQueue.push(new appendEl()); 698 gQueue.push(new removeEl()); 699 gQueue.push(new removeId()); 700 gQueue.push(new setId()); 701 702 // test2 703 gQueue.push(new removeA11eteiner()); 704 705 // test3 706 gQueue.push(new stealFromOtherARIAOwns()); 707 gQueue.push(new appendElToRecacheChildren()); 708 709 // test4 710 gQueue.push(new showHiddenElement()); 711 712 // test5 713 gQueue.push(new rearrangeARIAOwns( 714 "t5_container", "t5_checkbox t5_radio t5_button", 715 [ "t5_checkbox", "t5_radio", "t5_button" ], 716 [ "CHECKBUTTON", "RADIOBUTTON", "PUSHBUTTON" ])); 717 gQueue.push(new rearrangeARIAOwns( 718 "t5_container", "t5_radio t5_button t5_checkbox", 719 [ "t5_radio", "t5_button" ], 720 [ "RADIOBUTTON", "PUSHBUTTON", "CHECKBUTTON" ])); 721 722 gQueue.push(new removeNotARIAOwnedEl("t6_container", "t6_span")); 723 724 gQueue.push(new setARIAOwnsOnElToRemove("t7_parent", "t7_child")); 725 726 gQueue.push(new test8()); 727 gQueue.push(new test9_prepare()); 728 gQueue.push(new test9_setARIAOwns()); 729 gQueue.push(new test9_finish()); 730 731 gQueue.push(new test10_removeARIAOwner()); 732 gQueue.push(new test10_finishTest()); 733 734 gQueue.invoke(); 735 await queueFinished; 736 737 let owned = document.createElement('div'); 738 owned.id = 't11_child'; 739 owned.textContent = 'owned'; 740 let evtPromise = PromEvents.waitForEvent(EVENT_SHOW, "t11_child"); 741 getNode("t11_container").append(owned); 742 let evt = await evtPromise; 743 is(evt.accessible.parent.name, "t11_owner"); 744 745 // Test owning an ancestor which isn't created yet. 746 testAccessibleTree("t12_container", { SECTION: [ // t12_container 747 { SECTION: [ // t12b 748 { SECTION: [] }, // t12c 749 ] }, 750 { SECTION: [] }, // t12d 751 ] }); 752 // Owning t12a would create a cycle, so we expect it to do nothing. 753 // We own t12d so we get an event when aria-owns relocation is complete. 754 evtPromise = PromEvents.waitForEvent(EVENT_SHOW, "t12d"); 755 getNode("t12c").setAttribute("aria-owns", "t12a t12d"); 756 await evtPromise; 757 testAccessibleTree("t12_container", { SECTION: [ // t12_container 758 { SECTION: [ // t12b 759 { SECTION: [ // t12c 760 { SECTION: [] }, // t12d 761 ] }, 762 ] }, 763 ] }); 764 765 SimpleTest.finish(); 766 } 767 768 SimpleTest.waitForExplicitFinish(); 769 addA11yLoadEvent(doTest); 770 771 </script> 772 </head> 773 774 <body> 775 776 <p id="display"></p> 777 <div id="content" style="display: none"></div> 778 <pre id="test"> 779 </pre> 780 781 <div id="t1_container" aria-owns="t1_checkbox t1_button"> 782 <div role="button" id="t1_button"></div> 783 <div role="checkbox" id="t1_checkbox"> 784 <span id="t1_span"> 785 <div id="t1_subdiv"></div> 786 </span> 787 </div> 788 </div> 789 <div id="t1_group" role="group"></div> 790 <div id="t1_grouptmp" role="group"></div> 791 792 <div id="t2_container1" aria-owns="t2_owned"></div> 793 <div id="t2_container2"> 794 <div id="t2_container3"><div id="t2_owned" role="checkbox"></div></div> 795 </div> 796 797 <div id="t3_container1" aria-owns="t3_child"></div> 798 <div id="t3_child" role="checkbox"></div> 799 <div id="t3_container2"> 800 <div id="t3_child2" role="checkbox"></div> 801 </div> 802 <div id="t3_container3"></div> 803 804 <div id="t4_container1" aria-owns="t4_child1 t4_child2"></div> 805 <div id="t4_container2"> 806 <div id="t4_child1" style="display:none" role="checkbox"></div> 807 <div id="t4_child2" role="radio"></div> 808 </div> 809 810 <div id="t5_container"> 811 <div role="button" id="t5_button"></div> 812 <div role="checkbox" id="t5_checkbox"></div> 813 <div role="radio" id="t5_radio"></div> 814 </div> 815 816 <div id="t6_container" aria-owns="t6_fake"> 817 <span id="t6_span">hey</span> 818 </div> 819 <div id="t6_fake" role="group"></div> 820 821 <div id="t7_container"> 822 <div id="t7_parent"> 823 <div id="t7_child"></div> 824 </div> 825 </div> 826 827 <div id="t8_container"> 828 <input id="t8_button" type="button"><span id="t8_span"><input><input><input></span> 829 </div> 830 831 <iframe id="t9_container"></iframe> 832 833 <div id="t10_container"> 834 <div id="t10_owner" aria-owns="t10_child"></div> 835 <input id="t10_child"> 836 </div> 837 838 <div id="t11_container" aria-label="t11_container"> 839 <div aria-owns="t11_child" aria-label="t11_owner"></div> 840 </div> 841 842 <div id="t12_container"> 843 <span id="t12a"> 844 <div id="t12b" aria-owns="t12c"></div> 845 </span> 846 <div id="t12c"></div> 847 <div id="t12d"></div> 848 </div> 849 </body> 850 851 </html>