tor-browser

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

test_input_event.html (18467B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <!--
      4 https://bugzilla.mozilla.org/show_bug.cgi?id=851780
      5 -->
      6 <head>
      7 <title>Test for input event</title>
      8 <script src="/tests/SimpleTest/SimpleTest.js"></script>
      9 <script src="/tests/SimpleTest/EventUtils.js"></script>
     10 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
     11 </head>
     12 <body>
     13 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=851780">Mozilla Bug 851780</a>
     14 <p id="display"></p>
     15 <div id="content"></div>
     16 <pre id="test">
     17 <script class="testbody" type="text/javascript">
     18 
     19  /** Test for input event. This is highly based on test_change_event.html */
     20 
     21  const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
     22 
     23  let expectedInputType = "";
     24  let expectedData = null;
     25  let expectedBeforeInputCancelable = false;
     26  function checkBeforeInputEvent(aEvent, aDescription) {
     27    ok(aEvent instanceof InputEvent,
     28       `"beforeinput" event should be dispatched with InputEvent interface ${aDescription}`);
     29    is(aEvent.inputType, expectedInputType,
     30       `inputType of "beforeinput" event should be "${expectedInputType}" ${aDescription}`);
     31    is(aEvent.data, expectedData,
     32       `data of "beforeinput" event should be ${expectedData} ${aDescription}`);
     33    is(aEvent.dataTransfer, null,
     34       `dataTransfer of "beforeinput" event should be null ${aDescription}`);
     35    is(aEvent.getTargetRanges().length, 0,
     36       `getTargetRanges() of "beforeinput" event should return empty array ${aDescription}`);
     37    is(aEvent.cancelable, expectedBeforeInputCancelable,
     38       `"beforeinput" event for "${expectedInputType}" should ${expectedBeforeInputCancelable ? "be" : "not be"} cancelable ${aDescription}`);
     39    is(aEvent.bubbles, true,
     40       `"beforeinput" event should always bubble ${aDescription}`);
     41  }
     42 
     43  let skipExpectedDataCheck = false;
     44  function checkIfInputIsInputEvent(aEvent, aDescription) {
     45    ok(aEvent instanceof InputEvent,
     46       `"input" event should be dispatched with InputEvent interface ${aDescription}`);
     47    is(aEvent.inputType, expectedInputType,
     48       `inputType should be "${expectedInputType}" ${aDescription}`);
     49    if (!skipExpectedDataCheck)
     50      is(aEvent.data, expectedData, `data should be ${expectedData} ${aDescription}`);
     51    else
     52      info(`data is ${aEvent.data} ${aDescription}`);
     53    is(aEvent.dataTransfer, null,
     54       `dataTransfer should be null ${aDescription}`);
     55    is(aEvent.cancelable, false,
     56       `"input" event should be never cancelable ${aDescription}`);
     57    is(aEvent.bubbles, true,
     58       `"input" event should always bubble ${aDescription}`);
     59  }
     60 
     61  function checkIfInputIsEvent(aEvent, aDescription) {
     62    ok(aEvent instanceof Event && !(aEvent instanceof UIEvent),
     63       `"input" event should be dispatched with InputEvent interface ${aDescription}`);
     64    is(aEvent.cancelable, false,
     65       `"input" event should be never cancelable ${aDescription}`);
     66    is(aEvent.bubbles, true,
     67       `"input" event should always bubble ${aDescription}`);
     68  }
     69 
     70  let textareaInput = 0, textareaBeforeInput = 0;
     71  let textTypes = ["text", "email", "search", "tel", "url", "password"];
     72  let textBeforeInput = [0, 0, 0, 0, 0, 0];
     73  let textInput = [0, 0, 0, 0, 0, 0];
     74  let nonTextTypes = ["button", "submit", "image", "reset", "radio", "checkbox"];
     75  let nonTextBeforeInput = [0, 0, 0, 0, 0, 0];
     76  let nonTextInput = [0, 0, 0, 0, 0, 0];
     77  let rangeInput = 0, rangeBeforeInput = 0;
     78  let numberInput = 0, numberBeforeInput = 0;
     79 
     80  // Don't create elements whose event listener attributes are required before enabling `beforeinput` event.
     81  function init() {
     82    document.getElementById("content").innerHTML =
     83    `<input type="file" id="fileInput">
     84     <textarea id="textarea"></textarea>
     85     <input type="text" id="input_text">
     86     <input type="email" id="input_email">
     87     <input type="search" id="input_search">
     88     <input type="tel" id="input_tel">
     89     <input type="url" id="input_url">
     90     <input type="password" id="input_password">
     91 
     92     <!-- "Non-text" inputs-->
     93     <input type="button" id="input_button">
     94     <input type="submit" id="input_submit">
     95     <input type="image" id="input_image">
     96     <input type="reset" id="input_reset">
     97     <input type="radio" id="input_radio">
     98     <input type="checkbox" id="input_checkbox">
     99     <input type="range" id="input_range">
    100     <input type="number" id="input_number">`;
    101 
    102    document.getElementById("textarea").addEventListener("beforeinput", (aEvent) => {
    103      ++textareaBeforeInput;
    104      checkBeforeInputEvent(aEvent, "on textarea element");
    105    });
    106    document.getElementById("textarea").addEventListener("input", (aEvent) => {
    107      ++textareaInput;
    108      checkIfInputIsInputEvent(aEvent, "on textarea element");
    109    });
    110 
    111    // These are the type were the input event apply.
    112    for (let id of ["input_text", "input_email", "input_search", "input_tel", "input_url", "input_password"]) {
    113      document.getElementById(id).addEventListener("beforeinput", (aEvent) => {
    114        ++textBeforeInput[textTypes.indexOf(aEvent.target.type)];
    115        checkBeforeInputEvent(aEvent, `on input element whose type is ${aEvent.target.type}`);
    116      });
    117      document.getElementById(id).addEventListener("input", (aEvent) => {
    118        ++textInput[textTypes.indexOf(aEvent.target.type)];
    119        checkIfInputIsInputEvent(aEvent, `on input element whose type is ${aEvent.target.type}`);
    120      });
    121    }
    122 
    123    // These are the type were the input event does not apply.
    124    for (let id of ["input_button", "input_submit", "input_image", "input_reset", "input_radio", "input_checkbox"]) {
    125      document.getElementById(id).addEventListener("beforeinput", (aEvent) => {
    126        ++nonTextBeforeInput[nonTextTypes.indexOf(aEvent.target.type)];
    127      });
    128      document.getElementById(id).addEventListener("input", (aEvent) => {
    129        ++nonTextInput[nonTextTypes.indexOf(aEvent.target.type)];
    130        checkIfInputIsEvent(aEvent, `on input element whose type is ${aEvent.target.type}`);
    131      });
    132    }
    133 
    134    document.getElementById("input_range").addEventListener("beforeinput", (aEvent) => {
    135      ++rangeBeforeInput;
    136    });
    137    document.getElementById("input_range").addEventListener("input", (aEvent) => {
    138      ++rangeInput;
    139      checkIfInputIsEvent(aEvent, "on input element whose type is range");
    140    });
    141 
    142    document.getElementById("input_number").addEventListener("beforeinput", (aEvent) => {
    143      ++numberBeforeInput;
    144    });
    145    document.getElementById("input_number").addEventListener("input", (aEvent) => {
    146      ++numberInput;
    147      checkIfInputIsInputEvent(aEvent, "on input element whose type is number");
    148    });
    149  }
    150 
    151  var MockFilePicker = SpecialPowers.MockFilePicker;
    152  MockFilePicker.init(SpecialPowers.wrap(window).browsingContext);
    153 
    154  function testUserInput() {
    155    // Simulating an OK click and with a file name return.
    156    MockFilePicker.useBlobFile();
    157    MockFilePicker.returnValue = MockFilePicker.returnOK;
    158    var input = document.getElementById('fileInput');
    159    input.focus();
    160 
    161    input.addEventListener("beforeinput", function (aEvent) {
    162      ok(false, "beforeinput event shouldn't be dispatched on file input.");
    163    });
    164    input.addEventListener("input", function (aEvent) {
    165      ok(true, "input event should've been dispatched on file input.");
    166      checkIfInputIsEvent(aEvent, "on file input");
    167    });
    168 
    169    input.click();
    170    SimpleTest.executeSoon(testUserInput2);
    171  }
    172 
    173  function testUserInput2() {
    174    // Some generic checks for types that support the input event.
    175    for (var i = 0; i < textTypes.length; ++i) {
    176      input = document.getElementById("input_" + textTypes[i]);
    177      input.focus();
    178      expectedInputType = "insertLineBreak";
    179      expectedData = null;
    180      expectedBeforeInputCancelable = true;
    181      synthesizeKey("KEY_Enter");
    182      is(textBeforeInput[i], 1, "beforeinput event should've been dispatched on " + textTypes[i] + " input element");
    183      is(textInput[i], 0, "input event shouldn't be dispatched on " + textTypes[i] + " input element");
    184 
    185      expectedInputType = "insertText";
    186      expectedData = "m";
    187      expectedBeforeInputCancelable = true;
    188      sendString("m");
    189      is(textBeforeInput[i], 2, textTypes[i] + " input element should've been dispatched beforeinput event.");
    190      is(textInput[i], 1, textTypes[i] + " input element should've been dispatched input event.");
    191      expectedInputType = "insertLineBreak";
    192      expectedData = null;
    193      expectedBeforeInputCancelable = true;
    194      synthesizeKey("KEY_Enter", {shiftKey: true});
    195      is(textBeforeInput[i], 3, "input event should've been dispatched on " + textTypes[i] + " input element");
    196      is(textInput[i], 1, "input event shouldn't be dispatched on " + textTypes[i] + " input element");
    197 
    198      expectedInputType = "deleteContentBackward";
    199      expectedData = null;
    200      expectedBeforeInputCancelable = true;
    201      synthesizeKey("KEY_Backspace");
    202      is(textBeforeInput[i], 4, textTypes[i] + " input element should've been dispatched beforeinput event.");
    203      is(textInput[i], 2, textTypes[i] + " input element should've been dispatched input event.");
    204    }
    205 
    206    // Some scenarios of value changing from script and from user input.
    207    input = document.getElementById("input_text");
    208    input.focus();
    209    expectedInputType = "insertText";
    210    expectedData = "f";
    211    expectedBeforeInputCancelable = true;
    212    sendString("f");
    213    is(textBeforeInput[0], 5, "beforeinput event should've been dispatched");
    214    is(textInput[0], 3, "input event should've been dispatched");
    215    input.blur();
    216    is(textBeforeInput[0], 5, "input event should not have been dispatched");
    217    is(textInput[0], 3, "input event should not have been dispatched");
    218 
    219    input.focus();
    220    input.value = 'foo';
    221    is(textBeforeInput[0], 5, "beforeinput event should not have been dispatched");
    222    is(textInput[0], 3, "input event should not have been dispatched");
    223    input.blur();
    224    is(textBeforeInput[0], 5, "beforeinput event should not have been dispatched");
    225    is(textInput[0], 3, "input event should not have been dispatched");
    226 
    227    input.focus();
    228    expectedInputType = "insertText";
    229    expectedData = "f";
    230    expectedBeforeInputCancelable = true;
    231    sendString("f");
    232    is(textBeforeInput[0], 6, "beforeinput event should've been dispatched");
    233    is(textInput[0], 4, "input event should've been dispatched");
    234    input.value = 'bar';
    235    is(textBeforeInput[0], 6, "beforeinput event should not have been dispatched");
    236    is(textInput[0], 4, "input event should not have been dispatched");
    237    input.blur();
    238    is(textBeforeInput[0], 6, "beforeinput event should not have been dispatched");
    239    is(textInput[0], 4, "input event should not have been dispatched");
    240 
    241    // Same for textarea.
    242    var textarea = document.getElementById("textarea");
    243    textarea.focus();
    244    expectedInputType = "insertText";
    245    expectedData = "f";
    246    expectedBeforeInputCancelable = true;
    247    sendString("f");
    248    is(textareaBeforeInput, 1, "beforeinput event should've been dispatched");
    249    is(textareaInput, 1, "input event should've been dispatched");
    250    textarea.blur();
    251    is(textareaBeforeInput, 1, "beforeinput event should not have been dispatched");
    252    is(textareaInput, 1, "input event should not have been dispatched");
    253 
    254    textarea.focus();
    255    textarea.value = 'foo';
    256    is(textareaBeforeInput, 1, "beforeinput event should not have been dispatched");
    257    is(textareaInput, 1, "input event should not have been dispatched");
    258    textarea.blur();
    259    is(textareaBeforeInput, 1, "beforeinput event should not have been dispatched");
    260    is(textareaInput, 1, "input event should not have been dispatched");
    261 
    262    textarea.focus();
    263    expectedInputType = "insertText";
    264    expectedData = "f";
    265    expectedBeforeInputCancelable = true;
    266    sendString("f");
    267    is(textareaBeforeInput, 2, "beforeinput event should've been dispatched");
    268    is(textareaInput, 2, "input event should've been dispatched");
    269    textarea.value = 'bar';
    270    is(textareaBeforeInput, 2, "beforeinput event should not have been dispatched");
    271    is(textareaInput, 2, "input event should not have been dispatched");
    272    expectedInputType = "deleteContentBackward";
    273    expectedData = null;
    274    expectedBeforeInputCancelable = true;
    275    synthesizeKey("KEY_Backspace");
    276    is(textareaBeforeInput, 3, "beforeinput event should've been dispatched");
    277    is(textareaInput, 3, "input event should've been dispatched");
    278    textarea.blur();
    279    is(textareaBeforeInput, 3, "beforeinput event should not have been dispatched");
    280    is(textareaInput, 3, "input event should not have been dispatched");
    281 
    282    // Non-text input tests:
    283    for (var i = 0; i < nonTextTypes.length; ++i) {
    284      // Button, submit, image and reset input type tests.
    285      if (i < 4) {
    286        input = document.getElementById("input_" + nonTextTypes[i]);
    287        input.focus();
    288        input.click();
    289        is(nonTextBeforeInput[i], 0, "beforeinput event doesn't apply");
    290        is(nonTextInput[i], 0, "input event doesn't apply");
    291        input.blur();
    292        is(nonTextBeforeInput[i], 0, "beforeinput event doesn't apply");
    293        is(nonTextInput[i], 0, "input event doesn't apply");
    294      }
    295      // For radio and checkboxes, input event should be dispatched.
    296      else {
    297        input = document.getElementById("input_" + nonTextTypes[i]);
    298        input.focus();
    299        input.click();
    300        is(nonTextBeforeInput[i], 0, "beforeinput event should not have been dispatched");
    301        is(nonTextInput[i], 1, "input event should've been dispatched");
    302        input.blur();
    303        is(nonTextBeforeInput[i], 0, "beforeinput event should not have been dispatched");
    304        is(nonTextInput[i], 1, "input event should not have been dispatched");
    305 
    306        // Test that input event is not dispatched if click event is cancelled.
    307        function preventDefault(e) {
    308          e.preventDefault();
    309        }
    310        input.addEventListener("click", preventDefault);
    311        input.click();
    312        is(nonTextBeforeInput[i], 0, "beforeinput event shouldn't be dispatched if click event is cancelled");
    313        is(nonTextInput[i], 1, "input event shouldn't be dispatched if click event is cancelled");
    314        input.removeEventListener("click", preventDefault);
    315      }
    316    }
    317 
    318    // Type changes.
    319    var input = document.createElement('input');
    320    input.type = 'text';
    321    input.value = 'foo';
    322    input.onbeforeinput = function () {
    323      ok(false, "we shouldn't get a beforeinput event when the type changes");
    324    };
    325    input.oninput = function() {
    326      ok(false, "we shouldn't get an input event when the type changes");
    327    };
    328    input.type = 'range';
    329    isnot(input.value, 'foo');
    330 
    331    // Tests for type='range'.
    332    var range = document.getElementById("input_range");
    333 
    334    range.focus();
    335    sendString("a");
    336    range.blur();
    337    is(rangeBeforeInput, 0, "beforeinput event shouldn't be dispatched on range input " +
    338                            "element for key changes that don't change its value");
    339    is(rangeInput, 0, "input event shouldn't be dispatched on range input " +
    340                      "element for key changes that don't change its value");
    341 
    342    range.focus();
    343    synthesizeKey("KEY_Home");
    344    is(rangeBeforeInput, 0, "beforeinput event shouldn't be dispatched even for key changes");
    345    is(rangeInput, 1, "input event should be dispatched for key changes");
    346    range.blur();
    347    is(rangeBeforeInput, 0, "beforeinput event shouldn't be dispatched on blur");
    348    is(rangeInput, 1, "input event shouldn't be dispatched on blur");
    349 
    350    range.focus();
    351    var bcr = range.getBoundingClientRect();
    352    var centerOfRangeX = bcr.width / 2;
    353    var centerOfRangeY = bcr.height / 2;
    354    synthesizeMouse(range, centerOfRangeX - 10, centerOfRangeY, { type: "mousedown" });
    355    is(rangeBeforeInput, 0, "beforeinput event shouldn't be dispatched on mousedown if the value changes");
    356    is(rangeInput, 2, "Input event should be dispatched on mousedown if the value changes");
    357    synthesizeMouse(range, centerOfRangeX - 5, centerOfRangeY, { type: "mousemove" });
    358    is(rangeBeforeInput, 0, "beforeinput event shouldn't be dispatched during a drag");
    359    is(rangeInput, 3, "Input event should be dispatched during a drag");
    360    synthesizeMouse(range, centerOfRangeX, centerOfRangeY, { type: "mouseup" });
    361    is(rangeBeforeInput, 0, "beforeinput event shouldn't be dispatched at the end of a drag");
    362    is(rangeInput, 4, "Input event should be dispatched at the end of a drag");
    363 
    364    // Tests for type='number'.
    365    // We only test key events here since input events for mouse event changes
    366    // are tested in test_input_number_mouse_events.html
    367    var number = document.getElementById("input_number");
    368 
    369    if (isDesktop) { // up/down arrow keys not supported on android
    370      number.value = "";
    371      number.focus();
    372      // <input type="number">'s inputType value hasn't been decided, see
    373      // https://github.com/w3c/input-events/issues/88
    374      expectedInputType = "insertReplacementText";
    375      expectedData = "1";
    376      expectedBeforeInputCancelable = false;
    377      synthesizeKey("KEY_ArrowUp");
    378      is(numberBeforeInput, 1, "beforeinput event should be dispatched for up/down arrow key keypress");
    379      is(numberInput, 1, "input event should be dispatched for up/down arrow key keypress");
    380      is(number.value, "1", "sanity check value of number control after keypress");
    381 
    382      // `data` will be the value of the input, but we can't change
    383      // `expectedData` and use {repeat: 3} at the same time.
    384      skipExpectedDataCheck = true;
    385      synthesizeKey("KEY_ArrowDown", {repeat: 3});
    386      is(numberBeforeInput, 4, "beforeinput event should be dispatched for each up/down arrow key keypress event, even when rapidly repeated");
    387      is(numberInput, 4, "input event should be dispatched for each up/down arrow key keypress event, even when rapidly repeated");
    388      is(number.value, "-2", "sanity check value of number control after multiple keydown events");
    389      skipExpectedDataCheck = false;
    390 
    391      number.blur();
    392      is(numberBeforeInput, 4, "beforeinput event shouldn't be dispatched on blur");
    393      is(numberInput, 4, "input event shouldn't be dispatched on blur");
    394    }
    395 
    396    MockFilePicker.cleanup();
    397    SimpleTest.finish();
    398  }
    399 
    400  SimpleTest.waitForExplicitFinish();
    401  document.addEventListener("DOMContentLoaded", () => {
    402    init();
    403    SimpleTest.waitForFocus(testUserInput);
    404  }, {once: true});
    405 
    406 </script>
    407 </pre>
    408 </body>
    409 </html>