1<!DOCTYPE html>
2<html>
3<head>
4  <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
5<script src="/resources/testharness.js"></script>
6<script src="/resources/testharnessreport.js"></script>
7<script src="/resources/testdriver.js"></script>
8<script src="/resources/testdriver-actions.js"></script>
9<script src="/resources/testdriver-vendor.js"></script>
10<script src="scroll_support.js"></script>
11<style>
12    #targetDiv {
13        width: 200px;
14        height: 200px;
15        overflow: scroll;
16    }
17
18    #innerDiv {
19        width: 400px;
20        height: 400px;
21    }
22</style>
23</head>
24<body style="margin:0" onload=runTest()>
25    <div id="targetDiv">
26        <div id="innerDiv">
27        </div>
28    </div>
29</body>
30
31<script>
32var target_div = document.getElementById('targetDiv');
33
34async function resetTargetScrollState(test) {
35  if (target_div.scrollTop != 0 || target_div.scrollLeft != 0) {
36    target_div.scrollTop = 0;
37    target_div.scrollLeft = 0;
38    return waitForScrollendEvent(test, target_div);
39  }
40}
41
42async function verifyScrollStopped(test) {
43  const unscaled_pause_time_in_ms = 100;
44  const x = target_div.scrollLeft;
45  const y = target_div.scrollTop;
46  return new Promise(resolve => {
47    test.step_timeout(() => {
48      assert_equals(x, target_div.scrollLeft);
49      assert_equals(y, target_div.scrollTop);
50      resolve();
51    }, unscaled_pause_time_in_ms);
52  });
53}
54
55async function verifyNoScrollendOnDocument(test) {
56  const callback =
57      test.unreached_func("window got unexpected scrollend event.");
58  window.addEventListener('scrollend', callback);
59}
60
61async function createScrollendPromise(test) {
62  return waitForScrollendEvent(test, target_div).then(evt => {
63      assert_false(evt.cancelable, 'Event is not cancelable');
64      assert_false(evt.bubbles, 'Event targeting element does not bubble');
65  });
66}
67
68function runTest() {
69  promise_test(async (t) => {
70    // Skip the test on a Mac as they do not support touch screens.
71    const isMac = navigator.platform.toUpperCase().indexOf('MAC')>=0;
72    if (isMac)
73      return;
74
75    await resetTargetScrollState(t);
76    await waitForCompositorCommit();
77
78    const targetScrollendPromise = createScrollendPromise(t);
79    verifyNoScrollendOnDocument(t);
80
81    // Perform a touch drag on target div and wait for target_div to get
82    // a scrollend event.
83    await new test_driver.Actions()
84        .addPointer('TestPointer', 'touch')
85        .pointerMove(0, 0, {origin: target_div}) // 0, 0 is center of element.
86        .pointerDown()
87        .addTick()
88        .pointerMove(0, -40, {origin: target_div}) //  Drag up to move down.
89        .addTick()
90        .pause(200) //  Prevent inertial scroll.
91        .pointerUp()
92        .send();
93
94    await targetScrollendPromise;
95
96    assert_true(target_div.scrollTop > 0);
97    await verifyScrollStopped(t);
98  }, 'Tests that the target_div gets scrollend event when touch dragging.');
99
100  promise_test(async (t) => {
101    // Skip test on platforms that do not have a visible scrollbar (e.g.
102    // overlay scrollbar).
103    const scrollbar_width = target_div.offsetWidth - target_div.clientWidth;
104    if (scrollbar_width == 0)
105      return;
106
107    await resetTargetScrollState(t);
108    await waitForCompositorCommit();
109
110    const targetScrollendPromise = createScrollendPromise(t);
111    verifyNoScrollendOnDocument(t);
112
113    const bounds = target_div.getBoundingClientRect();
114    const x = bounds.right - scrollbar_width / 2;
115    const y = bounds.bottom - 20;
116    await new test_driver.Actions()
117        .addPointer('TestPointer', 'mouse')
118        .pointerMove(x, y, {origin: 'viewport'})
119        .pointerDown()
120        .addTick()
121        .pointerUp()
122        .send();
123
124    await targetScrollendPromise;
125    assert_true(target_div.scrollTop > 0);
126    await verifyScrollStopped(t);
127  }, 'Tests that the target_div gets scrollend event when clicking ' +
128     'scrollbar.');
129
130  // Same issue as previous test.
131  promise_test(async (t) => {
132    // Skip test on platforms that do not have a visible scrollbar (e.g.
133    // overlay scrollbar).
134    const scrollbar_width = target_div.offsetWidth - target_div.clientWidth;
135    if (scrollbar_width == 0)
136      return;
137
138    resetTargetScrollState(t);
139    const targetScrollendPromise = createScrollendPromise(t);
140    verifyNoScrollendOnDocument(t);
141
142    const bounds = target_div.getBoundingClientRect();
143    const x = bounds.right - scrollbar_width / 2;
144    const y = bounds.top + 30;
145    const dy = 30;
146    await new test_driver.Actions()
147        .addPointer('TestPointer', 'mouse')
148        .pointerMove(x, y, { origin: 'viewport' })
149        .pointerDown()
150        .pointerMove(x, y + dy, { origin: 'viewport' })
151        .addTick()
152        .pointerUp()
153        .send();
154
155    await targetScrollendPromise;
156    assert_true(target_div.scrollTop > 0);
157    await verifyScrollStopped(t);
158  }, 'Tests that the target_div gets scrollend event when dragging the ' +
159      'scrollbar thumb.');
160
161  promise_test(async (t) => {
162    resetTargetScrollState(t);
163    const targetScrollendPromise = createScrollendPromise(t);
164    verifyNoScrollendOnDocument(t);
165
166    const x = 0;
167    const y = 0;
168    const dx = 0;
169    const dy = 40;
170    const duration_ms = 10;
171    await new test_driver.Actions()
172        .scroll(x, y, dx, dy, { origin: target_div }, duration_ms)
173        .send();
174
175    await targetScrollendPromise;
176    assert_true(target_div.scrollTop > 0);
177    await verifyScrollStopped(t);
178  }, 'Tests that the target_div gets scrollend event when mouse wheel ' +
179     'scrolling.');
180
181  promise_test(async (t) => {
182    await resetTargetScrollState(t);
183    await waitForCompositorCommit();
184
185    verifyNoScrollendOnDocument(t);
186    const targetScrollendPromise = createScrollendPromise(t);
187
188    target_div.focus();
189    window.test_driver.send_keys(target_div, '\ue015');
190
191    await targetScrollendPromise;
192    assert_true(target_div.scrollTop > 0);
193    await verifyScrollStopped(t);
194  }, 'Tests that the target_div gets scrollend event when sending DOWN key ' +
195     'to the target.');
196}
197
198</script>
199</html>
200