tor-browser

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

browser_relationProps.js (6439B)


      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 function testUiaRelationArray(id, prop, targets) {
      8  return isUiaElementArray(
      9    `findUiaByDomId(doc, "${id}").Current${prop}`,
     10    targets,
     11    `${id} has correct ${prop} targets`
     12  );
     13 }
     14 
     15 function testCustomUiaRelationArray(id, prop, targets) {
     16  return isUiaElementArray(
     17    `
     18      findUiaByDomId(doc, "${id}")
     19      .GetCurrentPropertyValue(uia${prop}PropertyId)
     20      .QueryInterface(IUIAutomationElementArray)
     21    `,
     22    targets,
     23    `${id} has correct ${prop} targets`
     24  );
     25 }
     26 
     27 /**
     28 * Test the ControllerFor property.
     29 */
     30 addUiaTask(
     31  `
     32 <input id="controls" aria-controls="t1 t2">
     33 <input id="error" aria-errormessage="t3 t4" aria-invalid="true">
     34 <input id="controlsError" aria-controls="t1 t2" aria-errormessage="t3 t4" aria-invalid="true">
     35 <div id="t1">t1</div>
     36 <div id="t2">t2</div>
     37 <div id="t3">t3</div>
     38 <div id="t4">t4</div>
     39 <button id="none">none</button>
     40  `,
     41  async function testControllerFor() {
     42    await definePyVar("doc", `getDocUia()`);
     43    await testUiaRelationArray("controls", "ControllerFor", ["t1", "t2"]);
     44    // The IA2 -> UIA proxy doesn't support IA2_RELATION_ERROR.
     45    if (gIsUiaEnabled) {
     46      await testUiaRelationArray("error", "ControllerFor", ["t3", "t4"]);
     47      await testUiaRelationArray("controlsError", "ControllerFor", [
     48        "t1",
     49        "t2",
     50        "t3",
     51        "t4",
     52      ]);
     53    }
     54    await testUiaRelationArray("none", "ControllerFor", []);
     55  }
     56 );
     57 
     58 /**
     59 * Test the DescribedBy property.
     60 */
     61 addUiaTask(
     62  `
     63 <input id="describedby" aria-describedby="t1 t2">
     64 <input id="details" aria-details="t3 t4">
     65 <input id="describedbyDetails" aria-describedby="t1 t2" aria-details="t3 t4" aria-invalid="true">
     66 <div id="t1">t1</div>
     67 <div id="t2">t2</div>
     68 <div id="t3">t3</div>
     69 <div id="t4">t4</div>
     70 <button id="none">none</button>
     71  `,
     72  async function testDescribedBy() {
     73    await definePyVar("doc", `getDocUia()`);
     74    await testUiaRelationArray("describedby", "DescribedBy", ["t1", "t2"]);
     75    // The IA2 -> UIA proxy doesn't support IA2_RELATION_DETAILS.
     76    if (gIsUiaEnabled) {
     77      await testUiaRelationArray("details", "DescribedBy", ["t3", "t4"]);
     78      await testUiaRelationArray("describedbyDetails", "DescribedBy", [
     79        "t1",
     80        "t2",
     81        "t3",
     82        "t4",
     83      ]);
     84    }
     85    await testUiaRelationArray("none", "DescribedBy", []);
     86  }
     87 );
     88 
     89 /**
     90 * Test the FlowsFrom and FlowsTo properties.
     91 */
     92 addUiaTask(
     93  `
     94 <div id="t1" aria-flowto="t2">t1</div>
     95 <div id="t2">t2</div>
     96 <button id="none">none</button>
     97  `,
     98  async function testFlows() {
     99    await definePyVar("doc", `getDocUia()`);
    100    await testUiaRelationArray("t1", "FlowsTo", ["t2"]);
    101    await testUiaRelationArray("t2", "FlowsFrom", ["t1"]);
    102    await testUiaRelationArray("none", "FlowsFrom", []);
    103    await testUiaRelationArray("none", "FlowsTo", []);
    104  }
    105 );
    106 
    107 /**
    108 * Test the LabeledBy property.
    109 */
    110 addUiaTask(
    111  `
    112 <label id="label">label</label>
    113 <input id="input" aria-labelledby="label">
    114 <label id="wrappingLabel">
    115  <input id="wrappedInput" value="wrappedInput">
    116  <p id="wrappingLabelP">wrappingLabel</p>
    117 </label>
    118 <button id="button" aria-labelledby="label">content</button>
    119 <button id="noLabel">noLabel</button>
    120  `,
    121  async function testLabeledBy() {
    122    await definePyVar("doc", `getDocUia()`);
    123    // input's LabeledBy should be label's text leaf.
    124    let result = await runPython(`
    125      input = findUiaByDomId(doc, "input")
    126      label = findUiaByDomId(doc, "label")
    127      labelLeaf = uiaClient.RawViewWalker.GetFirstChildElement(label)
    128      return uiaClient.CompareElements(input.CurrentLabeledBy, labelLeaf)
    129    `);
    130    ok(result, "input has correct LabeledBy");
    131    // wrappedInput's LabeledBy should be wrappingLabelP's text leaf.
    132    result = await runPython(`
    133      wrappedInput = findUiaByDomId(doc, "wrappedInput")
    134      wrappingLabelP = findUiaByDomId(doc, "wrappingLabelP")
    135      wrappingLabelLeaf = uiaClient.RawViewWalker.GetFirstChildElement(wrappingLabelP)
    136      return uiaClient.CompareElements(wrappedInput.CurrentLabeledBy, wrappingLabelLeaf)
    137    `);
    138    ok(result, "wrappedInput has correct LabeledBy");
    139    // button has aria-labelledby, but UIA prohibits LabeledBy on buttons.
    140    ok(
    141      !(await runPython(
    142        `bool(findUiaByDomId(doc, "button").CurrentLabeledBy)`
    143      )),
    144      "button has no LabeledBy"
    145    );
    146    ok(
    147      !(await runPython(
    148        `bool(findUiaByDomId(doc, "noLabel").CurrentLabeledBy)`
    149      )),
    150      "noLabel has no LabeledBy"
    151    );
    152  },
    153  // The IA2 -> UIA proxy doesn't expose LabeledBy properly.
    154  { uiaEnabled: true, uiaDisabled: false }
    155 );
    156 
    157 /**
    158 * Test the AccessibleActions property.
    159 */
    160 addUiaTask(
    161  `
    162 <dialog aria-actions="btn" id="dlg" onclick="" open>
    163  Dialog with its own click listener
    164  <form method="dialog">
    165    <button id="btn">Close</button>
    166  </form>
    167 </dialog>
    168  `,
    169  async function testActions() {
    170    await definePyVar("doc", `getDocUia()`);
    171    await testCustomUiaRelationArray("dlg", "AccessibleActions", ["btn"]);
    172    await testCustomUiaRelationArray("btn", "AccessibleActions", []);
    173  },
    174  // The IA2 -> UIA proxy doesn't support AccessibleActions.
    175  { uiaEnabled: true, uiaDisabled: false }
    176 );
    177 
    178 /**
    179 * Test exposure of AriaProperties.hasactions.
    180 */
    181 addUiaTask(
    182  `
    183 <button id="button">button</button>
    184 <div role="tablist">
    185  <div id="tab1" role="tab" tabindex="0" aria-actions="tab1Button">
    186    tab1
    187    <button id="tab1Button">tab1Button</button>
    188  </div>
    189  <div id="tab2" role="tab" aria-actions="tab2Button">
    190    tab2
    191    <button id="tab2Button" hidden>tab2Button</button>
    192  </div>
    193 </div>
    194  `,
    195  async function testHasActions() {
    196    await definePyVar("doc", `getDocUia()`);
    197    is(
    198      await runPython(`findUiaByDomId(doc, "button").CurrentAriaProperties`),
    199      "",
    200      "button missing hasactions"
    201    );
    202    // tab1 has a visible action.
    203    is(
    204      await runPython(`findUiaByDomId(doc, "tab1").CurrentAriaProperties`),
    205      "hasactions=true",
    206      "tab1 hasactions=true"
    207    );
    208    // tab2 has an action, but it's hidden.
    209    is(
    210      await runPython(`findUiaByDomId(doc, "tab2").CurrentAriaProperties`),
    211      "hasactions=true",
    212      "tab2 hasactions=true"
    213    );
    214  },
    215  // The IA2 -> UIA proxy doesn't support hasactions.
    216  { uiaEnabled: true, uiaDisabled: false }
    217 );