tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 );