<?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin" type="text/css"?> <window title="Wheel scroll tests" width="600" height="600" onload="onload();" onunload="onunload();" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" /> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" /> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/paint_listener.js" /> <body xmlns="http://www.w3.org/1999/xhtml"> <style type="text/css"> #rootview { overflow: auto; width: 400px; height: 400px; border: 1px solid; } #container { overflow: auto; width: 600px; height: 600px; } #rootview pre { margin: 20px 0 20px 20px; padding: 0; overflow: auto; display: block; width: 100px; height: 100.5px; font-size: 16px; } </style> <div id="rootview" onscroll="onScrollView(event);"> <div id="container"> <pre id="subview1" onscroll="onScrollView(event);"> Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. </pre> <pre id="subview2" onscroll="onScrollView(event);"> Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. </pre> <pre id="subview3" onscroll="onScrollView(event);"> Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. </pre> </div> </div> <div id="content" style="display: none"> </div> <pre id="test"> </pre> </body> <script class="testbody" type="application/javascript"> <![CDATA[ function ok(aCondition, aMessage) { window.opener.wrappedJSObject.SimpleTest.ok(aCondition, aMessage); } function is(aLeft, aRight, aMessage) { window.opener.wrappedJSObject.SimpleTest.is(aLeft, aRight, aMessage); } function isnot(aLeft, aRight, aMessage) { window.opener.wrappedJSObject.SimpleTest.isnot(aLeft, aRight, aMessage); } var gCurrentTestListStatus = { nextListIndex: 0 }; var gCurrentTest; const kListenEvent_None = 0; const kListenEvent_OnScroll = 1; const kListenEvent_OnScrollFailed = 2; const kListenEvent_OnTransactionTimeout = 4; const kListenEvent_All = kListenEvent_OnScroll | kListenEvent_OnScrollFailed | kListenEvent_OnTransactionTimeout; var gLitesnEvents = kListenEvent_None; /** * At unexpected transaction timeout, we need to stop *all* timers. But it is * difficult and it can be create more complex testing code. So, we should use * only one timer at one time. For that, we must store the timer id to this * variable. And the functions which may be called via a timer must clear the * current timer by |_clearTimer| function. */ var gTimer; var gPrefSvc = Components.classes["@mozilla.org/preferences-service;1"]. getService(Components.interfaces.nsIPrefBranch); const kPrefSmoothScroll = "general.smoothScroll"; const kPrefNameTimeout = "mousewheel.transaction.timeout"; const kPrefNameIgnoreMoveDelay = "mousewheel.transaction.ignoremovedelay"; const kPrefTestEventsAsyncEnabled = "test.events.async.enabled"; const kDefaultTimeout = gPrefSvc.getIntPref(kPrefNameTimeout); const kDefaultIgnoreMoveDelay = gPrefSvc.getIntPref(kPrefNameIgnoreMoveDelay); gPrefSvc.setBoolPref(kPrefSmoothScroll, false); gPrefSvc.setBoolPref(kPrefTestEventsAsyncEnabled, true); var gTimeout, gIgnoreMoveDelay; var gEnoughForTimeout, gEnoughForIgnoreMoveDelay; function setTimeoutPrefs(aTimeout, aIgnoreMoveDelay) { gPrefSvc.setIntPref(kPrefNameTimeout, aTimeout); gPrefSvc.setIntPref(kPrefNameIgnoreMoveDelay, aIgnoreMoveDelay); gTimeout = aTimeout; gIgnoreMoveDelay = aIgnoreMoveDelay; gEnoughForTimeout = gTimeout * 2; gEnoughForIgnoreMoveDelay = gIgnoreMoveDelay * 1.2; } function resetTimeoutPrefs() { if (gTimeout == kDefaultTimeout) return; setTimeoutPrefs(kDefaultTimeout, kDefaultIgnoreMoveDelay); initTestList(); } function growUpTimeoutPrefs() { if (gTimeout != kDefaultTimeout) return; setTimeoutPrefs(5000, 1000); initTestList(); } // setting enough time for testing. gPrefSvc.setIntPref(kPrefNameTimeout, gTimeout); gPrefSvc.setIntPref(kPrefNameIgnoreMoveDelay, gIgnoreMoveDelay); var gRootView = document.getElementById("rootview"); var gSubView1 = document.getElementById("subview1"); var gSubView2 = document.getElementById("subview2"); var gSubView3 = document.getElementById("subview3"); gRootView.addEventListener("MozMouseScrollFailed", onMouseScrollFailed, false); gRootView.addEventListener("MozMouseScrollTransactionTimeout", onTransactionTimeout, false); function finish() { window.close(); } function onload() { runNextTestList(); } function onunload() { resetTimeoutPrefs(); gPrefSvc.clearUserPref(kPrefSmoothScroll); gPrefSvc.clearUserPref(kPrefTestEventsAsyncEnabled); disableNonTestMouseEvents(false); SpecialPowers.DOMWindowUtils.restoreNormalRefresh(); window.opener.wrappedJSObject.SimpleTest.finish(); } const kSubView1Offset = { x: 20, y: 20 }; const kSubView2Offset = { x: 20, y: 20 + 100 + 20 }; const kSubView3Offset = { x: 20, y: 20 + (100 + 20) * 2 }; function _getSubViewTestPtForV(aPt) { return { x: aPt.x + 10, y: aPt.y + 10 }; } const kPtInRootViewForV = { x: kSubView1Offset.x + 10, y: kSubView1Offset.y - 10 }; const kPtInSubView1ForV = _getSubViewTestPtForV(kSubView1Offset); const kPtInSubView2ForV = _getSubViewTestPtForV(kSubView2Offset); const kPtInSubView3ForV = _getSubViewTestPtForV(kSubView3Offset); function _convertTestPtForH(aPt) { return { x: aPt.y, y: aPt.x }; } const kPtInRootViewForH = _convertTestPtForH(kPtInRootViewForV); const kPtInSubView1ForH = _convertTestPtForH(kPtInSubView1ForV); const kPtInSubView2ForH = _convertTestPtForH(kPtInSubView2ForV); const kPtInSubView3ForH = _convertTestPtForH(kPtInSubView3ForV); /** * Define the tests here: * Scrolls are processed async always. Therefore, we need to call all tests * by timer. gTestLists is array of testing lists. In other words, an item * of gTestList is a group of one or more testing. Each items has following * properties: * * - retryWhenTransactionTimeout * The testing of wheel transaction might be fialed randomly by * timeout. Then, automatically the failed test list will be retested * automatically only this number of times. * * - steps * This property is array of testing. Each steps must have following * properties at least. * * - func * This property means function which will be called via * |setTimeout|. The function cannot have params. If you need * some additional parameters, you can specify some original * properties for the test function. If you do so, you should * document it in the testing function. * - delay * This property means delay time until the function to be called. * I.e., the value used for the second param of |setTimeout|. * * And also you need one more property when you call a testing function. * * - description * This property is description of the test. This is used for * logging. * * At testing, you can access to current step via |gCurrentTest|. */ var gTestLists; function initTestList() { gTestLists = [ /************************************************************************** * Continuous scrolling test for |gRootView| * |gRootView| has both scrollbars and it has three children which are * |gSubView1|, |gSubView2| and |gSubView3|. They have scrollbars. If * the current transaction targets |gRootView|, other children should not * be scrolled even if the wheel events are fired on them. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ // Vertical case { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Vertical wheel events should scroll |gRootView| even if the position // of wheel events in a child view which has scrollbar. { func: testContinuousScroll, delay: 0, offset: kPtInRootViewForV, isForward: true, isVertical: true, expectedView: gRootView, description: "Continuous scrolling test for root view (vertical/forward)" }, { func: testContinuousScroll, delay: 0, offset: kPtInRootViewForV, isForward: false, isVertical: true, expectedView: gRootView, description: "Continuous scrolling test for root view (vertical/backward)" } ] }, { retryWhenTransactionTimeout: 5, steps: [ // Horizontal case { func: initElements, delay: 0, forVertical: false, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Horizontal wheel events should scroll |gRootView| even if the // position of wheel events in a child view which has scrollbar. { func: testContinuousScroll, delay: 0, offset: kPtInRootViewForH, isForward: true, isVertical: false, expectedView: gRootView, description: "Continuous scrolling test for root view (horizontal/forward)" }, { func: testContinuousScroll, delay: 0, offset: kPtInRootViewForH, isForward: false, isVertical: false, expectedView: gRootView, description: "Continuous scrolling test for root view (horizontal/backward)" } ] }, /************************************************************************** * Continuous scrolling test for |gSubView1| * |gSubView1| has both scrollbars. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ // Vertical case { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Vertical wheel events should scroll |gSubView1|. { func: testContinuousScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gSubView1, description: "Continuous scrolling test for sub view 1 (vertical/forward)" }, { func: testContinuousScroll, delay: 0, offset: kPtInSubView1ForV, isForward: false, isVertical: true, expectedView: gSubView1, description: "Continuous scrolling test for sub view 1 (vertical/backward)" } ] }, { retryWhenTransactionTimeout: 5, steps: [ // Horizontal case { func: initElements, delay: 0, forVertical: false, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Horitontal wheel events should scroll |gSubView1|. { func: testContinuousScroll, delay: 0, offset: kPtInSubView1ForH, isForward: true, isVertical: false, expectedView: gSubView1, description: "Continuous scrolling test for sub view 1 (horizontal/forward)" }, { func: testContinuousScroll, delay: 0, offset: kPtInSubView1ForH, isForward: false, isVertical: false, expectedView: gSubView1, description: "Continuous scrolling test for sub view 1 (horizontal/backward)" } ] }, /************************************************************************** * Continuous scrolling test for |gSubView2| * |gSubView2| has only vertical scrollbar. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ // Vertical case { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Vertical wheel events should scroll |gSubView2|. { func: testContinuousScroll, delay: 0, offset: kPtInSubView2ForV, isForward: true, isVertical: true, expectedView: gSubView2, description: "Continuous scrolling test for sub view 2 (vertical/forward)" }, { func: testContinuousScroll, delay: 0, offset: kPtInSubView2ForV, isForward: false, isVertical: true, expectedView: gSubView2, description: "Continuous scrolling test for sub view 2 (vertical/backward)" } ] }, { retryWhenTransactionTimeout: 5, steps: [ // Horizontal case { func: initElements, delay: 0, forVertical: false, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Horizontal wheel events should scroll its nearest scrollable ancestor // view, i.e., it is |gRootView|. { func: testContinuousScroll, delay: 0, offset: kPtInSubView2ForH, isForward: true, isVertical: false, expectedView: gRootView, description: "Continuous scrolling test for sub view 2 (horizontal/forward)" }, { func: testContinuousScroll, delay: 0, offset: kPtInSubView2ForH, isForward: false, isVertical: false, expectedView: gRootView, description: "Continuous scrolling test for sub view 2 (horizontal/backward)" } ] }, /************************************************************************** * Continuous scrolling test for |gSubView3| * |gSubView3| has only horizontal scrollbar. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ // Vertical case { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Vertical wheel events should scroll its nearest scrollable ancestor // view, i.e., it is |gRootView|. { func: testContinuousScroll, delay: 0, offset: kPtInSubView3ForV, isForward: true, isVertical: true, expectedView: gRootView, description: "Continuous scrolling test for sub view 3 (vertical/forward)" }, { func: testContinuousScroll, delay: 0, offset: kPtInSubView3ForV, isForward: false, isVertical: true, expectedView: gRootView, description: "Continuous scrolling test for sub view 3 (vertical/backward)" } ] }, { retryWhenTransactionTimeout: 5, steps: [ // Horizontal case { func: initElements, delay: 0, forVertical: false, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Horitontal wheel events should scroll |gSubView3|. { func: testContinuousScroll, delay: 0, offset: kPtInSubView3ForH, isForward: true, isVertical: false, expectedView: gSubView3, description: "Continuous scrolling test for sub view 3 (horizontal/forward)" }, { func: testContinuousScroll, delay: 0, offset: kPtInSubView3ForH, isForward: false, isVertical: false, expectedView: gSubView3, description: "Continuous scrolling test for sub view 3 (horizontal/backward)" } ] }, /************************************************************************** * Don't reset transaction by a different direction wheel event * Even if a wheel event doesn't same direction as last wheel event, the * current transaction should not be reset. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ // Vertical -> Horizontal { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Create a transaction which targets |gRootView| by a vertical wheel // event. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV, isForward: true, isVertical: true, expectedView: gRootView, description: "Don't reset transaction by a different direction wheel event (1-1)" }, // Scroll back to top-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV, isForward: false, isVertical: true, expectedView: gRootView, description: "Don't reset transaction by a different direction wheel event (1-2)" }, // Send a horizontal wheel event over |gSubView1| but |gRootView| should // be scrolled. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: false, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Don't reset transaction by a different direction wheel event (1-3)" } ] }, { retryWhenTransactionTimeout: 5, steps: [ // Horizontal -> Vertical { func: initElements, delay: 0, forVertical: false, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Create a transaction which targets |gRootView| by a horizontal wheel // event. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH, isForward: true, isVertical: false, expectedView: gRootView, description: "Don't reset transaction by a different direction wheel event (2-1)" }, // Scroll back to left-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH, isForward: false, isVertical: false, expectedView: gRootView, description: "Don't reset transaction by a different direction wheel event (2-2)" }, // Send a vertical wheel event over |gSubView1| but |gRootView| should // be scrolled. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH, isForward: true, isVertical: true, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Don't reset transaction by a different direction wheel event (2-3)" } ] }, /************************************************************************** * Don't reset transaction even if a wheel event cannot scroll * Even if a wheel event cannot scroll to specified direction in the * current target view, the transaction should not be reset. E.g., there * are some devices which can scroll obliquely. If so, probably, users * cannot input only intended direction. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ // A view only has vertical scrollbar case. { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Create a transaction which targets |gSubView2|. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView2ForV, isForward: true, isVertical: true, expectedView: gSubView2, description: "Don't reset transaction even if a wheel event cannot scroll (1-1)" }, // |gSubView2| doesn't have horizontal scrollbar but should not scroll // any views. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView2ForV, isForward: true, isVertical: false, expectedView: null, description: "Don't reset transaction even if a wheel event cannot scroll (1-2)" } ] }, { retryWhenTransactionTimeout: 5, steps: [ // A view only has horizontal scrollbar case. { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Create a transaction which targets |gSubView3|. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView3ForV, isForward: true, isVertical: false, expectedView: gSubView3, description: "Don't reset transaction even if a wheel event cannot scroll (2-1)" }, // |gSubView3| doesn't have vertical scrollbar but should not scroll any // views. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView3ForV, isForward: true, isVertical: true, expectedView: null, description: "Don't reset transaction even if a wheel event cannot scroll (2-2)" } ] }, /************************************************************************** * Reset transaction by mouse down/mouse up events * Mouse down and mouse up events should cause resetting the current * transaction. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ // Vertical case { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Create a transaction which targets |gRootView|. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV, isForward: true, isVertical: true, expectedView: gRootView, description: "Reset transaction by mouse down/mouse up events (v-1)" }, // Scroll back to top-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV, isForward: false, isVertical: true, expectedView: gRootView, description: "Reset transaction by mouse down/mouse up events (v-2)" }, // Send mouse button events which should reset the current transaction. // So, the next wheel event should scroll |gSubView1|. { func: sendMouseButtonEvents, delay: 0, description: "sendMouseButtonEvents" }, { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gSubView1, description: "Reset transaction by mouse down/mouse up events (v-3)" } ] }, { retryWhenTransactionTimeout: 5, steps: [ // Horizontal case { func: initElements, delay: 0, forVertical: false, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Create a transaction which targets |gRootView|. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH, isForward: true, isVertical: false, expectedView: gRootView, description: "Reset transaction by mouse down/mouse up events (h-1)" }, // Scroll back to left-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH, isForward: false, isVertical: false, expectedView: gRootView, description: "Reset transaction by mouse down/mouse up events (h-2)" }, // Send mouse button events which should reset the current transaction. // So, the next wheel event should scroll |gSubView1|. { func: sendMouseButtonEvents, delay: 0, description: "sendMouseButtonEvents" }, { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH, isForward: true, isVertical: false, expectedView: gSubView1, description: "Reset transaction by mouse down/mouse up events (h-3)" } ] }, /************************************************************************** * Reset transaction by a key event * A key event should cause resetting the current transaction. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ // Vertical case { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Create a transaction which targets |gRootView|. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV, isForward: true, isVertical: true, expectedView: gRootView, description: "Reset transaction by a key event (v-1)" }, // Scroll back to top-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV, isForward: false, isVertical: true, expectedView: gRootView, description: "Reset transaction by a key event (v-2)" }, // Send a key event which should reset the current transaction. So, the // next wheel event should scroll |gSubView1|. { func: sendKeyEvents, delay: 0, key: "a", description: "sendKeyEvents" }, { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gSubView1, description: "Reset transaction by a key event (v-3)" } ] }, { retryWhenTransactionTimeout: 5, steps: [ // Horizontal case { func: initElements, delay: 0, forVertical: false, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Create a transaction which targets |gRootView|. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH, isForward: true, isVertical: false, expectedView: gRootView, description: "Reset transaction by a key event (h-1)" }, // Scroll back to left-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH, isForward: false, isVertical: false, expectedView: gRootView, description: "Reset transaction by a key event (h-2)" }, // Send a key event which should reset the current transaction. So, the // next wheel event should scroll |gSubView1|. { func: sendKeyEvents, delay: 0, key: "a", description: "sendKeyEvents" }, { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH, isForward: true, isVertical: false, expectedView: gSubView1, description: "Reset transaction by a key event (h-3)" } ] }, /************************************************************************** * Reset transaction by a mouse move event * A mouse move event can cause reseting the current transaction even if * mouse cursor is inside the target view of current transaction. Only * when a wheel event is fired after |gIgnoreMoveDelay| milliseconds since * the first mouse move event from last wheel event, the transaction * should be reset. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ // Vertical case { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Create a transaction which targets |gRootView|. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV, isForward: true, isVertical: true, expectedView: gRootView, description: "Reset transaction by a mouse move event (v-1)" }, // Scroll back to top-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV, isForward: false, isVertical: true, expectedView: gRootView, description: "Reset transaction by a mouse move event (v-2)" }, // Send a mouse move event immediately after last wheel event, then, // current transaction should be kept. { func: sendMouseMoveEvent, delay: 0, offset: kPtInSubView1ForV, description: "sendMouseMoveEvent" }, { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (v-3)" }, // Scroll back to top-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: false, isVertical: true, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (v-4)" }, // Send a mouse move event after |gIgnoreMoveDelay| milliseconds since // last wheel event, then, current transaction should be kept. { func: sendMouseMoveEvent, delay: gEnoughForIgnoreMoveDelay, offset: kPtInSubView1ForV, description: "sendMouseMoveEvent" }, { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (v-5)" }, // Scroll back to top-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: false, isVertical: true, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (v-6)" }, // Send a wheel event after |gIgnoreMoveDelay| milliseconds since last // mouse move event but it is fired immediately after the last wheel // event, then, current transaction should be kept. { func: sendMouseMoveEvent, delay: 0, offset: kPtInSubView1ForV, description: "sendMouseMoveEvent" }, { func: testOneTimeScroll, delay: gEnoughForIgnoreMoveDelay, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (v-7)" }, // Scroll back to top-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: false, isVertical: true, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (v-8)" }, // Send a wheel event after |gIgnoreMoveDelay| milliseconds have passed // since last mouse move event which is fired after |gIgnoreMoveDelay| // milliseconds since last wheel event, then, current transaction should // be reset. { func: sendMouseMoveEvent, delay: gEnoughForIgnoreMoveDelay, offset: kPtInSubView1ForV, description: "sendMouseMoveEvent" }, { func: testOneTimeScroll, delay: gEnoughForIgnoreMoveDelay, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gSubView1, canFailRandomly: { possibleView: gRootView }, description: "Reset transaction by a mouse move event (v-9)" } ] }, { retryWhenTransactionTimeout: 5, steps: [ // Horizontal case { func: initElements, delay: 0, forVertical: false, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Create a transaction which targets |gRootView|. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH, isForward: true, isVertical: false, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (h-1)" }, // Scroll back to top-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH, isForward: false, isVertical: false, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (h-2)" }, // Send a mouse move event immediately after last wheel event, then, // current transaction should be kept. { func: sendMouseMoveEvent, delay: 0, offset: kPtInSubView1ForH, description: "sendMouseMoveEvent" }, { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH, isForward: true, isVertical: false, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (h-3)" }, // Scroll back to top-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH, isForward: false, isVertical: false, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (h-4)" }, // Send a mouse move event after |gIgnoreMoveDelay| milliseconds since // last wheel event, then, current transaction should be kept. { func: sendMouseMoveEvent, delay: gEnoughForIgnoreMoveDelay, offset: kPtInSubView1ForH, description: "sendMouseMoveEvent" }, { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH, isForward: true, isVertical: false, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (h-5)" }, // Scroll back to top-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH, isForward: false, isVertical: false, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (h-6)" }, // Send a wheel event after |gIgnoreMoveDelay| milliseconds since last // mouse move event but it is fired immediately after the last wheel // event, then, current transaction should be kept. { func: sendMouseMoveEvent, delay: 0, offset: kPtInSubView1ForH, description: "sendMouseMoveEvent" }, { func: testOneTimeScroll, delay: gEnoughForIgnoreMoveDelay, offset: kPtInSubView1ForH, isForward: true, isVertical: false, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (h-7)" }, // Scroll back to top-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH, isForward: false, isVertical: false, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Reset transaction by a mouse move event (h-8)" }, // Send a wheel event after |gIgnoreMoveDelay| milliseconds have passed // since last mouse move event which is fired after |gIgnoreMoveDelay| // milliseconds since last wheel event, then, current transaction should // be reset. { func: sendMouseMoveEvent, delay: gEnoughForIgnoreMoveDelay, offset: kPtInSubView1ForH, description: "sendMouseMoveEvent" }, { func: testOneTimeScroll, delay: gEnoughForIgnoreMoveDelay, offset: kPtInSubView1ForH, isForward: true, isVertical: false, expectedView: gSubView1, canFailRandomly: { possibleView: gRootView }, description: "Reset transaction by a mouse move event (h-9)" } ] }, /************************************************************************** * Reset transaction by a mouse move event on outside of view * When mouse cursor is moved to outside of the current target view, the * transaction should be reset immediately. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ // Vertical case { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Create a transaction which targets |gSubView1|. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gSubView1, description: "Reset transaction by a mouse move event on outside of view (v-1)" }, // Send mouse move event over |gRootView|. { func: sendMouseMoveEvent, delay: 0, offset: kPtInRootViewForV, description: "sendMouseMoveEvent" }, // Send Wheel event over |gRootView| which should be scrolled. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV, isForward: true, isVertical: true, expectedView: gRootView, description: "Reset transaction by a mouse move event on outside of view (v-2)" } ] }, { retryWhenTransactionTimeout: 5, steps: [ // Horizontal case { func: initElements, delay: 0, forVertical: false, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Create a transaction which targets |gSubView1|. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH, isForward: true, isVertical: true, expectedView: gSubView1, description: "Reset transaction by a mouse move event on outside of view (h-1)" }, // Send mouse move event over |gRootView|. { func: sendMouseMoveEvent, delay: 0, offset: kPtInRootViewForH, description: "sendMouseMoveEvent" }, // Send Wheel event over |gRootView| which should be scrolled. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH, isForward: true, isVertical: true, expectedView: gRootView, description: "Reset transaction by a mouse move event on outside of view (h-2)" } ] }, /************************************************************************** * Timeout test * A view should not be scrolled during another to be transaction for * another view scrolling. However, a wheel event which is sent after * timeout, a view which is under the mouse cursor should be scrolled. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ // Vertical case { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // First, create a transaction which should target the |gRootView|. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV, isForward: true, isVertical: true, expectedView: gRootView, description: "Timeout test (v-1)" }, // Scroll back to top-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForV, isForward: false, isVertical: true, expectedView: gRootView, description: "Timeout test (v-2)" }, // A wheel event over |gSubView1| should not scroll it during current // transaction. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Timeout test (v-3)" }, // Scroll back to top-most again. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: false, isVertical: true, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Timeout test (v-4)" }, // A wheel event over |gSubView1| after timeout should scroll // |gSubView1|. { func: testOneTimeScroll, delay: gEnoughForTimeout, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gSubView1, isTimeoutTesting: true, description: "Timeout test (v-5)" } ] }, { retryWhenTransactionTimeout: 5, steps: [ // Horizontal case { func: initElements, delay: 0, forVertical: false, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // First, create a transaction which should target the |gRootView|. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH, isForward: true, isVertical: false, expectedView: gRootView, description: "Timeout test (h-1)" }, // Scroll back to left-most for easy cursor position specifying. { func: testOneTimeScroll, delay: 0, offset: kPtInRootViewForH, isForward: false, isVertical: false, expectedView: gRootView, description: "Timeout test (h-2)" }, // A wheel event over |gSubView1| should not scroll it during current // transaction. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH, isForward: true, isVertical: false, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Timeout test (h-3)" }, // Scroll back to left-most again. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH, isForward: false, isVertical: false, expectedView: gRootView, canFailRandomly: { possibleView: gSubView1 }, description: "Timeout test (h-4)" }, // A wheel event over |gSubView1| after timeout should scroll // |gSubView1|. { func: testOneTimeScroll, delay: gEnoughForTimeout, offset: kPtInSubView1ForH, isForward: true, isVertical: false, expectedView: gSubView1, isTimeoutTesting: true, description: "Timeout test (h-5)" } ] }, /************************************************************************** * Timeout test even with many wheel events * This tests whether timeout is occurred event if wheel events are sent. * The transaction should not be updated by non-scrollable wheel events. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ // Vertical case { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Scroll |gSubView1| to bottom-most. { func: testContinuousScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gSubView1, description: "Timeout test even with many wheel events (v-1)" }, // Don't scroll any views before timeout. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: null, canFailRandomly: { possibleView: gRootView }, description: "Timeout test even with many wheel events (v-2)" }, // Recreate a transaction which is scrolling |gRootView| after time out. { func: testRestartScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gRootView, description: "Timeout test even with many wheel events (v-3)" } ] }, { retryWhenTransactionTimeout: 5, steps: [ // Horizontal case { func: initElements, delay: 0, forVertical: false, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, // Scroll |gSubView1| to right-most. { func: testContinuousScroll, delay: 0, offset: kPtInSubView1ForH, isForward: true, isVertical: false, expectedView: gSubView1, description: "Timeout test even with many wheel events (h-1)" }, // Don't scroll any views before timeout. { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForH, isForward: true, isVertical: false, expectedView: null, canFailRandomly: { possibleView: gRootView }, description: "Timeout test even with many wheel events (h-2)" }, // Recreate a transaction which is scrolling |gRootView| after time out. { func: testRestartScroll, delay: 0, offset: kPtInSubView1ForH, isForward: true, isVertical: false, expectedView: gRootView, description: "Timeout test even with many wheel events (h-3)" } ] }, /************************************************************************** * Very large scrolling wheel event * If the delta value is larger than the scrolling page size, it should be * scrolled only one page instead of the delta value. **************************************************************************/ { retryWhenTransactionTimeout: 5, steps: [ { func: initElements, delay: 0, forVertical: true, description: "initElements" }, { func: clearWheelTransaction, delay: 0, description: "clearWheelTransaction" }, { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gSubView1, delta: 5000, description: "Very large delta scrolling (v-1)" }, { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: true, expectedView: gSubView1, delta: 5000, description: "Very large delta scrolling (v-2)" }, { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: false, expectedView: gSubView1, delta: 5000, description: "Very large delta scrolling (h-1)" }, { func: testOneTimeScroll, delay: 0, offset: kPtInSubView1ForV, isForward: true, isVertical: false, expectedView: gSubView1, delta: 5000, description: "Very large delta scrolling (h-2)" } ] } ]; } /****************************************************************************** * Actions for preparing tests ******************************************************************************/ function initElements() { _clearTimer(); function resetScrollPosition(aElement) { aElement.scrollTop = 0; aElement.scrollLeft = 0; } function initInRootView(aElement, aPt) { aElement.offset = gCurrentTest.forVertical ? aPt : { x: aPt.y, y: aPt.x }; } const kDisplay = gCurrentTest.forVertical ? "block" : "inline-block"; gSubView1.style.display = kDisplay; gSubView2.style.display = kDisplay; gSubView3.style.display = kDisplay; resetScrollPosition(gRootView); resetScrollPosition(gSubView1); resetScrollPosition(gSubView2); resetScrollPosition(gSubView3); _getDOMWindowUtils(window).advanceTimeAndRefresh(0); runNextTestStep(); } function clearWheelTransaction() { _clearTimer(); _clearTransaction(); runNextTestStep(); } function sendKeyEvents() { _clearTimer(); synthesizeKey(gCurrentTest.key, {}, window); runNextTestStep(); } function sendMouseButtonEvents() { _clearTimer(); synthesizeMouse(gRootView, -1, -1, { type:"mousedown" }, window); synthesizeMouse(gRootView, -1, -1, { type:"mouseup" }, window); runNextTestStep(); } function sendMouseMoveEvent() { _clearTimer(); _fireMouseMoveEvent(gCurrentTest.offset); runNextTestStep(); } /****************************************************************************** * Utilities for testing functions ******************************************************************************/ function _clearTransaction() { synthesizeMouse(gRootView, -1, -1, { type:"mousedown" }, window); synthesizeMouse(gRootView, -1, -1, { type:"mouseup" }, window); } function _saveScrollPositions() { function save(aElement) { aElement.prevTop = aElement.scrollTop; aElement.prevLeft = aElement.scrollLeft; } save(gRootView); save(gSubView1); save(gSubView2); save(gSubView3); } function _fireMouseMoveEvent(aOffset) { synthesizeMouse(gRootView, aOffset.x, aOffset.y, { type:"mousemove" }, window); } function _fireWheelScrollEvent(aOffset, aIsVertical, aForward, aDelta) { var event = { deltaMode: WheelEvent.DOM_DELTA_LINE }; if (aIsVertical) { event.deltaY = aForward ? aDelta : -aDelta; } else { event.deltaX = aForward ? aDelta : -aDelta; } sendWheelAndPaint(gRootView, aOffset.x, aOffset.y, event, null, window); } function _canScroll(aElement, aIsVertical, aForward) { if (aIsVertical) { if (!aForward) return aElement.scrollTop > 0; return aElement.scrollHeight > aElement.scrollTop + aElement.clientHeight; } if (!aForward) return aElement.scrollLeft > 0; return aElement.scrollWidth > aElement.scrollLeft + aElement.clientWidth; } const kNotScrolled = 0; const kScrolledToTop = 1; const kScrolledToBottom = 2; const kScrolledToLeft = 4; const kScrolledToRight = 8; const kScrolledVertical = kScrolledToTop | kScrolledToBottom; const kScrolledHorizontal = kScrolledToLeft | kScrolledToRight; function _getScrolledState(aElement) { var ret = kNotScrolled; if (aElement.scrollTop != aElement.prevTop) { ret |= aElement.scrollTop < aElement.prevTop ? kScrolledToTop : kScrolledToBottom; } if (aElement.scrollLeft != aElement.prevLeft) { ret |= aElement.scrollLeft < aElement.prevLeft ? kScrolledToLeft : kScrolledToRight; } return ret; } function _getExpectedScrolledState() { return gCurrentTest.isVertical ? gCurrentTest.isForward ? kScrolledToBottom : kScrolledToTop : gCurrentTest.isForward ? kScrolledToRight : kScrolledToLeft; } function _getScrolledStateText(aScrolledState) { if (aScrolledState == kNotScrolled) return "Not scrolled"; var s = "scrolled to "; if (aScrolledState & kScrolledVertical) { s += aScrolledState & kScrolledToTop ? "backward" : "forward"; s += " (vertical)" if (aScrolledState & kScrolledHorizontal) s += " and to "; } if (aScrolledState & kScrolledHorizontal) { s += aScrolledState & kScrolledToLeft ? "backward" : "forward"; s += " (horizontal)" } return s; } function _getCurrentTestList() { return gTestLists[gCurrentTestListStatus.nextListIndex - 1]; } function _clearTimer() { clearTimeout(gTimer); gTimer = 0; } /****************************************************************************** * Testing functions ******************************************************************************/ /** * Note that testing functions must set following variables: * * gCurrentTest.repeatTest: See comment in |continueTest|. * gCurrentTest.autoRepeatDelay: See comment in |continueTest|. * gListenScrollEvent: When this is not true, the event handlers ignores the * events. */ function testContinuousScroll() { /** * Testing continuous scrolling. This function synthesizes a wheel event. If * the test was success, this function will be recalled automatically. * And when a generating wheel event cannot scroll the expected view, this * function fires the wheel event only one time. * * @param gCurrentTest.offset * The cursor position of firing wheel event. The values are offset * from |gRootView|. * @param gCurrentTest.isVertical * Whether the wheel event is for virtical scrolling or horizontal. * @param gCurrentTest.isForward * Whether the wheel event is to forward or to backward. * @param gCurrentTest.expectedView * The expected view which will be scrolled by wheel event. This * value must not be null. */ _clearTimer(); _saveScrollPositions(); if (!gCurrentTest.expectedView) { runNextTestStep(); return; } gLitesnEvents = kListenEvent_All; gCurrentTest.repeatTest = true; gCurrentTest.autoRepeatDelay = 0; if (!_canScroll(gCurrentTest.expectedView, gCurrentTest.isVertical, gCurrentTest.isForward)) { gCurrentTest.expectedView = null; } var delta = gCurrentTest.delta ? gCurrentTest.delta : 4; _fireWheelScrollEvent(gCurrentTest.offset, gCurrentTest.isVertical, gCurrentTest.isForward, delta); } function testOneTimeScroll() { /** * Testing one wheel event. |runNextTestStep| will be called immediately * after this function by |onScrollView| or |onTimeout|. * * @param gCurrentTest.offset * The cursor position of firing wheel event. The values are offset * from |gRootView|. * @param gCurrentTest.isVertical * Whether the wheel event is for virtical scrolling or horizontal. * @param gCurrentTest.isForward * Whether the wheel event is to forward or to backward. * @param gCurrentTest.expectedView * The expected view which will be scrolled by wheel event. This * value can be null. It means any views should not be scrolled. */ _clearTimer(); _saveScrollPositions(); gLitesnEvents = kListenEvent_All; gCurrentTest.repeatTest = false; gCurrentTest.autoRepeatDelay = 0; var delta = gCurrentTest.delta ? gCurrentTest.delta : 4; _fireWheelScrollEvent(gCurrentTest.offset, gCurrentTest.isVertical, gCurrentTest.isForward, delta); } function testRestartScroll() { /** * Testing restart to scroll in expected view after timeout from the current * transaction. This function recall this itself until to success this test * or timeout from this test. * * @param gCurrentTest.offset * The cursor position of firing wheel event. The values are offset * from |gRootView|. * @param gCurrentTest.isVertical * Whether the wheel event is for virtical scrolling or horizontal. * @param gCurrentTest.isForward * Whether the wheel event is to forward or to backward. * @param gCurrentTest.expectedView * The expected view which will be scrolled by wheel event. This * value must not be null. */ _clearTimer(); _saveScrollPositions(); if (!gCurrentTest.wasTransactionTimeout) { gCurrentTest.repeatTest = true; gCurrentTest.autoRepeatDelay = gTimeout / 3; gLitesnEvents = kListenEvent_All; gCurrentTest.isTimeoutTesting = true; if (gCurrentTest.expectedView) { gCurrentTest.expectedViewAfterTimeout = gCurrentTest.expectedView; gCurrentTest.expectedView = null; } } else { gCurrentTest.repeatTest = false; gCurrentTest.autoRepeatDelay = 0; gLitesnEvents = kListenEvent_All; gCurrentTest.isTimeoutTesting = false; gCurrentTest.expectedView = gCurrentTest.expectedViewAfterTimeout; } var delta = gCurrentTest.delta ? gCurrentTest.delta : 4; _fireWheelScrollEvent(gCurrentTest.offset, gCurrentTest.isVertical, gCurrentTest.isForward, delta); } /****************************************************************************** * Event handlers ******************************************************************************/ function onScrollView(aEvent) { /** * Scroll event handler of |gRootView|, |gSubView1|, |gSubView2| and * |gSubView3|. If testing is failed, this function cancels all left tests. * For checking the event is expected, the event firer must call * |_saveScrollPositions|. * * @param gCurrentTest.expectedView * The expected view which should be scrolled by the wheel event. * This value can be null. It means any views should not be * scrolled. * @param gCurrentTest.isVertical * The expected view should be scrolled vertical or horizontal. * @param gCurrentTest.isForward * The expected view should be scrolled to forward or backward. * @param gCurrentTest.canFailRandomly * If this is not undefined, this test can fail by unexpected view * scrolling which is caused by unexpected timeout. If this is * defined, |gCurrentTest.possibleView| must be set. If the view is * same as the event target, the failure can be random. At this * time, we should retry the current test list. */ if (!(gLitesnEvents & kListenEvent_OnScroll)) return; // Now testing a timeout, but a view is scrolled before timeout. if (gCurrentTest.isTimeoutTesting && !gCurrentTest.wasTransactionTimeout) { is(aEvent.target.id, "", "The view scrolled before timeout (the expected view after timeout is " + gCurrentTest.expectedView ? gCurrentTest.expectedView.id : "null" + "): " + gCurrentTest.description); runNextTestList(); return; } // Check whether the scrolled event should be fired or not. if (!gCurrentTest.expectedView) { is(aEvent.target.id, "", "no views should be scrolled (" + _getScrolledStateText(_getScrolledState(aEvent.target)) + "): " + gCurrentTest.description); runNextTestList(); return; } // Check whether the scrolled view is expected or not. if (aEvent.target != gCurrentTest.expectedView) { // If current test can fail randomly and the possible view is same as the // event target, this failure may be caused by unexpected timeout. // At this time, we should retry the current tests with slower settings. if (gCurrentTest.canFailRandomly && gCurrentTest.canFailRandomly.possibleView == aEvent.target && gCurrentTestListStatus.retryWhenTransactionTimeout > 0) { gCurrentTestListStatus.retryWhenTransactionTimeout--; retryCurrentTestList(); return; } is(aEvent.target.id, gCurrentTest.expectedView.id, "wrong view was scrolled: " + gCurrentTest.description); runNextTestList(); return; } // Check whether the scrolling direction is expected or not. var expectedState = _getExpectedScrolledState(); var currentState = _getScrolledState(aEvent.target); if (expectedState != currentState) { is(_getScrolledStateText(currentState), _getScrolledStateText(expectedState), "scrolled to wrong direction: " + gCurrentTest.description); runNextTestList(); return; } ok(true, "passed: " + gCurrentTest.description); continueTest(); } function onMouseScrollFailed() { /** * Scroll failed event handler. If testing is failed, this function cancels * all remains of current test-list, and go to next test-list. * * NOTE: This event is fired immediately after |_fireWheelScrollEvent|. * * @param gCurrentTest.expectedView * The expected view which should be scrolled by the wheel event. * This value can be null. It means any views should not be * scrolled. When this is not null, this event means the test may * be failed. */ if (!(gLitesnEvents & kListenEvent_OnScrollFailed)) return; ok(!gCurrentTest.expectedView, "failed to scroll on current target: " + gCurrentTest.description); if (gCurrentTest.expectedView) { runNextTestList(); return; } continueTest(); } function onTransactionTimeout() { /** * Scroll transaction timeout event handler. If the timeout is unexpected, * i.e., |gCurrentTest.isTimeoutTesting| is not true, this function retry * the current test-list. However, if the current test-list failed by timeout * |gCurrentTestListStatus.retryWhenTransactionTimeout| times already, marking * to failed the current test-list, and go to next test-list. * * @param gCurrentTest.expectedView * The expected view which should be scrolled by the wheel event. * This value can be null. It means any views should not be * scrolled. When this is not null, this event means the testing may * be failed. * @param gCurrentTest.isTimeoutTesting * If this value is true, the current testing have waited this * event. Otherwise, the testing may be failed. * @param gCurrentTestListStatus.retryWhenTransactionTimeout * If |gCurrentTest.isTimeoutTesting| is not true but this event is * fired, the failure may be randomly. Then, this event handler * retry to test the current test-list until this cound will be zero. */ if (!gCurrentTest.isTimeoutTesting && gCurrentTestListStatus.retryWhenTransactionTimeout > 0) { gCurrentTestListStatus.retryWhenTransactionTimeout--; // retry current test list retryCurrentTestList(); return; } gCurrentTest.wasTransactionTimeout = true; if (!(gLitesnEvents & kListenEvent_OnTransactionTimeout)) return; ok(gCurrentTest.isTimeoutTesting, "transaction timeout: " + gCurrentTest.description); if (!gCurrentTest.isTimeoutTesting) { runNextTestList(); return; } continueTest(); } /****************************************************************************** * Main function for this tests ******************************************************************************/ function runNextTestStep() { // When this is first time or the current test list is finised, load next // test-list. _clearTimer(); if (!gCurrentTest) runNextTestList(); else runTestStepAt(gCurrentTestListStatus.nextStepIndex); } function runNextTestList() { _clearTimer(); gLitesnEvents = kListenEvent_None; _clearTransaction(); resetTimeoutPrefs(); if (gCurrentTestListStatus.nextListIndex >= gTestLists.length) { finish(); return; } gCurrentTestListStatus.nextListIndex++; gCurrentTestListStatus.retryWhenTransactionTimeout = _getCurrentTestList().retryWhenTransactionTimeout; runTestStepAt(0); } function runTestStepAt(aStepIndex) { _clearTimer(); disableNonTestMouseEvents(true); // load a step of testing. gCurrentTestListStatus.nextStepIndex = aStepIndex; gCurrentTest = _getCurrentTestList().steps[gCurrentTestListStatus.nextStepIndex++]; if (gCurrentTest) { gCurrentTest.wasTransactionTimeout = false; gTimer = setTimeout(gCurrentTest.func, gCurrentTest.delay); } else { // If current test-list doesn't have more testing, go to next test-list // after cleaning up the current transaction. _clearTransaction(); runNextTestList(); } } function retryCurrentTestList() { _clearTimer(); gLitesnEvents = kListenEvent_None; _clearTransaction(); ok(true, "WARNING: retry current test-list..."); growUpTimeoutPrefs(); // retry the test with longer timeout settings. runTestStepAt(0); } function continueTest() { /** * This function is called from an event handler when a test succeeded. * * @param gCurrentTest.repeatTest * When this is true, onScrollView calls |gCurrentTest.func|. So, * same test can repeat. Otherwise, this calls |runNextTestStep|. * @param gCurrentTest.autoRepeatDelay * The delay value in milliseconds, this is used to call * |gCurrentTest.func| via |setTimeout|. */ _clearTimer(); gLitesnEvents = kListenEvent_OnTransactionTimeout; // We should call each functions via setTimeout. Because sometimes this test // is broken by stack overflow. if (gCurrentTest.repeatTest) { gTimer = setTimeout(gCurrentTest.func, gCurrentTest.autoRepeatDelay); } else { gTimer = setTimeout(runNextTestStep, 0); } } ]]> </script> </window>