summaryrefslogtreecommitdiffstats
path: root/dom/html/test/forms/test_input_number_mouse_events.html
blob: 6d14eb22631af4fe2fe726f9b8d257a31fe90659 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=935501
-->
<head>
  <title>Test mouse events for number</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script src="/tests/SimpleTest/EventUtils.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    input {
      margin: 0;
      border: 0;
      padding: 0;
      width: 200px;
      box-sizing: border-box;
    }
  </style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=935501">Mozilla Bug 935501</a>
<p id="display"></p>
<div id="content">
  <input id="input" type="number">
</div>
<pre id="test">
<script>

/**
 * Test for Bug 935501
 * This test checks how the value of <input type=number> changes in response to
 * various mouse events.
 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
SimpleTest.waitForFocus(function() {
  test();
});

var input = document.getElementById("input");
var inputRect = input.getBoundingClientRect();

// Points over the input's spin-up and spin-down buttons (as offsets from the
// top-left of the input's bounding client rect):
const SPIN_UP_X = inputRect.width - 3;
const SPIN_UP_Y = 3;
const SPIN_DOWN_X = inputRect.width - 3;
const SPIN_DOWN_Y = inputRect.height - 3;

function checkInputEvent(aEvent, aDescription) {
  // Probably, key operation should fire "input" event with InputEvent interface.
  // See https://github.com/w3c/input-events/issues/88
  ok(aEvent instanceof InputEvent, `"input" event should be dispatched with InputEvent interface on input element whose type is number ${aDescription}`);
  is(aEvent.cancelable, false, `"input" event should be never cancelable on input element whose type is number ${aDescription}`);
  is(aEvent.bubbles, true, `"input" event should always bubble on input element whose type is number ${aDescription}`);
  info(`Data: ${aEvent.data}, value: ${aEvent.target.value}`);
}

function test() {
  input.value = 0;

  // Test click on spin-up button:
  synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousedown" });
  is(input.value, "1", "Test step-up on mousedown on spin-up button");
  synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mouseup" });
  is(input.value, "1", "Test mouseup on spin-up button");

  // Test click on spin-down button:
  synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousedown" });
  is(input.value, "0", "Test step-down on mousedown on spin-down button");
  synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mouseup" });
  is(input.value, "0", "Test mouseup on spin-down button");

  // Test clicks with modifiers that mean we should ignore the click:
  var modifiersIgnore = ["altGrKey", "fnKey", "osKey"];
  for (var modifier of modifiersIgnore) {
    input.value = 0;
    var eventParams = { type: "mousedown" };
    eventParams[modifier] = true;
    synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, eventParams);
    is(input.value, "0", "We should ignore mousedown on spin-up button with modifier " + modifier);
    synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mouseup" });
  }

  // Test clicks with modifiers that mean we should allow the click:
  var modifiersAllow = ["shiftKey", "ctrlKey", "altKey", "metaKey"];
  for (var modifier of modifiersAllow) {
    input.value = 0;
    var eventParams = { type: "mousedown" };
    eventParams[modifier] = true;
    synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, eventParams);
    is(input.value, "1", "We should allow mousedown on spin-up button with modifier " + modifier);
    synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mouseup" });
  }

  // Test step="any" behavior:
  input.value = 0;
  var oldStep = input.step;
  input.step = "any";
  synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousedown" });
  is(input.value, "1", "Test step-up on mousedown on spin-up button with step='any'");
  synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mouseup" });
  is(input.value, "1", "Test mouseup on spin-up button with step='any'");
  synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousedown" });
  is(input.value, "0", "Test step-down on mousedown on spin-down button with step='any'");
  synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mouseup" });
  is(input.value, "0", "Test mouseup on spin-down button with step='any'");
  input.step = oldStep; // restore

  // Test that preventDefault() works:
  function preventDefault(e) {
    e.preventDefault();
  }
  input.value = 1;
  input.addEventListener("mousedown", preventDefault);
  synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, {});
  is(input.value, "1", "Test that preventDefault() works for click on spin-up button");
  synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, {});
  is(input.value, "1", "Test that preventDefault() works for click on spin-down button");
  input.removeEventListener("mousedown", preventDefault);

  // Test for bug 1707070.
  input.style.paddingRight = "30px";
  input.getBoundingClientRect(); // flush layout

  input.value = 0;
  synthesizeMouse(input, SPIN_UP_X - 30, SPIN_UP_Y, { type: "mousedown" });
  is(input.value, "1", "Spinner down works on with padding (mousedown)");
  synthesizeMouse(input, SPIN_UP_X - 30, SPIN_UP_Y, { type: "mouseup" });
  is(input.value, "1", "Spinner down works with padding (mouseup)");

  synthesizeMouse(input, SPIN_DOWN_X - 30, SPIN_DOWN_Y, { type: "mousedown" });
  is(input.value, "0", "Spinner works with padding (mousedown)");
  synthesizeMouse(input, SPIN_DOWN_X - 30, SPIN_DOWN_Y, { type: "mouseup" });
  is(input.value, "0", "Spinner works with padding (mouseup)");

  input.style.paddingRight = "";
  input.getBoundingClientRect(); // flush layout

  // Run the spin tests:
  runNextSpinTest();
}

function runNextSpinTest() {
  var nextTest = spinTests.shift();
  if (!nextTest) {
    SimpleTest.finish();
    return;
  }
  nextTest();
}

function waitForTick() {
  return new Promise(SimpleTest.executeSoon);
}

const SETTIMEOUT_DELAY = 500;

var spinTests = [
  // Test spining when the mouse button is kept depressed on the spin-up
  // button, then moved over the spin-down button:
  function() {
    var inputEventCount = 0;
    input.value = 0;
    input.addEventListener("input", async function(evt) {
      ++inputEventCount;
      checkInputEvent(evt, "#1");
      if (inputEventCount == 3) {
        is(input.value, "3", "Testing spin-up button");
        await waitForTick();
        synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousemove" });
      } else if (inputEventCount == 6) {
        is(input.value, "0", "Testing spin direction is reversed after mouse moves from spin-up button to spin-down button");
        input.removeEventListener("input", arguments.callee);
        await waitForTick();
        synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mouseup" });
        runNextSpinTest();
      }
    });
    synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousedown" });
  },

  // Test spining when the mouse button is kept depressed on the spin-down
  // button, then moved over the spin-up button:
  function() {
    var inputEventCount = 0;
    input.value = 0;
    input.addEventListener("input", async function(evt) {
      ++inputEventCount;
      checkInputEvent(evt, "#2");
      if (inputEventCount == 3) {
        is(input.value, "-3", "Testing spin-down button");
        await waitForTick();
        synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousemove" });
      } else if (inputEventCount == 6) {
        is(input.value, "0", "Testing spin direction is reversed after mouse moves from spin-down button to spin-up button");
        input.removeEventListener("input", arguments.callee);
        await waitForTick();
        synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mouseup" });
        runNextSpinTest();
      }
    });
    synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousedown" });
  },

  // Test that the spin is stopped when the mouse button is depressod on the
  // spin-up button, then moved outside both buttons once the spin starts:
  function() {
    var inputEventCount = 0;
    input.value = 0;
    input.addEventListener("input", async function(evt) {
      ++inputEventCount;
      checkInputEvent(evt, "#3");
      if (inputEventCount == 3) {
        await waitForTick();
        synthesizeMouse(input, -1, -1, { type: "mousemove" });
        var eventHandler = arguments.callee;
        setTimeout(function() {
          is(input.value, "3", "Testing moving the mouse outside the spin buttons stops the spin");
          is(inputEventCount, 3, "Testing moving the mouse outside the spin buttons stops the spin input events");
          input.removeEventListener("input", eventHandler);
          synthesizeMouse(input, -1, -1, { type: "mouseup" });
          runNextSpinTest();
        }, SETTIMEOUT_DELAY);
      }
    });
    synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousedown" });
  },

  // Test that changing the input type in the middle of a spin cancels the spin:
  function() {
    var inputEventCount = 0;
    input.value = 0;
    input.addEventListener("input", function(evt) {
      ++inputEventCount;
      checkInputEvent(evt, "#4");
      if (inputEventCount == 3) {
        input.type = "text"
        var eventHandler = arguments.callee;
        setTimeout(function() {
          is(input.value, "-3", "Testing changing input type during a spin stops the spin");
          is(inputEventCount, 3, "Testing changing input type during a spin stops the spin input events");
          input.removeEventListener("input", eventHandler);
          synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mouseup" });
          input.type = "number"; // restore
          runNextSpinTest();
        }, SETTIMEOUT_DELAY);
      }
    });
    synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousedown" });
  }
];
</script>
</pre>
</body>
</html>