tor-browser

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

helper_inplace_editor.js (6087B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 /* eslint no-unused-vars: [2, {"vars": "local", "args": "none"}] */
      4 /* import-globals-from head.js */
      5 
      6 "use strict";
      7 
      8 /**
      9 * Helper methods for the HTMLTooltip integration tests.
     10 */
     11 
     12 const HTML_NS = "http://www.w3.org/1999/xhtml";
     13 const {
     14  editableField,
     15 } = require("resource://devtools/client/shared/inplace-editor.js");
     16 const { colorUtils } = require("resource://devtools/shared/css/color.js");
     17 
     18 /**
     19 * Create an inplace editor linked to a span element and click on the span to
     20 * to turn to edit mode.
     21 *
     22 * @param {object} options
     23 *        Options passed to the InplaceEditor/editableField constructor.
     24 * @param {Document} doc
     25 *        Document where the span element will be created.
     26 * @param {string} textContent
     27 *        (optional) String that will be used as the text content of the span.
     28 */
     29 const createInplaceEditorAndClick = async function (options, doc, textContent) {
     30  const span = (options.element = createSpan(doc));
     31  if (textContent) {
     32    span.textContent = textContent;
     33  }
     34 
     35  info("Creating an inplace-editor field");
     36  editableField(options);
     37 
     38  info("Clicking on the inplace-editor field to turn to edit mode");
     39  span.click();
     40 };
     41 
     42 /**
     43 * Helper to create a span in the provided document.
     44 *
     45 * @param {Document} doc
     46 *        Document where the span element will be created.
     47 * @return {Element} the created span element.
     48 */
     49 function createSpan(doc) {
     50  info("Creating a new span element");
     51  const div = doc.createElementNS(HTML_NS, "div");
     52  const span = doc.createElementNS(HTML_NS, "span");
     53  span.setAttribute("tabindex", "0");
     54  span.style.fontSize = "11px";
     55  span.style.display = "inline-block";
     56  span.style.width = "100px";
     57  span.style.border = "1px solid red";
     58  span.style.fontFamily = "monospace";
     59 
     60  div.style.height = "100%";
     61  div.style.position = "absolute";
     62  div.appendChild(span);
     63 
     64  const parent = doc.querySelector("window") || doc.body;
     65  parent.appendChild(div);
     66  return span;
     67 }
     68 
     69 /**
     70 * Test helper simulating a key event in an InplaceEditor and checking that the
     71 * autocompletion works as expected.
     72 *
     73 * @param {Array} testData
     74 *        - {String|Object} key, the key to send. An object can be passed with a `key` property.
     75 *                          The other properties will be the options for the event (e.g. `shiftKey`)
     76 *        - {String} completion, the expected value of the auto-completion
     77 *        - {Number} index, the index of the selected suggestion in the popup
     78 *        - {Number|Array} items, the number of suggestions in the popup, or, alternatively
     79 *                         an array of the items label
     80 *        - {String} postLabel, the expected post label for the selected suggestion
     81 *        - {Boolean} colorSwatch, if there is a swatch of color expected to be visible
     82 *        - {Boolean} noSuggestion, true if the keypress doesn't trigger an "after-suggest" event
     83 * @param {InplaceEditor} editor
     84 *        The InplaceEditor instance being tested
     85 */
     86 async function testCompletion(
     87  [key, completion, index, items, postLabel, colorSwatch, noSuggestion],
     88  editor
     89 ) {
     90  let eventOptions = {};
     91  if (typeof key === "object") {
     92    ({ key, ...eventOptions } = key);
     93  }
     94 
     95  info(`Pressing key <${key}> | options: ${JSON.stringify(eventOptions)}`);
     96  info("Expecting " + completion);
     97 
     98  let onVisibilityChange = null;
     99  const total = Array.isArray(items) ? items.length : items;
    100  const open = total > 0;
    101  if (editor.popup.isOpen != open) {
    102    onVisibilityChange = editor.popup.once(
    103      open ? "popup-opened" : "popup-closed"
    104    );
    105  }
    106 
    107  let onSuggest;
    108  if (/(left|right|back_space|escape)/gi.test(key) || noSuggestion) {
    109    info("Waiting for next keypress event");
    110    onSuggest = once(editor.input, "keypress");
    111  } else {
    112    info("Waiting for after-suggest event on the editor");
    113    onSuggest = editor.once("after-suggest");
    114  }
    115 
    116  info("Synthesizing key " + key);
    117  EventUtils.synthesizeKey(key, eventOptions, editor.input.defaultView);
    118 
    119  await onSuggest;
    120  await onVisibilityChange;
    121  await waitForTime(5);
    122 
    123  info("Checking the state");
    124  if (completion !== null) {
    125    is(editor.input.value, completion, "Correct value is autocompleted");
    126  }
    127 
    128  if (postLabel) {
    129    const selectedItem = editor.popup.getItems()[index];
    130    const selectedElement = editor.popup.elements.get(selectedItem);
    131    ok(
    132      selectedElement.textContent.includes(postLabel),
    133      "Selected popup element contains the expected post-label"
    134    );
    135 
    136    // Determines if there is a color swatch attached to the label
    137    // and if the color swatch's background color matches the post label
    138    const swatchSpan = selectedElement.getElementsByClassName(
    139      "autocomplete-swatch autocomplete-colorswatch"
    140    );
    141    if (colorSwatch) {
    142      Assert.strictEqual(
    143        swatchSpan.length,
    144        1,
    145        "Displayed the expected color swatch"
    146      );
    147      const color = new colorUtils.CssColor(
    148        swatchSpan[0].style.backgroundColor
    149      );
    150      const swatchColor = color.rgba;
    151      const postColor = new colorUtils.CssColor(postLabel).rgba;
    152      Assert.equal(
    153        swatchColor,
    154        postColor,
    155        "Color swatch matches postLabel value"
    156      );
    157    } else {
    158      Assert.strictEqual(
    159        swatchSpan.length,
    160        0,
    161        "As expected no swatches were available"
    162      );
    163    }
    164  }
    165 
    166  if (total === 0) {
    167    ok(!(editor.popup && editor.popup.isOpen), "Popup is closed");
    168  } else {
    169    ok(editor.popup.isOpen, "Popup is open");
    170    const popupItems = editor.popup.getItems();
    171    if (Array.isArray(items)) {
    172      Assert.deepEqual(
    173        popupItems.map(item => item.label),
    174        items,
    175        "Suggestions match"
    176      );
    177    } else {
    178      is(
    179        popupItems.length,
    180        total,
    181        "Number of suggestions match" +
    182          (popupItems.length !== total
    183            ? ` - got ${JSON.stringify(popupItems.map(item => item.label))}`
    184            : "")
    185      );
    186    }
    187    is(editor.popup.selectedIndex, index, "Expected item is selected");
    188  }
    189 }