Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / widget / tests / window_wheeltransaction.xhtml
blobf3c081b105142b221dcfa2f638b2ae39e6794eb0
1 <?xml version="1.0"?>
2 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
3 <window title="Wheel scroll tests"
4 width="600" height="600"
5 onload="onload();"
6 onunload="onunload();"
7 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
9 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
10 <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
11 <script src="chrome://mochikit/content/tests/SimpleTest/paint_listener.js" />
13 <body xmlns="http://www.w3.org/1999/xhtml">
14 <style type="text/css">
15 #rootview {
16 overflow: auto;
17 width: 400px;
18 height: 400px;
19 border: 1px solid;
21 #container {
22 overflow: auto;
23 width: 600px;
24 height: 600px;
26 #rootview pre {
27 margin: 20px 0 20px 20px;
28 padding: 0;
29 overflow: auto;
30 display: block;
31 width: 100px;
32 height: 100.5px;
33 font-size: 16px;
35 </style>
36 <div id="rootview" onscroll="onScrollView(event);">
37 <div id="container">
38 <pre id="subview1" onscroll="onScrollView(event);">
39 Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
40 Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
41 Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
42 Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
43 Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
44 Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
45 Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
46 Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
47 Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
48 Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
49 </pre>
50 <pre id="subview2" onscroll="onScrollView(event);">
51 Text.
52 Text.
53 Text.
54 Text.
55 Text.
56 Text.
57 Text.
58 Text.
59 Text.
60 Text.
61 </pre>
62 <pre id="subview3" onscroll="onScrollView(event);">
63 Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
64 </pre>
65 </div>
66 </div>
67 <div id="content" style="display: none">
68 </div>
69 <pre id="test">
70 </pre>
71 </body>
73 <script class="testbody" type="application/javascript">
74 <![CDATA[
76 function ok(aCondition, aMessage)
78 window.arguments[0].SimpleTest.ok(aCondition, aMessage);
81 function is(aLeft, aRight, aMessage)
83 window.arguments[0].SimpleTest.is(aLeft, aRight, aMessage);
86 function isnot(aLeft, aRight, aMessage)
88 window.arguments[0].SimpleTest.isnot(aLeft, aRight, aMessage);
91 var gCurrentTestListStatus = { nextListIndex: 0 };
92 var gCurrentTest;
94 const kListenEvent_None = 0;
95 const kListenEvent_OnScroll = 1;
96 const kListenEvent_OnScrollFailed = 2;
97 const kListenEvent_OnTransactionTimeout = 4;
98 const kListenEvent_All = kListenEvent_OnScroll |
99 kListenEvent_OnScrollFailed |
100 kListenEvent_OnTransactionTimeout;
101 var gLitesnEvents = kListenEvent_None;
104 * At unexpected transaction timeout, we need to stop *all* timers. But it is
105 * difficult and it can be create more complex testing code. So, we should use
106 * only one timer at one time. For that, we must store the timer id to this
107 * variable. And the functions which may be called via a timer must clear the
108 * current timer by |_clearTimer| function.
110 var gTimer;
112 var gPrefSvc = SpecialPowers.Services.prefs;
113 const kPrefSmoothScroll = "general.smoothScroll";
114 const kPrefNameTimeout = "mousewheel.transaction.timeout";
115 const kPrefNameIgnoreMoveDelay = "mousewheel.transaction.ignoremovedelay";
116 const kPrefTestEventsAsyncEnabled = "test.events.async.enabled";
118 const kDefaultTimeout = gPrefSvc.getIntPref(kPrefNameTimeout);
119 const kDefaultIgnoreMoveDelay = gPrefSvc.getIntPref(kPrefNameIgnoreMoveDelay);
121 gPrefSvc.setBoolPref(kPrefSmoothScroll, false);
122 gPrefSvc.setBoolPref(kPrefTestEventsAsyncEnabled, true);
124 var gTimeout, gIgnoreMoveDelay;
125 var gEnoughForTimeout, gEnoughForIgnoreMoveDelay;
127 function setTimeoutPrefs(aTimeout, aIgnoreMoveDelay)
129 gPrefSvc.setIntPref(kPrefNameTimeout, aTimeout);
130 gPrefSvc.setIntPref(kPrefNameIgnoreMoveDelay, aIgnoreMoveDelay);
131 gTimeout = aTimeout;
132 gIgnoreMoveDelay = aIgnoreMoveDelay;
133 gEnoughForTimeout = gTimeout * 2;
134 gEnoughForIgnoreMoveDelay = gIgnoreMoveDelay * 1.2;
137 function resetTimeoutPrefs()
139 if (gTimeout == kDefaultTimeout)
140 return;
141 setTimeoutPrefs(kDefaultTimeout, kDefaultIgnoreMoveDelay);
142 initTestList();
145 function growUpTimeoutPrefs()
147 if (gTimeout != kDefaultTimeout)
148 return;
149 setTimeoutPrefs(5000, 1000);
150 initTestList();
153 // setting enough time for testing.
154 gPrefSvc.setIntPref(kPrefNameTimeout, gTimeout);
155 gPrefSvc.setIntPref(kPrefNameIgnoreMoveDelay, gIgnoreMoveDelay);
157 var gRootView = document.getElementById("rootview");
158 var gSubView1 = document.getElementById("subview1");
159 var gSubView2 = document.getElementById("subview2");
160 var gSubView3 = document.getElementById("subview3");
162 gRootView.addEventListener("MozMouseScrollFailed", onMouseScrollFailed);
163 gRootView.addEventListener("MozMouseScrollTransactionTimeout",
164 onTransactionTimeout);
166 function finish()
168 window.close();
171 async function onload()
173 // Before actually running tests, we disable auto-dir scrolling, becasue the
174 // tests in this file are meant to test scrolling transactions, not meant to
175 // test default actions for wheel events, so we simply disabled auto-dir
176 // scrolling, which are well tested in
177 // dom/events/test/window_wheel_default_action.html.
178 await SpecialPowers.pushPrefEnv({"set": [["mousewheel.autodir.enabled",
179 false]]});
181 runNextTestList();
184 function onunload()
186 resetTimeoutPrefs();
187 gPrefSvc.clearUserPref(kPrefSmoothScroll);
188 gPrefSvc.clearUserPref(kPrefTestEventsAsyncEnabled);
189 disableNonTestMouseEvents(false);
190 SpecialPowers.DOMWindowUtils.restoreNormalRefresh();
191 window.arguments[0].SimpleTest.finish();
194 function offsetForRootView()
196 let rootViewRect = gRootView.getBoundingClientRect();
197 let subView1Rect = gSubView1.getBoundingClientRect();
198 return {
199 x: (subView1Rect.left - rootViewRect.left) / 2,
200 y: (subView1Rect.top - rootViewRect.top) / 2,
204 function _offsetFor(aSubView)
206 let rootViewRect = gRootView.getBoundingClientRect();
207 let subViewRect = aSubView.getBoundingClientRect();
208 return {
209 x: subViewRect.left - rootViewRect.left + subViewRect.width / 2,
210 y: subViewRect.top - rootViewRect.top + subViewRect.height / 2,
214 function offsetForSubView1()
216 return _offsetFor(gSubView1);
219 function offsetForSubView2()
221 return _offsetFor(gSubView2);
224 function offsetForSubView3()
226 return _offsetFor(gSubView3);
230 * Define the tests here:
231 * Scrolls are processed async always. Therefore, we need to call all tests
232 * by timer. gTestLists is array of testing lists. In other words, an item
233 * of gTestList is a group of one or more testing. Each items has following
234 * properties:
236 * - retryWhenTransactionTimeout
237 * The testing of wheel transaction might be fialed randomly by
238 * timeout. Then, automatically the failed test list will be retested
239 * automatically only this number of times.
241 * - steps
242 * This property is array of testing. Each steps must have following
243 * properties at least.
245 * - func
246 * This property means function which will be called via
247 * |setTimeout|. The function cannot have params. If you need
248 * some additional parameters, you can specify some original
249 * properties for the test function. If you do so, you should
250 * document it in the testing function.
251 * - delay
252 * This property means delay time until the function to be called.
253 * I.e., the value used for the second param of |setTimeout|.
255 * And also you need one more property when you call a testing function.
257 * - description
258 * This property is description of the test. This is used for
259 * logging.
261 * At testing, you can access to current step via |gCurrentTest|.
264 var gTestLists;
265 function initTestList()
267 gTestLists = [
268 /**************************************************************************
269 * Continuous scrolling test for |gRootView|
270 * |gRootView| has both scrollbars and it has three children which are
271 * |gSubView1|, |gSubView2| and |gSubView3|. They have scrollbars. If
272 * the current transaction targets |gRootView|, other children should not
273 * be scrolled even if the wheel events are fired on them.
274 **************************************************************************/
275 { retryWhenTransactionTimeout: 5,
276 steps: [
277 // Vertical case
278 { func: initElements, delay: 0, forVertical: true,
279 description: "initElements" },
280 { func: clearWheelTransaction, delay: 0,
281 description: "clearWheelTransaction" },
282 // Vertical wheel events should scroll |gRootView| even if the position
283 // of wheel events in a child view which has scrollbar.
284 { func: testContinuousScroll, delay: 0, offset: offsetForRootView,
285 isForward: true, isVertical: true, expectedView: gRootView,
286 description: "Continuous scrolling test for root view (vertical/forward)" },
287 { func: testContinuousScroll, delay: 0, offset: offsetForRootView,
288 isForward: false, isVertical: true, expectedView: gRootView,
289 description: "Continuous scrolling test for root view (vertical/backward)" }
294 { retryWhenTransactionTimeout: 5,
295 steps: [
296 // Horizontal case
297 { func: initElements, delay: 0, forVertical: false,
298 description: "initElements" },
299 { func: clearWheelTransaction, delay: 0,
300 description: "clearWheelTransaction" },
301 // Horizontal wheel events should scroll |gRootView| even if the
302 // position of wheel events in a child view which has scrollbar.
303 { func: testContinuousScroll, delay: 0, offset: offsetForRootView,
304 isForward: true, isVertical: false, expectedView: gRootView,
305 description: "Continuous scrolling test for root view (horizontal/forward)" },
306 { func: testContinuousScroll, delay: 0, offset: offsetForRootView,
307 isForward: false, isVertical: false, expectedView: gRootView,
308 description: "Continuous scrolling test for root view (horizontal/backward)" }
313 /**************************************************************************
314 * Continuous scrolling test for |gSubView1|
315 * |gSubView1| has both scrollbars.
316 **************************************************************************/
317 { retryWhenTransactionTimeout: 5,
318 steps: [
319 // Vertical case
320 { func: initElements, delay: 0, forVertical: true,
321 description: "initElements" },
322 { func: clearWheelTransaction, delay: 0,
323 description: "clearWheelTransaction" },
324 // Vertical wheel events should scroll |gSubView1|.
325 { func: testContinuousScroll, delay: 0, offset: offsetForSubView1,
326 isForward: true, isVertical: true, expectedView: gSubView1,
327 description: "Continuous scrolling test for sub view 1 (vertical/forward)" },
328 { func: testContinuousScroll, delay: 0, offset: offsetForSubView1,
329 isForward: false, isVertical: true, expectedView: gSubView1,
330 description: "Continuous scrolling test for sub view 1 (vertical/backward)" }
335 { retryWhenTransactionTimeout: 5,
336 steps: [
337 // Horizontal case
338 { func: initElements, delay: 0, forVertical: false,
339 description: "initElements" },
340 { func: clearWheelTransaction, delay: 0,
341 description: "clearWheelTransaction" },
342 // Horitontal wheel events should scroll |gSubView1|.
343 { func: testContinuousScroll, delay: 0, offset: offsetForSubView1,
344 isForward: true, isVertical: false, expectedView: gSubView1,
345 description: "Continuous scrolling test for sub view 1 (horizontal/forward)" },
346 { func: testContinuousScroll, delay: 0, offset: offsetForSubView1,
347 isForward: false, isVertical: false, expectedView: gSubView1,
348 description: "Continuous scrolling test for sub view 1 (horizontal/backward)" }
353 /**************************************************************************
354 * Continuous scrolling test for |gSubView2|
355 * |gSubView2| has only vertical scrollbar.
356 **************************************************************************/
357 { retryWhenTransactionTimeout: 5,
358 steps: [
359 // Vertical case
360 { func: initElements, delay: 0, forVertical: true,
361 description: "initElements" },
362 { func: clearWheelTransaction, delay: 0,
363 description: "clearWheelTransaction" },
364 // Vertical wheel events should scroll |gSubView2|.
365 { func: testContinuousScroll, delay: 0, offset: offsetForSubView2,
366 isForward: true, isVertical: true, expectedView: gSubView2,
367 description: "Continuous scrolling test for sub view 2 (vertical/forward)" },
368 { func: testContinuousScroll, delay: 0, offset: offsetForSubView2,
369 isForward: false, isVertical: true, expectedView: gSubView2,
370 description: "Continuous scrolling test for sub view 2 (vertical/backward)" }
375 { retryWhenTransactionTimeout: 5,
376 steps: [
377 // Horizontal case
378 { func: initElements, delay: 0, forVertical: false,
379 description: "initElements" },
380 { func: clearWheelTransaction, delay: 0,
381 description: "clearWheelTransaction" },
382 // Horizontal wheel events should scroll its nearest scrollable ancestor
383 // view, i.e., it is |gRootView|.
384 { func: testContinuousScroll, delay: 0, offset: offsetForSubView2,
385 isForward: true, isVertical: false, expectedView: gRootView,
386 description: "Continuous scrolling test for sub view 2 (horizontal/forward)" },
387 { func: testContinuousScroll, delay: 0, offset: offsetForSubView2,
388 isForward: false, isVertical: false, expectedView: gRootView,
389 description: "Continuous scrolling test for sub view 2 (horizontal/backward)" }
394 /**************************************************************************
395 * Continuous scrolling test for |gSubView3|
396 * |gSubView3| has only horizontal scrollbar.
397 **************************************************************************/
398 { retryWhenTransactionTimeout: 5,
399 steps: [
400 // Vertical case
401 { func: initElements, delay: 0, forVertical: true,
402 description: "initElements" },
403 { func: clearWheelTransaction, delay: 0,
404 description: "clearWheelTransaction" },
405 // Vertical wheel events should scroll its nearest scrollable ancestor
406 // view, i.e., it is |gRootView|.
407 { func: testContinuousScroll, delay: 0, offset: offsetForSubView3,
408 isForward: true, isVertical: true, expectedView: gRootView,
409 description: "Continuous scrolling test for sub view 3 (vertical/forward)" },
410 { func: testContinuousScroll, delay: 0, offset: offsetForSubView3,
411 isForward: false, isVertical: true, expectedView: gRootView,
412 description: "Continuous scrolling test for sub view 3 (vertical/backward)" }
417 { retryWhenTransactionTimeout: 5,
418 steps: [
419 // Horizontal case
420 { func: initElements, delay: 0, forVertical: false,
421 description: "initElements" },
422 { func: clearWheelTransaction, delay: 0,
423 description: "clearWheelTransaction" },
424 // Horitontal wheel events should scroll |gSubView3|.
425 { func: testContinuousScroll, delay: 0, offset: offsetForSubView3,
426 isForward: true, isVertical: false, expectedView: gSubView3,
427 description: "Continuous scrolling test for sub view 3 (horizontal/forward)" },
428 { func: testContinuousScroll, delay: 0, offset: offsetForSubView3,
429 isForward: false, isVertical: false, expectedView: gSubView3,
430 description: "Continuous scrolling test for sub view 3 (horizontal/backward)" }
435 /**************************************************************************
436 * Don't reset transaction by a different direction wheel event
437 * Even if a wheel event doesn't same direction as last wheel event, the
438 * current transaction should not be reset.
439 **************************************************************************/
440 { retryWhenTransactionTimeout: 5,
441 steps: [
442 // Vertical -> Horizontal
443 { func: initElements, delay: 0, forVertical: true,
444 description: "initElements" },
445 { func: clearWheelTransaction, delay: 0,
446 description: "clearWheelTransaction" },
447 // Create a transaction which targets |gRootView| by a vertical wheel
448 // event.
449 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
450 isForward: true, isVertical: true, expectedView: gRootView,
451 description: "Don't reset transaction by a different direction wheel event (1-1)" },
452 // Scroll back to top-most for easy cursor position specifying.
453 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
454 isForward: false, isVertical: true, expectedView: gRootView,
455 description: "Don't reset transaction by a different direction wheel event (1-2)" },
456 // Send a horizontal wheel event over |gSubView1| but |gRootView| should
457 // be scrolled.
458 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
459 isForward: true, isVertical: false, expectedView: gRootView,
460 canFailRandomly: { possibleView: gSubView1 },
461 description: "Don't reset transaction by a different direction wheel event (1-3)" }
466 { retryWhenTransactionTimeout: 5,
467 steps: [
468 // Horizontal -> Vertical
469 { func: initElements, delay: 0, forVertical: false,
470 description: "initElements" },
471 { func: clearWheelTransaction, delay: 0,
472 description: "clearWheelTransaction" },
473 // Create a transaction which targets |gRootView| by a horizontal wheel
474 // event.
475 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
476 isForward: true, isVertical: false, expectedView: gRootView,
477 description: "Don't reset transaction by a different direction wheel event (2-1)" },
478 // Scroll back to left-most for easy cursor position specifying.
479 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
480 isForward: false, isVertical: false, expectedView: gRootView,
481 description: "Don't reset transaction by a different direction wheel event (2-2)" },
482 // Send a vertical wheel event over |gSubView1| but |gRootView| should
483 // be scrolled.
484 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
485 isForward: true, isVertical: true, expectedView: gRootView,
486 canFailRandomly: { possibleView: gSubView1 },
487 description: "Don't reset transaction by a different direction wheel event (2-3)" }
492 /**************************************************************************
493 * Don't reset transaction even if a wheel event cannot scroll
494 * Even if a wheel event cannot scroll to specified direction in the
495 * current target view, the transaction should not be reset. E.g., there
496 * are some devices which can scroll obliquely. If so, probably, users
497 * cannot input only intended direction.
498 **************************************************************************/
499 { retryWhenTransactionTimeout: 5,
500 steps: [
501 // A view only has vertical scrollbar case.
502 { func: initElements, delay: 0, forVertical: true,
503 description: "initElements" },
504 { func: clearWheelTransaction, delay: 0,
505 description: "clearWheelTransaction" },
506 // Create a transaction which targets |gSubView2|.
507 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView2,
508 isForward: true, isVertical: true, expectedView: gSubView2,
509 description: "Don't reset transaction even if a wheel event cannot scroll (1-1)" },
510 // |gSubView2| doesn't have horizontal scrollbar but should not scroll
511 // any views.
512 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView2,
513 isForward: true, isVertical: false, expectedView: null,
514 description: "Don't reset transaction even if a wheel event cannot scroll (1-2)" }
519 { retryWhenTransactionTimeout: 5,
520 steps: [
521 // A view only has horizontal scrollbar case.
522 { func: initElements, delay: 0, forVertical: true,
523 description: "initElements" },
524 { func: clearWheelTransaction, delay: 0,
525 description: "clearWheelTransaction" },
526 // Create a transaction which targets |gSubView3|.
527 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView3,
528 isForward: true, isVertical: false, expectedView: gSubView3,
529 description: "Don't reset transaction even if a wheel event cannot scroll (2-1)" },
530 // |gSubView3| doesn't have vertical scrollbar but should not scroll any
531 // views.
532 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView3,
533 isForward: true, isVertical: true, expectedView: null,
534 description: "Don't reset transaction even if a wheel event cannot scroll (2-2)" }
539 /**************************************************************************
540 * Reset transaction by mouse down/mouse up events
541 * Mouse down and mouse up events should cause resetting the current
542 * transaction.
543 **************************************************************************/
544 { retryWhenTransactionTimeout: 5,
545 steps: [
546 // Vertical case
547 { func: initElements, delay: 0, forVertical: true,
548 description: "initElements" },
549 { func: clearWheelTransaction, delay: 0,
550 description: "clearWheelTransaction" },
551 // Create a transaction which targets |gRootView|.
552 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
553 isForward: true, isVertical: true, expectedView: gRootView,
554 description: "Reset transaction by mouse down/mouse up events (v-1)" },
555 // Scroll back to top-most for easy cursor position specifying.
556 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
557 isForward: false, isVertical: true, expectedView: gRootView,
558 description: "Reset transaction by mouse down/mouse up events (v-2)" },
559 // Send mouse button events which should reset the current transaction.
560 // So, the next wheel event should scroll |gSubView1|.
561 { func: sendMouseButtonEvents, delay: 0,
562 description: "sendMouseButtonEvents" },
563 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
564 isForward: true, isVertical: true, expectedView: gSubView1,
565 description: "Reset transaction by mouse down/mouse up events (v-3)" }
570 { retryWhenTransactionTimeout: 5,
571 steps: [
572 // Horizontal case
573 { func: initElements, delay: 0, forVertical: false,
574 description: "initElements" },
575 { func: clearWheelTransaction, delay: 0,
576 description: "clearWheelTransaction" },
577 // Create a transaction which targets |gRootView|.
578 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
579 isForward: true, isVertical: false, expectedView: gRootView,
580 description: "Reset transaction by mouse down/mouse up events (h-1)" },
581 // Scroll back to left-most for easy cursor position specifying.
582 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
583 isForward: false, isVertical: false, expectedView: gRootView,
584 description: "Reset transaction by mouse down/mouse up events (h-2)" },
585 // Send mouse button events which should reset the current transaction.
586 // So, the next wheel event should scroll |gSubView1|.
587 { func: sendMouseButtonEvents, delay: 0,
588 description: "sendMouseButtonEvents" },
589 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
590 isForward: true, isVertical: false, expectedView: gSubView1,
591 description: "Reset transaction by mouse down/mouse up events (h-3)" }
596 /**************************************************************************
597 * Reset transaction by a key event
598 * A key event should cause resetting the current transaction.
599 **************************************************************************/
600 { retryWhenTransactionTimeout: 5,
601 steps: [
602 // Vertical case
603 { func: initElements, delay: 0, forVertical: true,
604 description: "initElements" },
605 { func: clearWheelTransaction, delay: 0,
606 description: "clearWheelTransaction" },
607 // Create a transaction which targets |gRootView|.
608 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
609 isForward: true, isVertical: true, expectedView: gRootView,
610 description: "Reset transaction by a key event (v-1)" },
611 // Scroll back to top-most for easy cursor position specifying.
612 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
613 isForward: false, isVertical: true, expectedView: gRootView,
614 description: "Reset transaction by a key event (v-2)" },
615 // Send a key event which should reset the current transaction. So, the
616 // next wheel event should scroll |gSubView1|.
617 { func: sendKeyEvents, delay: 0, key: "a",
618 description: "sendKeyEvents" },
619 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
620 isForward: true, isVertical: true, expectedView: gSubView1,
621 description: "Reset transaction by a key event (v-3)" }
626 { retryWhenTransactionTimeout: 5,
627 steps: [
628 // Horizontal case
629 { func: initElements, delay: 0, forVertical: false,
630 description: "initElements" },
631 { func: clearWheelTransaction, delay: 0,
632 description: "clearWheelTransaction" },
633 // Create a transaction which targets |gRootView|.
634 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
635 isForward: true, isVertical: false, expectedView: gRootView,
636 description: "Reset transaction by a key event (h-1)" },
637 // Scroll back to left-most for easy cursor position specifying.
638 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
639 isForward: false, isVertical: false, expectedView: gRootView,
640 description: "Reset transaction by a key event (h-2)" },
641 // Send a key event which should reset the current transaction. So, the
642 // next wheel event should scroll |gSubView1|.
643 { func: sendKeyEvents, delay: 0, key: "a",
644 description: "sendKeyEvents" },
645 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
646 isForward: true, isVertical: false, expectedView: gSubView1,
647 description: "Reset transaction by a key event (h-3)" }
652 /**************************************************************************
653 * Reset transaction by a mouse move event
654 * A mouse move event can cause reseting the current transaction even if
655 * mouse cursor is inside the target view of current transaction. Only
656 * when a wheel event is fired after |gIgnoreMoveDelay| milliseconds since
657 * the first mouse move event from last wheel event, the transaction
658 * should be reset.
659 **************************************************************************/
660 { retryWhenTransactionTimeout: 5,
661 steps: [
662 // Vertical case
663 { func: initElements, delay: 0, forVertical: true,
664 description: "initElements" },
665 { func: clearWheelTransaction, delay: 0,
666 description: "clearWheelTransaction" },
667 // Create a transaction which targets |gRootView|.
668 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
669 isForward: true, isVertical: true, expectedView: gRootView,
670 description: "Reset transaction by a mouse move event (v-1)" },
671 // Scroll back to top-most for easy cursor position specifying.
672 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
673 isForward: false, isVertical: true, expectedView: gRootView,
674 description: "Reset transaction by a mouse move event (v-2)" },
675 // Send a mouse move event immediately after last wheel event, then,
676 // current transaction should be kept.
677 { func: sendMouseMoveEvent, delay: 0, offset: offsetForSubView1,
678 description: "sendMouseMoveEvent" },
679 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
680 isForward: true, isVertical: true, expectedView: gRootView,
681 canFailRandomly: { possibleView: gSubView1 },
682 description: "Reset transaction by a mouse move event (v-3)" },
683 // Scroll back to top-most for easy cursor position specifying.
684 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
685 isForward: false, isVertical: true, expectedView: gRootView,
686 canFailRandomly: { possibleView: gSubView1 },
687 description: "Reset transaction by a mouse move event (v-4)" },
688 // Send a mouse move event after |gIgnoreMoveDelay| milliseconds since
689 // last wheel event, then, current transaction should be kept.
690 { func: sendMouseMoveEvent, delay: gEnoughForIgnoreMoveDelay,
691 offset: offsetForSubView1,
692 description: "sendMouseMoveEvent" },
693 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
694 isForward: true, isVertical: true, expectedView: gRootView,
695 canFailRandomly: { possibleView: gSubView1 },
696 description: "Reset transaction by a mouse move event (v-5)" },
697 // Scroll back to top-most for easy cursor position specifying.
698 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
699 isForward: false, isVertical: true, expectedView: gRootView,
700 canFailRandomly: { possibleView: gSubView1 },
701 description: "Reset transaction by a mouse move event (v-6)" },
702 // Send a wheel event after |gIgnoreMoveDelay| milliseconds since last
703 // mouse move event but it is fired immediately after the last wheel
704 // event, then, current transaction should be kept.
705 { func: sendMouseMoveEvent, delay: 0, offset: offsetForSubView1,
706 description: "sendMouseMoveEvent" },
707 { func: testOneTimeScroll, delay: gEnoughForIgnoreMoveDelay,
708 offset: offsetForSubView1,
709 isForward: true, isVertical: true, expectedView: gRootView,
710 canFailRandomly: { possibleView: gSubView1 },
711 description: "Reset transaction by a mouse move event (v-7)" },
712 // Scroll back to top-most for easy cursor position specifying.
713 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
714 isForward: false, isVertical: true, expectedView: gRootView,
715 canFailRandomly: { possibleView: gSubView1 },
716 description: "Reset transaction by a mouse move event (v-8)" },
717 // Send a wheel event after |gIgnoreMoveDelay| milliseconds have passed
718 // since last mouse move event which is fired after |gIgnoreMoveDelay|
719 // milliseconds since last wheel event, then, current transaction should
720 // be reset.
721 { func: sendMouseMoveEvent, delay: gEnoughForIgnoreMoveDelay,
722 offset: offsetForSubView1,
723 description: "sendMouseMoveEvent" },
724 { func: testOneTimeScroll, delay: gEnoughForIgnoreMoveDelay,
725 offset: offsetForSubView1,
726 isForward: true, isVertical: true, expectedView: gSubView1,
727 canFailRandomly: { possibleView: gRootView },
728 description: "Reset transaction by a mouse move event (v-9)" }
733 { retryWhenTransactionTimeout: 5,
734 steps: [
735 // Horizontal case
736 { func: initElements, delay: 0, forVertical: false,
737 description: "initElements" },
738 { func: clearWheelTransaction, delay: 0,
739 description: "clearWheelTransaction" },
740 // Create a transaction which targets |gRootView|.
741 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
742 isForward: true, isVertical: false, expectedView: gRootView,
743 canFailRandomly: { possibleView: gSubView1 },
744 description: "Reset transaction by a mouse move event (h-1)" },
745 // Scroll back to top-most for easy cursor position specifying.
746 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
747 isForward: false, isVertical: false, expectedView: gRootView,
748 canFailRandomly: { possibleView: gSubView1 },
749 description: "Reset transaction by a mouse move event (h-2)" },
750 // Send a mouse move event immediately after last wheel event, then,
751 // current transaction should be kept.
752 { func: sendMouseMoveEvent, delay: 0, offset: offsetForSubView1,
753 description: "sendMouseMoveEvent" },
754 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
755 isForward: true, isVertical: false, expectedView: gRootView,
756 canFailRandomly: { possibleView: gSubView1 },
757 description: "Reset transaction by a mouse move event (h-3)" },
758 // Scroll back to top-most for easy cursor position specifying.
759 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
760 isForward: false, isVertical: false, expectedView: gRootView,
761 canFailRandomly: { possibleView: gSubView1 },
762 description: "Reset transaction by a mouse move event (h-4)" },
763 // Send a mouse move event after |gIgnoreMoveDelay| milliseconds since
764 // last wheel event, then, current transaction should be kept.
765 { func: sendMouseMoveEvent, delay: gEnoughForIgnoreMoveDelay,
766 offset: offsetForSubView1,
767 description: "sendMouseMoveEvent" },
768 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
769 isForward: true, isVertical: false, expectedView: gRootView,
770 canFailRandomly: { possibleView: gSubView1 },
771 description: "Reset transaction by a mouse move event (h-5)" },
772 // Scroll back to top-most for easy cursor position specifying.
773 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
774 isForward: false, isVertical: false, expectedView: gRootView,
775 canFailRandomly: { possibleView: gSubView1 },
776 description: "Reset transaction by a mouse move event (h-6)" },
777 // Send a wheel event after |gIgnoreMoveDelay| milliseconds since last
778 // mouse move event but it is fired immediately after the last wheel
779 // event, then, current transaction should be kept.
780 { func: sendMouseMoveEvent, delay: 0, offset: offsetForSubView1,
781 description: "sendMouseMoveEvent" },
782 { func: testOneTimeScroll, delay: gEnoughForIgnoreMoveDelay,
783 offset: offsetForSubView1,
784 isForward: true, isVertical: false, expectedView: gRootView,
785 canFailRandomly: { possibleView: gSubView1 },
786 description: "Reset transaction by a mouse move event (h-7)" },
787 // Scroll back to top-most for easy cursor position specifying.
788 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
789 isForward: false, isVertical: false, expectedView: gRootView,
790 canFailRandomly: { possibleView: gSubView1 },
791 description: "Reset transaction by a mouse move event (h-8)" },
792 // Send a wheel event after |gIgnoreMoveDelay| milliseconds have passed
793 // since last mouse move event which is fired after |gIgnoreMoveDelay|
794 // milliseconds since last wheel event, then, current transaction should
795 // be reset.
796 { func: sendMouseMoveEvent, delay: gEnoughForIgnoreMoveDelay,
797 offset: offsetForSubView1,
798 description: "sendMouseMoveEvent" },
799 { func: testOneTimeScroll, delay: gEnoughForIgnoreMoveDelay,
800 offset: offsetForSubView1,
801 isForward: true, isVertical: false, expectedView: gSubView1,
802 canFailRandomly: { possibleView: gRootView },
803 description: "Reset transaction by a mouse move event (h-9)" }
808 /**************************************************************************
809 * Reset transaction by a mouse move event on outside of view
810 * When mouse cursor is moved to outside of the current target view, the
811 * transaction should be reset immediately.
812 **************************************************************************/
813 { retryWhenTransactionTimeout: 5,
814 steps: [
815 // Vertical case
816 { func: initElements, delay: 0, forVertical: true,
817 description: "initElements" },
818 { func: clearWheelTransaction, delay: 0,
819 description: "clearWheelTransaction" },
820 // Create a transaction which targets |gSubView1|.
821 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
822 isForward: true, isVertical: true, expectedView: gSubView1,
823 description: "Reset transaction by a mouse move event on outside of view (v-1)" },
824 // Send mouse move event over |gRootView|.
825 { func: sendMouseMoveEvent, delay: 0, offset: offsetForRootView,
826 description: "sendMouseMoveEvent" },
827 // Send Wheel event over |gRootView| which should be scrolled.
828 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
829 isForward: true, isVertical: true, expectedView: gRootView,
830 description: "Reset transaction by a mouse move event on outside of view (v-2)" }
835 { retryWhenTransactionTimeout: 5,
836 steps: [
837 // Horizontal case
838 { func: initElements, delay: 0, forVertical: false,
839 description: "initElements" },
840 { func: clearWheelTransaction, delay: 0,
841 description: "clearWheelTransaction" },
842 // Create a transaction which targets |gSubView1|.
843 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
844 isForward: true, isVertical: true, expectedView: gSubView1,
845 description: "Reset transaction by a mouse move event on outside of view (h-1)" },
846 // Send mouse move event over |gRootView|.
847 { func: sendMouseMoveEvent, delay: 0, offset: offsetForRootView,
848 description: "sendMouseMoveEvent" },
849 // Send Wheel event over |gRootView| which should be scrolled.
850 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
851 isForward: true, isVertical: true, expectedView: gRootView,
852 description: "Reset transaction by a mouse move event on outside of view (h-2)" }
857 /**************************************************************************
858 * Timeout test
859 * A view should not be scrolled during another to be transaction for
860 * another view scrolling. However, a wheel event which is sent after
861 * timeout, a view which is under the mouse cursor should be scrolled.
862 **************************************************************************/
863 { retryWhenTransactionTimeout: 5,
864 steps: [
865 // Vertical case
866 { func: initElements, delay: 0, forVertical: true,
867 description: "initElements" },
868 { func: clearWheelTransaction, delay: 0,
869 description: "clearWheelTransaction" },
870 // First, create a transaction which should target the |gRootView|.
871 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
872 isForward: true, isVertical: true, expectedView: gRootView,
873 description: "Timeout test (v-1)" },
874 // Scroll back to top-most for easy cursor position specifying.
875 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
876 isForward: false, isVertical: true, expectedView: gRootView,
877 description: "Timeout test (v-2)" },
878 // A wheel event over |gSubView1| should not scroll it during current
879 // transaction.
880 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
881 isForward: true, isVertical: true, expectedView: gRootView,
882 canFailRandomly: { possibleView: gSubView1 },
883 description: "Timeout test (v-3)" },
884 // Scroll back to top-most again.
885 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
886 isForward: false, isVertical: true, expectedView: gRootView,
887 canFailRandomly: { possibleView: gSubView1 },
888 description: "Timeout test (v-4)" },
889 // A wheel event over |gSubView1| after timeout should scroll
890 // |gSubView1|.
891 { func: testOneTimeScroll, delay: gEnoughForTimeout,
892 offset: offsetForSubView1,
893 isForward: true, isVertical: true, expectedView: gSubView1,
894 isTimeoutTesting: true,
895 description: "Timeout test (v-5)" }
900 { retryWhenTransactionTimeout: 5,
901 steps: [
902 // Horizontal case
903 { func: initElements, delay: 0, forVertical: false,
904 description: "initElements" },
905 { func: clearWheelTransaction, delay: 0,
906 description: "clearWheelTransaction" },
907 // First, create a transaction which should target the |gRootView|.
908 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
909 isForward: true, isVertical: false, expectedView: gRootView,
910 description: "Timeout test (h-1)" },
911 // Scroll back to left-most for easy cursor position specifying.
912 { func: testOneTimeScroll, delay: 0, offset: offsetForRootView,
913 isForward: false, isVertical: false, expectedView: gRootView,
914 description: "Timeout test (h-2)" },
915 // A wheel event over |gSubView1| should not scroll it during current
916 // transaction.
917 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
918 isForward: true, isVertical: false, expectedView: gRootView,
919 canFailRandomly: { possibleView: gSubView1 },
920 description: "Timeout test (h-3)" },
921 // Scroll back to left-most again.
922 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
923 isForward: false, isVertical: false, expectedView: gRootView,
924 canFailRandomly: { possibleView: gSubView1 },
925 description: "Timeout test (h-4)" },
926 // A wheel event over |gSubView1| after timeout should scroll
927 // |gSubView1|.
928 { func: testOneTimeScroll, delay: gEnoughForTimeout,
929 offset: offsetForSubView1,
930 isForward: true, isVertical: false, expectedView: gSubView1,
931 isTimeoutTesting: true,
932 description: "Timeout test (h-5)" }
937 /**************************************************************************
938 * Timeout test even with many wheel events
939 * This tests whether timeout is occurred event if wheel events are sent.
940 * The transaction should not be updated by non-scrollable wheel events.
941 **************************************************************************/
942 { retryWhenTransactionTimeout: 5,
943 steps: [
944 // Vertical case
945 { func: initElements, delay: 0, forVertical: true,
946 description: "initElements" },
947 { func: clearWheelTransaction, delay: 0,
948 description: "clearWheelTransaction" },
949 // Scroll |gSubView1| to bottom-most.
950 { func: testContinuousScroll, delay: 0, offset: offsetForSubView1,
951 isForward: true, isVertical: true, expectedView: gSubView1,
952 description: "Timeout test even with many wheel events (v-1)" },
953 // Don't scroll any views before timeout.
954 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
955 isForward: true, isVertical: true, expectedView: null,
956 canFailRandomly: { possibleView: gRootView },
957 description: "Timeout test even with many wheel events (v-2)" },
958 // Recreate a transaction which is scrolling |gRootView| after time out.
959 { func: testRestartScroll, delay: 0, offset: offsetForSubView1,
960 isForward: true, isVertical: true, expectedView: gRootView,
961 description: "Timeout test even with many wheel events (v-3)" }
966 { retryWhenTransactionTimeout: 5,
967 steps: [
968 // Horizontal case
969 { func: initElements, delay: 0, forVertical: false,
970 description: "initElements" },
971 { func: clearWheelTransaction, delay: 0,
972 description: "clearWheelTransaction" },
973 // Scroll |gSubView1| to right-most.
974 { func: testContinuousScroll, delay: 0, offset: offsetForSubView1,
975 isForward: true, isVertical: false, expectedView: gSubView1,
976 description: "Timeout test even with many wheel events (h-1)" },
977 // Don't scroll any views before timeout.
978 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
979 isForward: true, isVertical: false, expectedView: null,
980 canFailRandomly: { possibleView: gRootView },
981 description: "Timeout test even with many wheel events (h-2)" },
982 // Recreate a transaction which is scrolling |gRootView| after time out.
983 { func: testRestartScroll, delay: 0, offset: offsetForSubView1,
984 isForward: true, isVertical: false, expectedView: gRootView,
985 description: "Timeout test even with many wheel events (h-3)" }
990 /**************************************************************************
991 * Very large scrolling wheel event
992 * If the delta value is larger than the scrolling page size, it should be
993 * scrolled only one page instead of the delta value.
994 **************************************************************************/
995 { retryWhenTransactionTimeout: 5,
996 steps: [
997 { func: initElements, delay: 0, forVertical: true,
998 description: "initElements" },
999 { func: clearWheelTransaction, delay: 0,
1000 description: "clearWheelTransaction" },
1001 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
1002 isForward: true, isVertical: true, expectedView: gSubView1,
1003 delta: 5000,
1004 description: "Very large delta scrolling (v-1)" },
1005 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
1006 isForward: true, isVertical: true, expectedView: gSubView1,
1007 delta: 5000,
1008 description: "Very large delta scrolling (v-2)" },
1009 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
1010 isForward: true, isVertical: false, expectedView: gSubView1,
1011 delta: 5000,
1012 description: "Very large delta scrolling (h-1)" },
1013 { func: testOneTimeScroll, delay: 0, offset: offsetForSubView1,
1014 isForward: true, isVertical: false, expectedView: gSubView1,
1015 delta: 5000,
1016 description: "Very large delta scrolling (h-2)" }
1022 /******************************************************************************
1023 * Actions for preparing tests
1024 ******************************************************************************/
1026 function initElements()
1028 _clearTimer();
1030 function resetScrollPosition(aElement)
1032 aElement.scrollTop = 0;
1033 aElement.scrollLeft = 0;
1036 const kDisplay = gCurrentTest.forVertical ? "block" : "inline-block";
1037 gSubView1.style.display = kDisplay;
1038 gSubView2.style.display = kDisplay;
1039 gSubView3.style.display = kDisplay;
1041 resetScrollPosition(gRootView);
1042 resetScrollPosition(gSubView1);
1043 resetScrollPosition(gSubView2);
1044 resetScrollPosition(gSubView3);
1045 _getDOMWindowUtils(window).advanceTimeAndRefresh(0);
1047 runNextTestStep();
1050 function clearWheelTransaction()
1052 _clearTimer();
1053 _clearTransaction();
1054 runNextTestStep();
1057 function sendKeyEvents()
1059 _clearTimer();
1060 synthesizeKey(gCurrentTest.key, {}, window);
1061 runNextTestStep();
1064 function sendMouseButtonEvents()
1066 _clearTimer();
1067 synthesizeMouse(gRootView, -1, -1, { type:"mousedown" }, window);
1068 synthesizeMouse(gRootView, -1, -1, { type:"mouseup" }, window);
1069 runNextTestStep();
1072 function sendMouseMoveEvent()
1074 _clearTimer();
1075 _fireMouseMoveEvent(gCurrentTest.offset());
1076 runNextTestStep();
1079 /******************************************************************************
1080 * Utilities for testing functions
1081 ******************************************************************************/
1083 function _clearTransaction()
1085 synthesizeMouse(gRootView, -1, -1, { type:"mousedown" }, window);
1086 synthesizeMouse(gRootView, -1, -1, { type:"mouseup" }, window);
1089 function _saveScrollPositions()
1091 function save(aElement)
1093 aElement.prevTop = aElement.scrollTop;
1094 aElement.prevLeft = aElement.scrollLeft;
1096 save(gRootView);
1097 save(gSubView1);
1098 save(gSubView2);
1099 save(gSubView3);
1102 function _fireMouseMoveEvent(aOffset)
1104 synthesizeMouse(gRootView, aOffset.x, aOffset.y, { type:"mousemove" }, window);
1107 function _fireWheelScrollEvent(aOffset, aIsVertical, aForward, aDelta)
1109 var event = { deltaMode: WheelEvent.DOM_DELTA_LINE };
1110 if (aIsVertical) {
1111 event.deltaY = aForward ? aDelta : -aDelta;
1112 } else {
1113 event.deltaX = aForward ? aDelta : -aDelta;
1115 sendWheelAndPaint(gRootView, aOffset.x, aOffset.y, event, null, window);
1118 function _canScroll(aElement, aIsVertical, aForward)
1120 if (aIsVertical) {
1121 if (!aForward)
1122 return aElement.scrollTop > 0;
1123 return aElement.scrollHeight > aElement.scrollTop + aElement.clientHeight;
1125 if (!aForward)
1126 return aElement.scrollLeft > 0;
1127 return aElement.scrollWidth > aElement.scrollLeft + aElement.clientWidth;
1130 const kNotScrolled = 0;
1131 const kScrolledToTop = 1;
1132 const kScrolledToBottom = 2;
1133 const kScrolledToLeft = 4;
1134 const kScrolledToRight = 8;
1136 const kScrolledVertical = kScrolledToTop | kScrolledToBottom;
1137 const kScrolledHorizontal = kScrolledToLeft | kScrolledToRight;
1139 function _getScrolledState(aElement)
1141 var ret = kNotScrolled;
1142 if (aElement.scrollTop != aElement.prevTop) {
1143 ret |= aElement.scrollTop < aElement.prevTop ? kScrolledToTop :
1144 kScrolledToBottom;
1146 if (aElement.scrollLeft != aElement.prevLeft) {
1147 ret |= aElement.scrollLeft < aElement.prevLeft ? kScrolledToLeft :
1148 kScrolledToRight;
1150 return ret;
1153 function _getExpectedScrolledState()
1155 // eslint-disable-next-line no-nested-ternary
1156 return gCurrentTest.isVertical ?
1157 gCurrentTest.isForward ? kScrolledToBottom : kScrolledToTop :
1158 gCurrentTest.isForward ? kScrolledToRight : kScrolledToLeft;
1161 function _getScrolledStateText(aScrolledState)
1163 if (aScrolledState == kNotScrolled)
1164 return "Not scrolled";
1166 var s = "scrolled to ";
1167 if (aScrolledState & kScrolledVertical) {
1168 s += aScrolledState & kScrolledToTop ? "backward" : "forward";
1169 s += " (vertical)"
1170 if (aScrolledState & kScrolledHorizontal)
1171 s += " and to ";
1173 if (aScrolledState & kScrolledHorizontal) {
1174 s += aScrolledState & kScrolledToLeft ? "backward" : "forward";
1175 s += " (horizontal)"
1177 return s;
1180 function _getCurrentTestList()
1182 return gTestLists[gCurrentTestListStatus.nextListIndex - 1];
1185 function _clearTimer()
1187 clearTimeout(gTimer);
1188 gTimer = 0;
1191 /******************************************************************************
1192 * Testing functions
1193 ******************************************************************************/
1196 * Note that testing functions must set following variables:
1198 * gCurrentTest.repeatTest: See comment in |continueTest|.
1199 * gCurrentTest.autoRepeatDelay: See comment in |continueTest|.
1200 * gListenScrollEvent: When this is not true, the event handlers ignores the
1201 * events.
1204 function testContinuousScroll()
1207 * Testing continuous scrolling. This function synthesizes a wheel event. If
1208 * the test was success, this function will be recalled automatically.
1209 * And when a generating wheel event cannot scroll the expected view, this
1210 * function fires the wheel event only one time.
1212 * @param gCurrentTest.offset
1213 * A function to compute the cursor position of firing wheel event.
1214 * The values are offset from |gRootView|.
1215 * @param gCurrentTest.isVertical
1216 * Whether the wheel event is for virtical scrolling or horizontal.
1217 * @param gCurrentTest.isForward
1218 * Whether the wheel event is to forward or to backward.
1219 * @param gCurrentTest.expectedView
1220 * The expected view which will be scrolled by wheel event. This
1221 * value must not be null.
1224 _clearTimer();
1225 _saveScrollPositions();
1226 if (!gCurrentTest.expectedView) {
1227 runNextTestStep();
1228 return;
1231 gLitesnEvents = kListenEvent_All;
1232 gCurrentTest.repeatTest = true;
1233 gCurrentTest.autoRepeatDelay = 0;
1235 if (!_canScroll(gCurrentTest.expectedView,
1236 gCurrentTest.isVertical, gCurrentTest.isForward)) {
1237 gCurrentTest.expectedView = null;
1239 var delta = gCurrentTest.delta ? gCurrentTest.delta : 4;
1240 _fireWheelScrollEvent(gCurrentTest.offset(),
1241 gCurrentTest.isVertical, gCurrentTest.isForward, delta);
1244 function testOneTimeScroll()
1247 * Testing one wheel event. |runNextTestStep| will be called immediately
1248 * after this function by |onScrollView| or |onTimeout|.
1250 * @param gCurrentTest.offset
1251 * A function to compute the cursor position of firing wheel event.
1252 * The values are offset from |gRootView|.
1253 * @param gCurrentTest.isVertical
1254 * Whether the wheel event is for virtical scrolling or horizontal.
1255 * @param gCurrentTest.isForward
1256 * Whether the wheel event is to forward or to backward.
1257 * @param gCurrentTest.expectedView
1258 * The expected view which will be scrolled by wheel event. This
1259 * value can be null. It means any views should not be scrolled.
1262 _clearTimer();
1263 _saveScrollPositions();
1265 gLitesnEvents = kListenEvent_All;
1266 gCurrentTest.repeatTest = false;
1267 gCurrentTest.autoRepeatDelay = 0;
1269 var delta = gCurrentTest.delta ? gCurrentTest.delta : 4;
1270 _fireWheelScrollEvent(gCurrentTest.offset(),
1271 gCurrentTest.isVertical, gCurrentTest.isForward, delta);
1274 function testRestartScroll()
1277 * Testing restart to scroll in expected view after timeout from the current
1278 * transaction. This function recall this itself until to success this test
1279 * or timeout from this test.
1281 * @param gCurrentTest.offset
1282 * A function to compute the cursor position of firing wheel event.
1283 * The values are offset from |gRootView|.
1284 * @param gCurrentTest.isVertical
1285 * Whether the wheel event is for virtical scrolling or horizontal.
1286 * @param gCurrentTest.isForward
1287 * Whether the wheel event is to forward or to backward.
1288 * @param gCurrentTest.expectedView
1289 * The expected view which will be scrolled by wheel event. This
1290 * value must not be null.
1293 _clearTimer();
1294 _saveScrollPositions();
1296 if (!gCurrentTest.wasTransactionTimeout) {
1297 gCurrentTest.repeatTest = true;
1298 gCurrentTest.autoRepeatDelay = gTimeout / 3;
1299 gLitesnEvents = kListenEvent_All;
1300 gCurrentTest.isTimeoutTesting = true;
1301 if (gCurrentTest.expectedView) {
1302 gCurrentTest.expectedViewAfterTimeout = gCurrentTest.expectedView;
1303 gCurrentTest.expectedView = null;
1305 } else {
1306 gCurrentTest.repeatTest = false;
1307 gCurrentTest.autoRepeatDelay = 0;
1308 gLitesnEvents = kListenEvent_All;
1309 gCurrentTest.isTimeoutTesting = false;
1310 gCurrentTest.expectedView = gCurrentTest.expectedViewAfterTimeout;
1313 var delta = gCurrentTest.delta ? gCurrentTest.delta : 4;
1314 _fireWheelScrollEvent(gCurrentTest.offset(),
1315 gCurrentTest.isVertical, gCurrentTest.isForward, delta);
1318 /******************************************************************************
1319 * Event handlers
1320 ******************************************************************************/
1322 function onScrollView(aEvent)
1325 * Scroll event handler of |gRootView|, |gSubView1|, |gSubView2| and
1326 * |gSubView3|. If testing is failed, this function cancels all left tests.
1327 * For checking the event is expected, the event firer must call
1328 * |_saveScrollPositions|.
1330 * @param gCurrentTest.expectedView
1331 * The expected view which should be scrolled by the wheel event.
1332 * This value can be null. It means any views should not be
1333 * scrolled.
1334 * @param gCurrentTest.isVertical
1335 * The expected view should be scrolled vertical or horizontal.
1336 * @param gCurrentTest.isForward
1337 * The expected view should be scrolled to forward or backward.
1338 * @param gCurrentTest.canFailRandomly
1339 * If this is not undefined, this test can fail by unexpected view
1340 * scrolling which is caused by unexpected timeout. If this is
1341 * defined, |gCurrentTest.possibleView| must be set. If the view is
1342 * same as the event target, the failure can be random. At this
1343 * time, we should retry the current test list.
1346 if (!(gLitesnEvents & kListenEvent_OnScroll))
1347 return;
1349 // Now testing a timeout, but a view is scrolled before timeout.
1350 if (gCurrentTest.isTimeoutTesting && !gCurrentTest.wasTransactionTimeout) {
1351 is(aEvent.target.id, "",
1352 "The view scrolled before timeout (the expected view after timeout is " +
1353 gCurrentTest.expectedView ? gCurrentTest.expectedView.id : "null" +
1354 "): " + gCurrentTest.description);
1355 runNextTestList();
1356 return;
1359 // Check whether the scrolled event should be fired or not.
1360 if (!gCurrentTest.expectedView) {
1361 is(aEvent.target.id, "",
1362 "no views should be scrolled (" +
1363 _getScrolledStateText(_getScrolledState(aEvent.target)) + "): " +
1364 gCurrentTest.description);
1365 runNextTestList();
1366 return;
1369 // Check whether the scrolled view is expected or not.
1370 if (aEvent.target != gCurrentTest.expectedView) {
1371 // If current test can fail randomly and the possible view is same as the
1372 // event target, this failure may be caused by unexpected timeout.
1373 // At this time, we should retry the current tests with slower settings.
1374 if (gCurrentTest.canFailRandomly &&
1375 gCurrentTest.canFailRandomly.possibleView == aEvent.target &&
1376 gCurrentTestListStatus.retryWhenTransactionTimeout > 0) {
1377 gCurrentTestListStatus.retryWhenTransactionTimeout--;
1378 retryCurrentTestList();
1379 return;
1381 is(aEvent.target.id, gCurrentTest.expectedView.id,
1382 "wrong view was scrolled: " + gCurrentTest.description);
1383 runNextTestList();
1384 return;
1387 // Check whether the scrolling direction is expected or not.
1388 var expectedState = _getExpectedScrolledState();
1389 var currentState = _getScrolledState(aEvent.target);
1390 if (expectedState != currentState) {
1391 is(_getScrolledStateText(currentState),
1392 _getScrolledStateText(expectedState),
1393 "scrolled to wrong direction: " + gCurrentTest.description);
1394 runNextTestList();
1395 return;
1398 ok(true, "passed: " + gCurrentTest.description);
1399 continueTest();
1402 function onMouseScrollFailed()
1405 * Scroll failed event handler. If testing is failed, this function cancels
1406 * all remains of current test-list, and go to next test-list.
1408 * NOTE: This event is fired immediately after |_fireWheelScrollEvent|.
1410 * @param gCurrentTest.expectedView
1411 * The expected view which should be scrolled by the wheel event.
1412 * This value can be null. It means any views should not be
1413 * scrolled. When this is not null, this event means the test may
1414 * be failed.
1417 if (!(gLitesnEvents & kListenEvent_OnScrollFailed))
1418 return;
1420 ok(!gCurrentTest.expectedView,
1421 "failed to scroll on current target: " + gCurrentTest.description);
1422 if (gCurrentTest.expectedView) {
1423 runNextTestList();
1424 return;
1427 continueTest();
1430 function onTransactionTimeout()
1433 * Scroll transaction timeout event handler. If the timeout is unexpected,
1434 * i.e., |gCurrentTest.isTimeoutTesting| is not true, this function retry
1435 * the current test-list. However, if the current test-list failed by timeout
1436 * |gCurrentTestListStatus.retryWhenTransactionTimeout| times already, marking
1437 * to failed the current test-list, and go to next test-list.
1439 * @param gCurrentTest.expectedView
1440 * The expected view which should be scrolled by the wheel event.
1441 * This value can be null. It means any views should not be
1442 * scrolled. When this is not null, this event means the testing may
1443 * be failed.
1444 * @param gCurrentTest.isTimeoutTesting
1445 * If this value is true, the current testing have waited this
1446 * event. Otherwise, the testing may be failed.
1447 * @param gCurrentTestListStatus.retryWhenTransactionTimeout
1448 * If |gCurrentTest.isTimeoutTesting| is not true but this event is
1449 * fired, the failure may be randomly. Then, this event handler
1450 * retry to test the current test-list until this cound will be zero.
1453 if (!gCurrentTest.isTimeoutTesting &&
1454 gCurrentTestListStatus.retryWhenTransactionTimeout > 0) {
1455 gCurrentTestListStatus.retryWhenTransactionTimeout--;
1456 // retry current test list
1457 retryCurrentTestList();
1458 return;
1461 gCurrentTest.wasTransactionTimeout = true;
1463 if (!(gLitesnEvents & kListenEvent_OnTransactionTimeout))
1464 return;
1466 ok(gCurrentTest.isTimeoutTesting,
1467 "transaction timeout: " + gCurrentTest.description);
1468 if (!gCurrentTest.isTimeoutTesting) {
1469 runNextTestList();
1470 return;
1473 continueTest();
1476 /******************************************************************************
1477 * Main function for this tests
1478 ******************************************************************************/
1480 function runNextTestStep()
1482 // When this is first time or the current test list is finised, load next
1483 // test-list.
1484 _clearTimer();
1485 if (!gCurrentTest)
1486 runNextTestList();
1487 else
1488 runTestStepAt(gCurrentTestListStatus.nextStepIndex);
1491 function runNextTestList()
1493 _clearTimer();
1495 gLitesnEvents = kListenEvent_None;
1496 _clearTransaction();
1497 resetTimeoutPrefs();
1498 if (gCurrentTestListStatus.nextListIndex >= gTestLists.length) {
1499 finish();
1500 return;
1503 gCurrentTestListStatus.nextListIndex++;
1504 gCurrentTestListStatus.retryWhenTransactionTimeout =
1505 _getCurrentTestList().retryWhenTransactionTimeout;
1506 runTestStepAt(0);
1509 function runTestStepAt(aStepIndex)
1511 _clearTimer();
1513 disableNonTestMouseEvents(true);
1515 // load a step of testing.
1516 gCurrentTestListStatus.nextStepIndex = aStepIndex;
1517 gCurrentTest =
1518 _getCurrentTestList().steps[gCurrentTestListStatus.nextStepIndex++];
1519 if (gCurrentTest) {
1520 gCurrentTest.wasTransactionTimeout = false;
1521 gTimer = setTimeout(gCurrentTest.func, gCurrentTest.delay);
1522 } else {
1523 // If current test-list doesn't have more testing, go to next test-list
1524 // after cleaning up the current transaction.
1525 _clearTransaction();
1526 runNextTestList();
1530 function retryCurrentTestList()
1532 _clearTimer();
1534 gLitesnEvents = kListenEvent_None;
1535 _clearTransaction();
1536 ok(true, "WARNING: retry current test-list...");
1537 growUpTimeoutPrefs(); // retry the test with longer timeout settings.
1538 runTestStepAt(0);
1541 function continueTest()
1544 * This function is called from an event handler when a test succeeded.
1546 * @param gCurrentTest.repeatTest
1547 * When this is true, onScrollView calls |gCurrentTest.func|. So,
1548 * same test can repeat. Otherwise, this calls |runNextTestStep|.
1549 * @param gCurrentTest.autoRepeatDelay
1550 * The delay value in milliseconds, this is used to call
1551 * |gCurrentTest.func| via |setTimeout|.
1554 _clearTimer();
1555 gLitesnEvents = kListenEvent_OnTransactionTimeout;
1557 // We should call each functions via setTimeout. Because sometimes this test
1558 // is broken by stack overflow.
1559 if (gCurrentTest.repeatTest) {
1560 gTimer = setTimeout(gCurrentTest.func, gCurrentTest.autoRepeatDelay);
1561 } else {
1562 gTimer = setTimeout(runNextTestStep, 0);
1567 </script>
1569 </window>