browser_rotor.js (47443B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 /* import-globals-from ../../mochitest/states.js */ 8 loadScripts({ name: "states.js", dir: MOCHITESTS_DIR }); 9 10 ChromeUtils.defineESModuleGetters(this, { 11 PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", 12 }); 13 14 /** 15 * Test rotor with heading 16 */ 17 addAccessibleTask( 18 `<h1 id="hello">hello</h1><br><h2 id="world">world</h2><br>goodbye`, 19 async (browser, accDoc) => { 20 const searchPred = { 21 AXSearchKey: "AXHeadingSearchKey", 22 AXImmediateDescendantsOnly: 1, 23 AXResultsLimit: -1, 24 AXDirection: "AXDirectionNext", 25 }; 26 27 const webArea = accDoc.nativeInterface.QueryInterface( 28 Ci.nsIAccessibleMacInterface 29 ); 30 is( 31 webArea.getAttributeValue("AXRole"), 32 "AXWebArea", 33 "Got web area accessible" 34 ); 35 36 const headingCount = webArea.getParameterizedAttributeValue( 37 "AXUIElementCountForSearchPredicate", 38 NSDictionary(searchPred) 39 ); 40 is(2, headingCount, "Found two headings"); 41 42 const headings = webArea.getParameterizedAttributeValue( 43 "AXUIElementsForSearchPredicate", 44 NSDictionary(searchPred) 45 ); 46 const hello = getNativeInterface(accDoc, "hello"); 47 const world = getNativeInterface(accDoc, "world"); 48 is( 49 hello.getAttributeValue("AXTitle"), 50 headings[0].getAttributeValue("AXTitle"), 51 "Found correct first heading" 52 ); 53 is( 54 world.getAttributeValue("AXTitle"), 55 headings[1].getAttributeValue("AXTitle"), 56 "Found correct second heading" 57 ); 58 } 59 ); 60 61 /** 62 * Test rotor with heading and empty search text 63 */ 64 addAccessibleTask( 65 `<h1 id="hello">hello</h1><br><h2 id="world">world</h2><br>goodbye`, 66 async (browser, accDoc) => { 67 const searchPred = { 68 AXSearchKey: "AXHeadingSearchKey", 69 AXImmediateDescendantsOnly: 1, 70 AXResultsLimit: -1, 71 AXDirection: "AXDirectionNext", 72 AXSearchText: "", 73 }; 74 75 const webArea = accDoc.nativeInterface.QueryInterface( 76 Ci.nsIAccessibleMacInterface 77 ); 78 is( 79 webArea.getAttributeValue("AXRole"), 80 "AXWebArea", 81 "Got web area accessible" 82 ); 83 84 const headingCount = webArea.getParameterizedAttributeValue( 85 "AXUIElementCountForSearchPredicate", 86 NSDictionary(searchPred) 87 ); 88 is(headingCount, 2, "Found two headings"); 89 90 const headings = webArea.getParameterizedAttributeValue( 91 "AXUIElementsForSearchPredicate", 92 NSDictionary(searchPred) 93 ); 94 const hello = getNativeInterface(accDoc, "hello"); 95 const world = getNativeInterface(accDoc, "world"); 96 is( 97 headings[0].getAttributeValue("AXTitle"), 98 hello.getAttributeValue("AXTitle"), 99 "Found correct first heading" 100 ); 101 is( 102 headings[1].getAttributeValue("AXTitle"), 103 world.getAttributeValue("AXTitle"), 104 "Found correct second heading" 105 ); 106 } 107 ); 108 109 /** 110 * Test rotor with articles 111 */ 112 addAccessibleTask( 113 `<article id="google"> 114 <h2>Google Chrome</h2> 115 <p>Google Chrome is a web browser developed by Google, released in 2008. Chrome is the world's most popular web browser today!</p> 116 </article> 117 118 <article id="moz"> 119 <h2>Mozilla Firefox</h2> 120 <p>Mozilla Firefox is an open-source web browser developed by Mozilla. Firefox has been the second most popular web browser since January, 2018.</p> 121 </article> 122 123 <article id="microsoft"> 124 <h2>Microsoft Edge</h2> 125 <p>Microsoft Edge is a web browser developed by Microsoft, released in 2015. Microsoft Edge replaced Internet Explorer.</p> 126 </article> `, 127 async (browser, accDoc) => { 128 const searchPred = { 129 AXSearchKey: "AXArticleSearchKey", 130 AXImmediateDescendantsOnly: 1, 131 AXResultsLimit: -1, 132 AXDirection: "AXDirectionNext", 133 }; 134 135 const webArea = accDoc.nativeInterface.QueryInterface( 136 Ci.nsIAccessibleMacInterface 137 ); 138 is( 139 webArea.getAttributeValue("AXRole"), 140 "AXWebArea", 141 "Got web area accessible" 142 ); 143 144 const articleCount = webArea.getParameterizedAttributeValue( 145 "AXUIElementCountForSearchPredicate", 146 NSDictionary(searchPred) 147 ); 148 is(3, articleCount, "Found three articles"); 149 150 const articles = webArea.getParameterizedAttributeValue( 151 "AXUIElementsForSearchPredicate", 152 NSDictionary(searchPred) 153 ); 154 const google = getNativeInterface(accDoc, "google"); 155 const moz = getNativeInterface(accDoc, "moz"); 156 const microsoft = getNativeInterface(accDoc, "microsoft"); 157 158 is( 159 google.getAttributeValue("AXTitle"), 160 articles[0].getAttributeValue("AXTitle"), 161 "Found correct first article" 162 ); 163 is( 164 moz.getAttributeValue("AXTitle"), 165 articles[1].getAttributeValue("AXTitle"), 166 "Found correct second article" 167 ); 168 is( 169 microsoft.getAttributeValue("AXTitle"), 170 articles[2].getAttributeValue("AXTitle"), 171 "Found correct third article" 172 ); 173 } 174 ); 175 176 /** 177 * Test rotor with tables 178 */ 179 addAccessibleTask( 180 ` 181 <table id="shapes"> 182 <tr> 183 <th>Shape</th> 184 <th>Color</th> 185 <th>Do I like it?</th> 186 </tr> 187 <tr> 188 <td>Triangle</td> 189 <td>Green</td> 190 <td>No</td> 191 </tr> 192 <tr> 193 <td>Square</td> 194 <td>Red</td> 195 <td>Yes</td> 196 </tr> 197 </table> 198 <br> 199 <table id="food"> 200 <tr> 201 <th>Grocery Item</th> 202 <th>Quantity</th> 203 </tr> 204 <tr> 205 <td>Onions</td> 206 <td>2</td> 207 </tr> 208 <tr> 209 <td>Yogurt</td> 210 <td>1</td> 211 </tr> 212 <tr> 213 <td>Spinach</td> 214 <td>1</td> 215 </tr> 216 <tr> 217 <td>Cherries</td> 218 <td>12</td> 219 </tr> 220 <tr> 221 <td>Carrots</td> 222 <td>5</td> 223 </tr> 224 </table> 225 <br> 226 <div role="table" id="ariaTable"> 227 <div role="row"> 228 <div role="cell"> 229 I am a tiny aria table 230 </div> 231 </div> 232 </div> 233 <br> 234 <table role="grid" id="grid"> 235 <tr> 236 <th>A</th> 237 <th>B</th> 238 <th>C</th> 239 <th>D</th> 240 <th>E</th> 241 </tr> 242 <tr> 243 <th>F</th> 244 <th>G</th> 245 <th>H</th> 246 <th>I</th> 247 <th>J</th> 248 </tr> 249 </table> 250 `, 251 async (browser, accDoc) => { 252 const searchPred = { 253 AXSearchKey: "AXTableSearchKey", 254 AXImmediateDescendantsOnly: 1, 255 AXResultsLimit: -1, 256 AXDirection: "AXDirectionNext", 257 }; 258 259 const webArea = accDoc.nativeInterface.QueryInterface( 260 Ci.nsIAccessibleMacInterface 261 ); 262 is( 263 webArea.getAttributeValue("AXRole"), 264 "AXWebArea", 265 "Got web area accessible" 266 ); 267 268 const tableCount = webArea.getParameterizedAttributeValue( 269 "AXUIElementCountForSearchPredicate", 270 NSDictionary(searchPred) 271 ); 272 is(tableCount, 3, "Found three tables"); 273 274 const tables = webArea.getParameterizedAttributeValue( 275 "AXUIElementsForSearchPredicate", 276 NSDictionary(searchPred) 277 ); 278 const shapes = getNativeInterface(accDoc, "shapes"); 279 const food = getNativeInterface(accDoc, "food"); 280 const ariaTable = getNativeInterface(accDoc, "ariaTable"); 281 282 is( 283 shapes.getAttributeValue("AXColumnCount"), 284 tables[0].getAttributeValue("AXColumnCount"), 285 "Found correct first table" 286 ); 287 is( 288 food.getAttributeValue("AXColumnCount"), 289 tables[1].getAttributeValue("AXColumnCount"), 290 "Found correct second table" 291 ); 292 is( 293 ariaTable.getAttributeValue("AXColumnCount"), 294 tables[2].getAttributeValue("AXColumnCount"), 295 "Found correct third table" 296 ); 297 } 298 ); 299 300 /** 301 * Test rotor with landmarks 302 */ 303 addAccessibleTask( 304 ` 305 <header id="header"> 306 <h1>This is a heading within a header</h1> 307 </header> 308 309 <nav id="nav"> 310 <a href="example.com">I am a link in a nav</a> 311 </nav> 312 313 <main id="main"> 314 I am some text in a main element 315 </main> 316 317 <footer id="footer"> 318 <h2>Heading in footer</h2> 319 </footer> 320 `, 321 async (browser, accDoc) => { 322 const searchPred = { 323 AXSearchKey: "AXLandmarkSearchKey", 324 AXImmediateDescendantsOnly: 1, 325 AXResultsLimit: -1, 326 AXDirection: "AXDirectionNext", 327 }; 328 329 const webArea = accDoc.nativeInterface.QueryInterface( 330 Ci.nsIAccessibleMacInterface 331 ); 332 is( 333 webArea.getAttributeValue("AXRole"), 334 "AXWebArea", 335 "Got web area accessible" 336 ); 337 338 const landmarkCount = webArea.getParameterizedAttributeValue( 339 "AXUIElementCountForSearchPredicate", 340 NSDictionary(searchPred) 341 ); 342 is(4, landmarkCount, "Found four landmarks"); 343 344 const landmarks = webArea.getParameterizedAttributeValue( 345 "AXUIElementsForSearchPredicate", 346 NSDictionary(searchPred) 347 ); 348 const header = getNativeInterface(accDoc, "header"); 349 const nav = getNativeInterface(accDoc, "nav"); 350 const main = getNativeInterface(accDoc, "main"); 351 const footer = getNativeInterface(accDoc, "footer"); 352 353 is( 354 header.getAttributeValue("AXSubrole"), 355 landmarks[0].getAttributeValue("AXSubrole"), 356 "Found correct first landmark" 357 ); 358 is( 359 nav.getAttributeValue("AXSubrole"), 360 landmarks[1].getAttributeValue("AXSubrole"), 361 "Found correct second landmark" 362 ); 363 is( 364 main.getAttributeValue("AXSubrole"), 365 landmarks[2].getAttributeValue("AXSubrole"), 366 "Found correct third landmark" 367 ); 368 is( 369 footer.getAttributeValue("AXSubrole"), 370 landmarks[3].getAttributeValue("AXSubrole"), 371 "Found correct fourth landmark" 372 ); 373 } 374 ); 375 376 /** 377 * Test rotor with aria landmarks 378 */ 379 addAccessibleTask( 380 ` 381 <div id="banner" role="banner"> 382 <h1>This is a heading within a banner</h1> 383 </div> 384 385 <div id="nav" role="navigation"> 386 <a href="example.com">I am a link in a nav</a> 387 </div> 388 389 <div id="main" role="main"> 390 I am some text in a main element 391 </div> 392 393 <div id="contentinfo" role="contentinfo"> 394 <h2>Heading in contentinfo</h2> 395 </div> 396 `, 397 async (browser, accDoc) => { 398 const searchPred = { 399 AXSearchKey: "AXLandmarkSearchKey", 400 AXImmediateDescendantsOnly: 1, 401 AXResultsLimit: -1, 402 AXDirection: "AXDirectionNext", 403 }; 404 405 const webArea = accDoc.nativeInterface.QueryInterface( 406 Ci.nsIAccessibleMacInterface 407 ); 408 is( 409 webArea.getAttributeValue("AXRole"), 410 "AXWebArea", 411 "Got web area accessible" 412 ); 413 414 const landmarkCount = webArea.getParameterizedAttributeValue( 415 "AXUIElementCountForSearchPredicate", 416 NSDictionary(searchPred) 417 ); 418 is(4, landmarkCount, "Found four landmarks"); 419 420 const landmarks = webArea.getParameterizedAttributeValue( 421 "AXUIElementsForSearchPredicate", 422 NSDictionary(searchPred) 423 ); 424 const banner = getNativeInterface(accDoc, "banner"); 425 const nav = getNativeInterface(accDoc, "nav"); 426 const main = getNativeInterface(accDoc, "main"); 427 const contentinfo = getNativeInterface(accDoc, "contentinfo"); 428 429 is( 430 banner.getAttributeValue("AXSubrole"), 431 landmarks[0].getAttributeValue("AXSubrole"), 432 "Found correct first landmark" 433 ); 434 is( 435 nav.getAttributeValue("AXSubrole"), 436 landmarks[1].getAttributeValue("AXSubrole"), 437 "Found correct second landmark" 438 ); 439 is( 440 main.getAttributeValue("AXSubrole"), 441 landmarks[2].getAttributeValue("AXSubrole"), 442 "Found correct third landmark" 443 ); 444 is( 445 contentinfo.getAttributeValue("AXSubrole"), 446 landmarks[3].getAttributeValue("AXSubrole"), 447 "Found correct fourth landmark" 448 ); 449 } 450 ); 451 452 /** 453 * Test rotor with buttons 454 */ 455 addAccessibleTask( 456 ` 457 <button id="button">hello world</button><br> 458 459 <input type="button" value="another kinda button" id="input"><br> 460 `, 461 async (browser, accDoc) => { 462 const searchPred = { 463 AXSearchKey: "AXButtonSearchKey", 464 AXImmediateDescendantsOnly: 1, 465 AXResultsLimit: -1, 466 AXDirection: "AXDirectionNext", 467 }; 468 469 const webArea = accDoc.nativeInterface.QueryInterface( 470 Ci.nsIAccessibleMacInterface 471 ); 472 is( 473 webArea.getAttributeValue("AXRole"), 474 "AXWebArea", 475 "Got web area accessible" 476 ); 477 478 const buttonCount = webArea.getParameterizedAttributeValue( 479 "AXUIElementCountForSearchPredicate", 480 NSDictionary(searchPred) 481 ); 482 is(2, buttonCount, "Found two buttons"); 483 484 const buttons = webArea.getParameterizedAttributeValue( 485 "AXUIElementsForSearchPredicate", 486 NSDictionary(searchPred) 487 ); 488 const button = getNativeInterface(accDoc, "button"); 489 const input = getNativeInterface(accDoc, "input"); 490 491 is( 492 button.getAttributeValue("AXRole"), 493 buttons[0].getAttributeValue("AXRole"), 494 "Found correct button" 495 ); 496 is( 497 input.getAttributeValue("AXRole"), 498 buttons[1].getAttributeValue("AXRole"), 499 "Found correct input button" 500 ); 501 } 502 ); 503 504 /** 505 * Test rotor with heading 506 */ 507 addAccessibleTask( 508 `<h1 id="hello">hello</h1><br><h2 id="world">world</h2><br>goodbye`, 509 async (browser, accDoc) => { 510 const searchPred = { 511 AXSearchKey: "AXHeadingSearchKey", 512 AXImmediateDescendants: 1, 513 AXResultsLimit: -1, 514 AXDirection: "AXDirectionNext", 515 }; 516 517 const webArea = accDoc.nativeInterface.QueryInterface( 518 Ci.nsIAccessibleMacInterface 519 ); 520 is( 521 webArea.getAttributeValue("AXRole"), 522 "AXWebArea", 523 "Got web area accessible" 524 ); 525 526 const headingCount = webArea.getParameterizedAttributeValue( 527 "AXUIElementCountForSearchPredicate", 528 NSDictionary(searchPred) 529 ); 530 is(2, headingCount, "Found two headings"); 531 532 const headings = webArea.getParameterizedAttributeValue( 533 "AXUIElementsForSearchPredicate", 534 NSDictionary(searchPred) 535 ); 536 const hello = getNativeInterface(accDoc, "hello"); 537 const world = getNativeInterface(accDoc, "world"); 538 is( 539 hello.getAttributeValue("AXTitle"), 540 headings[0].getAttributeValue("AXTitle"), 541 "Found correct first heading" 542 ); 543 is( 544 world.getAttributeValue("AXTitle"), 545 headings[1].getAttributeValue("AXTitle"), 546 "Found correct second heading" 547 ); 548 } 549 ); 550 551 /** 552 * Test rotor with buttons 553 */ 554 addAccessibleTask( 555 ` 556 <form> 557 <h2>input[type=button]</h2> 558 <input type="button" value="apply" id="button1"> 559 560 <h2>input[type=submit]</h2> 561 <input type="submit" value="submit now" id="submit"> 562 563 <h2>input[type=image]</h2> 564 <input type="image" src="sample.jpg" alt="submit image" id="image"> 565 566 <h2>input[type=reset]</h2> 567 <input type="reset" value="reset now" id="reset"> 568 569 <h2>button element</h2> 570 <button id="button2">Submit button</button> 571 </form> 572 `, 573 async (browser, accDoc) => { 574 const searchPred = { 575 AXSearchKey: "AXControlSearchKey", 576 AXImmediateDescendants: 1, 577 AXResultsLimit: -1, 578 AXDirection: "AXDirectionNext", 579 }; 580 581 const webArea = accDoc.nativeInterface.QueryInterface( 582 Ci.nsIAccessibleMacInterface 583 ); 584 is( 585 webArea.getAttributeValue("AXRole"), 586 "AXWebArea", 587 "Got web area accessible" 588 ); 589 590 const controlsCount = webArea.getParameterizedAttributeValue( 591 "AXUIElementCountForSearchPredicate", 592 NSDictionary(searchPred) 593 ); 594 is(5, controlsCount, "Found 5 controls"); 595 596 const controls = webArea.getParameterizedAttributeValue( 597 "AXUIElementsForSearchPredicate", 598 NSDictionary(searchPred) 599 ); 600 const button1 = getNativeInterface(accDoc, "button1"); 601 const submit = getNativeInterface(accDoc, "submit"); 602 const image = getNativeInterface(accDoc, "image"); 603 const reset = getNativeInterface(accDoc, "reset"); 604 const button2 = getNativeInterface(accDoc, "button2"); 605 606 is( 607 button1.getAttributeValue("AXTitle"), 608 controls[0].getAttributeValue("AXTitle"), 609 "Found correct first control" 610 ); 611 is( 612 submit.getAttributeValue("AXTitle"), 613 controls[1].getAttributeValue("AXTitle"), 614 "Found correct second control" 615 ); 616 is( 617 image.getAttributeValue("AXTitle"), 618 controls[2].getAttributeValue("AXTitle"), 619 "Found correct third control" 620 ); 621 is( 622 reset.getAttributeValue("AXTitle"), 623 controls[3].getAttributeValue("AXTitle"), 624 "Found correct third control" 625 ); 626 is( 627 button2.getAttributeValue("AXTitle"), 628 controls[4].getAttributeValue("AXTitle"), 629 "Found correct third control" 630 ); 631 } 632 ); 633 634 /** 635 * Test rotor with inputs 636 */ 637 addAccessibleTask( 638 ` 639 <input type="text" value="I'm a text field." id="text"><br> 640 <input type="text" value="me too" id="implText"><br> 641 <textarea id="textarea">this is some text in a text area</textarea><br> 642 <input type="tel" value="0000000000" id="tel"><br> 643 <input type="url" value="https://example.com" id="url"><br> 644 <input type="email" value="hi@example.com" id="email"><br> 645 <input type="password" value="blah" id="password"><br> 646 <input type="month" value="2020-01" id="month"><br> 647 <input type="week" value="2020-W01" id="week"><br> 648 <input type="number" value="12" id="number"><br> 649 <input type="range" value="12" min="0" max="20" id="range"><br> 650 <input type="date" value="2020-01-01" id="date"><br> 651 <input type="time" value="10:10:10" id="time"><br> 652 `, 653 async (browser, accDoc) => { 654 const searchPred = { 655 AXSearchKey: "AXControlSearchKey", 656 AXImmediateDescendants: 1, 657 AXResultsLimit: -1, 658 AXDirection: "AXDirectionNext", 659 }; 660 661 const webArea = accDoc.nativeInterface.QueryInterface( 662 Ci.nsIAccessibleMacInterface 663 ); 664 is( 665 webArea.getAttributeValue("AXRole"), 666 "AXWebArea", 667 "Got web area accessible" 668 ); 669 670 const controlsCount = webArea.getParameterizedAttributeValue( 671 "AXUIElementCountForSearchPredicate", 672 NSDictionary(searchPred) 673 ); 674 675 is(13, controlsCount, "Found 13 controls"); 676 // the extra controls here come from our time control 677 // we can't filter out its internal buttons/incrementors 678 // like we do with the date entry because the time entry 679 // doesn't have its own specific role -- its just a grouping. 680 681 const controls = webArea.getParameterizedAttributeValue( 682 "AXUIElementsForSearchPredicate", 683 NSDictionary(searchPred) 684 ); 685 686 const text = getNativeInterface(accDoc, "text"); 687 const implText = getNativeInterface(accDoc, "implText"); 688 const textarea = getNativeInterface(accDoc, "textarea"); 689 const tel = getNativeInterface(accDoc, "tel"); 690 const url = getNativeInterface(accDoc, "url"); 691 const email = getNativeInterface(accDoc, "email"); 692 const password = getNativeInterface(accDoc, "password"); 693 const month = getNativeInterface(accDoc, "month"); 694 const week = getNativeInterface(accDoc, "week"); 695 const number = getNativeInterface(accDoc, "number"); 696 const range = getNativeInterface(accDoc, "range"); 697 698 const toCheck = [ 699 text, 700 implText, 701 textarea, 702 tel, 703 url, 704 email, 705 password, 706 month, 707 week, 708 number, 709 range, 710 ]; 711 712 for (let i = 0; i < toCheck.length; i++) { 713 is( 714 toCheck[i].getAttributeValue("AXValue"), 715 controls[i].getAttributeValue("AXValue"), 716 "Found correct input control" 717 ); 718 } 719 720 const date = getNativeInterface(accDoc, "date"); 721 const time = getNativeInterface(accDoc, "time"); 722 723 is( 724 date.getAttributeValue("AXRole"), 725 controls[11].getAttributeValue("AXRole"), 726 "Found corrent date editor" 727 ); 728 729 is( 730 time.getAttributeValue("AXRole"), 731 controls[12].getAttributeValue("AXRole"), 732 "Found corrent time editor" 733 ); 734 } 735 ); 736 737 /** 738 * Test rotor with groupings 739 */ 740 addAccessibleTask( 741 ` 742 <fieldset> 743 <legend>Radios</legend> 744 <div role="radiogroup" id="radios"> 745 <input id="radio1" type="radio" name="g1" checked="checked"> Radio 1 746 <input id="radio2" type="radio" name="g1"> Radio 2 747 </div> 748 </fieldset> 749 750 <fieldset id="checkboxes"> 751 <legend>Checkboxes</legend> 752 <input id="checkbox1" type="checkbox" name="g2"> Checkbox 1 753 <input id="checkbox2" type="checkbox" name="g2" checked="checked">Checkbox 2 754 </fieldset> 755 756 <fieldset id="switches"> 757 <legend>Switches</legend> 758 <input id="switch1" name="g3" role="switch" type="checkbox">Switch 1 759 <input checked="checked" id="switch2" name="g3" role="switch" type="checkbox">Switch 2 760 </fieldset> 761 `, 762 async (browser, accDoc) => { 763 const searchPred = { 764 AXSearchKey: "AXControlSearchKey", 765 AXImmediateDescendants: 1, 766 AXResultsLimit: -1, 767 AXDirection: "AXDirectionNext", 768 }; 769 770 const webArea = accDoc.nativeInterface.QueryInterface( 771 Ci.nsIAccessibleMacInterface 772 ); 773 is( 774 webArea.getAttributeValue("AXRole"), 775 "AXWebArea", 776 "Got web area accessible" 777 ); 778 779 const controlsCount = webArea.getParameterizedAttributeValue( 780 "AXUIElementCountForSearchPredicate", 781 NSDictionary(searchPred) 782 ); 783 is(9, controlsCount, "Found 9 controls"); 784 785 const controls = webArea.getParameterizedAttributeValue( 786 "AXUIElementsForSearchPredicate", 787 NSDictionary(searchPred) 788 ); 789 790 const radios = getNativeInterface(accDoc, "radios"); 791 const radio1 = getNativeInterface(accDoc, "radio1"); 792 const radio2 = getNativeInterface(accDoc, "radio2"); 793 794 is( 795 radios.getAttributeValue("AXRole"), 796 controls[0].getAttributeValue("AXRole"), 797 "Found correct group of radios" 798 ); 799 is( 800 radio1.getAttributeValue("AXRole"), 801 controls[1].getAttributeValue("AXRole"), 802 "Found correct radio 1" 803 ); 804 is( 805 radio2.getAttributeValue("AXRole"), 806 controls[2].getAttributeValue("AXRole"), 807 "Found correct radio 2" 808 ); 809 810 const checkboxes = getNativeInterface(accDoc, "checkboxes"); 811 const checkbox1 = getNativeInterface(accDoc, "checkbox1"); 812 const checkbox2 = getNativeInterface(accDoc, "checkbox2"); 813 814 is( 815 checkboxes.getAttributeValue("AXRole"), 816 controls[3].getAttributeValue("AXRole"), 817 "Found correct group of checkboxes" 818 ); 819 is( 820 checkbox1.getAttributeValue("AXRole"), 821 controls[4].getAttributeValue("AXRole"), 822 "Found correct checkbox 1" 823 ); 824 is( 825 checkbox2.getAttributeValue("AXRole"), 826 controls[5].getAttributeValue("AXRole"), 827 "Found correct checkbox 2" 828 ); 829 830 const switches = getNativeInterface(accDoc, "switches"); 831 const switch1 = getNativeInterface(accDoc, "switch1"); 832 const switch2 = getNativeInterface(accDoc, "switch2"); 833 834 is( 835 switches.getAttributeValue("AXRole"), 836 controls[6].getAttributeValue("AXRole"), 837 "Found correct group of switches" 838 ); 839 is( 840 switch1.getAttributeValue("AXRole"), 841 controls[7].getAttributeValue("AXRole"), 842 "Found correct switch 1" 843 ); 844 is( 845 switch2.getAttributeValue("AXRole"), 846 controls[8].getAttributeValue("AXRole"), 847 "Found correct switch 2" 848 ); 849 } 850 ); 851 852 /** 853 * Test rotor with misc controls 854 */ 855 addAccessibleTask( 856 ` 857 <input role="spinbutton" id="spinbutton" type="number" value="25"> 858 859 <details id="details"> 860 <summary>Hello</summary> 861 world 862 </details> 863 864 <ul role="tree" id="tree"> 865 <li role="treeitem">item1</li> 866 <li role="treeitem">item1</li> 867 </ul> 868 869 <a id="buttonMenu" role="button">Click Me</a> 870 `, 871 async (browser, accDoc) => { 872 const searchPred = { 873 AXSearchKey: "AXControlSearchKey", 874 AXImmediateDescendants: 1, 875 AXResultsLimit: -1, 876 AXDirection: "AXDirectionNext", 877 }; 878 879 const webArea = accDoc.nativeInterface.QueryInterface( 880 Ci.nsIAccessibleMacInterface 881 ); 882 is( 883 webArea.getAttributeValue("AXRole"), 884 "AXWebArea", 885 "Got web area accessible" 886 ); 887 888 const controlsCount = webArea.getParameterizedAttributeValue( 889 "AXUIElementCountForSearchPredicate", 890 NSDictionary(searchPred) 891 ); 892 is(4, controlsCount, "Found 4 controls"); 893 894 const controls = webArea.getParameterizedAttributeValue( 895 "AXUIElementsForSearchPredicate", 896 NSDictionary(searchPred) 897 ); 898 899 const spin = getNativeInterface(accDoc, "spinbutton"); 900 const details = getNativeInterface(accDoc, "details"); 901 const tree = getNativeInterface(accDoc, "tree"); 902 const buttonMenu = getNativeInterface(accDoc, "buttonMenu"); 903 904 is( 905 spin.getAttributeValue("AXRole"), 906 controls[0].getAttributeValue("AXRole"), 907 "Found correct spinbutton" 908 ); 909 is( 910 details.getAttributeValue("AXRole"), 911 controls[1].getAttributeValue("AXRole"), 912 "Found correct details element" 913 ); 914 is( 915 tree.getAttributeValue("AXRole"), 916 controls[2].getAttributeValue("AXRole"), 917 "Found correct tree" 918 ); 919 is( 920 buttonMenu.getAttributeValue("AXRole"), 921 controls[3].getAttributeValue("AXRole"), 922 "Found correct button menu" 923 ); 924 } 925 ); 926 927 /** 928 * Test rotor with links 929 */ 930 addAccessibleTask( 931 ` 932 <a href="" id="empty">empty link</a> 933 <a href="http://www.example.com/" id="href">Example link</a> 934 <a id="noHref">link without href</a> 935 `, 936 async (browser, accDoc) => { 937 let searchPred = { 938 AXSearchKey: "AXLinkSearchKey", 939 AXImmediateDescendants: 1, 940 AXResultsLimit: -1, 941 AXDirection: "AXDirectionNext", 942 }; 943 944 const webArea = accDoc.nativeInterface.QueryInterface( 945 Ci.nsIAccessibleMacInterface 946 ); 947 is( 948 webArea.getAttributeValue("AXRole"), 949 "AXWebArea", 950 "Got web area accessible" 951 ); 952 953 let linkCount = webArea.getParameterizedAttributeValue( 954 "AXUIElementCountForSearchPredicate", 955 NSDictionary(searchPred) 956 ); 957 is(2, linkCount, "Found two links"); 958 959 let links = webArea.getParameterizedAttributeValue( 960 "AXUIElementsForSearchPredicate", 961 NSDictionary(searchPred) 962 ); 963 const empty = getNativeInterface(accDoc, "empty"); 964 const href = getNativeInterface(accDoc, "href"); 965 966 is( 967 empty.getAttributeValue("AXTitle"), 968 links[0].getAttributeValue("AXTitle"), 969 "Found correct first link" 970 ); 971 is( 972 href.getAttributeValue("AXTitle"), 973 links[1].getAttributeValue("AXTitle"), 974 "Found correct second link" 975 ); 976 977 // unvisited links 978 979 searchPred = { 980 AXSearchKey: "AXUnvisitedLinkSearchKey", 981 AXImmediateDescendants: 1, 982 AXResultsLimit: -1, 983 AXDirection: "AXDirectionNext", 984 }; 985 986 linkCount = webArea.getParameterizedAttributeValue( 987 "AXUIElementCountForSearchPredicate", 988 NSDictionary(searchPred) 989 ); 990 991 is(2, linkCount, "Found two links"); 992 993 links = webArea.getParameterizedAttributeValue( 994 "AXUIElementsForSearchPredicate", 995 NSDictionary(searchPred) 996 ); 997 998 is( 999 empty.getAttributeValue("AXTitle"), 1000 links[0].getAttributeValue("AXTitle"), 1001 "Found correct first link" 1002 ); 1003 is( 1004 href.getAttributeValue("AXTitle"), 1005 links[1].getAttributeValue("AXTitle"), 1006 "Found correct second link" 1007 ); 1008 1009 // visited links 1010 1011 let stateChanged = waitForEvent(EVENT_STATE_CHANGE, "href"); 1012 1013 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 1014 await PlacesTestUtils.addVisits(["http://www.example.com/"]); 1015 1016 await stateChanged; 1017 1018 searchPred = { 1019 AXSearchKey: "AXVisitedLinkSearchKey", 1020 AXImmediateDescendants: 1, 1021 AXResultsLimit: -1, 1022 AXDirection: "AXDirectionNext", 1023 }; 1024 1025 linkCount = webArea.getParameterizedAttributeValue( 1026 "AXUIElementCountForSearchPredicate", 1027 NSDictionary(searchPred) 1028 ); 1029 is(1, linkCount, "Found one link"); 1030 1031 links = webArea.getParameterizedAttributeValue( 1032 "AXUIElementsForSearchPredicate", 1033 NSDictionary(searchPred) 1034 ); 1035 1036 is( 1037 href.getAttributeValue("AXTitle"), 1038 links[0].getAttributeValue("AXTitle"), 1039 "Found correct visited link" 1040 ); 1041 1042 // Ensure history is cleared before running again 1043 await PlacesUtils.history.clear(); 1044 } 1045 ); 1046 1047 /* 1048 * Test AXAnyTypeSearchKey with root group 1049 */ 1050 addAccessibleTask( 1051 `<h1 id="hello">hello</h1><br><h2 id="world">world</h2><br>goodbye`, 1052 (browser, accDoc) => { 1053 let searchPred = { 1054 AXSearchKey: "AXAnyTypeSearchKey", 1055 AXImmediateDescendantsOnly: 1, 1056 AXResultsLimit: 1, 1057 AXDirection: "AXDirectionNext", 1058 }; 1059 1060 const webArea = accDoc.nativeInterface.QueryInterface( 1061 Ci.nsIAccessibleMacInterface 1062 ); 1063 is( 1064 webArea.getAttributeValue("AXRole"), 1065 "AXWebArea", 1066 "Got web area accessible" 1067 ); 1068 1069 let results = webArea.getParameterizedAttributeValue( 1070 "AXUIElementsForSearchPredicate", 1071 NSDictionary(searchPred) 1072 ); 1073 is(results.length, 1, "One result for root group"); 1074 is( 1075 results[0].getAttributeValue("AXIdentifier"), 1076 "root-group", 1077 "Is generated root group" 1078 ); 1079 1080 searchPred.AXStartElement = results[0]; 1081 results = webArea.getParameterizedAttributeValue( 1082 "AXUIElementsForSearchPredicate", 1083 NSDictionary(searchPred) 1084 ); 1085 is(results.length, 0, "No more results past root group"); 1086 1087 searchPred.AXDirection = "AXDirectionPrevious"; 1088 results = webArea.getParameterizedAttributeValue( 1089 "AXUIElementsForSearchPredicate", 1090 NSDictionary(searchPred) 1091 ); 1092 is( 1093 results.length, 1094 0, 1095 "Searching backwards from root group should yield no results" 1096 ); 1097 1098 const rootGroup = webArea.getAttributeValue("AXChildren")[0]; 1099 is( 1100 rootGroup.getAttributeValue("AXIdentifier"), 1101 "root-group", 1102 "Is generated root group" 1103 ); 1104 1105 searchPred = { 1106 AXSearchKey: "AXAnyTypeSearchKey", 1107 AXImmediateDescendantsOnly: 1, 1108 AXResultsLimit: 1, 1109 AXDirection: "AXDirectionNext", 1110 }; 1111 1112 results = rootGroup.getParameterizedAttributeValue( 1113 "AXUIElementsForSearchPredicate", 1114 NSDictionary(searchPred) 1115 ); 1116 1117 is( 1118 results[0].getAttributeValue("AXRole"), 1119 "AXHeading", 1120 "Is first heading child" 1121 ); 1122 }, 1123 { contentDocBodyAttrs: { role: "application" } } 1124 ); 1125 1126 /** 1127 * Test rotor with checkboxes 1128 */ 1129 addAccessibleTask( 1130 ` 1131 <fieldset id="checkboxes"> 1132 <legend>Checkboxes</legend> 1133 <input id="checkbox1" type="checkbox" name="g2"> Checkbox 1 1134 <input id="checkbox2" type="checkbox" name="g2" checked="checked">Checkbox 2 1135 <div id="checkbox3" role="checkbox">Checkbox 3</div> 1136 <div id="checkbox4" role="checkbox" aria-checked="true">Checkbox 4</div> 1137 </fieldset> 1138 `, 1139 async (browser, accDoc) => { 1140 const searchPred = { 1141 AXSearchKey: "AXCheckBoxSearchKey", 1142 AXImmediateDescendantsOnly: 0, 1143 AXResultsLimit: -1, 1144 AXDirection: "AXDirectionNext", 1145 }; 1146 1147 const webArea = accDoc.nativeInterface.QueryInterface( 1148 Ci.nsIAccessibleMacInterface 1149 ); 1150 is( 1151 webArea.getAttributeValue("AXRole"), 1152 "AXWebArea", 1153 "Got web area accessible" 1154 ); 1155 1156 const checkboxCount = webArea.getParameterizedAttributeValue( 1157 "AXUIElementCountForSearchPredicate", 1158 NSDictionary(searchPred) 1159 ); 1160 is(4, checkboxCount, "Found 4 checkboxes"); 1161 1162 const checkboxes = webArea.getParameterizedAttributeValue( 1163 "AXUIElementsForSearchPredicate", 1164 NSDictionary(searchPred) 1165 ); 1166 1167 const checkbox1 = getNativeInterface(accDoc, "checkbox1"); 1168 const checkbox2 = getNativeInterface(accDoc, "checkbox2"); 1169 const checkbox3 = getNativeInterface(accDoc, "checkbox3"); 1170 const checkbox4 = getNativeInterface(accDoc, "checkbox4"); 1171 1172 is( 1173 checkbox1.getAttributeValue("AXValue"), 1174 checkboxes[0].getAttributeValue("AXValue"), 1175 "Found correct checkbox 1" 1176 ); 1177 is( 1178 checkbox2.getAttributeValue("AXValue"), 1179 checkboxes[1].getAttributeValue("AXValue"), 1180 "Found correct checkbox 2" 1181 ); 1182 is( 1183 checkbox3.getAttributeValue("AXValue"), 1184 checkboxes[2].getAttributeValue("AXValue"), 1185 "Found correct checkbox 3" 1186 ); 1187 is( 1188 checkbox4.getAttributeValue("AXValue"), 1189 checkboxes[3].getAttributeValue("AXValue"), 1190 "Found correct checkbox 4" 1191 ); 1192 } 1193 ); 1194 1195 /** 1196 * Test rotor with radiogroups 1197 */ 1198 addAccessibleTask( 1199 ` 1200 <div role="radiogroup" id="radios" aria-labelledby="desc"> 1201 <h1 id="desc">some radio buttons</h1> 1202 <div id="radio1" role="radio"> Radio 1</div> 1203 <div id="radio2" role="radio"> Radio 2</div> 1204 </div> 1205 `, 1206 async (browser, accDoc) => { 1207 const searchPred = { 1208 AXSearchKey: "AXRadioGroupSearchKey", 1209 AXImmediateDescendants: 1, 1210 AXResultsLimit: -1, 1211 AXDirection: "AXDirectionNext", 1212 }; 1213 1214 const webArea = accDoc.nativeInterface.QueryInterface( 1215 Ci.nsIAccessibleMacInterface 1216 ); 1217 is( 1218 webArea.getAttributeValue("AXRole"), 1219 "AXWebArea", 1220 "Got web area accessible" 1221 ); 1222 1223 const radiogroupCount = webArea.getParameterizedAttributeValue( 1224 "AXUIElementCountForSearchPredicate", 1225 NSDictionary(searchPred) 1226 ); 1227 is(1, radiogroupCount, "Found 1 radio group"); 1228 1229 const controls = webArea.getParameterizedAttributeValue( 1230 "AXUIElementsForSearchPredicate", 1231 NSDictionary(searchPred) 1232 ); 1233 1234 const radios = getNativeInterface(accDoc, "radios"); 1235 1236 is( 1237 radios.getAttributeValue("AXDescription"), 1238 controls[0].getAttributeValue("AXDescription"), 1239 "Found correct group of radios" 1240 ); 1241 } 1242 ); 1243 1244 /* 1245 * Test rotor with inputs 1246 */ 1247 addAccessibleTask( 1248 ` 1249 <input type="text" value="I'm a text field." id="text"><br> 1250 <input type="text" value="me too" id="implText"><br> 1251 <textarea id="textarea">this is some text in a text area</textarea><br> 1252 <input type="tel" value="0000000000" id="tel"><br> 1253 <input type="url" value="https://example.com" id="url"><br> 1254 <input type="email" value="hi@example.com" id="email"><br> 1255 <input type="password" value="blah" id="password"><br> 1256 <input type="month" value="2020-01" id="month"><br> 1257 <input type="week" value="2020-W01" id="week"><br> 1258 `, 1259 async (browser, accDoc) => { 1260 const searchPred = { 1261 AXSearchKey: "AXTextFieldSearchKey", 1262 AXImmediateDescendants: 1, 1263 AXResultsLimit: -1, 1264 AXDirection: "AXDirectionNext", 1265 }; 1266 1267 const webArea = accDoc.nativeInterface.QueryInterface( 1268 Ci.nsIAccessibleMacInterface 1269 ); 1270 is( 1271 webArea.getAttributeValue("AXRole"), 1272 "AXWebArea", 1273 "Got web area accessible" 1274 ); 1275 1276 const textfieldCount = webArea.getParameterizedAttributeValue( 1277 "AXUIElementCountForSearchPredicate", 1278 NSDictionary(searchPred) 1279 ); 1280 1281 is(9, textfieldCount, "Found 9 fields"); 1282 1283 const fields = webArea.getParameterizedAttributeValue( 1284 "AXUIElementsForSearchPredicate", 1285 NSDictionary(searchPred) 1286 ); 1287 1288 const text = getNativeInterface(accDoc, "text"); 1289 const implText = getNativeInterface(accDoc, "implText"); 1290 const textarea = getNativeInterface(accDoc, "textarea"); 1291 const tel = getNativeInterface(accDoc, "tel"); 1292 const url = getNativeInterface(accDoc, "url"); 1293 const email = getNativeInterface(accDoc, "email"); 1294 const password = getNativeInterface(accDoc, "password"); 1295 const month = getNativeInterface(accDoc, "month"); 1296 const week = getNativeInterface(accDoc, "week"); 1297 1298 const toCheck = [ 1299 text, 1300 implText, 1301 textarea, 1302 tel, 1303 url, 1304 email, 1305 password, 1306 month, 1307 week, 1308 ]; 1309 1310 for (let i = 0; i < toCheck.length; i++) { 1311 is( 1312 toCheck[i].getAttributeValue("AXValue"), 1313 fields[i].getAttributeValue("AXValue"), 1314 "Found correct input control" 1315 ); 1316 } 1317 } 1318 ); 1319 1320 /** 1321 * Test rotor with static text 1322 */ 1323 addAccessibleTask( 1324 ` 1325 <h1>Hello I am a heading</h1> 1326 This is some regular text.<p>this is some paragraph text</p><br> 1327 This is a list:<ul> 1328 <li>List item one</li> 1329 <li>List item two</li> 1330 </ul> 1331 1332 <a href="http://example.com">This is a link</a> 1333 `, 1334 async (browser, accDoc) => { 1335 const searchPred = { 1336 AXSearchKey: "AXStaticTextSearchKey", 1337 AXImmediateDescendants: 0, 1338 AXResultsLimit: -1, 1339 AXDirection: "AXDirectionNext", 1340 }; 1341 1342 const webArea = accDoc.nativeInterface.QueryInterface( 1343 Ci.nsIAccessibleMacInterface 1344 ); 1345 is( 1346 webArea.getAttributeValue("AXRole"), 1347 "AXWebArea", 1348 "Got web area accessible" 1349 ); 1350 1351 const textCount = webArea.getParameterizedAttributeValue( 1352 "AXUIElementCountForSearchPredicate", 1353 NSDictionary(searchPred) 1354 ); 1355 is(7, textCount, "Found 7 pieces of text"); 1356 1357 const text = webArea.getParameterizedAttributeValue( 1358 "AXUIElementsForSearchPredicate", 1359 NSDictionary(searchPred) 1360 ); 1361 1362 is( 1363 "Hello I am a heading", 1364 text[0].getAttributeValue("AXValue"), 1365 "Found correct text node for heading" 1366 ); 1367 is( 1368 "This is some regular text.", 1369 text[1].getAttributeValue("AXValue"), 1370 "Found correct text node" 1371 ); 1372 is( 1373 "this is some paragraph text", 1374 text[2].getAttributeValue("AXValue"), 1375 "Found correct text node for paragraph" 1376 ); 1377 is( 1378 "This is a list:", 1379 text[3].getAttributeValue("AXValue"), 1380 "Found correct text node for pre-list text node" 1381 ); 1382 is( 1383 "List item one", 1384 text[4].getAttributeValue("AXValue"), 1385 "Found correct text node for list item one" 1386 ); 1387 is( 1388 "List item two", 1389 text[5].getAttributeValue("AXValue"), 1390 "Found correct text node for list item two" 1391 ); 1392 is( 1393 "This is a link", 1394 text[6].getAttributeValue("AXValue"), 1395 "Found correct text node for link" 1396 ); 1397 } 1398 ); 1399 1400 /** 1401 * Test rotor with lists 1402 */ 1403 addAccessibleTask( 1404 ` 1405 <ul id="unordered"> 1406 <li>hello</li> 1407 <li>world</li> 1408 </ul> 1409 1410 <ol id="ordered"> 1411 <li>item one</li> 1412 <li>item two</li> 1413 </ol> 1414 `, 1415 async (browser, accDoc) => { 1416 const searchPred = { 1417 AXSearchKey: "AXListSearchKey", 1418 AXImmediateDescendants: 1, 1419 AXResultsLimit: -1, 1420 AXDirection: "AXDirectionNext", 1421 }; 1422 1423 const webArea = accDoc.nativeInterface.QueryInterface( 1424 Ci.nsIAccessibleMacInterface 1425 ); 1426 is( 1427 webArea.getAttributeValue("AXRole"), 1428 "AXWebArea", 1429 "Got web area accessible" 1430 ); 1431 1432 const listCount = webArea.getParameterizedAttributeValue( 1433 "AXUIElementCountForSearchPredicate", 1434 NSDictionary(searchPred) 1435 ); 1436 1437 is(2, listCount, "Found 2 lists"); 1438 1439 const lists = webArea.getParameterizedAttributeValue( 1440 "AXUIElementsForSearchPredicate", 1441 NSDictionary(searchPred) 1442 ); 1443 1444 const ordered = getNativeInterface(accDoc, "ordered"); 1445 const unordered = getNativeInterface(accDoc, "unordered"); 1446 1447 is( 1448 unordered.getAttributeValue("AXChildren")[0].getAttributeValue("AXTitle"), 1449 lists[0].getAttributeValue("AXChildren")[0].getAttributeValue("AXTitle"), 1450 "Found correct unordered list" 1451 ); 1452 is( 1453 ordered.getAttributeValue("AXChildren")[0].getAttributeValue("AXTitle"), 1454 lists[1].getAttributeValue("AXChildren")[0].getAttributeValue("AXTitle"), 1455 "Found correct ordered list" 1456 ); 1457 } 1458 ); 1459 1460 /* 1461 * Test rotor with images 1462 */ 1463 addAccessibleTask( 1464 ` 1465 <img id="img1" alt="image one" src="http://example.com/a11y/accessible/tests/mochitest/moz.png"><br> 1466 <a href="http://example.com"> 1467 <img id="img2" alt="image two" src="http://example.com/a11y/accessible/tests/mochitest/moz.png"> 1468 </a> 1469 <img src="" id="img3"> 1470 `, 1471 (browser, accDoc) => { 1472 let searchPred = { 1473 AXSearchKey: "AXImageSearchKey", 1474 AXImmediateDescendantsOnly: 0, 1475 AXResultsLimit: -1, 1476 AXDirection: "AXDirectionNext", 1477 }; 1478 1479 const webArea = accDoc.nativeInterface.QueryInterface( 1480 Ci.nsIAccessibleMacInterface 1481 ); 1482 is( 1483 webArea.getAttributeValue("AXRole"), 1484 "AXWebArea", 1485 "Got web area accessible" 1486 ); 1487 1488 let images = webArea.getParameterizedAttributeValue( 1489 "AXUIElementsForSearchPredicate", 1490 NSDictionary(searchPred) 1491 ); 1492 1493 is(images.length, 3, "Found three images"); 1494 1495 const img1 = getNativeInterface(accDoc, "img1"); 1496 const img2 = getNativeInterface(accDoc, "img2"); 1497 const img3 = getNativeInterface(accDoc, "img3"); 1498 1499 is( 1500 img1.getAttributeValue("AXDescription"), 1501 images[0].getAttributeValue("AXDescription"), 1502 "Found correct image" 1503 ); 1504 1505 is( 1506 img2.getAttributeValue("AXDescription"), 1507 images[1].getAttributeValue("AXDescription"), 1508 "Found correct image" 1509 ); 1510 1511 is( 1512 img3.getAttributeValue("AXDescription"), 1513 images[2].getAttributeValue("AXDescription"), 1514 "Found correct image" 1515 ); 1516 } 1517 ); 1518 1519 /** 1520 * Test rotor with frames 1521 */ 1522 addAccessibleTask( 1523 ` 1524 <iframe id="frame1" src="data:text/html,<h1>hello</h1>world"></iframe> 1525 <iframe id="frame2" src="data:text/html,<iframe id='frame3' src='data:text/html,<h1>goodbye</h1>'>"></iframe> 1526 `, 1527 async (browser, accDoc) => { 1528 const searchPred = { 1529 AXSearchKey: "AXFrameSearchKey", 1530 AXImmediateDescendantsOnly: 0, 1531 AXResultsLimit: -1, 1532 AXDirection: "AXDirectionNext", 1533 }; 1534 1535 const webArea = accDoc.nativeInterface.QueryInterface( 1536 Ci.nsIAccessibleMacInterface 1537 ); 1538 is( 1539 webArea.getAttributeValue("AXRole"), 1540 "AXWebArea", 1541 "Got web area accessible" 1542 ); 1543 1544 const frameCount = webArea.getParameterizedAttributeValue( 1545 "AXUIElementCountForSearchPredicate", 1546 NSDictionary(searchPred) 1547 ); 1548 is(3, frameCount, "Found 3 frames"); 1549 } 1550 ); 1551 1552 /** 1553 * Test rotor with static text 1554 */ 1555 addAccessibleTask( 1556 ` 1557 <h1>Hello I am a heading</h1> 1558 This is some regular text.<p>this is some paragraph text</p><br> 1559 This is a list:<ul> 1560 <li>List item one</li> 1561 <li>List item two</li> 1562 </ul> 1563 1564 <a href="http://example.com">This is a link</a> 1565 `, 1566 async (browser, accDoc) => { 1567 const searchPred = { 1568 AXSearchKey: "AXStaticTextSearchKey", 1569 AXImmediateDescendants: 0, 1570 AXResultsLimit: -1, 1571 AXDirection: "AXDirectionNext", 1572 }; 1573 1574 const webArea = accDoc.nativeInterface.QueryInterface( 1575 Ci.nsIAccessibleMacInterface 1576 ); 1577 is( 1578 webArea.getAttributeValue("AXRole"), 1579 "AXWebArea", 1580 "Got web area accessible" 1581 ); 1582 1583 const textCount = webArea.getParameterizedAttributeValue( 1584 "AXUIElementCountForSearchPredicate", 1585 NSDictionary(searchPred) 1586 ); 1587 is(7, textCount, "Found 7 pieces of text"); 1588 1589 const text = webArea.getParameterizedAttributeValue( 1590 "AXUIElementsForSearchPredicate", 1591 NSDictionary(searchPred) 1592 ); 1593 1594 is( 1595 "Hello I am a heading", 1596 text[0].getAttributeValue("AXValue"), 1597 "Found correct text node for heading" 1598 ); 1599 is( 1600 "This is some regular text.", 1601 text[1].getAttributeValue("AXValue"), 1602 "Found correct text node" 1603 ); 1604 is( 1605 "this is some paragraph text", 1606 text[2].getAttributeValue("AXValue"), 1607 "Found correct text node for paragraph" 1608 ); 1609 is( 1610 "This is a list:", 1611 text[3].getAttributeValue("AXValue"), 1612 "Found correct text node for pre-list text node" 1613 ); 1614 is( 1615 "List item one", 1616 text[4].getAttributeValue("AXValue"), 1617 "Found correct text node for list item one" 1618 ); 1619 is( 1620 "List item two", 1621 text[5].getAttributeValue("AXValue"), 1622 "Found correct text node for list item two" 1623 ); 1624 is( 1625 "This is a link", 1626 text[6].getAttributeValue("AXValue"), 1627 "Found correct text node for link" 1628 ); 1629 } 1630 ); 1631 1632 /** 1633 * Test search with non-webarea root 1634 */ 1635 addAccessibleTask( 1636 ` 1637 <div id="searchroot"><p id="p1">hello</p><p id="p2">world</p></div> 1638 <div><p>goodybe</p></div> 1639 `, 1640 async (browser, accDoc) => { 1641 let searchPred = { 1642 AXSearchKey: "AXAnyTypeSearchKey", 1643 AXImmediateDescendantsOnly: 1, 1644 AXResultsLimit: -1, 1645 AXDirection: "AXDirectionNext", 1646 }; 1647 1648 const searchRoot = getNativeInterface(accDoc, "searchroot"); 1649 const resultCount = searchRoot.getParameterizedAttributeValue( 1650 "AXUIElementCountForSearchPredicate", 1651 NSDictionary(searchPred) 1652 ); 1653 is(resultCount, 2, "Found 2 items"); 1654 1655 const p1 = getNativeInterface(accDoc, "p1"); 1656 searchPred = { 1657 AXSearchKey: "AXAnyTypeSearchKey", 1658 AXImmediateDescendantsOnly: 1, 1659 AXResultsLimit: -1, 1660 AXDirection: "AXDirectionNext", 1661 AXStartElement: p1, 1662 }; 1663 1664 let results = searchRoot.getParameterizedAttributeValue( 1665 "AXUIElementsForSearchPredicate", 1666 NSDictionary(searchPred) 1667 ); 1668 1669 Assert.deepEqual( 1670 results.map(r => r.getAttributeValue("AXDOMIdentifier")), 1671 ["p2"], 1672 "Result is next group sibling" 1673 ); 1674 1675 searchPred = { 1676 AXSearchKey: "AXAnyTypeSearchKey", 1677 AXImmediateDescendantsOnly: 1, 1678 AXResultsLimit: -1, 1679 AXDirection: "AXDirectionPrevious", 1680 }; 1681 1682 results = searchRoot.getParameterizedAttributeValue( 1683 "AXUIElementsForSearchPredicate", 1684 NSDictionary(searchPred) 1685 ); 1686 1687 Assert.deepEqual( 1688 results.map(r => r.getAttributeValue("AXDOMIdentifier")), 1689 ["p2", "p1"], 1690 "A reverse search should return groups in reverse" 1691 ); 1692 } 1693 ); 1694 1695 /** 1696 * Test search text 1697 */ 1698 addAccessibleTask( 1699 ` 1700 <p>It's about the future, isn't it?</p> 1701 <p>Okay, alright, Saturday is good, Saturday's good, I could spend a week in 1955.</p> 1702 <ul> 1703 <li>I could hang out, you could show me around.</li> 1704 <li>There's that word again, heavy.</li> 1705 </ul> 1706 `, 1707 async (browser, f, accDoc) => { 1708 let searchPred = { 1709 AXSearchKey: "AXAnyTypeSearchKey", 1710 AXResultsLimit: -1, 1711 AXDirection: "AXDirectionNext", 1712 AXSearchText: "could", 1713 }; 1714 1715 const webArea = accDoc.nativeInterface.QueryInterface( 1716 Ci.nsIAccessibleMacInterface 1717 ); 1718 is( 1719 webArea.getAttributeValue("AXRole"), 1720 "AXWebArea", 1721 "Got web area accessible" 1722 ); 1723 1724 const textSearchCount = webArea.getParameterizedAttributeValue( 1725 "AXUIElementCountForSearchPredicate", 1726 NSDictionary(searchPred) 1727 ); 1728 is(textSearchCount, 2, "Found 2 matching items in text search"); 1729 1730 const results = webArea.getParameterizedAttributeValue( 1731 "AXUIElementsForSearchPredicate", 1732 NSDictionary(searchPred) 1733 ); 1734 1735 info(results.map(r => r.getAttributeValue("AXMozDebugDescription"))); 1736 1737 Assert.deepEqual( 1738 results.map(r => r.getAttributeValue("AXValue")), 1739 [ 1740 "Okay, alright, Saturday is good, Saturday's good, I could spend a week in 1955.", 1741 "I could hang out, you could show me around.", 1742 ], 1743 "Correct text search results" 1744 ); 1745 }, 1746 { topLevel: false, iframe: true, remoteIframe: true } 1747 ); 1748 1749 /** 1750 * Test keyboard focusable search predicate 1751 */ 1752 addAccessibleTask( 1753 ` 1754 <p>Hello, <a href="http://www.example.com/" id="href">Example link</a> <a id="noHref">link without href</a></p> 1755 <input id="input"> 1756 <button id="button">Click me</button> 1757 <div id="container" style="height: 10px; overflow: auto;"><div style="height: 100px;"></div></div> 1758 `, 1759 async (browser, f, accDoc) => { 1760 const searchPred = { 1761 AXSearchKey: "AXKeyboardFocusableSearchKey", 1762 AXResultsLimit: -1, 1763 AXDirection: "AXDirectionNext", 1764 }; 1765 const webArea = accDoc.nativeInterface.QueryInterface( 1766 Ci.nsIAccessibleMacInterface 1767 ); 1768 1769 const results = webArea.getParameterizedAttributeValue( 1770 "AXUIElementsForSearchPredicate", 1771 NSDictionary(searchPred) 1772 ); 1773 1774 Assert.deepEqual( 1775 results.map(r => r.getAttributeValue("AXDOMIdentifier")), 1776 ["href", "input", "button"], 1777 "Correct keyboard focusable search results" 1778 ); 1779 }, 1780 { topLevel: false, iframe: true, remoteIframe: true } 1781 );