widget/tests/window_wheeltransaction.xul

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/tests/window_wheeltransaction.xul	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1551 @@
     1.4 +<?xml version="1.0"?>
     1.5 +<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
     1.6 +<window title="Wheel scroll tests"
     1.7 +  width="600" height="600"
     1.8 +  onload="onload();"
     1.9 +  onunload="onunload();"
    1.10 +  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    1.11 +
    1.12 +  <script type="application/javascript"
    1.13 +          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
    1.14 +
    1.15 +<body xmlns="http://www.w3.org/1999/xhtml">
    1.16 +<style type="text/css">
    1.17 +  #rootview {
    1.18 +    overflow: auto;
    1.19 +    width: 400px;
    1.20 +    height: 400px;
    1.21 +    border: 1px solid;
    1.22 +  }
    1.23 +  #container {
    1.24 +    overflow: auto;
    1.25 +    width: 600px;
    1.26 +    height: 600px;
    1.27 +  }
    1.28 +  #rootview pre {
    1.29 +    margin: 20px 0 20px 20px;
    1.30 +    padding: 0;
    1.31 +    overflow: auto;
    1.32 +    display: block;
    1.33 +    width: 100px;
    1.34 +    height: 100.5px;
    1.35 +    font-size: 16px;
    1.36 +  }
    1.37 +</style>
    1.38 +<div id="rootview" onscroll="onScrollView(event);">
    1.39 +  <div id="container">
    1.40 +    <pre id="subview1" onscroll="onScrollView(event);">
    1.41 +Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
    1.42 +Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
    1.43 +Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
    1.44 +Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
    1.45 +Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
    1.46 +Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
    1.47 +Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
    1.48 +Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
    1.49 +Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
    1.50 +Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
    1.51 +    </pre>
    1.52 +    <pre id="subview2" onscroll="onScrollView(event);">
    1.53 +Text.
    1.54 +Text.
    1.55 +Text.
    1.56 +Text.
    1.57 +Text.
    1.58 +Text.
    1.59 +Text.
    1.60 +Text.
    1.61 +Text.
    1.62 +Text.
    1.63 +    </pre>
    1.64 +    <pre id="subview3" onscroll="onScrollView(event);">
    1.65 +Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
    1.66 +    </pre>
    1.67 +  </div>
    1.68 +</div>
    1.69 +<div id="content" style="display: none">
    1.70 +</div>
    1.71 +<pre id="test">
    1.72 +</pre>
    1.73 +</body>
    1.74 +
    1.75 +<script class="testbody" type="application/javascript">
    1.76 +<![CDATA[
    1.77 +
    1.78 +function ok(aCondition, aMessage)
    1.79 +{
    1.80 +  window.opener.wrappedJSObject.SimpleTest.ok(aCondition, aMessage);
    1.81 +}
    1.82 +
    1.83 +function is(aLeft, aRight, aMessage)
    1.84 +{
    1.85 +  window.opener.wrappedJSObject.SimpleTest.is(aLeft, aRight, aMessage);
    1.86 +}
    1.87 +
    1.88 +function isnot(aLeft, aRight, aMessage)
    1.89 +{
    1.90 +  window.opener.wrappedJSObject.SimpleTest.isnot(aLeft, aRight, aMessage);
    1.91 +}
    1.92 +
    1.93 +var gCurrentTestListStatus = { nextListIndex: 0 };
    1.94 +var gCurrentTest;
    1.95 +
    1.96 +const kListenEvent_None                 = 0;
    1.97 +const kListenEvent_OnScroll             = 1;
    1.98 +const kListenEvent_OnScrollFailed       = 2;
    1.99 +const kListenEvent_OnTransactionTimeout = 4;
   1.100 +const kListenEvent_All = kListenEvent_OnScroll |
   1.101 +                         kListenEvent_OnScrollFailed |
   1.102 +                         kListenEvent_OnTransactionTimeout;
   1.103 +var gLitesnEvents = kListenEvent_None;
   1.104 +
   1.105 +/**
   1.106 + * At unexpected transaction timeout, we need to stop *all* timers.  But it is
   1.107 + * difficult and it can be create more complex testing code.  So, we should use
   1.108 + * only one timer at one time.  For that, we must store the timer id to this
   1.109 + * variable.  And the functions which may be called via a timer must clear the
   1.110 + * current timer by |_clearTimer| function.
   1.111 + */
   1.112 +var gTimer;
   1.113 +
   1.114 +var gPrefSvc = Components.classes["@mozilla.org/preferences-service;1"].
   1.115 +               getService(Components.interfaces.nsIPrefBranch);
   1.116 +const kPrefSmoothScroll = "general.smoothScroll";
   1.117 +const kPrefNameTimeout = "mousewheel.transaction.timeout";
   1.118 +const kPrefNameIgnoreMoveDelay = "mousewheel.transaction.ignoremovedelay";
   1.119 +
   1.120 +const kDefaultTimeout = gPrefSvc.getIntPref(kPrefNameTimeout);
   1.121 +const kDefaultIgnoreMoveDelay = gPrefSvc.getIntPref(kPrefNameIgnoreMoveDelay);
   1.122 +
   1.123 +gPrefSvc.setBoolPref(kPrefSmoothScroll, false);
   1.124 +
   1.125 +var gTimeout, gIgnoreMoveDelay;
   1.126 +var gEnoughForTimeout, gEnoughForIgnoreMoveDelay;
   1.127 +
   1.128 +function setTimeoutPrefs(aTimeout, aIgnoreMoveDelay)
   1.129 +{
   1.130 +  gPrefSvc.setIntPref(kPrefNameTimeout, aTimeout);
   1.131 +  gPrefSvc.setIntPref(kPrefNameIgnoreMoveDelay, aIgnoreMoveDelay);
   1.132 +  gTimeout = aTimeout;
   1.133 +  gIgnoreMoveDelay = aIgnoreMoveDelay;
   1.134 +  gEnoughForTimeout = gTimeout * 2;
   1.135 +  gEnoughForIgnoreMoveDelay = gIgnoreMoveDelay * 1.2;
   1.136 +}
   1.137 +
   1.138 +function resetTimeoutPrefs()
   1.139 +{
   1.140 +  if (gTimeout == kDefaultTimeout)
   1.141 +    return;
   1.142 +  setTimeoutPrefs(kDefaultTimeout, kDefaultIgnoreMoveDelay);
   1.143 +  initTestList();
   1.144 +}
   1.145 +
   1.146 +function growUpTimeoutPrefs()
   1.147 +{
   1.148 +  if (gTimeout != kDefaultTimeout)
   1.149 +    return;
   1.150 +  setTimeoutPrefs(5000, 1000);
   1.151 +  initTestList();
   1.152 +}
   1.153 +
   1.154 +// setting enough time for testing.
   1.155 +gPrefSvc.setIntPref(kPrefNameTimeout, gTimeout);
   1.156 +gPrefSvc.setIntPref(kPrefNameIgnoreMoveDelay, gIgnoreMoveDelay);
   1.157 +
   1.158 +var gRootView = document.getElementById("rootview");
   1.159 +var gSubView1 = document.getElementById("subview1");
   1.160 +var gSubView2 = document.getElementById("subview2");
   1.161 +var gSubView3 = document.getElementById("subview3");
   1.162 +
   1.163 +gRootView.addEventListener("MozMouseScrollFailed", onMouseScrollFailed, false);
   1.164 +gRootView.addEventListener("MozMouseScrollTransactionTimeout",
   1.165 +                           onTransactionTimeout, false);
   1.166 +
   1.167 +function finish()
   1.168 +{
   1.169 +  window.close();
   1.170 +}
   1.171 +
   1.172 +function onload()
   1.173 +{
   1.174 +  runNextTestList();
   1.175 +}
   1.176 +
   1.177 +function onunload()
   1.178 +{
   1.179 +  resetTimeoutPrefs();
   1.180 +  gPrefSvc.clearUserPref(kPrefSmoothScroll);
   1.181 +  disableNonTestMouseEvents(false);
   1.182 +  window.opener.wrappedJSObject.SimpleTest.finish();
   1.183 +}
   1.184 +
   1.185 +const kSubView1Offset = { x: 20, y: 20 };
   1.186 +const kSubView2Offset = { x: 20, y: 20 + 100 + 20 };
   1.187 +const kSubView3Offset = { x: 20, y: 20 + (100 + 20) * 2 };
   1.188 +
   1.189 +function _getSubViewTestPtForV(aPt)
   1.190 +{
   1.191 +  return { x: aPt.x + 10, y: aPt.y + 10 };
   1.192 +}
   1.193 +
   1.194 +const kPtInRootViewForV = { x: kSubView1Offset.x + 10,
   1.195 +                            y: kSubView1Offset.y - 10 };
   1.196 +const kPtInSubView1ForV = _getSubViewTestPtForV(kSubView1Offset);
   1.197 +const kPtInSubView2ForV = _getSubViewTestPtForV(kSubView2Offset);
   1.198 +const kPtInSubView3ForV = _getSubViewTestPtForV(kSubView3Offset);
   1.199 +
   1.200 +function _convertTestPtForH(aPt)
   1.201 +{
   1.202 +  return { x: aPt.y, y: aPt.x };
   1.203 +}
   1.204 +
   1.205 +const kPtInRootViewForH = _convertTestPtForH(kPtInRootViewForV);
   1.206 +const kPtInSubView1ForH = _convertTestPtForH(kPtInSubView1ForV);
   1.207 +const kPtInSubView2ForH = _convertTestPtForH(kPtInSubView2ForV);
   1.208 +const kPtInSubView3ForH = _convertTestPtForH(kPtInSubView3ForV);
   1.209 +
   1.210 +/**
   1.211 + * Define the tests here:
   1.212 + *   Scrolls are processed async always.  Therefore, we need to call all tests
   1.213 + *   by timer.  gTestLists is array of testing lists. In other words, an item
   1.214 + *   of gTestList is a group of one or more testing. Each items has following
   1.215 + *   properties:
   1.216 + *
   1.217 + *     - retryWhenTransactionTimeout
   1.218 + *         The testing of wheel transaction might be fialed randomly by
   1.219 + *         timeout.  Then, automatically the failed test list will be retested
   1.220 + *         automatically only this number of times.
   1.221 + *
   1.222 + *     - steps
   1.223 + *         This property is array of testing.  Each steps must have following
   1.224 + *         properties at least.
   1.225 + *
   1.226 + *         - func
   1.227 + *             This property means function which will be called via
   1.228 + *             |setTimeout|.  The function cannot have params.  If you need
   1.229 + *             some additional parameters, you can specify some original
   1.230 + *             properties for the test function.  If you do so, you should
   1.231 + *             document it in the testing function.
   1.232 + *         - delay
   1.233 + *             This property means delay time until the function to be called.
   1.234 + *             I.e., the value used for the second param of |setTimeout|.
   1.235 + *
   1.236 + *         And also you need one more property when you call a testing function.
   1.237 + *
   1.238 + *         - description
   1.239 + *             This property is description of the test.  This is used for
   1.240 + *             logging.
   1.241 + *
   1.242 + *         At testing, you can access to current step via |gCurrentTest|.
   1.243 + */
   1.244 +
   1.245 +var gTestLists;
   1.246 +function initTestList()
   1.247 +{
   1.248 +  gTestLists = [
   1.249 +    /**************************************************************************
   1.250 +     * Continuous scrolling test for |gRootView|
   1.251 +     *   |gRootView| has both scrollbars and it has three children which are
   1.252 +     *   |gSubView1|, |gSubView2| and |gSubView3|.  They have scrollbars.  If
   1.253 +     *   the current transaction targets |gRootView|, other children should not
   1.254 +     *   be scrolled even if the wheel events are fired on them.
   1.255 +     **************************************************************************/
   1.256 +    { retryWhenTransactionTimeout: 5,
   1.257 +      steps: [
   1.258 +        // Vertical case
   1.259 +        { func: initElements, delay: 0, forVertical: true,
   1.260 +          description: "initElements" },
   1.261 +        { func: clearWheelTransaction, delay: 0,
   1.262 +          description: "clearWheelTransaction" },
   1.263 +        // Vertical wheel events should scroll |gRootView| even if the position
   1.264 +        // of wheel events in a child view which has scrollbar.
   1.265 +        { func: testContinuousScroll, delay: 0, offset: kPtInRootViewForV,
   1.266 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.267 +          description: "Continuous scrolling test for root view (vertical/forward)" },
   1.268 +        { func: testContinuousScroll, delay: 0, offset: kPtInRootViewForV,
   1.269 +          isForward: false, isVertical: true, expectedView: gRootView,
   1.270 +          description: "Continuous scrolling test for root view (vertical/backward)" }
   1.271 +      ]
   1.272 +    },
   1.273 +
   1.274 +
   1.275 +    { retryWhenTransactionTimeout: 5,
   1.276 +      steps: [
   1.277 +        // Horizontal case
   1.278 +        { func: initElements, delay: 0, forVertical: false,
   1.279 +          description: "initElements" },
   1.280 +        { func: clearWheelTransaction, delay: 0,
   1.281 +          description: "clearWheelTransaction" },
   1.282 +        // Horizontal wheel events should scroll |gRootView| even if the
   1.283 +        // position of wheel events in a child view which has scrollbar.
   1.284 +        { func: testContinuousScroll, delay: 0, offset: kPtInRootViewForH,
   1.285 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.286 +          description: "Continuous scrolling test for root view (horizontal/forward)" },
   1.287 +        { func: testContinuousScroll, delay: 0, offset: kPtInRootViewForH,
   1.288 +          isForward: false, isVertical: false, expectedView: gRootView,
   1.289 +          description: "Continuous scrolling test for root view (horizontal/backward)" }
   1.290 +      ]
   1.291 +    },
   1.292 +
   1.293 +
   1.294 +    /**************************************************************************
   1.295 +     * Continuous scrolling test for |gSubView1|
   1.296 +     *   |gSubView1| has both scrollbars.
   1.297 +     **************************************************************************/
   1.298 +    { retryWhenTransactionTimeout: 5,
   1.299 +      steps: [
   1.300 +        // Vertical case
   1.301 +        { func: initElements, delay: 0, forVertical: true,
   1.302 +          description: "initElements" },
   1.303 +        { func: clearWheelTransaction, delay: 0,
   1.304 +          description: "clearWheelTransaction" },
   1.305 +        // Vertical wheel events should scroll |gSubView1|.
   1.306 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView1ForV,
   1.307 +          isForward: true, isVertical: true, expectedView: gSubView1,
   1.308 +          description: "Continuous scrolling test for sub view 1 (vertical/forward)" },
   1.309 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView1ForV,
   1.310 +          isForward: false, isVertical: true, expectedView: gSubView1,
   1.311 +          description: "Continuous scrolling test for sub view 1 (vertical/backward)" }
   1.312 +      ]
   1.313 +    },
   1.314 +
   1.315 +
   1.316 +    { retryWhenTransactionTimeout: 5,
   1.317 +      steps: [
   1.318 +        // Horizontal case
   1.319 +        { func: initElements, delay: 0, forVertical: false,
   1.320 +          description: "initElements" },
   1.321 +        { func: clearWheelTransaction, delay: 0,
   1.322 +          description: "clearWheelTransaction" },
   1.323 +        // Horitontal wheel events should scroll |gSubView1|.
   1.324 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView1ForH,
   1.325 +          isForward: true, isVertical: false, expectedView: gSubView1,
   1.326 +          description: "Continuous scrolling test for sub view 1 (horizontal/forward)" },
   1.327 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView1ForH,
   1.328 +          isForward: false, isVertical: false, expectedView: gSubView1,
   1.329 +          description: "Continuous scrolling test for sub view 1 (horizontal/backward)" }
   1.330 +      ]
   1.331 +    },
   1.332 +
   1.333 +
   1.334 +    /**************************************************************************
   1.335 +     * Continuous scrolling test for |gSubView2|
   1.336 +     *   |gSubView2| has only vertical scrollbar.
   1.337 +     **************************************************************************/
   1.338 +    { retryWhenTransactionTimeout: 5,
   1.339 +      steps: [
   1.340 +        // Vertical case
   1.341 +        { func: initElements, delay: 0, forVertical: true,
   1.342 +          description: "initElements" },
   1.343 +        { func: clearWheelTransaction, delay: 0,
   1.344 +          description: "clearWheelTransaction" },
   1.345 +        // Vertical wheel events should scroll |gSubView2|.
   1.346 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView2ForV,
   1.347 +          isForward: true, isVertical: true, expectedView: gSubView2,
   1.348 +          description: "Continuous scrolling test for sub view 2 (vertical/forward)" },
   1.349 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView2ForV,
   1.350 +          isForward: false, isVertical: true, expectedView: gSubView2,
   1.351 +          description: "Continuous scrolling test for sub view 2 (vertical/backward)" }
   1.352 +      ]
   1.353 +    },
   1.354 +
   1.355 +
   1.356 +    { retryWhenTransactionTimeout: 5,
   1.357 +      steps: [
   1.358 +        // Horizontal case
   1.359 +        { func: initElements, delay: 0, forVertical: false,
   1.360 +          description: "initElements" },
   1.361 +        { func: clearWheelTransaction, delay: 0,
   1.362 +          description: "clearWheelTransaction" },
   1.363 +        // Horizontal wheel events should scroll its nearest scrollable ancestor
   1.364 +        // view, i.e., it is |gRootView|.
   1.365 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView2ForH,
   1.366 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.367 +          description: "Continuous scrolling test for sub view 2 (horizontal/forward)" },
   1.368 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView2ForH,
   1.369 +          isForward: false, isVertical: false, expectedView: gRootView,
   1.370 +          description: "Continuous scrolling test for sub view 2 (horizontal/backward)" }
   1.371 +      ]
   1.372 +    },
   1.373 +
   1.374 +
   1.375 +    /**************************************************************************
   1.376 +     * Continuous scrolling test for |gSubView3|
   1.377 +     *   |gSubView3| has only horizontal scrollbar.
   1.378 +     **************************************************************************/
   1.379 +    { retryWhenTransactionTimeout: 5,
   1.380 +      steps: [
   1.381 +        // Vertical case
   1.382 +        { func: initElements, delay: 0, forVertical: true,
   1.383 +          description: "initElements" },
   1.384 +        { func: clearWheelTransaction, delay: 0,
   1.385 +          description: "clearWheelTransaction" },
   1.386 +        // Vertical wheel events should scroll its nearest scrollable ancestor
   1.387 +        // view, i.e., it is |gRootView|.
   1.388 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView3ForV,
   1.389 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.390 +          description: "Continuous scrolling test for sub view 3 (vertical/forward)" },
   1.391 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView3ForV,
   1.392 +          isForward: false, isVertical: true, expectedView: gRootView,
   1.393 +          description: "Continuous scrolling test for sub view 3 (vertical/backward)" }
   1.394 +      ]
   1.395 +    },
   1.396 +
   1.397 +
   1.398 +    { retryWhenTransactionTimeout: 5,
   1.399 +      steps: [
   1.400 +        // Horizontal case
   1.401 +        { func: initElements, delay: 0, forVertical: false,
   1.402 +          description: "initElements" },
   1.403 +        { func: clearWheelTransaction, delay: 0,
   1.404 +          description: "clearWheelTransaction" },
   1.405 +        // Horitontal wheel events should scroll |gSubView3|.
   1.406 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView3ForH,
   1.407 +          isForward: true, isVertical: false, expectedView: gSubView3,
   1.408 +          description: "Continuous scrolling test for sub view 3 (horizontal/forward)" },
   1.409 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView3ForH,
   1.410 +          isForward: false, isVertical: false, expectedView: gSubView3,
   1.411 +          description: "Continuous scrolling test for sub view 3 (horizontal/backward)" }
   1.412 +      ]
   1.413 +    },
   1.414 +
   1.415 +
   1.416 +    /**************************************************************************
   1.417 +     * Don't reset transaction by a different direction wheel event
   1.418 +     *   Even if a wheel event doesn't same direction as last wheel event, the
   1.419 +     *   current transaction should not be reset.
   1.420 +     **************************************************************************/
   1.421 +    { retryWhenTransactionTimeout: 5,
   1.422 +      steps: [
   1.423 +        // Vertical -> Horizontal
   1.424 +        { func: initElements, delay: 0, forVertical: true,
   1.425 +          description: "initElements" },
   1.426 +        { func: clearWheelTransaction, delay: 0,
   1.427 +          description: "clearWheelTransaction" },
   1.428 +        // Create a transaction which targets |gRootView| by a vertical wheel
   1.429 +        // event.
   1.430 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV,
   1.431 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.432 +          description: "Don't reset transaction by a different direction wheel event (1-1)" },
   1.433 +        // Scroll back to top-most for easy cursor position specifying.
   1.434 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV,
   1.435 +          isForward: false, isVertical: true, expectedView: gRootView,
   1.436 +          description: "Don't reset transaction by a different direction wheel event (1-2)" },
   1.437 +        // Send a horizontal wheel event over |gSubView1| but |gRootView| should
   1.438 +        // be scrolled.
   1.439 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.440 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.441 +          canFailRandomly: { possibleView: gSubView1 },
   1.442 +          description: "Don't reset transaction by a different direction wheel event (1-3)" }
   1.443 +      ]
   1.444 +    },
   1.445 +
   1.446 +
   1.447 +    { retryWhenTransactionTimeout: 5,
   1.448 +      steps: [
   1.449 +        // Horizontal -> Vertical
   1.450 +        { func: initElements, delay: 0, forVertical: false,
   1.451 +          description: "initElements" },
   1.452 +        { func: clearWheelTransaction, delay: 0,
   1.453 +          description: "clearWheelTransaction" },
   1.454 +        // Create a transaction which targets |gRootView| by a horizontal wheel
   1.455 +        // event.
   1.456 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH,
   1.457 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.458 +          description: "Don't reset transaction by a different direction wheel event (2-1)" },
   1.459 +        // Scroll back to left-most for easy cursor position specifying.
   1.460 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH,
   1.461 +          isForward: false, isVertical: false, expectedView: gRootView,
   1.462 +          description: "Don't reset transaction by a different direction wheel event (2-2)" },
   1.463 +        // Send a vertical wheel event over |gSubView1| but |gRootView| should
   1.464 +        // be scrolled.
   1.465 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH,
   1.466 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.467 +          canFailRandomly: { possibleView: gSubView1 },
   1.468 +          description: "Don't reset transaction by a different direction wheel event (2-3)" }
   1.469 +      ]
   1.470 +    },
   1.471 +
   1.472 +
   1.473 +    /**************************************************************************
   1.474 +     * Don't reset transaction even if a wheel event cannot scroll
   1.475 +     *   Even if a wheel event cannot scroll to specified direction in the
   1.476 +     *   current target view, the transaction should not be reset.  E.g., there
   1.477 +     *   are some devices which can scroll obliquely.  If so, probably, users
   1.478 +     *   cannot input only intended direction.
   1.479 +     **************************************************************************/
   1.480 +    { retryWhenTransactionTimeout: 5,
   1.481 +      steps: [
   1.482 +        // A view only has vertical scrollbar case.
   1.483 +        { func: initElements, delay: 0, forVertical: true,
   1.484 +          description: "initElements" },
   1.485 +        { func: clearWheelTransaction, delay: 0,
   1.486 +          description: "clearWheelTransaction" },
   1.487 +        // Create a transaction which targets |gSubView2|.
   1.488 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView2ForV,
   1.489 +          isForward: true, isVertical: true, expectedView: gSubView2,
   1.490 +          description: "Don't reset transaction even if a wheel event cannot scroll (1-1)" },
   1.491 +        // |gSubView2| doesn't have horizontal scrollbar but should not scroll
   1.492 +        // any views.
   1.493 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView2ForV,
   1.494 +          isForward: true, isVertical: false, expectedView: null,
   1.495 +          description: "Don't reset transaction even if a wheel event cannot scroll (1-2)" }
   1.496 +      ]
   1.497 +    },
   1.498 +
   1.499 +
   1.500 +    { retryWhenTransactionTimeout: 5,
   1.501 +      steps: [
   1.502 +        // A view only has horizontal scrollbar case.
   1.503 +        { func: initElements, delay: 0, forVertical: true,
   1.504 +          description: "initElements" },
   1.505 +        { func: clearWheelTransaction, delay: 0,
   1.506 +          description: "clearWheelTransaction" },
   1.507 +        // Create a transaction which targets |gSubView3|.
   1.508 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView3ForV,
   1.509 +          isForward: true, isVertical: false, expectedView: gSubView3,
   1.510 +          description: "Don't reset transaction even if a wheel event cannot scroll (2-1)" },
   1.511 +        // |gSubView3| doesn't have vertical scrollbar but should not scroll any
   1.512 +        // views.
   1.513 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView3ForV,
   1.514 +          isForward: true, isVertical: true, expectedView: null,
   1.515 +          description: "Don't reset transaction even if a wheel event cannot scroll (2-2)" }
   1.516 +      ]
   1.517 +    },
   1.518 +
   1.519 +
   1.520 +    /**************************************************************************
   1.521 +     * Reset transaction by mouse down/mouse up events
   1.522 +     *   Mouse down and mouse up events should cause resetting the current
   1.523 +     *   transaction.
   1.524 +     **************************************************************************/
   1.525 +    { retryWhenTransactionTimeout: 5,
   1.526 +      steps: [
   1.527 +        // Vertical case
   1.528 +        { func: initElements, delay: 0, forVertical: true,
   1.529 +          description: "initElements" },
   1.530 +        { func: clearWheelTransaction, delay: 0,
   1.531 +          description: "clearWheelTransaction" },
   1.532 +        // Create a transaction which targets |gRootView|.
   1.533 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV,
   1.534 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.535 +          description: "Reset transaction by mouse down/mouse up events (v-1)" },
   1.536 +        // Scroll back to top-most for easy cursor position specifying.
   1.537 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV,
   1.538 +          isForward: false, isVertical: true, expectedView: gRootView,
   1.539 +          description: "Reset transaction by mouse down/mouse up events (v-2)" },
   1.540 +        // Send mouse button events which should reset the current transaction.
   1.541 +        // So, the next wheel event should scroll |gSubView1|.
   1.542 +        { func: sendMouseButtonEvents, delay: 0,
   1.543 +          description: "sendMouseButtonEvents" },
   1.544 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.545 +          isForward: true, isVertical: true, expectedView: gSubView1,
   1.546 +          description: "Reset transaction by mouse down/mouse up events (v-3)" }
   1.547 +      ]
   1.548 +    },
   1.549 +
   1.550 +
   1.551 +    { retryWhenTransactionTimeout: 5,
   1.552 +      steps: [
   1.553 +        // Horizontal case
   1.554 +        { func: initElements, delay: 0, forVertical: false,
   1.555 +          description: "initElements" },
   1.556 +        { func: clearWheelTransaction, delay: 0,
   1.557 +          description: "clearWheelTransaction" },
   1.558 +        // Create a transaction which targets |gRootView|.
   1.559 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH,
   1.560 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.561 +          description: "Reset transaction by mouse down/mouse up events (h-1)" },
   1.562 +        // Scroll back to left-most for easy cursor position specifying.
   1.563 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH,
   1.564 +          isForward: false, isVertical: false, expectedView: gRootView,
   1.565 +          description: "Reset transaction by mouse down/mouse up events (h-2)" },
   1.566 +        // Send mouse button events which should reset the current transaction.
   1.567 +        // So, the next wheel event should scroll |gSubView1|.
   1.568 +        { func: sendMouseButtonEvents, delay: 0,
   1.569 +          description: "sendMouseButtonEvents" },
   1.570 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH,
   1.571 +          isForward: true, isVertical: false, expectedView: gSubView1,
   1.572 +          description: "Reset transaction by mouse down/mouse up events (h-3)" }
   1.573 +      ]
   1.574 +    },
   1.575 +
   1.576 +
   1.577 +    /**************************************************************************
   1.578 +     * Reset transaction by a key event
   1.579 +     *   A key event should cause resetting the current transaction.
   1.580 +     **************************************************************************/
   1.581 +    { retryWhenTransactionTimeout: 5,
   1.582 +      steps: [
   1.583 +        // Vertical case
   1.584 +        { func: initElements, delay: 0, forVertical: true,
   1.585 +          description: "initElements" },
   1.586 +        { func: clearWheelTransaction, delay: 0,
   1.587 +          description: "clearWheelTransaction" },
   1.588 +        // Create a transaction which targets |gRootView|.
   1.589 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV,
   1.590 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.591 +          description: "Reset transaction by a key event (v-1)" },
   1.592 +        // Scroll back to top-most for easy cursor position specifying.
   1.593 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV,
   1.594 +          isForward: false, isVertical: true, expectedView: gRootView,
   1.595 +          description: "Reset transaction by a key event (v-2)" },
   1.596 +        // Send a key event which should reset the current transaction.  So, the
   1.597 +        // next wheel event should scroll |gSubView1|.
   1.598 +        { func: sendKeyEvents, delay: 0, key: "a",
   1.599 +          description: "sendKeyEvents" },
   1.600 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.601 +          isForward: true, isVertical: true, expectedView: gSubView1,
   1.602 +          description: "Reset transaction by a key event (v-3)" }
   1.603 +      ]
   1.604 +    },
   1.605 +
   1.606 +
   1.607 +    { retryWhenTransactionTimeout: 5,
   1.608 +      steps: [
   1.609 +        // Horizontal case
   1.610 +        { func: initElements, delay: 0, forVertical: false,
   1.611 +          description: "initElements" },
   1.612 +        { func: clearWheelTransaction, delay: 0,
   1.613 +          description: "clearWheelTransaction" },
   1.614 +        // Create a transaction which targets |gRootView|.
   1.615 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH,
   1.616 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.617 +          description: "Reset transaction by a key event (h-1)" },
   1.618 +        // Scroll back to left-most for easy cursor position specifying.
   1.619 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH,
   1.620 +          isForward: false, isVertical: false, expectedView: gRootView,
   1.621 +          description: "Reset transaction by a key event (h-2)" },
   1.622 +        // Send a key event which should reset the current transaction.  So, the
   1.623 +        // next wheel event should scroll |gSubView1|.
   1.624 +        { func: sendKeyEvents, delay: 0, key: "a",
   1.625 +          description: "sendKeyEvents" },
   1.626 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH,
   1.627 +          isForward: true, isVertical: false, expectedView: gSubView1,
   1.628 +          description: "Reset transaction by a key event (h-3)" }
   1.629 +      ]
   1.630 +    },
   1.631 +
   1.632 +
   1.633 +    /**************************************************************************
   1.634 +     * Reset transaction by a mouse move event
   1.635 +     *   A mouse move event can cause reseting the current transaction even if
   1.636 +     *   mouse cursor is inside the target view of current transaction. Only
   1.637 +     *   when a wheel event is fired after |gIgnoreMoveDelay| milliseconds since
   1.638 +     *   the first mouse move event from last wheel event, the transaction
   1.639 +     *   should be reset.
   1.640 +     **************************************************************************/
   1.641 +    { retryWhenTransactionTimeout: 5,
   1.642 +      steps: [
   1.643 +        // Vertical case
   1.644 +        { func: initElements, delay: 0, forVertical: true,
   1.645 +          description: "initElements" },
   1.646 +        { func: clearWheelTransaction, delay: 0,
   1.647 +          description: "clearWheelTransaction" },
   1.648 +        // Create a transaction which targets |gRootView|.
   1.649 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV,
   1.650 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.651 +          description: "Reset transaction by a mouse move event (v-1)" },
   1.652 +        // Scroll back to top-most for easy cursor position specifying.
   1.653 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV,
   1.654 +          isForward: false, isVertical: true, expectedView: gRootView,
   1.655 +          description: "Reset transaction by a mouse move event (v-2)" },
   1.656 +        // Send a mouse move event immediately after last wheel event, then,
   1.657 +        // current transaction should be kept.
   1.658 +        { func: sendMouseMoveEvent, delay: 0, offset: kPtInSubView1ForV,
   1.659 +          description: "sendMouseMoveEvent" },
   1.660 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.661 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.662 +          canFailRandomly: { possibleView: gSubView1 },
   1.663 +          description: "Reset transaction by a mouse move event (v-3)" },
   1.664 +        // Scroll back to top-most for easy cursor position specifying.
   1.665 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.666 +          isForward: false, isVertical: true, expectedView: gRootView,
   1.667 +          canFailRandomly: { possibleView: gSubView1 },
   1.668 +          description: "Reset transaction by a mouse move event (v-4)" },
   1.669 +        // Send a mouse move event after |gIgnoreMoveDelay| milliseconds since
   1.670 +        // last wheel event, then, current transaction should be kept.
   1.671 +        { func: sendMouseMoveEvent, delay: gEnoughForIgnoreMoveDelay,
   1.672 +          offset: kPtInSubView1ForV,
   1.673 +          description: "sendMouseMoveEvent" },
   1.674 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.675 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.676 +          canFailRandomly: { possibleView: gSubView1 },
   1.677 +          description: "Reset transaction by a mouse move event (v-5)" },
   1.678 +        // Scroll back to top-most for easy cursor position specifying.
   1.679 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.680 +          isForward: false, isVertical: true, expectedView: gRootView,
   1.681 +          canFailRandomly: { possibleView: gSubView1 },
   1.682 +          description: "Reset transaction by a mouse move event (v-6)" },
   1.683 +        // Send a wheel event after |gIgnoreMoveDelay| milliseconds since last
   1.684 +        // mouse move event but it is fired immediately after the last wheel
   1.685 +        // event, then, current transaction should be kept.
   1.686 +        { func: sendMouseMoveEvent, delay: 0, offset: kPtInSubView1ForV,
   1.687 +          description: "sendMouseMoveEvent" },
   1.688 +        { func: testOneTimeScroll, delay: gEnoughForIgnoreMoveDelay,
   1.689 +          offset: kPtInSubView1ForV,
   1.690 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.691 +          canFailRandomly: { possibleView: gSubView1 },
   1.692 +          description: "Reset transaction by a mouse move event (v-7)" },
   1.693 +        // Scroll back to top-most for easy cursor position specifying.
   1.694 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.695 +          isForward: false, isVertical: true, expectedView: gRootView,
   1.696 +          canFailRandomly: { possibleView: gSubView1 },
   1.697 +          description: "Reset transaction by a mouse move event (v-8)" },
   1.698 +        // Send a wheel event after |gIgnoreMoveDelay| milliseconds have passed
   1.699 +        // since last mouse move event which is fired after |gIgnoreMoveDelay|
   1.700 +        // milliseconds since last wheel event, then, current transaction should
   1.701 +        // be reset.
   1.702 +        { func: sendMouseMoveEvent, delay: gEnoughForIgnoreMoveDelay,
   1.703 +          offset: kPtInSubView1ForV,
   1.704 +          description: "sendMouseMoveEvent" },
   1.705 +        { func: testOneTimeScroll, delay: gEnoughForIgnoreMoveDelay,
   1.706 +          offset: kPtInSubView1ForV,
   1.707 +          isForward: true, isVertical: true, expectedView: gSubView1,
   1.708 +          canFailRandomly: { possibleView: gRootView },
   1.709 +          description: "Reset transaction by a mouse move event (v-9)" }
   1.710 +      ]
   1.711 +    },
   1.712 +
   1.713 +
   1.714 +    { retryWhenTransactionTimeout: 5,
   1.715 +      steps: [
   1.716 +        // Horizontal case
   1.717 +        { func: initElements, delay: 0, forVertical: false,
   1.718 +          description: "initElements" },
   1.719 +        { func: clearWheelTransaction, delay: 0,
   1.720 +          description: "clearWheelTransaction" },
   1.721 +        // Create a transaction which targets |gRootView|.
   1.722 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH,
   1.723 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.724 +          canFailRandomly: { possibleView: gSubView1 },
   1.725 +          description: "Reset transaction by a mouse move event (h-1)" },
   1.726 +        // Scroll back to top-most for easy cursor position specifying.
   1.727 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH,
   1.728 +          isForward: false, isVertical: false, expectedView: gRootView,
   1.729 +          canFailRandomly: { possibleView: gSubView1 },
   1.730 +          description: "Reset transaction by a mouse move event (h-2)" },
   1.731 +        // Send a mouse move event immediately after last wheel event, then,
   1.732 +        // current transaction should be kept.
   1.733 +        { func: sendMouseMoveEvent, delay: 0, offset: kPtInSubView1ForH,
   1.734 +          description: "sendMouseMoveEvent" },
   1.735 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH,
   1.736 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.737 +          canFailRandomly: { possibleView: gSubView1 },
   1.738 +          description: "Reset transaction by a mouse move event (h-3)" },
   1.739 +        // Scroll back to top-most for easy cursor position specifying.
   1.740 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH,
   1.741 +          isForward: false, isVertical: false, expectedView: gRootView,
   1.742 +          canFailRandomly: { possibleView: gSubView1 },
   1.743 +          description: "Reset transaction by a mouse move event (h-4)" },
   1.744 +        // Send a mouse move event after |gIgnoreMoveDelay| milliseconds since
   1.745 +        // last wheel event, then, current transaction should be kept.
   1.746 +        { func: sendMouseMoveEvent, delay: gEnoughForIgnoreMoveDelay,
   1.747 +          offset: kPtInSubView1ForH,
   1.748 +          description: "sendMouseMoveEvent" },
   1.749 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH,
   1.750 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.751 +          canFailRandomly: { possibleView: gSubView1 },
   1.752 +          description: "Reset transaction by a mouse move event (h-5)" },
   1.753 +        // Scroll back to top-most for easy cursor position specifying.
   1.754 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH,
   1.755 +          isForward: false, isVertical: false, expectedView: gRootView,
   1.756 +          canFailRandomly: { possibleView: gSubView1 },
   1.757 +          description: "Reset transaction by a mouse move event (h-6)" },
   1.758 +        // Send a wheel event after |gIgnoreMoveDelay| milliseconds since last
   1.759 +        // mouse move event but it is fired immediately after the last wheel
   1.760 +        // event, then, current transaction should be kept.
   1.761 +        { func: sendMouseMoveEvent, delay: 0, offset: kPtInSubView1ForH,
   1.762 +          description: "sendMouseMoveEvent" },
   1.763 +        { func: testOneTimeScroll, delay: gEnoughForIgnoreMoveDelay,
   1.764 +          offset: kPtInSubView1ForH,
   1.765 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.766 +          canFailRandomly: { possibleView: gSubView1 },
   1.767 +          description: "Reset transaction by a mouse move event (h-7)" },
   1.768 +        // Scroll back to top-most for easy cursor position specifying.
   1.769 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH,
   1.770 +          isForward: false, isVertical: false, expectedView: gRootView,
   1.771 +          canFailRandomly: { possibleView: gSubView1 },
   1.772 +          description: "Reset transaction by a mouse move event (h-8)" },
   1.773 +        // Send a wheel event after |gIgnoreMoveDelay| milliseconds have passed
   1.774 +        // since last mouse move event which is fired after |gIgnoreMoveDelay|
   1.775 +        // milliseconds since last wheel event, then, current transaction should
   1.776 +        // be reset.
   1.777 +        { func: sendMouseMoveEvent, delay: gEnoughForIgnoreMoveDelay,
   1.778 +          offset: kPtInSubView1ForH,
   1.779 +          description: "sendMouseMoveEvent" },
   1.780 +        { func: testOneTimeScroll, delay: gEnoughForIgnoreMoveDelay,
   1.781 +          offset: kPtInSubView1ForH,
   1.782 +          isForward: true, isVertical: false, expectedView: gSubView1,
   1.783 +          canFailRandomly: { possibleView: gRootView },
   1.784 +          description: "Reset transaction by a mouse move event (h-9)" }
   1.785 +      ]
   1.786 +    },
   1.787 +
   1.788 +
   1.789 +    /**************************************************************************
   1.790 +     * Reset transaction by a mouse move event on outside of view
   1.791 +     *   When mouse cursor is moved to outside of the current target view, the
   1.792 +     *   transaction should be reset immediately.
   1.793 +     **************************************************************************/
   1.794 +    { retryWhenTransactionTimeout: 5,
   1.795 +      steps: [
   1.796 +        // Vertical case
   1.797 +        { func: initElements, delay: 0, forVertical: true,
   1.798 +          description: "initElements" },
   1.799 +        { func: clearWheelTransaction, delay: 0,
   1.800 +          description: "clearWheelTransaction" },
   1.801 +        // Create a transaction which targets |gSubView1|.
   1.802 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.803 +          isForward: true, isVertical: true, expectedView: gSubView1,
   1.804 +          description: "Reset transaction by a mouse move event on outside of view (v-1)" },
   1.805 +        // Send mouse move event over |gRootView|.
   1.806 +        { func: sendMouseMoveEvent, delay: 0, offset: kPtInRootViewForV,
   1.807 +          description: "sendMouseMoveEvent" },
   1.808 +        // Send Wheel event over |gRootView| which should be scrolled.
   1.809 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV,
   1.810 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.811 +          description: "Reset transaction by a mouse move event on outside of view (v-2)" }
   1.812 +      ]
   1.813 +    },
   1.814 +
   1.815 +
   1.816 +    { retryWhenTransactionTimeout: 5,
   1.817 +      steps: [
   1.818 +        // Horizontal case
   1.819 +        { func: initElements, delay: 0, forVertical: false,
   1.820 +          description: "initElements" },
   1.821 +        { func: clearWheelTransaction, delay: 0,
   1.822 +          description: "clearWheelTransaction" },
   1.823 +        // Create a transaction which targets |gSubView1|.
   1.824 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH,
   1.825 +          isForward: true, isVertical: true, expectedView: gSubView1,
   1.826 +          description: "Reset transaction by a mouse move event on outside of view (h-1)" },
   1.827 +        // Send mouse move event over |gRootView|.
   1.828 +        { func: sendMouseMoveEvent, delay: 0, offset: kPtInRootViewForH,
   1.829 +          description: "sendMouseMoveEvent" },
   1.830 +        // Send Wheel event over |gRootView| which should be scrolled.
   1.831 +        { func: testOneTimeScroll, delay: 0,  offset: kPtInRootViewForH,
   1.832 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.833 +          description: "Reset transaction by a mouse move event on outside of view (h-2)" }
   1.834 +      ]
   1.835 +    },
   1.836 +
   1.837 +
   1.838 +    /**************************************************************************
   1.839 +     * Timeout test
   1.840 +     *   A view should not be scrolled during another to be transaction for
   1.841 +     *   another view scrolling. However, a wheel event which is sent after
   1.842 +     *   timeout, a view which is under the mouse cursor should be scrolled.
   1.843 +     **************************************************************************/
   1.844 +    { retryWhenTransactionTimeout: 5,
   1.845 +      steps: [
   1.846 +        // Vertical case
   1.847 +        { func: initElements, delay: 0, forVertical: true,
   1.848 +          description: "initElements" },
   1.849 +        { func: clearWheelTransaction, delay: 0,
   1.850 +          description: "clearWheelTransaction" },
   1.851 +        // First, create a transaction which should target the |gRootView|.
   1.852 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV,
   1.853 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.854 +          description: "Timeout test (v-1)" },
   1.855 +        // Scroll back to top-most for easy cursor position specifying.
   1.856 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV,
   1.857 +          isForward: false, isVertical: true, expectedView: gRootView,
   1.858 +          description: "Timeout test (v-2)" },
   1.859 +        // A wheel event over |gSubView1| should not scroll it during current
   1.860 +        // transaction.
   1.861 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.862 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.863 +          canFailRandomly: { possibleView: gSubView1 },
   1.864 +          description: "Timeout test (v-3)" },
   1.865 +        // Scroll back to top-most again.
   1.866 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.867 +          isForward: false, isVertical: true, expectedView: gRootView,
   1.868 +          canFailRandomly: { possibleView: gSubView1 },
   1.869 +          description: "Timeout test (v-4)" },
   1.870 +        // A wheel event over |gSubView1| after timeout should scroll
   1.871 +        // |gSubView1|.
   1.872 +        { func: testOneTimeScroll, delay: gEnoughForTimeout,
   1.873 +          offset: kPtInSubView1ForV,
   1.874 +          isForward: true, isVertical: true, expectedView: gSubView1,
   1.875 +          isTimeoutTesting: true,
   1.876 +          description: "Timeout test (v-5)" }
   1.877 +      ]
   1.878 +    },
   1.879 +
   1.880 +
   1.881 +    { retryWhenTransactionTimeout: 5,
   1.882 +      steps: [
   1.883 +        // Horizontal case
   1.884 +        { func: initElements, delay: 0, forVertical: false,
   1.885 +          description: "initElements" },
   1.886 +        { func: clearWheelTransaction, delay: 0,
   1.887 +          description: "clearWheelTransaction" },
   1.888 +        // First, create a transaction which should target the |gRootView|.
   1.889 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH,
   1.890 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.891 +          description: "Timeout test (h-1)" },
   1.892 +        // Scroll back to left-most for easy cursor position specifying.
   1.893 +        { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH,
   1.894 +          isForward: false, isVertical: false, expectedView: gRootView,
   1.895 +          description: "Timeout test (h-2)" },
   1.896 +        // A wheel event over |gSubView1| should not scroll it during current
   1.897 +        // transaction.
   1.898 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH,
   1.899 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.900 +          canFailRandomly: { possibleView: gSubView1 },
   1.901 +          description: "Timeout test (h-3)" },
   1.902 +        // Scroll back to left-most again.
   1.903 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH,
   1.904 +          isForward: false, isVertical: false, expectedView: gRootView,
   1.905 +          canFailRandomly: { possibleView: gSubView1 },
   1.906 +          description: "Timeout test (h-4)" },
   1.907 +        // A wheel event over |gSubView1| after timeout should scroll
   1.908 +        // |gSubView1|.
   1.909 +        { func: testOneTimeScroll, delay: gEnoughForTimeout,
   1.910 +          offset: kPtInSubView1ForH,
   1.911 +          isForward: true, isVertical: false, expectedView: gSubView1,
   1.912 +          isTimeoutTesting: true,
   1.913 +          description: "Timeout test (h-5)" }
   1.914 +      ]
   1.915 +    },
   1.916 +
   1.917 +
   1.918 +    /**************************************************************************
   1.919 +     * Timeout test even with many wheel events
   1.920 +     *   This tests whether timeout is occurred event if wheel events are sent.
   1.921 +     *   The transaction should not be updated by non-scrollable wheel events.
   1.922 +     **************************************************************************/
   1.923 +    { retryWhenTransactionTimeout: 5,
   1.924 +      steps: [
   1.925 +        // Vertical case
   1.926 +        { func: initElements, delay: 0, forVertical: true,
   1.927 +          description: "initElements" },
   1.928 +        { func: clearWheelTransaction, delay: 0,
   1.929 +          description: "clearWheelTransaction" },
   1.930 +        // Scroll |gSubView1| to bottom-most.
   1.931 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView1ForV,
   1.932 +          isForward: true, isVertical: true, expectedView: gSubView1,
   1.933 +          description: "Timeout test even with many wheel events (v-1)" },
   1.934 +        // Don't scroll any views before timeout.
   1.935 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.936 +          isForward: true, isVertical: true, expectedView: null,
   1.937 +          canFailRandomly: { possibleView: gRootView },
   1.938 +          description: "Timeout test even with many wheel events (v-2)" },
   1.939 +        // Recreate a transaction which is scrolling |gRootView| after time out.
   1.940 +        { func: testRestartScroll, delay: 0, offset: kPtInSubView1ForV,
   1.941 +          isForward: true, isVertical: true, expectedView: gRootView,
   1.942 +          description: "Timeout test even with many wheel events (v-3)" }
   1.943 +      ]
   1.944 +    },
   1.945 +
   1.946 +
   1.947 +    { retryWhenTransactionTimeout: 5,
   1.948 +      steps: [
   1.949 +        // Horizontal case
   1.950 +        { func: initElements, delay: 0, forVertical: false,
   1.951 +          description: "initElements" },
   1.952 +        { func: clearWheelTransaction, delay: 0,
   1.953 +          description: "clearWheelTransaction" },
   1.954 +        // Scroll |gSubView1| to right-most.
   1.955 +        { func: testContinuousScroll, delay: 0, offset: kPtInSubView1ForH,
   1.956 +          isForward: true, isVertical: false, expectedView: gSubView1,
   1.957 +          description: "Timeout test even with many wheel events (h-1)" },
   1.958 +        // Don't scroll any views before timeout.
   1.959 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH,
   1.960 +          isForward: true, isVertical: false, expectedView: null,
   1.961 +          canFailRandomly: { possibleView: gRootView },
   1.962 +          description: "Timeout test even with many wheel events (h-2)" },
   1.963 +        // Recreate a transaction which is scrolling |gRootView| after time out.
   1.964 +        { func: testRestartScroll, delay: 0, offset: kPtInSubView1ForH,
   1.965 +          isForward: true, isVertical: false, expectedView: gRootView,
   1.966 +          description: "Timeout test even with many wheel events (h-3)" }
   1.967 +      ]
   1.968 +    },
   1.969 +
   1.970 +
   1.971 +    /**************************************************************************
   1.972 +     * Very large scrolling wheel event
   1.973 +     *   If the delta value is larger than the scrolling page size, it should be
   1.974 +     *   scrolled only one page instead of the delta value.
   1.975 +     **************************************************************************/
   1.976 +    { retryWhenTransactionTimeout: 5,
   1.977 +      steps: [
   1.978 +        { func: initElements, delay: 0, forVertical: true,
   1.979 +          description: "initElements" },
   1.980 +        { func: clearWheelTransaction, delay: 0,
   1.981 +          description: "clearWheelTransaction" },
   1.982 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.983 +          isForward: true, isVertical: true, expectedView: gSubView1,
   1.984 +          delta: 5000,
   1.985 +          description: "Very large delta scrolling (v-1)" },
   1.986 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.987 +          isForward: true, isVertical: true, expectedView: gSubView1,
   1.988 +          delta: 5000,
   1.989 +          description: "Very large delta scrolling (v-2)" },
   1.990 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.991 +          isForward: true, isVertical: false, expectedView: gSubView1,
   1.992 +          delta: 5000,
   1.993 +          description: "Very large delta scrolling (h-1)" },
   1.994 +        { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV,
   1.995 +          isForward: true, isVertical: false, expectedView: gSubView1,
   1.996 +          delta: 5000,
   1.997 +          description: "Very large delta scrolling (h-2)" }
   1.998 +      ]
   1.999 +    }
  1.1000 +  ];
  1.1001 +}
  1.1002 +
  1.1003 +/******************************************************************************
  1.1004 + * Actions for preparing tests
  1.1005 + ******************************************************************************/
  1.1006 +
  1.1007 +function initElements()
  1.1008 +{
  1.1009 +  _clearTimer();
  1.1010 +
  1.1011 +  function resetScrollPosition(aElement)
  1.1012 +  {
  1.1013 +    aElement.scrollTop = 0;
  1.1014 +    aElement.scrollLeft = 0;
  1.1015 +  }
  1.1016 +
  1.1017 +  function initInRootView(aElement, aPt)
  1.1018 +  {
  1.1019 +    aElement.offset =
  1.1020 +      gCurrentTest.forVertical ? aPt : { x: aPt.y, y: aPt.x };
  1.1021 +  }
  1.1022 +
  1.1023 +  const kDisplay = gCurrentTest.forVertical ? "block" : "inline-block";
  1.1024 +  gSubView1.style.display = kDisplay;
  1.1025 +  gSubView2.style.display = kDisplay;
  1.1026 +  gSubView3.style.display = kDisplay;
  1.1027 +
  1.1028 +  resetScrollPosition(gRootView);
  1.1029 +  resetScrollPosition(gSubView1);
  1.1030 +  resetScrollPosition(gSubView2);
  1.1031 +  resetScrollPosition(gSubView3);
  1.1032 +
  1.1033 +  runNextTestStep();
  1.1034 +}
  1.1035 +
  1.1036 +function clearWheelTransaction()
  1.1037 +{
  1.1038 +  _clearTimer();
  1.1039 +  _clearTransaction();
  1.1040 +  runNextTestStep();
  1.1041 +}
  1.1042 +
  1.1043 +function sendKeyEvents()
  1.1044 +{
  1.1045 +  _clearTimer();
  1.1046 +  synthesizeKey(gCurrentTest.key, {}, window);
  1.1047 +  runNextTestStep();
  1.1048 +}
  1.1049 +
  1.1050 +function sendMouseButtonEvents()
  1.1051 +{
  1.1052 +  _clearTimer();
  1.1053 +  synthesizeMouse(gRootView, -1, -1, { type:"mousedown" }, window);
  1.1054 +  synthesizeMouse(gRootView, -1, -1, { type:"mouseup" }, window);
  1.1055 +  runNextTestStep();
  1.1056 +}
  1.1057 +
  1.1058 +function sendMouseMoveEvent()
  1.1059 +{
  1.1060 +  _clearTimer();
  1.1061 +  _fireMouseMoveEvent(gCurrentTest.offset);
  1.1062 +  runNextTestStep();
  1.1063 +}
  1.1064 +
  1.1065 +/******************************************************************************
  1.1066 + * Utilities for testing functions
  1.1067 + ******************************************************************************/
  1.1068 +
  1.1069 +function _clearTransaction()
  1.1070 +{
  1.1071 +  synthesizeMouse(gRootView, -1, -1, { type:"mousedown" }, window);
  1.1072 +  synthesizeMouse(gRootView, -1, -1, { type:"mouseup" }, window);
  1.1073 +}
  1.1074 +
  1.1075 +function _saveScrollPositions()
  1.1076 +{
  1.1077 +  function save(aElement)
  1.1078 +  {
  1.1079 +    aElement.prevTop = aElement.scrollTop;
  1.1080 +    aElement.prevLeft = aElement.scrollLeft;
  1.1081 +  }
  1.1082 +  save(gRootView);
  1.1083 +  save(gSubView1);
  1.1084 +  save(gSubView2);
  1.1085 +  save(gSubView3);
  1.1086 +}
  1.1087 +
  1.1088 +function _fireMouseMoveEvent(aOffset)
  1.1089 +{
  1.1090 +  synthesizeMouse(gRootView, aOffset.x, aOffset.y, { type:"mousemove" }, window);
  1.1091 +}
  1.1092 +
  1.1093 +function _fireWheelScrollEvent(aOffset, aIsVertical, aForward, aDelta)
  1.1094 +{
  1.1095 +  var event = { deltaMode: WheelEvent.DOM_DELTA_LINE };
  1.1096 +  if (aIsVertical) {
  1.1097 +    event.deltaY = aForward ? aDelta : -aDelta;
  1.1098 +  } else {
  1.1099 +    event.deltaX = aForward ? aDelta : -aDelta;
  1.1100 +  }
  1.1101 +  synthesizeWheel(gRootView, aOffset.x, aOffset.y, event, window);
  1.1102 +}
  1.1103 +
  1.1104 +function _canScroll(aElement, aIsVertical, aForward)
  1.1105 +{
  1.1106 +  if (aIsVertical) {
  1.1107 +    if (!aForward)
  1.1108 +      return aElement.scrollTop > 0;
  1.1109 +    return aElement.scrollHeight > aElement.scrollTop + aElement.clientHeight;
  1.1110 +  }
  1.1111 +  if (!aForward)
  1.1112 +    return aElement.scrollLeft > 0;
  1.1113 +  return aElement.scrollWidth > aElement.scrollLeft + aElement.clientWidth;
  1.1114 +}
  1.1115 +
  1.1116 +const kNotScrolled      = 0;
  1.1117 +const kScrolledToTop    = 1;
  1.1118 +const kScrolledToBottom = 2;
  1.1119 +const kScrolledToLeft   = 4;
  1.1120 +const kScrolledToRight  = 8;
  1.1121 +
  1.1122 +const kScrolledVertical   = kScrolledToTop | kScrolledToBottom;
  1.1123 +const kScrolledHorizontal = kScrolledToLeft | kScrolledToRight;
  1.1124 +
  1.1125 +function _getScrolledState(aElement)
  1.1126 +{
  1.1127 +  var ret = kNotScrolled;
  1.1128 +  if (aElement.scrollTop != aElement.prevTop) {
  1.1129 +    ret |= aElement.scrollTop < aElement.prevTop ? kScrolledToTop :
  1.1130 +                                                   kScrolledToBottom;
  1.1131 +  }
  1.1132 +  if (aElement.scrollLeft != aElement.prevLeft) {
  1.1133 +    ret |= aElement.scrollLeft < aElement.prevLeft ? kScrolledToLeft :
  1.1134 +                                                     kScrolledToRight;
  1.1135 +  }
  1.1136 +  return ret;
  1.1137 +}
  1.1138 +
  1.1139 +function _getExpectedScrolledState()
  1.1140 +{
  1.1141 +  return gCurrentTest.isVertical ?
  1.1142 +           gCurrentTest.isForward ? kScrolledToBottom : kScrolledToTop :
  1.1143 +           gCurrentTest.isForward ? kScrolledToRight : kScrolledToLeft;
  1.1144 +}
  1.1145 +
  1.1146 +function _getScrolledStateText(aScrolledState)
  1.1147 +{
  1.1148 +  if (aScrolledState == kNotScrolled)
  1.1149 +    return "Not scrolled";
  1.1150 +
  1.1151 +  var s = "scrolled to ";
  1.1152 +  if (aScrolledState & kScrolledVertical) {
  1.1153 +    s += aScrolledState & kScrolledToTop ? "backward" : "forward";
  1.1154 +    s += " (vertical)"
  1.1155 +    if (aScrolledState & kScrolledHorizontal)
  1.1156 +      s += " and to ";
  1.1157 +  }
  1.1158 +  if (aScrolledState & kScrolledHorizontal) {
  1.1159 +    s += aScrolledState & kScrolledToLeft ? "backward" : "forward";
  1.1160 +    s += " (horizontal)"
  1.1161 +  }
  1.1162 +  return s;
  1.1163 +}
  1.1164 +
  1.1165 +function _getCurrentTestList()
  1.1166 +{
  1.1167 +  return gTestLists[gCurrentTestListStatus.nextListIndex - 1];
  1.1168 +}
  1.1169 +
  1.1170 +function _clearTimer()
  1.1171 +{
  1.1172 +  clearTimeout(gTimer);
  1.1173 +  gTimer = 0;
  1.1174 +}
  1.1175 +
  1.1176 +/******************************************************************************
  1.1177 + * Testing functions
  1.1178 + ******************************************************************************/
  1.1179 +
  1.1180 +/**
  1.1181 + * Note that testing functions must set following variables:
  1.1182 + *
  1.1183 + *   gCurrentTest.repeatTest:  See comment in |continueTest|.
  1.1184 + *   gCurrentTest.autoRepeatDelay:  See comment in |continueTest|.
  1.1185 + *   gListenScrollEvent: When this is not true, the event handlers ignores the
  1.1186 + *                       events.
  1.1187 + */
  1.1188 +
  1.1189 +function testContinuousScroll()
  1.1190 +{
  1.1191 +  /**
  1.1192 +   * Testing continuous scrolling.  This function synthesizes a wheel event.  If
  1.1193 +   * the test was success, this function will be recalled automatically.
  1.1194 +   * And when a generating wheel event cannot scroll the expected view, this
  1.1195 +   * function fires the wheel event only one time.
  1.1196 +   *
  1.1197 +   * @param gCurrentTest.offset
  1.1198 +   *          The cursor position of firing wheel event.  The values are offset
  1.1199 +   *          from |gRootView|.
  1.1200 +   * @param gCurrentTest.isVertical
  1.1201 +   *          Whether the wheel event is for virtical scrolling or horizontal.
  1.1202 +   * @param gCurrentTest.isForward
  1.1203 +   *          Whether the wheel event is to forward or to backward.
  1.1204 +   * @param gCurrentTest.expectedView
  1.1205 +   *          The expected view which will be scrolled by wheel event. This
  1.1206 +   *          value must not be null.
  1.1207 +   */
  1.1208 +
  1.1209 +  _clearTimer();
  1.1210 +  _saveScrollPositions();
  1.1211 +  if (!gCurrentTest.expectedView) {
  1.1212 +    runNextTestStep();
  1.1213 +    return;
  1.1214 +  }
  1.1215 +
  1.1216 +  gLitesnEvents = kListenEvent_All;
  1.1217 +  gCurrentTest.repeatTest = true;
  1.1218 +  gCurrentTest.autoRepeatDelay = 0;
  1.1219 +
  1.1220 +  if (!_canScroll(gCurrentTest.expectedView,
  1.1221 +                  gCurrentTest.isVertical, gCurrentTest.isForward)) {
  1.1222 +    gCurrentTest.expectedView = null;
  1.1223 +  }
  1.1224 +  var delta = gCurrentTest.delta ? gCurrentTest.delta : 4;
  1.1225 +  _fireWheelScrollEvent(gCurrentTest.offset,
  1.1226 +                        gCurrentTest.isVertical, gCurrentTest.isForward, delta);
  1.1227 +}
  1.1228 +
  1.1229 +function testOneTimeScroll()
  1.1230 +{
  1.1231 +  /**
  1.1232 +   * Testing one wheel event.  |runNextTestStep| will be called immediately
  1.1233 +   * after this function by |onScrollView| or |onTimeout|.
  1.1234 +   *
  1.1235 +   * @param gCurrentTest.offset
  1.1236 +   *          The cursor position of firing wheel event.  The values are offset
  1.1237 +   *          from |gRootView|.
  1.1238 +   * @param gCurrentTest.isVertical
  1.1239 +   *          Whether the wheel event is for virtical scrolling or horizontal.
  1.1240 +   * @param gCurrentTest.isForward
  1.1241 +   *          Whether the wheel event is to forward or to backward.
  1.1242 +   * @param gCurrentTest.expectedView
  1.1243 +   *          The expected view which will be scrolled by wheel event. This
  1.1244 +   *          value can be null.  It means any views should not be scrolled.
  1.1245 +   */
  1.1246 +
  1.1247 +  _clearTimer();
  1.1248 +  _saveScrollPositions();
  1.1249 +
  1.1250 +  gLitesnEvents = kListenEvent_All;
  1.1251 +  gCurrentTest.repeatTest = false;
  1.1252 +  gCurrentTest.autoRepeatDelay = 0;
  1.1253 +
  1.1254 +  var delta = gCurrentTest.delta ? gCurrentTest.delta : 4;
  1.1255 +  _fireWheelScrollEvent(gCurrentTest.offset,
  1.1256 +                        gCurrentTest.isVertical, gCurrentTest.isForward, delta);
  1.1257 +}
  1.1258 +
  1.1259 +function testRestartScroll()
  1.1260 +{
  1.1261 +  /**
  1.1262 +   * Testing restart to scroll in expected view after timeout from the current
  1.1263 +   * transaction.  This function recall this itself until to success this test
  1.1264 +   * or timeout from this test.
  1.1265 +   *
  1.1266 +   * @param gCurrentTest.offset
  1.1267 +   *          The cursor position of firing wheel event.  The values are offset
  1.1268 +   *          from |gRootView|.
  1.1269 +   * @param gCurrentTest.isVertical
  1.1270 +   *          Whether the wheel event is for virtical scrolling or horizontal.
  1.1271 +   * @param gCurrentTest.isForward
  1.1272 +   *          Whether the wheel event is to forward or to backward.
  1.1273 +   * @param gCurrentTest.expectedView
  1.1274 +   *          The expected view which will be scrolled by wheel event. This
  1.1275 +   *          value must not be null.
  1.1276 +   */
  1.1277 +
  1.1278 +  _clearTimer();
  1.1279 +  _saveScrollPositions();
  1.1280 +
  1.1281 +  if (!gCurrentTest.wasTransactionTimeout) {
  1.1282 +    gCurrentTest.repeatTest = true;
  1.1283 +    gCurrentTest.autoRepeatDelay = gTimeout / 3;
  1.1284 +    gLitesnEvents = kListenEvent_All;
  1.1285 +    gCurrentTest.isTimeoutTesting = true;
  1.1286 +    if (gCurrentTest.expectedView) {
  1.1287 +      gCurrentTest.expectedViewAfterTimeout = gCurrentTest.expectedView;
  1.1288 +      gCurrentTest.expectedView = null;
  1.1289 +    }
  1.1290 +  } else {
  1.1291 +    gCurrentTest.repeatTest = false;
  1.1292 +    gCurrentTest.autoRepeatDelay = 0;
  1.1293 +    gLitesnEvents = kListenEvent_All;
  1.1294 +    gCurrentTest.isTimeoutTesting = false;
  1.1295 +    gCurrentTest.expectedView = gCurrentTest.expectedViewAfterTimeout;
  1.1296 +  }
  1.1297 +
  1.1298 +  var delta = gCurrentTest.delta ? gCurrentTest.delta : 4;
  1.1299 +  _fireWheelScrollEvent(gCurrentTest.offset,
  1.1300 +                        gCurrentTest.isVertical, gCurrentTest.isForward, delta);
  1.1301 +}
  1.1302 +
  1.1303 +/******************************************************************************
  1.1304 + * Event handlers
  1.1305 + ******************************************************************************/
  1.1306 +
  1.1307 +function onScrollView(aEvent)
  1.1308 +{
  1.1309 +  /**
  1.1310 +   * Scroll event handler of |gRootView|, |gSubView1|, |gSubView2| and 
  1.1311 +   * |gSubView3|.  If testing is failed, this function cancels all left tests.
  1.1312 +   * For checking the event is expected, the event firer must call
  1.1313 +   * |_saveScrollPositions|.
  1.1314 +   *
  1.1315 +   * @param gCurrentTest.expectedView
  1.1316 +   *          The expected view which should be scrolled by the wheel event.
  1.1317 +   *          This value can be null.  It means any views should not be
  1.1318 +   *          scrolled.
  1.1319 +   * @param gCurrentTest.isVertical
  1.1320 +   *          The expected view should be scrolled vertical or horizontal.
  1.1321 +   * @param gCurrentTest.isForward
  1.1322 +   *          The expected view should be scrolled to forward or backward.
  1.1323 +   * @param gCurrentTest.canFailRandomly
  1.1324 +   *          If this is not undefined, this test can fail by unexpected view
  1.1325 +   *          scrolling which is caused by unexpected timeout.  If this is
  1.1326 +   *          defined, |gCurrentTest.possibleView| must be set.  If the view is
  1.1327 +   *          same as the event target, the failure can be random.  At this
  1.1328 +   *          time, we should retry the current test list.
  1.1329 +   */
  1.1330 +
  1.1331 +  if (!(gLitesnEvents & kListenEvent_OnScroll))
  1.1332 +    return;
  1.1333 +
  1.1334 +  // Now testing a timeout, but a view is scrolled before timeout.
  1.1335 +  if (gCurrentTest.isTimeoutTesting && !gCurrentTest.wasTransactionTimeout) {
  1.1336 +    is(aEvent.target.id, "",
  1.1337 +       "The view scrolled before timeout (the expected view after timeout is " +
  1.1338 +         gCurrentTest.expectedView ? gCurrentTest.expectedView.id : "null" +
  1.1339 +         "): " + gCurrentTest.description);
  1.1340 +    runNextTestList();
  1.1341 +    return;
  1.1342 +  }
  1.1343 +
  1.1344 +  // Check whether the scrolled event should be fired or not.
  1.1345 +  if (!gCurrentTest.expectedView) {
  1.1346 +    is(aEvent.target.id, "",
  1.1347 +         "no views should be scrolled (" +
  1.1348 +         _getScrolledStateText(_getScrolledState(aEvent.target)) + "): " +
  1.1349 +         gCurrentTest.description);
  1.1350 +    runNextTestList();
  1.1351 +    return;
  1.1352 +  }
  1.1353 +
  1.1354 +  // Check whether the scrolled view is expected or not.
  1.1355 +  if (aEvent.target != gCurrentTest.expectedView) {
  1.1356 +    // If current test can fail randomly and the possible view is same as the
  1.1357 +    // event target, this failure may be caused by unexpected timeout.
  1.1358 +    // At this time, we should retry the current tests with slower settings.
  1.1359 +    if (gCurrentTest.canFailRandomly &&
  1.1360 +        gCurrentTest.canFailRandomly.possibleView == aEvent.target &&
  1.1361 +        gCurrentTestListStatus.retryWhenTransactionTimeout > 0) {
  1.1362 +      gCurrentTestListStatus.retryWhenTransactionTimeout--;
  1.1363 +      retryCurrentTestList();
  1.1364 +      return;
  1.1365 +    }
  1.1366 +    is(aEvent.target.id, gCurrentTest.expectedView.id,
  1.1367 +       "wrong view was scrolled: " + gCurrentTest.description);
  1.1368 +    runNextTestList();
  1.1369 +    return;
  1.1370 +  }
  1.1371 +
  1.1372 +  // Check whether the scrolling direction is expected or not.
  1.1373 +  var expectedState = _getExpectedScrolledState();
  1.1374 +  var currentState = _getScrolledState(aEvent.target);
  1.1375 +  if (expectedState != currentState) {
  1.1376 +    is(_getScrolledStateText(currentState),
  1.1377 +       _getScrolledStateText(expectedState),
  1.1378 +       "scrolled to wrong direction: " + gCurrentTest.description);
  1.1379 +    runNextTestList();
  1.1380 +    return;
  1.1381 +  }
  1.1382 +
  1.1383 +  ok(true, "passed: " + gCurrentTest.description);
  1.1384 +  continueTest();
  1.1385 +}
  1.1386 +
  1.1387 +function onMouseScrollFailed()
  1.1388 +{
  1.1389 +  /**
  1.1390 +   * Scroll failed event handler. If testing is failed, this function cancels
  1.1391 +   * all remains of current test-list, and go to next test-list.
  1.1392 +   *
  1.1393 +   * NOTE: This event is fired immediately after |_fireWheelScrollEvent|.
  1.1394 +   *
  1.1395 +   * @param gCurrentTest.expectedView
  1.1396 +   *          The expected view which should be scrolled by the wheel event.
  1.1397 +   *          This value can be null.  It means any views should not be
  1.1398 +   *          scrolled.  When this is not null, this event means the test may
  1.1399 +   *          be failed.
  1.1400 +   */
  1.1401 +
  1.1402 +  if (!(gLitesnEvents & kListenEvent_OnScrollFailed))
  1.1403 +    return;
  1.1404 +
  1.1405 +  ok(!gCurrentTest.expectedView,
  1.1406 +     "failed to scroll on current target: " + gCurrentTest.description);
  1.1407 +  if (gCurrentTest.expectedView) {
  1.1408 +    runNextTestList();
  1.1409 +    return;
  1.1410 +  }
  1.1411 +
  1.1412 +  continueTest();
  1.1413 +}
  1.1414 +
  1.1415 +function onTransactionTimeout()
  1.1416 +{
  1.1417 +  /**
  1.1418 +   * Scroll transaction timeout event handler.  If the timeout is unexpected,
  1.1419 +   * i.e., |gCurrentTest.isTimeoutTesting| is not true, this function retry
  1.1420 +   * the current test-list.  However, if the current test-list failed by timeout
  1.1421 +   * |gCurrentTestListStatus.retryWhenTransactionTimeout| times already, marking
  1.1422 +   * to failed the current test-list, and go to next test-list.
  1.1423 +   *
  1.1424 +   * @param gCurrentTest.expectedView
  1.1425 +   *          The expected view which should be scrolled by the wheel event.
  1.1426 +   *          This value can be null.  It means any views should not be
  1.1427 +   *          scrolled.  When this is not null, this event means the testing may
  1.1428 +   *          be failed.
  1.1429 +   * @param gCurrentTest.isTimeoutTesting
  1.1430 +   *          If this value is true, the current testing have waited this
  1.1431 +   *          event.  Otherwise, the testing may be failed.
  1.1432 +   * @param gCurrentTestListStatus.retryWhenTransactionTimeout
  1.1433 +   *          If |gCurrentTest.isTimeoutTesting| is not true but this event is
  1.1434 +   *          fired, the failure may be randomly.  Then, this event handler
  1.1435 +   *          retry to test the current test-list until this cound will be zero.
  1.1436 +   */
  1.1437 +
  1.1438 +  if (!gCurrentTest.isTimeoutTesting &&
  1.1439 +      gCurrentTestListStatus.retryWhenTransactionTimeout > 0) {
  1.1440 +    gCurrentTestListStatus.retryWhenTransactionTimeout--;
  1.1441 +    // retry current test list
  1.1442 +    retryCurrentTestList();
  1.1443 +    return;
  1.1444 +  }
  1.1445 +
  1.1446 +  gCurrentTest.wasTransactionTimeout = true;
  1.1447 +
  1.1448 +  if (!(gLitesnEvents & kListenEvent_OnTransactionTimeout))
  1.1449 +    return;
  1.1450 +
  1.1451 +  ok(gCurrentTest.isTimeoutTesting,
  1.1452 +     "transaction timeout: " + gCurrentTest.description);
  1.1453 +  if (!gCurrentTest.isTimeoutTesting) {
  1.1454 +    runNextTestList();
  1.1455 +    return;
  1.1456 +  }
  1.1457 +
  1.1458 +  continueTest();
  1.1459 +}
  1.1460 +
  1.1461 +/******************************************************************************
  1.1462 + * Main function for this tests
  1.1463 + ******************************************************************************/
  1.1464 +
  1.1465 +function runNextTestStep()
  1.1466 +{
  1.1467 +  // When this is first time or the current test list is finised, load next
  1.1468 +  // test-list.
  1.1469 +  _clearTimer();
  1.1470 +  if (!gCurrentTest)
  1.1471 +    runNextTestList();
  1.1472 +  else
  1.1473 +    runTestStepAt(gCurrentTestListStatus.nextStepIndex);
  1.1474 +}
  1.1475 +
  1.1476 +function runNextTestList()
  1.1477 +{
  1.1478 +  _clearTimer();
  1.1479 +
  1.1480 +  gLitesnEvents = kListenEvent_None;
  1.1481 +  _clearTransaction();
  1.1482 +  resetTimeoutPrefs();
  1.1483 +  if (gCurrentTestListStatus.nextListIndex >= gTestLists.length) {
  1.1484 +    finish();
  1.1485 +    return;
  1.1486 +  }
  1.1487 +
  1.1488 +  gCurrentTestListStatus.nextListIndex++;
  1.1489 +  gCurrentTestListStatus.retryWhenTransactionTimeout =
  1.1490 +    _getCurrentTestList().retryWhenTransactionTimeout;
  1.1491 +  runTestStepAt(0);
  1.1492 +}
  1.1493 +
  1.1494 +function runTestStepAt(aStepIndex)
  1.1495 +{
  1.1496 +  _clearTimer();
  1.1497 +
  1.1498 +  disableNonTestMouseEvents(true);
  1.1499 +
  1.1500 +  // load a step of testing.
  1.1501 +  gCurrentTestListStatus.nextStepIndex = aStepIndex;
  1.1502 +  gCurrentTest =
  1.1503 +    _getCurrentTestList().steps[gCurrentTestListStatus.nextStepIndex++];
  1.1504 +  if (gCurrentTest) {
  1.1505 +    gCurrentTest.wasTransactionTimeout = false;
  1.1506 +    gTimer = setTimeout(gCurrentTest.func, gCurrentTest.delay);
  1.1507 +  } else {
  1.1508 +    // If current test-list doesn't have more testing, go to next test-list
  1.1509 +    // after cleaning up the current transaction.
  1.1510 +    _clearTransaction();
  1.1511 +    runNextTestList();
  1.1512 +  }
  1.1513 +}
  1.1514 +
  1.1515 +function retryCurrentTestList()
  1.1516 +{
  1.1517 +  _clearTimer();
  1.1518 +
  1.1519 +  gLitesnEvents = kListenEvent_None;
  1.1520 +  _clearTransaction();
  1.1521 +  ok(true, "WARNING: retry current test-list...");
  1.1522 +  growUpTimeoutPrefs(); // retry the test with longer timeout settings.
  1.1523 +  runTestStepAt(0);
  1.1524 +}
  1.1525 +
  1.1526 +function continueTest()
  1.1527 +{
  1.1528 +  /**
  1.1529 +   * This function is called from an event handler when a test succeeded.
  1.1530 +   *
  1.1531 +   * @param gCurrentTest.repeatTest
  1.1532 +   *          When this is true, onScrollView calls |gCurrentTest.func|. So,
  1.1533 +   *          same test can repeat.  Otherwise, this calls |runNextTestStep|.
  1.1534 +   * @param gCurrentTest.autoRepeatDelay
  1.1535 +   *          The delay value in milliseconds, this is used to call
  1.1536 +   *          |gCurrentTest.func| via |setTimeout|.
  1.1537 +   */
  1.1538 +
  1.1539 +  _clearTimer();
  1.1540 +  gLitesnEvents = kListenEvent_OnTransactionTimeout;
  1.1541 +
  1.1542 +  // We should call each functions via setTimeout. Because sometimes this test
  1.1543 +  // is broken by stack overflow.
  1.1544 +  if (gCurrentTest.repeatTest) {
  1.1545 +    gTimer = setTimeout(gCurrentTest.func, gCurrentTest.autoRepeatDelay);
  1.1546 +  } else {
  1.1547 +    gTimer = setTimeout(runNextTestStep, 0);
  1.1548 +  }
  1.1549 +}
  1.1550 +
  1.1551 +]]>
  1.1552 +</script>
  1.1553 +
  1.1554 +</window>

mercurial