tor-browser

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

head.js (7785B)


      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 /* exported testCachedRelation, testRelated */
      8 
      9 // Load the shared-head file first.
     10 Services.scriptloader.loadSubScript(
     11  "chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
     12  this
     13 );
     14 
     15 // Loading and common.js from accessible/tests/mochitest/ for all tests, as
     16 // well as promisified-events.js and relations.js.
     17 /* import-globals-from ../../mochitest/relations.js */
     18 loadScripts(
     19  { name: "common.js", dir: MOCHITESTS_DIR },
     20  { name: "promisified-events.js", dir: MOCHITESTS_DIR },
     21  { name: "relations.js", dir: MOCHITESTS_DIR }
     22 );
     23 
     24 /**
     25 * Test the accessible relation.
     26 *
     27 * @param identifier          [in] identifier to get an accessible, may be ID
     28 *                             attribute or DOM element or accessible object
     29 * @param relType             [in] relation type (see constants above)
     30 * @param relatedIdentifiers  [in] identifier or array of identifiers of
     31 *                             expected related accessibles
     32 */
     33 async function testCachedRelation(
     34  identifier,
     35  relType,
     36  relatedIdentifiers = []
     37 ) {
     38  const relDescr = getRelationErrorMsg(identifier, relType);
     39 
     40  const relatedIds =
     41    relatedIdentifiers instanceof Array
     42      ? relatedIdentifiers
     43      : [relatedIdentifiers];
     44 
     45  await untilCacheIs(
     46    () => {
     47      let r = getRelationByType(identifier, relType);
     48      return r ? r.targetsCount : -1;
     49    },
     50    relatedIds.length,
     51    "Found correct number of expected relations"
     52  );
     53 
     54  let targetSet = new Set(relatedIds.map(id => getAccessible(id)));
     55 
     56  await untilCacheOk(function () {
     57    const relation = getRelationByType(identifier, relType);
     58    const actualTargets = relation ? relation.getTargets() : null;
     59    if (!actualTargets) {
     60      info("Could not fetch relations");
     61      return false;
     62    }
     63 
     64    const actualTargetsSet = new Set(
     65      Array.from({ length: actualTargets.length }, (_, idx) =>
     66        actualTargets.queryElementAt(idx, Ci.nsIAccessible)
     67      )
     68    );
     69 
     70    const unexpectedTargets = actualTargetsSet.difference(targetSet);
     71    for (let extraAcc of unexpectedTargets) {
     72      info(
     73        prettyName(extraAcc) +
     74          " was found, but shouldn't be in relation: " +
     75          relDescr
     76      );
     77    }
     78 
     79    const missingTargets = targetSet.difference(actualTargetsSet);
     80    for (let missingAcc of missingTargets) {
     81      info(
     82        prettyName(missingAcc) + " could not be found in relation: " + relDescr
     83      );
     84    }
     85 
     86    return unexpectedTargets.size == 0 && missingTargets.size == 0;
     87  }, "Expected targets match");
     88 }
     89 
     90 /**
     91 * Asynchronously set or remove content element's reflected elements attribute
     92 * (in content process if e10s is enabled).
     93 *
     94 * @param  {object}  browser  current "tabbrowser" element
     95 * @param  {string}  id       content element id
     96 * @param  {string}  attr     attribute name
     97 * @param  {string?} value    optional attribute value, if not present, remove
     98 *                            attribute
     99 * @return {Promise}          promise indicating that attribute is set/removed
    100 */
    101 function invokeSetReflectedElementsAttribute(browser, id, attr, targetIds) {
    102  if (targetIds) {
    103    Logger.log(
    104      `Setting reflected ${attr} attribute to ${targetIds} for node with id: ${id}`
    105    );
    106  } else {
    107    Logger.log(`Removing reflected ${attr} attribute from node with id: ${id}`);
    108  }
    109 
    110  return invokeContentTask(
    111    browser,
    112    [id, attr, targetIds],
    113    (contentId, contentAttr, contentTargetIds) => {
    114      let elm = content.document.getElementById(contentId);
    115      if (contentTargetIds) {
    116        elm[contentAttr] = contentTargetIds.map(targetId =>
    117          content.document.getElementById(targetId)
    118        );
    119      } else {
    120        elm[contentAttr] = null;
    121      }
    122    }
    123  );
    124 }
    125 
    126 const REFLECTEDATTR_NAME_MAP = {
    127  "aria-controls": "ariaControlsElements",
    128  "aria-describedby": "ariaDescribedByElements",
    129  "aria-details": "ariaDetailsElements",
    130  "aria-errormessage": "ariaErrorMessageElements",
    131  "aria-flowto": "ariaFlowToElements",
    132  "aria-labelledby": "ariaLabelledByElements",
    133 };
    134 
    135 async function testRelated(
    136  browser,
    137  accDoc,
    138  attr,
    139  hostRelation,
    140  dependantRelation
    141 ) {
    142  let host = findAccessibleChildByID(accDoc, "host");
    143  let dependant1 = findAccessibleChildByID(accDoc, "dependant1");
    144  let dependant2 = findAccessibleChildByID(accDoc, "dependant2");
    145 
    146  /**
    147   * Test data has the format of:
    148   * {
    149   *   desc          {String}   description for better logging
    150   *   attrs         {?Array}   an optional list of attributes to update
    151   *   reflectedattr {?Array}   an optional list of reflected attributes to update
    152   *   expected      {Array}    expected relation values for dependant1, dependant2
    153   *                        and host respectively.
    154   * }
    155   */
    156  let tests = [
    157    {
    158      desc: "No attribute",
    159      expected: [null, null, null],
    160    },
    161    {
    162      desc: "Set attribute",
    163      attrs: [{ id: "host", key: attr, value: "dependant1" }],
    164      expected: [host, null, dependant1],
    165    },
    166    {
    167      desc: "Change attribute",
    168      attrs: [{ id: "host", key: attr, value: "dependant2" }],
    169      expected: [null, host, dependant2],
    170    },
    171    {
    172      desc: "Change attribute to multiple targets",
    173      attrs: [{ id: "host", key: attr, value: "dependant1 dependant2" }],
    174      expected: [host, host, [dependant1, dependant2]],
    175    },
    176    {
    177      desc: "Change 'dependent2' id to 'invalid'",
    178      attrs: [{ id: "dependant2", key: "id", value: "invalid" }],
    179      expected: [host, null, dependant1],
    180    },
    181    {
    182      desc: "Change 'invalid' id back to 'dependent2'",
    183      attrs: [{ id: "invalid", key: "id", value: "dependant2" }],
    184      expected: [host, host, [dependant1, dependant2]],
    185    },
    186    {
    187      desc: "Remove attribute",
    188      attrs: [{ id: "host", key: attr }],
    189      expected: [null, null, null],
    190    },
    191  ];
    192 
    193  let reflectedAttrName = REFLECTEDATTR_NAME_MAP[attr];
    194  if (reflectedAttrName) {
    195    tests = tests.concat([
    196      {
    197        desc: "Set reflected attribute",
    198        reflectedattr: [
    199          { id: "host", key: reflectedAttrName, value: ["dependant1"] },
    200        ],
    201        expected: [host, null, dependant1],
    202      },
    203      {
    204        desc: "Change reflected attribute",
    205        reflectedattr: [
    206          { id: "host", key: reflectedAttrName, value: ["dependant2"] },
    207        ],
    208        expected: [null, host, dependant2],
    209      },
    210      {
    211        desc: "Change reflected attribute to multiple targets",
    212        reflectedattr: [
    213          {
    214            id: "host",
    215            key: reflectedAttrName,
    216            value: ["dependant2", "dependant1"],
    217          },
    218        ],
    219        expected: [host, host, [dependant1, dependant2]],
    220      },
    221      {
    222        desc: "Remove reflected attribute",
    223        reflectedattr: [{ id: "host", key: reflectedAttrName, value: null }],
    224        expected: [null, null, null],
    225      },
    226    ]);
    227  }
    228 
    229  for (let { desc, attrs, reflectedattr, expected } of tests) {
    230    info(desc);
    231 
    232    if (attrs) {
    233      for (let { id, key, value } of attrs) {
    234        await invokeSetAttribute(browser, id, key, value);
    235      }
    236    } else if (reflectedattr) {
    237      for (let { id, key, value } of reflectedattr) {
    238        await invokeSetReflectedElementsAttribute(browser, id, key, value);
    239      }
    240    }
    241 
    242    await testCachedRelation(
    243      dependant1,
    244      dependantRelation,
    245      expected[0] ? expected[0] : []
    246    );
    247    await testCachedRelation(
    248      dependant2,
    249      dependantRelation,
    250      expected[1] ? expected[1] : []
    251    );
    252    await testCachedRelation(
    253      host,
    254      hostRelation,
    255      expected[2] ? expected[2] : []
    256    );
    257  }
    258 }