tor-browser

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

frameSelectEvents.html (31742B)


      1 <!doctype html>
      2 <html>
      3  <head>
      4    <title>Testing Selection Events</title>
      5    <script src="/tests/SimpleTest/EventUtils.js"></script>
      6    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
      7  </head>
      8 
      9  <body>
     10    <div id="normal">
     11      <span id="inner">A bunch of text in a span inside of a div which should be selected</span>
     12    </div>
     13 
     14    <div id="ce">
     15      This is a random block of text
     16    </div>
     17 
     18    <input type="text" id="input" value="XXXXXXXXXXXXXXXXXXX" width="200"> <br>
     19 
     20    <textarea id="textarea" width="200">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</textarea>
     21 
     22    <script>
     23      // Call the testing methods from the parent window
     24      var is = parent.is;
     25      var ok = parent.ok;
     26 
     27      // spin() spins the event loop for two cycles, giving time for
     28      // selectionchange events to be fired, and handled by our listeners.
     29      function spin() {
     30        return new Promise(function(a) {
     31          parent.SimpleTest.executeSoon(function() {
     32            parent.SimpleTest.executeSoon(a)
     33          });
     34        });
     35      }
     36 
     37      /**
     38       * @param {Node} node
     39       */
     40      function isProperSelectionChangeTarget(node) {
     41        return node === document || node === input || node === textarea;
     42      }
     43 
     44      // The main test
     45      parent.add_task(async function() {
     46        await spin();
     47 
     48        var selectstart = 0;
     49        var selectionchange = 0;
     50        var inputSelectionchange = 0;
     51        var textareaSelectionchange = 0;
     52 
     53        var cancel = false;
     54        var selectstartTarget = null;
     55 
     56        async function UpdateSelectEventsOnTextControlsPref({ selectstart, selectionchange }) {
     57          await SpecialPowers.pushPrefEnv({
     58            'set': [
     59              ['dom.select_events.textcontrols.selectstart.enabled', !!selectstart],
     60              ['dom.select_events.textcontrols.selectionchange.enabled', !!selectionchange],
     61            ]
     62          });
     63        }
     64        await UpdateSelectEventsOnTextControlsPref({
     65          selectstart: false,
     66          selectionchange: false,
     67        });
     68 
     69        document.addEventListener('selectstart', function(aEvent) {
     70          console.log("originaltarget", aEvent.originalTarget, "new", selectstartTarget);
     71          is(aEvent.originalTarget, selectstartTarget,
     72             "The original target of selectstart");
     73          selectstartTarget = null;
     74 
     75          console.log(selectstart);
     76          selectstart++;
     77 
     78          if (cancel) {
     79            aEvent.preventDefault();
     80          }
     81        });
     82        document.addEventListener('selectionchange', function(aEvent) {
     83          ok(isProperSelectionChangeTarget(aEvent.target),
     84             "The target of selectionchange should be one of document, input, or textarea");
     85          console.log(selectionchange);
     86          selectionchange++;
     87        });
     88 
     89        function elt(aId) { return document.getElementById(aId); }
     90        function reset() {
     91          selectstart = 0;
     92          selectionchange = 0;
     93          inputSelectionchange = 0;
     94          textareaSelectionchange = 0;
     95          cancel = false;
     96        }
     97 
     98        elt("input").addEventListener('selectionchange', function(aEvent) {
     99          is (aEvent.originalTarget, elt("input"),
    100              "The original target of selectionchange should be the input");
    101          console.log(inputSelectionchange);
    102          inputSelectionchange++;
    103        });
    104        elt("textarea").addEventListener('selectionchange', function(aEvent) {
    105          is (aEvent.originalTarget, elt("textarea"),
    106              "The original target of selectionchange should be the textarea");
    107          console.log(textareaSelectionchange);
    108          textareaSelectionchange++;
    109        });
    110 
    111        function checkEventCounts(
    112          aTestDescription,
    113          aSituationDescription,
    114          aExpectedEventCounts
    115        ) {
    116          let {
    117            selectstartOnDocument = 0,
    118            selectionchangeOnDocument = 0,
    119            selectionchangeOnInput = 0,
    120            selectionchangeOnTextarea = 0,
    121          } = aExpectedEventCounts;
    122 
    123          is(
    124            selectstart,
    125            selectstartOnDocument,
    126            `${
    127              aTestDescription
    128            }: "selectstart" event on the document node should be fired ${
    129              selectstartOnDocument
    130            } times ${aSituationDescription}`
    131          );
    132          is(
    133            selectionchange,
    134            selectionchangeOnDocument,
    135            `${
    136              aTestDescription
    137            }: "selectionchange" event on the document node should be fired ${
    138              selectionchangeOnDocument
    139            } times ${aSituationDescription}`
    140          );
    141          is(
    142            inputSelectionchange,
    143            selectionchangeOnInput,
    144            `${
    145              aTestDescription
    146            }: "selectionchange" event on the <input> should be fired ${
    147              selectionchangeOnInput
    148            } times ${aSituationDescription}`
    149          );
    150          is(
    151            textareaSelectionchange,
    152            selectionchangeOnTextarea,
    153            `${
    154              aTestDescription
    155            }: "selectionchange" event on the <textarea> should be fired ${
    156              selectionchangeOnTextarea
    157            } times ${aSituationDescription}`
    158          );
    159        }
    160 
    161        async function testWithSynthesizingMouse(
    162          aDescription,
    163          aElement,
    164          aOffset,
    165          aType,
    166          aExpectedEventCounts
    167        ) {
    168          const eventObject = aType == "click" ? {} : { type: aType };
    169          if (aOffset.y === undefined || aOffset.y === null) {
    170            aOffset.y = 10;
    171          }
    172          synthesizeMouse(aElement, aOffset.x, aOffset.y, eventObject);
    173          await spin();
    174 
    175          checkEventCounts(
    176            aDescription,
    177            `after synthesizing ${aType} at ${aOffset.x}, ${aOffset.y}`,
    178            aExpectedEventCounts
    179          );
    180          reset();
    181        }
    182 
    183        async function testWithSynthesizingKey(
    184          aDescription,
    185          aKey,
    186          aEventObject,
    187          aExpectedEventCounts
    188        ) {
    189          synthesizeKey(aKey, aEventObject);
    190          await spin();
    191 
    192          checkEventCounts(
    193            aDescription,
    194            `after synthesizing a key press of "${aKey}"`,
    195            aExpectedEventCounts
    196          );
    197          reset();
    198        }
    199 
    200        async function testWithSettingContentEditableAttribute(
    201          aDescription,
    202          aElement,
    203          aContentEditableValue,
    204          aExpectedEventCounts
    205        ) {
    206          aElement.setAttribute("contenteditable",
    207                                aContentEditableValue ? "true" : "false");
    208          await spin();
    209 
    210          checkEventCounts(
    211            aDescription,
    212            `after setting contenteditable attribute to ${
    213              aElement.getAttribute("contenteditable")
    214            }`,
    215            aExpectedEventCounts
    216          );
    217          reset();
    218        }
    219 
    220        var selection = document.getSelection();
    221        function isCollapsed() {
    222          is(selection.isCollapsed, true, "Selection is collapsed");
    223        }
    224        function isNotCollapsed() {
    225          is(selection.isCollapsed, false, "Selection is not collapsed");
    226        }
    227 
    228        // Make sure setting the element to contentEditable doesn't cause any selectionchange events
    229        await testWithSettingContentEditableAttribute(
    230          "Setting contenteditable attribute to true of <div> should not change selection",
    231          elt("ce"),
    232          true,
    233          {}
    234        );
    235 
    236        // Make sure setting the element to not be contentEditable doesn't cause any selectionchange events
    237        await testWithSettingContentEditableAttribute(
    238          'Setting contenteditable attribute to false of <div contenteditable="true"> should not change selection',
    239          elt("ce"),
    240          false,
    241          {}
    242        );
    243 
    244        // Now make the div contentEditable and proceed with the test
    245        await testWithSettingContentEditableAttribute(
    246          'Setting contenteditable attribute to true of <div contenteditable="false"> should not change selection',
    247          elt("ce"),
    248          true,
    249          {}
    250        );
    251 
    252        // Focus the contenteditable text
    253        await testWithSynthesizingMouse(
    254          'Clicking in <div contenteditable="true"> should change selection',
    255          elt("ce"),
    256          { x: 100 },
    257          "click",
    258          { selectionchangeOnDocument: 1 }
    259        );
    260        isCollapsed();
    261 
    262        // Move the selection to the right, this should only fire selectstart once
    263        selectstartTarget = elt("ce").firstChild;
    264        await testWithSynthesizingKey(
    265          'Synthesizing Shift-ArrowRight to select a character in the text node of <div contenteditable="true"> should start to select again and change selection',
    266          "KEY_ArrowRight",
    267          { shiftKey: true },
    268          { selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
    269        );
    270        isNotCollapsed();
    271        await testWithSynthesizingKey(
    272          'Synthesizing Shift-ArrowRight again to select 2 characters in the text node of <div contenteditable="true"> should change selection',
    273          "KEY_ArrowRight",
    274          { shiftKey: true },
    275          { selectionchangeOnDocument: 1 }
    276        );
    277        isNotCollapsed();
    278 
    279        // Move it back so that the selection is empty again
    280        await testWithSynthesizingKey(
    281          'Synthesizing Shift-ArrowLeft to shrink selection in the text node of <div contenteditable="true"> should change selection',
    282          "KEY_ArrowLeft",
    283          { shiftKey: true },
    284          { selectionchangeOnDocument: 1 }
    285        );
    286        isNotCollapsed();
    287        await testWithSynthesizingKey(
    288          'Synthesizing Shift-ArrowLeft again to collapse selection in the text node of <div contenteditable="true"> should change selection',
    289          "KEY_ArrowLeft",
    290          { shiftKey: true },
    291          { selectionchangeOnDocument: 1 }
    292        );
    293        isCollapsed();
    294 
    295        // Going from empty to non-empty should fire selectstart again
    296        selectstartTarget = elt("ce").firstChild;
    297        await testWithSynthesizingKey(
    298          'Synthesizing Shift-ArrowLeft again to select a character on the other side in the text node of <div contenteditable="true"> should start to select and change selection',
    299          "KEY_ArrowLeft",
    300          { shiftKey: true },
    301          { selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
    302        );
    303        isNotCollapsed();
    304 
    305        async function testWithSynthesizingMouseDrag(
    306          aDescription,
    307          aElement,
    308          aSelectstartTarget
    309        ) {
    310          // Select a region
    311          await testWithSynthesizingMouse(
    312            `Pressing left mouse button ${
    313              aDescription
    314            } should not start to select but should change selection`,
    315            aElement,
    316            { x: 50 },
    317            "mousedown",
    318            { selectionchangeOnDocument: 1 }
    319          );
    320          isCollapsed();
    321 
    322          selectstartTarget = aSelectstartTarget;
    323          await testWithSynthesizingMouse(
    324            `Dragging mouse to right to extend selection ${
    325              aDescription
    326            } should start to select and change selection`,
    327            aElement,
    328            { x: 100 },
    329            "mousemove",
    330            { selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
    331          );
    332          isNotCollapsed();
    333 
    334          // Moving it more shouldn't trigger a start (move back to empty)
    335          await testWithSynthesizingMouse(
    336            `Dragging mouse to left to shrink selection ${
    337              aDescription
    338            } should change selection`,
    339            aElement,
    340            { x: 75 },
    341            "mousemove",
    342            { selectionchangeOnDocument: 1 }
    343          );
    344          isNotCollapsed();
    345          await testWithSynthesizingMouse(
    346            `Dragging mouse to left to collapse selection ${
    347              aDescription
    348            } should change selection`,
    349            aElement,
    350            { x: 50 },
    351            "mousemove",
    352            { selectionchangeOnDocument: 1 }
    353          );
    354          isCollapsed();
    355 
    356          // Wiggling the mouse a little such that it doesn't select any
    357          // characters shouldn't trigger a selection
    358          await testWithSynthesizingMouse(
    359            `Dragging mouse to bottom a bit ${
    360              aDescription
    361            } should not cause selection change`,
    362            aElement,
    363            { x: 50, y: 11 },
    364            "mousemove",
    365            {}
    366          );
    367          isCollapsed();
    368 
    369          // Moving the mouse again from an empty selection should trigger a
    370          // selectstart
    371          selectstartTarget = aSelectstartTarget;
    372          await testWithSynthesizingMouse(
    373            `Dragging mouse to left to extend selection ${
    374              aDescription
    375            } should start to select and change selection`,
    376            aElement,
    377            { x: 25 },
    378            "mousemove",
    379            { selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
    380          );
    381          isNotCollapsed();
    382 
    383          // Releasing the mouse shouldn't do anything
    384          await testWithSynthesizingMouse(
    385            `Releasing left mouse button to stop dragging ${
    386              aDescription
    387            } should not change selection`,
    388            aElement,
    389            { x: 25 },
    390            "mouseup",
    391            {}
    392          );
    393          isNotCollapsed();
    394 
    395          // And neither should moving your mouse around when the mouse
    396          // button isn't pressed
    397          await testWithSynthesizingMouse(
    398            `Just moving mouse to right ${
    399              aDescription
    400            } should not start to select nor change selection`,
    401            aElement,
    402            { x: 50 },
    403            "mousemove",
    404            {}
    405          );
    406          isNotCollapsed();
    407 
    408          // Clicking in an random location should move the selection, but not perform a
    409          // selectstart
    410          await testWithSynthesizingMouse(
    411            `Clicking to collapse selection ${
    412              aDescription
    413            } should cause only selection change`,
    414            aElement,
    415            { x: 50 },
    416            "click",
    417            { selectionchangeOnDocument: 1 }
    418          );
    419          isCollapsed();
    420 
    421          // Clicking there again should do nothing
    422          await testWithSynthesizingMouse(
    423            `Clicking same position again ${
    424              aDescription
    425            } should not change selection`,
    426            aElement,
    427            { x: 50 },
    428            "click",
    429            {}
    430          );
    431          isCollapsed();
    432 
    433          // Selecting a region, and canceling the selectstart should mean that the
    434          // selection remains collapsed
    435          await testWithSynthesizingMouse(
    436            `Pressing left mouse button on different character to move caret ${
    437              aDescription
    438            } should cause only selection change`,
    439            aElement,
    440            { x: 75 },
    441            "mousedown",
    442            { selectionchangeOnDocument: 1 }
    443          );
    444          isCollapsed();
    445          cancel = true;
    446          selectstartTarget = aSelectstartTarget;
    447          await testWithSynthesizingMouse(
    448            `Moving mouse to right to extend selection but selectstart event will be prevented default ${
    449              aDescription
    450            } should start to select and change selection`,
    451            aElement,
    452            { x: 100 },
    453            "mousemove",
    454            { selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
    455          );
    456          isCollapsed();
    457          await testWithSynthesizingMouse(
    458            `Releasing the left mouse button after dragging but selectstart was prevented the default ${
    459              aDescription
    460            } should not change selection`,
    461            aElement,
    462            { x: 100 },
    463            "mouseup",
    464            {}
    465          );
    466          isCollapsed();
    467        }
    468 
    469        // Should work both on normal
    470        await testWithSynthesizingMouseDrag(
    471          "on the text node in the non-editable <div>",
    472          elt("inner"),
    473          elt("inner").firstChild
    474        );
    475        // and contenteditable fields
    476        await testWithSynthesizingMouseDrag(
    477          'on the text node in the editable <div contenteditable="true">',
    478          elt("ce"),
    479          elt("ce").firstChild
    480        );
    481        // and fields with elements in them
    482        await testWithSynthesizingMouseDrag(
    483          "on the text node in the non-editable <div>'s child",
    484          elt("normal"),
    485          elt("inner").firstChild
    486        );
    487 
    488        await testWithSynthesizingMouse(
    489          "Clicking in the text node in the `<div>` should change selection",
    490          elt("inner"),
    491          { x: 50 },
    492          "click",
    493          { selectionchangeOnDocument: 1 }
    494        );
    495        isCollapsed();
    496 
    497        reset();
    498        // Select all should fire both selectstart and change
    499        selectstartTarget = document.body;
    500        await testWithSynthesizingKey(
    501          "Select All when no editor has focus should start to select and select all content",
    502          "a", { accelKey: true },
    503          { selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
    504        );
    505        isNotCollapsed();
    506 
    507        // Clear the selection
    508        await testWithSynthesizingMouse(
    509          "Clicking in the non-editable <div> should clear selection",
    510          elt("inner"),
    511          { x: 50 },
    512          "click",
    513          { selectionchangeOnDocument: 1 }
    514        );
    515        isCollapsed();
    516 
    517        // Even if we already have a selection
    518        await testWithSynthesizingMouse(
    519          "Pressing the left mouse button in non-editable <div> should change selection",
    520          elt("inner"),
    521          { x: 75 },
    522          "mousedown",
    523          { selectionchangeOnDocument: 1 }
    524        );
    525        isCollapsed();
    526        selectstartTarget = elt("inner").firstChild;
    527        await testWithSynthesizingMouse(
    528          "Dragging mouse to right to extend selection should start and change selection",
    529          elt("inner"),
    530          { x: 100 },
    531          "mousemove",
    532          { selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
    533        );
    534        isNotCollapsed();
    535        await testWithSynthesizingMouse(
    536          "Releasing the left mouse button should not change selection",
    537          elt("inner"),
    538          { x: 100 },
    539          "mouseup",
    540          {}
    541        );
    542        isNotCollapsed();
    543 
    544        selectstartTarget = document.body;
    545        await testWithSynthesizingKey(
    546          "Select All when no editor has focus should start to select and select all content (again)",
    547          "a",
    548          { accelKey: true },
    549          { selectstartOnDocument: 1, selectionchangeOnDocument: 1 }
    550        );
    551        isNotCollapsed();
    552 
    553        // Clear the selection
    554        await testWithSynthesizingMouse(
    555          "Clicking in the non-editable <div> should clear selection (again)",
    556          elt("inner"),
    557          { x: 50 },
    558          "click",
    559          {selectionchangeOnDocument: 1 }
    560        );
    561        isCollapsed();
    562 
    563        // Make sure that a synthesized selection change doesn't fire selectstart
    564        getSelection().removeAllRanges();
    565        await spin();
    566        is(
    567          selectstart,
    568          0,
    569          "Selection.removeAllRanges() should not cause selectstart event"
    570        );
    571        is(
    572          selectionchange,
    573          1,
    574          "Selection.removeAllRanges() should cause selectionchange event"
    575        );
    576        reset();
    577        isCollapsed();
    578 
    579        await (async function test_Selection_selectNode() {
    580          const range = document.createRange();
    581          range.selectNode(elt("inner"));
    582          getSelection().addRange(range);
    583          await spin();
    584          is(
    585            selectstart,
    586            0,
    587            "Selection.addRange() should not cause selectstart event"
    588          );
    589          is(
    590            selectionchange,
    591            1,
    592            "Selection.addRange() should cause selectionchange event"
    593          );
    594          reset();
    595          isNotCollapsed();
    596        })();
    597 
    598        // Change the range, without replacing
    599        await (async function test_Selection_getRangeAt_selectNode() {
    600          getSelection().getRangeAt(0).selectNode(elt("ce"));
    601          await spin();
    602          is(
    603            selectstart,
    604            0,
    605            "Selection.getRangeAt(0).selectNode() should not cause selectstart event"
    606          );
    607          is(
    608            selectionchange,
    609            1,
    610            "Selection.getRangeAt(0).selectNode() should cause selectionchange event"
    611          );
    612          reset();
    613          isNotCollapsed();
    614        })();
    615 
    616        // Remove the range
    617        getSelection().removeAllRanges();
    618        await spin();
    619        is(
    620          selectstart,
    621          0,
    622          "Selection.removeAllRanges() should not cause selectstart event (again)"
    623        );
    624        is(
    625          selectionchange,
    626          1,
    627          "Selection.removeAllRanges() should cause selectionchange event (again)"
    628        );
    629        reset();
    630        isCollapsed();
    631 
    632        for (const textControl of [elt("input"), elt("textarea")]) {
    633          await UpdateSelectEventsOnTextControlsPref({
    634            selectstart: false,
    635            selectionchange: false,
    636          });
    637 
    638          // Without the dom.select_events.textcontrols.enabled pref,
    639          // pressing the mouse shouldn't do anything.
    640          await testWithSynthesizingMouse(
    641            `Pressing the left mouse button in <${
    642                textControl.tagName.toLocaleLowerCase()
    643            }> should change selection of the document`,
    644            textControl,
    645            { x: 50 },
    646            "mousedown",
    647            {
    648              selectionchangeOnDocument: 1,
    649            }
    650          );
    651 
    652          // Releasing the mouse shouldn't do anything
    653          await testWithSynthesizingMouse(
    654            `Releasing the left mouse button in <${
    655                textControl.tagName.toLocaleLowerCase()
    656            }> should not change any selection`,
    657            textControl,
    658            { x: 50 },
    659            "mouseup",
    660            {}
    661          );
    662 
    663          for (const selectstart of [1, 0]) {
    664            await UpdateSelectEventsOnTextControlsPref({
    665              selectstart,
    666              selectionchange: true,
    667            });
    668 
    669            const selectstartEventSetting = `selectstart in text controls is ${
    670              selectstart ? "enabled" : "disabled"
    671            }`;
    672 
    673            const isInput = textControl.tagName.toLocaleLowerCase() == "input";
    674 
    675            await testWithSynthesizingMouse(
    676              `Pressing the left mouse button in <${
    677                textControl.tagName.toLocaleLowerCase()
    678              }> should change selection (${selectstartEventSetting})`,
    679              textControl,
    680              { x: 40 },
    681              "mousedown",
    682              {
    683                selectionchangeOnDocument: 1,
    684                selectionchangeOnInput: isInput ? 1 : 0,
    685                selectionchangeOnTextarea: isInput ? 0 : 1,
    686              }
    687            );
    688 
    689            selectstartTarget = textControl;
    690            await testWithSynthesizingMouse(
    691              `Dragging mouse to right to extend selection in <${
    692                textControl.tagName.toLocaleLowerCase()
    693              }> should start to select and change selection (${
    694                selectstartEventSetting
    695              })`,
    696              textControl,
    697              { x: 100 },
    698              "mousemove",
    699              {
    700                selectstartOnDocument: selectstart,
    701                selectionchangeOnDocument: 1,
    702                selectionchangeOnInput: isInput ? 1 : 0,
    703                selectionchangeOnTextarea: isInput ? 0 : 1,
    704              }
    705            );
    706 
    707            // Moving it more shouldn't trigger a start (move back to empty)
    708            await testWithSynthesizingMouse(
    709              `Dragging mouse to left to shrink selection in <${
    710                textControl.tagName.toLocaleLowerCase()
    711              }> should change selection (${selectstartEventSetting})`,
    712              textControl,
    713              { x: 75 },
    714              "mousemove",
    715              {
    716                selectionchangeOnDocument: 1,
    717                selectionchangeOnInput: isInput ? 1 : 0,
    718                selectionchangeOnTextarea: isInput ? 0 : 1,
    719              }
    720            );
    721            await testWithSynthesizingMouse(
    722              `Dragging mouse to left to collapse selection in <${
    723                textControl.tagName.toLocaleLowerCase()
    724              }> should change selection (${selectstartEventSetting})`,
    725              textControl,
    726              { x: 40 },
    727              "mousemove",
    728              {
    729                selectionchangeOnDocument: 1,
    730                selectionchangeOnInput: isInput ? 1 : 0,
    731                selectionchangeOnTextarea: isInput ? 0 : 1,
    732              }
    733            );
    734 
    735            // Wiggling the mouse a little such that it doesn't select any
    736            // characters shouldn't trigger a selection
    737            await testWithSynthesizingMouse(
    738              `Pressing the left mouse button at caret in <${
    739                textControl.tagName.toLocaleLowerCase()
    740              }> should not change selection (${selectstartEventSetting})`,
    741              textControl,
    742              {
    743                x: 40,
    744                y: 11,
    745              },
    746              "mousemove",
    747              {}
    748            );
    749 
    750            // Moving the mouse again from an empty selection should trigger a
    751            // selectstart
    752            selectstartTarget = textControl;
    753            await testWithSynthesizingMouse(
    754              `Dragging mouse to left to extend selection in <${
    755                textControl.tagName.toLocaleLowerCase()
    756              }> should start to select and change selection (${
    757                selectstartEventSetting
    758              })`,
    759              textControl,
    760              { x: 25 },
    761              "mousemove",
    762              {
    763                selectstartOnDocument: selectstart,
    764                selectionchangeOnDocument: 1,
    765                selectionchangeOnInput: isInput ? 1 : 0,
    766                selectionchangeOnTextarea: isInput ? 0 : 1,
    767              }
    768            );
    769 
    770            // Releasing the mouse shouldn't do anything
    771            await testWithSynthesizingMouse(
    772              `Releasing the left mouse button in <${
    773                textControl.tagName.toLocaleLowerCase()
    774              }> should not change selection (${selectstartEventSetting})`,
    775              textControl,
    776              { x: 25 },
    777              "mouseup",
    778              {}
    779            );
    780 
    781            // And neither should moving your mouse around when the mouse
    782            // button isn't pressed
    783            await testWithSynthesizingMouse(
    784              `Just moving mouse to right in <${
    785                textControl.tagName.toLocaleLowerCase()
    786              }> should not start to select nor change selection (${
    787                selectstartEventSetting
    788              })`,
    789              textControl,
    790              { x: 50 },
    791              "mousemove",
    792              {}
    793            );
    794 
    795            // Clicking in an random location should move the selection, but
    796            // not perform a selectstart
    797            await testWithSynthesizingMouse(
    798              `Clicking in <${
    799                textControl.tagName.toLocaleLowerCase()
    800              }> should change selection, but should not start selection (${
    801                selectstartEventSetting
    802              })`,
    803              textControl,
    804              { x: 50 },
    805              "click",
    806              {
    807                selectionchangeOnDocument: 1,
    808                selectionchangeOnInput: isInput ? 1 : 0,
    809                selectionchangeOnTextarea: isInput ? 0 : 1,
    810              }
    811            );
    812 
    813            // Clicking there again should do nothing
    814            await testWithSynthesizingMouse(
    815              `Clicking at caret in <${
    816                textControl.tagName.toLocaleLowerCase()
    817              }> should not change selection (${selectstartEventSetting})`,
    818              textControl,
    819              { x: 50 },
    820              "click",
    821              {}
    822            );
    823 
    824            // Selecting a region, and canceling the selectstart should mean that the
    825            // selection remains collapsed
    826            await testWithSynthesizingMouse(
    827              `Pressing the left mouse button at different character in <${
    828                textControl.tagName.toLocaleLowerCase()
    829              }> should change selection (${selectstartEventSetting})`,
    830              textControl,
    831              { x: 75 },
    832              "mousedown",
    833              {
    834                selectionchangeOnDocument: 1,
    835                selectionchangeOnInput: isInput ? 1 : 0,
    836                selectionchangeOnTextarea: isInput ? 0 : 1,
    837              }
    838            );
    839            cancel = true;
    840            selectstartTarget = textControl;
    841            await testWithSynthesizingMouse(
    842              `Dragging mouse to right to extend selection in <${
    843                textControl.tagName.toLocaleLowerCase()
    844              }> but the default of selectstart is prevented should cause selectstart and selectionchange events (${
    845                selectstartEventSetting
    846              })`,
    847              textControl,
    848              { x: 100 },
    849              "mousemove",
    850              {
    851                selectstartOnDocument: selectstart,
    852                selectionchangeOnDocument: 1,
    853                selectionchangeOnInput: isInput ? 1 : 0,
    854                selectionchangeOnTextarea: isInput ? 0 : 1,
    855              }
    856            );
    857            await testWithSynthesizingMouse(
    858              `Releasing the left mouse button in <${
    859                textControl.tagName.toLocaleLowerCase()
    860              }> should not cause changing selection (${selectstartEventSetting})`,
    861              textControl,
    862              { x: 100 },
    863              "mouseup",
    864              {}
    865            );
    866          }
    867        }
    868 
    869        // Marking the input and textarea as display: none and then as visible again
    870        // shouldn't trigger any changes, although the nodes will be re-framed
    871        for (const textControl of [elt("input"), elt("textarea")]) {
    872          await (async function test_set_display_of_text_control_to_none() {
    873            textControl.setAttribute("style", "display: none;");
    874            await spin();
    875            checkEventCounts(
    876              `Setting display of <${
    877                textControl.tagName.toLocaleLowerCase()
    878              }> to none`,
    879              "",
    880              {}
    881            );
    882            reset();
    883          })();
    884 
    885          await (async function test_remove_display_none_of_text_control() {
    886            textControl.setAttribute("style", "");
    887            await spin();
    888            checkEventCounts(
    889              `Removing display:none of <${
    890                textControl.tagName.toLocaleLowerCase()
    891              }>`,
    892              "",
    893              {}
    894            );
    895            reset();
    896          })();
    897        }
    898 
    899        // When selection is at the end of contentEditable's content,
    900        // clearing the content should trigger selection events.
    901        await (async function test_removing_contenteditable() {
    902          const savedContent = elt("ce").innerHTML;
    903          document.getSelection().setBaseAndExtent(elt("ce"), 1, elt("ce"), 1);
    904          await spin();
    905          reset();
    906 
    907          elt("ce").firstChild.remove();
    908          await spin();
    909          checkEventCounts(
    910            'Removing <div contenteditable="true"> from the DOM tree',
    911            "",
    912            { selectionchangeOnDocument: 1 }
    913          );
    914 
    915          elt("ce").innerHTML = savedContent;
    916          await spin();
    917          reset();
    918        })();
    919      });
    920    </script>
    921  </body>
    922 </html>