tor-browser

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

test_input_number_key_events.html (7313B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <!--
      4 https://bugzilla.mozilla.org/show_bug.cgi?id=935506
      5 -->
      6 <head>
      7  <title>Test key events for number control</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  <meta charset="UTF-8">
     12 </head>
     13 <body>
     14 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=935506">Mozilla Bug 935506</a>
     15 <p id="display"></p>
     16 <div id="content">
     17  <input id="input" type="number">
     18 </div>
     19 <pre id="test">
     20 <script type="application/javascript">
     21 
     22 /**
     23 * Test for Bug 935506
     24 * This test checks how the value of <input type=number> changes in response to
     25 * key events while it is in various states.
     26 */
     27 SimpleTest.waitForExplicitFinish();
     28 SimpleTest.waitForFocus(function() {
     29  test();
     30  SimpleTest.finish();
     31 });
     32 const defaultMinimum = "NaN";
     33 const defaultMaximum = "NaN";
     34 const defaultStep = 1;
     35 
     36 // Helpers:
     37 // For the sake of simplicity, we do not currently support fractional value,
     38 // step, etc.
     39 
     40 function getMinimum(element) {
     41  return Number(element.min || defaultMinimum);
     42 }
     43 
     44 function getMaximum(element) {
     45  return Number(element.max || defaultMaximum);
     46 }
     47 
     48 function getDefaultValue(element) {
     49  return 0;
     50 }
     51 
     52 function getValue(element) {
     53  return Number(element.value || getDefaultValue(element));
     54 }
     55 
     56 function getStep(element) {
     57  if (element.step == "any") {
     58    return "any";
     59  }
     60  var step = Number(element.step || defaultStep);
     61  return step <= 0 ? defaultStep : step;
     62 }
     63 
     64 function getStepBase(element) {
     65  return Number(element.getAttribute("min") || "NaN") ||
     66         Number(element.getAttribute("value") || "NaN") || 0;
     67 }
     68 
     69 function hasStepMismatch(element) {
     70  var value = element.value;
     71  if (value == "") {
     72    value = 0;
     73  }
     74  var step = getStep(element);
     75  if (step == "any") {
     76    return false;
     77  }
     78  return ((value - getStepBase(element)) % step) != 0;
     79 }
     80 
     81 function floorModulo(x, y) {
     82  return (x - y * Math.floor(x / y));
     83 }
     84 
     85 function expectedValueAfterStepUpOrDown(stepFactor, element) {
     86  var value = getValue(element);
     87  if (isNaN(value)) {
     88    value = 0;
     89  }
     90  var step = getStep(element);
     91  if (step == "any") {
     92    step = 1;
     93  }
     94 
     95  var minimum = getMinimum(element);
     96  var maximum = getMaximum(element);
     97  if (!isNaN(maximum)) {
     98    // "max - (max - stepBase) % step" is the nearest valid value to max.
     99    maximum = maximum - floorModulo(maximum - getStepBase(element), step);
    100  }
    101 
    102  // Cases where we are clearly going in the wrong way.
    103  // We don't use ValidityState because we can be higher than the maximal
    104  // allowed value and still not suffer from range overflow in the case of
    105  // of the value specified in @max isn't in the step.
    106  if ((value <= minimum && stepFactor < 0) ||
    107      (value >= maximum && stepFactor > 0)) {
    108    return value;
    109  }
    110 
    111  if (hasStepMismatch(element) &&
    112      value != minimum && value != maximum) {
    113    if (stepFactor > 0) {
    114      value -= floorModulo(value - getStepBase(element), step);
    115    } else if (stepFactor < 0) {
    116      value -= floorModulo(value - getStepBase(element), step);
    117      value += step;
    118    }
    119  }
    120 
    121  value += step * stepFactor;
    122 
    123  // When stepUp() is called and the value is below minimum, we should clamp on
    124  // minimum unless stepUp() moves us higher than minimum.
    125  if (element.validity.rangeUnderflow && stepFactor > 0 &&
    126      value <= minimum) {
    127    value = minimum;
    128  } else if (element.validity.rangeOverflow && stepFactor < 0 &&
    129             value >= maximum) {
    130    value = maximum;
    131  } else if (stepFactor < 0 && !isNaN(minimum)) {
    132    value = Math.max(value, minimum);
    133  } else if (stepFactor > 0 && !isNaN(maximum)) {
    134    value = Math.min(value, maximum);
    135  }
    136 
    137  return value;
    138 }
    139 
    140 function expectedValAfterKeyEvent(key, element) {
    141  return expectedValueAfterStepUpOrDown(key == "KEY_ArrowUp" ? 1 : -1, element);
    142 }
    143 
    144 function test() {
    145  var elem = document.getElementById("input");
    146  elem.focus();
    147 
    148  elem.min = -5;
    149  elem.max = 5;
    150  elem.step = 2;
    151  var defaultValue = 0;
    152  var oldVal, expectedVal;
    153 
    154  for (key of ["KEY_ArrowUp", "KEY_ArrowDown"]) {
    155    // Start at middle:
    156    oldVal = elem.value = -1;
    157    expectedVal = expectedValAfterKeyEvent(key, elem);
    158    synthesizeKey(key);
    159    is(elem.value, String(expectedVal), "Test " + key + " for number control with value set between min/max (" + oldVal + ")");
    160 
    161    // Same again:
    162    expectedVal = expectedValAfterKeyEvent(key, elem);
    163    synthesizeKey(key);
    164    is(elem.value, String(expectedVal), "Test repeat of " + key + " for number control");
    165 
    166    // Start at maximum:
    167    oldVal = elem.value = elem.max;
    168    expectedVal = expectedValAfterKeyEvent(key, elem);
    169    synthesizeKey(key);
    170    is(elem.value, String(expectedVal), "Test " + key + " for number control with value set to the maximum (" + oldVal + ")");
    171 
    172    // Same again:
    173    expectedVal = expectedValAfterKeyEvent(key, elem);
    174    synthesizeKey(key);
    175    is(elem.value, String(expectedVal), "Test repeat of " + key + " for number control");
    176 
    177    // Start at minimum:
    178    oldVal = elem.value = elem.min;
    179    expectedVal = expectedValAfterKeyEvent(key, elem);
    180    synthesizeKey(key);
    181    is(elem.value, String(expectedVal), "Test " + key + " for number control with value set to the minimum (" + oldVal + ")");
    182 
    183    // Same again:
    184    expectedVal = expectedValAfterKeyEvent(key, elem);
    185    synthesizeKey(key);
    186    is(elem.value, String(expectedVal), "Test repeat of " + key + " for number control");
    187 
    188    // Test preventDefault():
    189    elem.addEventListener("keydown", evt => evt.preventDefault(), {once: true});
    190    oldVal = elem.value = 0;
    191    expectedVal = 0;
    192    synthesizeKey(key);
    193    is(elem.value, String(expectedVal), "Test " + key + " for number control where scripted preventDefault() should prevent the value changing");
    194 
    195    // Test step="any" behavior:
    196    var oldStep = elem.step;
    197    elem.step = "any";
    198    oldVal = elem.value = 0;
    199    expectedVal = expectedValAfterKeyEvent(key, elem);
    200    synthesizeKey(key);
    201    is(elem.value, String(expectedVal), "Test " + key + " for number control with value set to the midpoint and step='any' (" + oldVal + ")");
    202    elem.step = oldStep; // restore
    203 
    204    // Test that invalid input blocks UI initiated stepping:
    205    oldVal = elem.value = "";
    206    elem.select();
    207    sendString("abc");
    208    synthesizeKey(key);
    209    is(elem.value, "", "Test " + key + " does nothing when the input is invalid");
    210 
    211    // Test that no value does not block UI initiated stepping:
    212    oldVal = elem.value = "";
    213    elem.setAttribute("required", "required");
    214    elem.select();
    215    expectedVal = expectedValAfterKeyEvent(key, elem);
    216    synthesizeKey(key);
    217    is(elem.value, String(expectedVal), "Test " + key + " for number control with value set to the empty string and with the 'required' attribute set");
    218 
    219    // Same again:
    220    expectedVal = expectedValAfterKeyEvent(key, elem);
    221    synthesizeKey(key);
    222    is(elem.value, String(expectedVal), "Test repeat of " + key + " for number control");
    223 
    224    // Reset 'required' attribute:
    225    elem.removeAttribute("required");
    226  }
    227 
    228  // Test that key events are correctly dispatched
    229  elem.max = "";
    230  elem.value = "";
    231  sendString("7837281");
    232  is(elem.value, "7837281", "Test keypress event dispatch for number control");
    233 }
    234 
    235 </script>
    236 </pre>
    237 </body>
    238 </html>