tor-browser

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

test_general.html (8815B)


      1 <html>
      2 
      3 <head>
      4  <title>Text selection testing</title>
      5 
      6  <link rel="stylesheet" type="text/css"
      7        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
      8 
      9  <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
     10 
     11  <script type="application/javascript"
     12          src="../common.js"></script>
     13  <script type="application/javascript"
     14          src="../promisified-events.js"></script>
     15 
     16  <script type="application/javascript">
     17    /**
     18     * Helper function to test selection bounds.
     19     *
     20     * @param {string} aID  The ID to test.
     21     * @param {nsIAccessibleText} acc  The accessible to test.
     22     * @param {int} index  The selection's index to test.
     23     * @param {Array} offsets  The start and end offset to test against.
     24     * @param {string} msgStart  The start of the message to return in test
     25     *                           messages.
     26     */
     27    function testSelectionBounds(aID, acc, index, offsets, msgStart) {
     28      const [expectedStart, expectedEnd] = offsets;
     29      const startOffset = {}, endOffset = {};
     30      acc.getSelectionBounds(index, startOffset, endOffset);
     31 
     32      is(startOffset.value, Math.min(expectedStart, expectedEnd),
     33         msgStart + ": Wrong start offset for " + aID);
     34      is(endOffset.value, Math.max(expectedStart, expectedEnd),
     35         msgStart + ": Wrong end offset for " + aID);
     36    }
     37 
     38    /**
     39     * Test adding selections to accessibles.
     40     *
     41     * @param {string} aID  The ID of the element to test.
     42     * @param {Array} aSelections  Array of selection start and end indices.
     43     */
     44    async function addSelections(aID, aSelections) {
     45      info("Test adding selections to " + aID);
     46      const hyperText = getAccessible(aID, [ nsIAccessibleText ]);
     47      const initialSelectionCount = hyperText.selectionCount;
     48 
     49      // Multiple selection changes will be coalesced, so just listen for one.
     50      const selectionChange = waitForEvent(EVENT_TEXT_SELECTION_CHANGED, aID);
     51      for (let [startOffset, endOffset] of aSelections) {
     52        hyperText.addSelection(startOffset, endOffset);
     53      }
     54      await selectionChange;
     55 
     56      is(hyperText.selectionCount,
     57         aSelections.length + initialSelectionCount,
     58         "addSelection: Wrong selection count for " + aID);
     59 
     60      for (let i in aSelections) {
     61        testSelectionBounds(aID, hyperText, initialSelectionCount + i,
     62                            aSelections[i], "addSelection");
     63      }
     64 
     65      is(hyperText.caretOffset, aSelections[hyperText.selectionCount -1][1],
     66         "addSelection: caretOffset not at selection end for " + aID);
     67    }
     68 
     69    /**
     70     * Test changing selections in accessibles.
     71     *
     72     * @param {string} aID  The ID of the element to test.
     73     * @param {int} aIndex  The index of the selection to change.
     74     * @param {Array} aSelection  Array of the selection's new start and end
     75     *                            indices.
     76     */
     77    async function changeSelection(aID, aIndex, aSelection) {
     78      info("Test changing the selection of " + aID + " at index " + aIndex);
     79      const [startOffset, endOffset] = aSelection;
     80      const hyperText = getAccessible(aID, [ nsIAccessibleText ]);
     81 
     82      const selectionChanged = waitForEvent(EVENT_TEXT_SELECTION_CHANGED, aID);
     83      hyperText.setSelectionBounds(aIndex, startOffset, endOffset);
     84      await selectionChanged;
     85 
     86      testSelectionBounds(aID, hyperText, aIndex,
     87                          aSelection, "setSelectionBounds");
     88 
     89      is(hyperText.caretOffset, endOffset,
     90         "setSelectionBounds: caretOffset not at selection end for " + aID);
     91    }
     92 
     93    /**
     94     * Test removing all selections from accessibles.
     95     *
     96     * @param {string} aID  The ID of the element to test.
     97     */
     98    async function removeSelections(aID) {
     99      info("Testing removal of all selections from " + aID);
    100      const hyperText = getAccessible(aID, [ nsIAccessibleText ]);
    101 
    102      let selectionsRemoved = waitForEvent(EVENT_TEXT_SELECTION_CHANGED, document);
    103      const selectionCount = hyperText.selectionCount;
    104      for (let i = 0; i < selectionCount; i++) {
    105        hyperText.removeSelection(0);
    106      }
    107      await selectionsRemoved;
    108 
    109      is(hyperText.selectionCount, 0,
    110         "removeSelection: Wrong selection count for " + aID);
    111    }
    112 
    113    /**
    114     * Test that changing the DOM selection is reflected in the accessibles.
    115     *
    116     * @param {string} aID  The container ID to test in
    117     * @param {string} aNodeID1  The start node of the selection
    118     * @param  {int} aNodeOffset1  The offset where the selection should start
    119     * @param {string} aNodeID2  The node in which the selection should end
    120     * @param {int} aNodeOffset2  The index at which the selection should end
    121     * @param {Array} aTests  An array of accessibles and their start and end
    122     *                        offsets to test.
    123     */
    124    async function changeDOMSelection(aID, aNodeID1, aNodeOffset1,
    125                                      aNodeID2, aNodeOffset2,
    126                                      aTests) {
    127      info("Test that DOM selection changes are reflected in the accessibles");
    128 
    129      let selectionChanged = waitForEvent(EVENT_TEXT_SELECTION_CHANGED, aID);
    130      // HyperTextAccessible::GetSelectionDOMRanges ignores hidden selections.
    131      // Here we may be focusing an editable element (and thus hiding the
    132      // main document selection), so blur it so that we test what we want to
    133      // test.
    134      document.activeElement.blur();
    135 
    136      const sel = window.getSelection();
    137      const range = document.createRange();
    138      range.setStart(getNode(aNodeID1), aNodeOffset1);
    139      range.setEnd(getNode(aNodeID2), aNodeOffset2);
    140      sel.addRange(range);
    141      await selectionChanged;
    142 
    143      for (let i = 0; i < aTests.length; i++) {
    144        const text = getAccessible(aTests[i][0], nsIAccessibleText);
    145        is(text.selectionCount, 1,
    146           "setSelectionBounds: Wrong selection count for " + aID);
    147        testSelectionBounds(aID, text, 0, [aTests[i][1], aTests[i][2]],
    148                            "setSelectionBounds");
    149      }
    150    }
    151 
    152    /**
    153     * Test  expected and unexpected events for selecting
    154     * all text and focusing both an input and text area. We expect a caret
    155     * move, but not a text selection change.
    156     *
    157     * @param {string} aID  The ID of the element to test.
    158     */
    159    async function eventsForSelectingAllTextAndFocus(aID) {
    160      info("Test expected caretMove and unexpected textSelection events for " +aID);
    161      let events = waitForEvents({
    162        expected: [[EVENT_TEXT_CARET_MOVED, aID]],
    163        unexpected: [[EVENT_TEXT_SELECTION_CHANGED, aID]]}, aID);
    164      selectAllTextAndFocus(aID);
    165      await events;
    166    }
    167 
    168    /**
    169     * Do tests
    170     */
    171 
    172    async function doTests() {
    173      await addSelections("paragraph", [[1, 3], [6, 10]]);
    174      await changeSelection("paragraph", 0, [2, 4]);
    175      await removeSelections("paragraph");
    176 
    177      // reverse selection
    178      await addSelections("paragraph", [[1, 3], [10, 6]]);
    179      await removeSelections("paragraph");
    180 
    181      await eventsForSelectingAllTextAndFocus("textbox");
    182      await changeSelection("textbox", 0, [1, 3]);
    183 
    184      // reverse selection
    185      await changeSelection("textbox", 0, [3, 1]);
    186 
    187      await eventsForSelectingAllTextAndFocus("textarea");
    188      await changeSelection("textarea", 0, [1, 3]);
    189 
    190      // XXX Bug 1973154: Because the two spans don't occupy hyperText
    191      // characters, the only way to represent this selection is (c2, 2, 2).
    192      // Because that is a collapsed range, it gets removed by
    193      // HyperTextAccessibleBase::CroppedSelectionRanges, resulting in
    194      // accessibility incorrectly reporting no selection.
    195      await changeDOMSelection("c1", "c1_span1", 0, "c1_span2", 0,
    196                               []);
    197      await changeDOMSelection("c2", "c2", 0, "c2_div2", 1,
    198                               [["c2", 0, 3], ["c2_div2", 0, 2]]);
    199 
    200      SimpleTest.finish();
    201    }
    202 
    203    SimpleTest.waitForExplicitFinish();
    204    addA11yLoadEvent(doTests);
    205  </script>
    206 </head>
    207 
    208 <body>
    209 
    210  <a target="_blank"
    211     href="https://bugzilla.mozilla.org/show_bug.cgi?id=688126"
    212     title="nsIAccessibleText::setSelectionBounds doesn't fire text selection changed events in some cases">
    213    Bug 688126
    214  </a>
    215  <a target="_blank"
    216     href="https://bugzilla.mozilla.org/show_bug.cgi?id=688124"
    217     title="no text selection changed event when selection is removed">
    218    Bug 688124
    219  </a>
    220  <p id="display"></p>
    221  <div id="content" style="display: none"></div>
    222  <pre id="test">
    223  </pre>
    224 
    225  <p id="paragraph">hello world</p>
    226  <input id="textbox" value="hello"/>
    227  <textarea id="textarea">hello</textarea>
    228  <div id="c1">hi<span id="c1_span1"></span><span id="c1_span2"></span>hi</div>
    229  <div id="c2">hi<div id="c2_div2">hi</div></div>
    230 
    231 </body>
    232 </html>