1 // A ScrollBehaviorTest runs a set of ScrollBehaviorTestCases. The only
2 // ScrollBehaviorTest method that should be called by external code is run().
4 // Creates a ScrollBehaviorTest with arguments:
5 // scrollElement - Element being scrolled.
6 // scrollEventTarget - Target for scroll events for |scrollElement|.
7 // testsCases - Array of ScrollBehaviorTestCases.
8 // getEndPosition - Callback that takes a test case and start position, and
9 // returns the corresponding end position (where positions
10 // are dictionaries with x and y fields).
11 // jsScroll - Callback that takes a test case and executes the corresponding
12 // js-driven scroll (e.g. by setting scrollLeft/scrollTop or by
13 // calling scroll, scrollTo, or scrollBy). This should assume that
14 // scrollElement's scroll-behavior CSS property has already been
16 function ScrollBehaviorTest(scrollElement
,
21 this.scrollElement
= scrollElement
;
22 this.scrollEventTarget
= scrollEventTarget
;
23 this.testCases
= testCases
;
24 this.currentTestCase
= 0;
25 this.getEndPosition
= getEndPosition
;
26 this.jsScroll
= jsScroll
;
29 ScrollBehaviorTest
.prototype.scrollListener = function(testCase
) {
30 var endReached
= (this.scrollElement
.scrollLeft
== testCase
.endX
&& this.scrollElement
.scrollTop
== testCase
.endY
);
32 this.testCaseComplete();
36 if (testCase
.waitForEnd
)
39 // Wait for the animation to start, then instant-scroll to the end state.
40 if (this.scrollElement
.scrollLeft
!= testCase
.startX
|| this.scrollElement
.scrollTop
!= testCase
.startY
) {
41 // Instant scroll, and then wait for the next scroll event. This allows
42 // the instant scroll to propagate to the compositor (when using
43 // composited scrolling) so that the next smooth scroll starts at this
44 // position (the compositor always starts smooth scrolls at the current
45 // scroll position on the compositor thread).
46 this.scrollElement
.scrollTo({left
: testCase
.endX
, top
: testCase
.endY
, behavior
: "instant"});
47 testCase
.waitForEnd
= true;
51 ScrollBehaviorTest
.prototype.startNextTestCase = function() {
52 if (this.currentTestCase
>= this.testCases
.length
) {
53 this.allTestCasesComplete();
56 var testCase
= this.testCases
[this.currentTestCase
];
57 if (testCase
.pageScaleFactor
&& window
.internals
) {
58 internals
.setPageScaleFactor(testCase
.pageScaleFactor
);
61 var isSmoothTest
= (testCase
.js
== "smooth" || (testCase
.css
== "smooth" && testCase
.js
!= "instant"));
63 this.asyncTest
= async_test("Scroll x:" + testCase
.x
+ ", y:" + testCase
.y
+ ", smooth:" + isSmoothTest
);
65 var currentPosition
= {};
66 currentPosition
.x
= this.scrollElement
.scrollLeft
;
67 currentPosition
.y
= this.scrollElement
.scrollTop
;
68 var endPosition
= this.getEndPosition(testCase
, currentPosition
);
69 testCase
.setStartPosition(currentPosition
);
70 testCase
.setEndPosition(endPosition
);
72 this.scrollElement
.style
.scrollBehavior
= testCase
.css
;
73 this.jsScroll(testCase
);
75 var scrollElement
= this.scrollElement
;
77 this.asyncTest
.step(function() {
78 assert_equals(scrollElement
.scrollLeft
+ ", " + scrollElement
.scrollTop
, testCase
.startX
+ ", " + testCase
.startY
);
80 if (scrollElement
.scrollLeft
== testCase
.endX
&& scrollElement
.scrollTop
== testCase
.endY
) {
81 // We've instant-scrolled. This means we've already failed the assert above, and will never
82 // reach an intermediate frame. End the test case now to avoid hanging while waiting for an
83 // intermediate frame.
84 this.testCaseComplete();
86 testCase
.scrollListener
= this.scrollListener
.bind(this, testCase
);
87 this.scrollEventTarget
.addEventListener("scroll", testCase
.scrollListener
);
90 this.asyncTest
.step(function() {
91 assert_equals(scrollElement
.scrollLeft
+ ", " + scrollElement
.scrollTop
, testCase
.endX
+ ", " + testCase
.endY
);
93 this.testCaseComplete();
97 ScrollBehaviorTest
.prototype.testCaseComplete = function() {
98 var currentScrollListener
= this.testCases
[this.currentTestCase
].scrollListener
;
99 if (currentScrollListener
) {
100 this.scrollEventTarget
.removeEventListener("scroll", currentScrollListener
);
102 this.asyncTest
.done();
104 this.currentTestCase
++;
105 this.startNextTestCase();
108 ScrollBehaviorTest
.prototype.run = function() {
109 setup({explicit_done
: true, explicit_timeout
: true});
110 this.startNextTestCase();
113 ScrollBehaviorTest
.prototype.allTestCasesComplete = function() {
118 // A ScrollBehaviorTestCase represents a single scroll.
120 // Creates a ScrollBehaviorTestCase. |testData| is a dictionary with fields:
121 // css - Value of scroll-behavior CSS property.
122 // js - (optional) Value of scroll behavior used in javascript.
123 // x, y - Coordinates to be used when carrying out the scroll.
124 // waitForEnd - (must be provided for smooth scrolls) Whether the test runner should
125 // wait until the scroll is complete, rather than only waiting until
126 // the scroll is underway.
127 // pageScaleFactor - (optional) if set, applies pinch-zoom by the given factor.
128 function ScrollBehaviorTestCase(testData
) {
129 this.js
= testData
.js
;
130 this.css
= testData
.css
;
131 this.waitForEnd
= testData
.waitForEnd
;
134 this.pageScaleFactor
= testData
.pageScaleFactor
;
137 ScrollBehaviorTestCase
.prototype.setStartPosition = function(startPosition
) {
138 this.startX
= startPosition
.x
;
139 this.startY
= startPosition
.y
;
142 ScrollBehaviorTestCase
.prototype.setEndPosition = function(endPosition
) {
143 this.endX
= endPosition
.x
;
144 this.endY
= endPosition
.y
;