tor-browser

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

head.js (9663B)


      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 /* eslint no-unused-vars: [2, {"vars": "local"}] */
      5 
      6 /* global _snapshots */
      7 
      8 "use strict";
      9 
     10 var { require } = ChromeUtils.importESModule(
     11  "resource://devtools/shared/loader/Loader.sys.mjs"
     12 );
     13 var { Assert } = ChromeUtils.importESModule(
     14  "resource://testing-common/Assert.sys.mjs"
     15 );
     16 var { gDevTools } = require("resource://devtools/client/framework/devtools.js");
     17 var { BrowserLoader } = ChromeUtils.importESModule(
     18  "resource://devtools/shared/loader/browser-loader.sys.mjs"
     19 );
     20 var {
     21  DevToolsServer,
     22 } = require("resource://devtools/server/devtools-server.js");
     23 var {
     24  DevToolsClient,
     25 } = require("resource://devtools/client/devtools-client.js");
     26 var DevToolsUtils = require("resource://devtools/shared/DevToolsUtils.js");
     27 var { Toolbox } = require("resource://devtools/client/framework/toolbox.js");
     28 
     29 var { require: browserRequire } = BrowserLoader({
     30  baseURI: "resource://devtools/client/shared/",
     31  window,
     32 });
     33 
     34 const React = browserRequire("devtools/client/shared/vendor/react");
     35 const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
     36 const dom = browserRequire("devtools/client/shared/vendor/react-dom-factories");
     37 const TestUtils = browserRequire(
     38  "devtools/client/shared/vendor/react-dom-test-utils"
     39 );
     40 
     41 const TestRenderer = browserRequire(
     42  "devtools/client/shared/vendor/react-test-renderer"
     43 );
     44 
     45 var EXAMPLE_URL = "https://example.com/browser/browser/devtools/shared/test/";
     46 
     47 SimpleTest.registerCleanupFunction(() => {
     48  window._snapshots = null;
     49 });
     50 
     51 function forceRender(comp) {
     52  return setState(comp, {}).then(() => setState(comp, {}));
     53 }
     54 
     55 // All tests are asynchronous.
     56 SimpleTest.waitForExplicitFinish();
     57 
     58 function onNextAnimationFrame(fn) {
     59  return () => requestAnimationFrame(() => requestAnimationFrame(fn));
     60 }
     61 
     62 function setState(component, newState) {
     63  return new Promise(resolve => {
     64    component.setState(newState, onNextAnimationFrame(resolve));
     65  });
     66 }
     67 
     68 function dumpn(msg) {
     69  dump(`SHARED-COMPONENTS-TEST: ${msg}\n`);
     70 }
     71 
     72 /**
     73 * Tree View
     74 */
     75 
     76 const TEST_TREE_VIEW = {
     77  A: { label: "A", value: "A" },
     78  B: { label: "B", value: "B" },
     79  C: { label: "C", value: "C" },
     80  D: { label: "D", value: "D" },
     81  E: { label: "E", value: "E" },
     82  F: { label: "F", value: "F" },
     83  G: { label: "G", value: "G" },
     84  H: { label: "H", value: "H" },
     85  I: { label: "I", value: "I" },
     86  J: { label: "J", value: "J" },
     87  K: { label: "K", value: "K" },
     88  L: { label: "L", value: "L" },
     89 };
     90 
     91 TEST_TREE_VIEW.children = {
     92  A: [TEST_TREE_VIEW.B, TEST_TREE_VIEW.C, TEST_TREE_VIEW.D],
     93  B: [TEST_TREE_VIEW.E, TEST_TREE_VIEW.F, TEST_TREE_VIEW.G],
     94  C: [TEST_TREE_VIEW.H, TEST_TREE_VIEW.I],
     95  D: [TEST_TREE_VIEW.J],
     96  E: [TEST_TREE_VIEW.K, TEST_TREE_VIEW.L],
     97  F: [],
     98  G: [],
     99  H: [],
    100  I: [],
    101  J: [],
    102  K: [],
    103  L: [],
    104 };
    105 
    106 const TEST_TREE_VIEW_INTERFACE = {
    107  provider: {
    108    getChildren: x => TEST_TREE_VIEW.children[x.label],
    109    hasChildren: x => !!TEST_TREE_VIEW.children[x.label].length,
    110    getLabel: x => x.label,
    111    getValue: x => x.value,
    112    getKey: x => x.label,
    113    getType: () => "string",
    114  },
    115  object: TEST_TREE_VIEW.A,
    116  columns: [{ id: "default" }, { id: "value" }],
    117 };
    118 
    119 /**
    120 * Tree
    121 */
    122 
    123 var TEST_TREE_INTERFACE = {
    124  getParent: x => TEST_TREE.parent[x],
    125  getChildren: x => TEST_TREE.children[x],
    126  renderItem: (x, depth, focused) =>
    127    "-".repeat(depth) + x + ":" + focused + "\n",
    128  getRoots: () => ["A", "M"],
    129  getKey: x => "key-" + x,
    130  itemHeight: 1,
    131  onExpand: x => TEST_TREE.expanded.add(x),
    132  onCollapse: x => TEST_TREE.expanded.delete(x),
    133  isExpanded: x => TEST_TREE.expanded.has(x),
    134 };
    135 
    136 function isRenderedTree(actual, expectedDescription, msg) {
    137  const expected = expectedDescription.map(x => x + "\n").join("");
    138  dumpn(`Expected tree:\n${expected}`);
    139  dumpn(`Actual tree:\n${actual}`);
    140  is(actual, expected, msg);
    141 }
    142 
    143 function isAccessibleTree(tree, options = {}) {
    144  const treeNode = tree.refs.tree;
    145  is(treeNode.getAttribute("tabindex"), "0", "Tab index is set");
    146  is(treeNode.getAttribute("role"), "tree", "Tree semantics is present");
    147  if (options.hasActiveDescendant) {
    148    ok(
    149      treeNode.hasAttribute("aria-activedescendant"),
    150      "Tree has an active descendant set"
    151    );
    152  }
    153 
    154  const treeNodes = [...treeNode.querySelectorAll(".tree-node")];
    155  for (const node of treeNodes) {
    156    ok(node.id, "TreeNode has an id");
    157    is(node.getAttribute("role"), "treeitem", "Tree item semantics is present");
    158    is(
    159      parseInt(node.getAttribute("aria-level"), 10),
    160      parseInt(node.getAttribute("data-depth"), 10) + 1,
    161      "Aria level attribute is set correctly"
    162    );
    163  }
    164 }
    165 
    166 // Encoding of the following tree/forest:
    167 //
    168 // A
    169 // |-- B
    170 // |   |-- E
    171 // |   |   |-- K
    172 // |   |   `-- L
    173 // |   |-- F
    174 // |   `-- G
    175 // |-- C
    176 // |   |-- H
    177 // |   `-- I
    178 // `-- D
    179 //     `-- J
    180 // M
    181 // `-- N
    182 //     `-- O
    183 var TEST_TREE = {
    184  children: {
    185    A: ["B", "C", "D"],
    186    B: ["E", "F", "G"],
    187    C: ["H", "I"],
    188    D: ["J"],
    189    E: ["K", "L"],
    190    F: [],
    191    G: [],
    192    H: [],
    193    I: [],
    194    J: [],
    195    K: [],
    196    L: [],
    197    M: ["N"],
    198    N: ["O"],
    199    O: [],
    200  },
    201  parent: {
    202    A: null,
    203    B: "A",
    204    C: "A",
    205    D: "A",
    206    E: "B",
    207    F: "B",
    208    G: "B",
    209    H: "C",
    210    I: "C",
    211    J: "D",
    212    K: "E",
    213    L: "E",
    214    M: null,
    215    N: "M",
    216    O: "N",
    217  },
    218  expanded: new Set(),
    219 };
    220 
    221 /**
    222 * Frame
    223 */
    224 function checkFrameString({
    225  el,
    226  file,
    227  line,
    228  column,
    229  source,
    230  functionName,
    231  shouldLink,
    232  tooltip,
    233  locationPrefix,
    234 }) {
    235  const $ = selector => el.querySelector(selector);
    236 
    237  const $func = $(".frame-link-function-display-name");
    238  const $source = $(".frame-link-source");
    239  const $locationPrefix = $(".frame-link-prefix");
    240  const $filename = $(".frame-link-filename");
    241  const $line = $(".frame-link-line");
    242 
    243  is($filename.textContent, file, "Correct filename");
    244  is(
    245    el.getAttribute("data-line"),
    246    line ? `${line}` : null,
    247    "Expected `data-line` found"
    248  );
    249  is(
    250    el.getAttribute("data-column"),
    251    column ? `${column}` : null,
    252    "Expected `data-column` found"
    253  );
    254  is($source.getAttribute("title"), tooltip, "Correct tooltip");
    255  is($source.tagName, shouldLink ? "A" : "SPAN", "Correct linkable status");
    256  if (shouldLink) {
    257    is($source.getAttribute("href"), source, "Correct source");
    258  }
    259 
    260  if (line != null) {
    261    let lineText = `:${line}`;
    262    if (column != null) {
    263      lineText += `:${column}`;
    264    }
    265 
    266    is($line.textContent, lineText, "Correct line number");
    267  } else {
    268    ok(!$line, "Should not have an element for `line`");
    269  }
    270 
    271  if (functionName != null) {
    272    is($func.textContent, functionName, "Correct function name");
    273  } else {
    274    ok(!$func, "Should not have an element for `functionName`");
    275  }
    276 
    277  if (locationPrefix != null) {
    278    is($locationPrefix.textContent, locationPrefix, "Correct prefix");
    279  } else {
    280    ok(!$locationPrefix, "Should not have an element for `locationPrefix`");
    281  }
    282 }
    283 
    284 function checkSmartFrameString({ el, location, functionName, tooltip }) {
    285  const $ = selector => el.querySelector(selector);
    286 
    287  const $func = $(".title");
    288  const $location = $(".location");
    289 
    290  is($location.textContent, location, "Correct filename");
    291  is(el.getAttribute("title"), tooltip, "Correct tooltip");
    292  if (functionName != null) {
    293    is($func.textContent, functionName, "Correct function name");
    294  } else {
    295    ok(!$func, "Should not have an element for `functionName`");
    296  }
    297 }
    298 
    299 function renderComponent(component, props) {
    300  const el = React.createElement(component, props, {});
    301  // By default, renderIntoDocument() won't work for stateless components, but
    302  // it will work if the stateless component is wrapped in a stateful one.
    303  // See https://github.com/facebook/react/issues/4839
    304  const wrappedEl = dom.span({}, [el]);
    305  const renderedComponent = TestUtils.renderIntoDocument(wrappedEl);
    306  return ReactDOM.findDOMNode(renderedComponent).children[0];
    307 }
    308 
    309 /**
    310 * Creates a React Component for testing
    311 *
    312 * @param {string} factory - factory object of the component to be created
    313 * @param {object} props - React props for the component
    314 * @returns {object} - container Node, Object with React component
    315 * and querySelector function with $ as name.
    316 */
    317 async function createComponentTest(factory, props) {
    318  const container = document.createElement("div");
    319  document.body.appendChild(container);
    320 
    321  const component = ReactDOM.render(factory(props), container);
    322  await forceRender(component);
    323 
    324  return {
    325    container,
    326    component,
    327    $: s => container.querySelector(s),
    328    element: container.firstChild,
    329  };
    330 }
    331 
    332 async function waitFor(condition = () => true, delay = 50) {
    333  do {
    334    const res = condition();
    335    if (res) {
    336      return res;
    337    }
    338    await new Promise(resolve => setTimeout(resolve, delay));
    339  } while (true);
    340 }
    341 
    342 /**
    343 * Matches a component tree rendererd using TestRenderer to a given expected JSON
    344 * snapshot.
    345 *
    346 * @param  {string} name
    347 *         Name of the function derived from a test [step] name.
    348 * @param  {object} el
    349 *         React element to be rendered using TestRenderer.
    350 */
    351 function matchSnapshot(name, el) {
    352  if (!_snapshots) {
    353    is(false, "No snapshots were loaded into test.");
    354  }
    355 
    356  const snapshot = _snapshots[name];
    357  if (snapshot === undefined) {
    358    is(false, `Snapshot for "${name}" not found.`);
    359  }
    360 
    361  const renderer = TestRenderer.create(el, {});
    362  const tree = renderer.toJSON();
    363 
    364  is(
    365    JSON.stringify(tree, (key, value) =>
    366      typeof value === "function" ? value.toString() : value
    367    ),
    368    JSON.stringify(snapshot),
    369    name
    370  );
    371 }