browser_test_scrolling.js (9075B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 /* import-globals-from ../../mochitest/role.js */ 8 loadScripts({ name: "role.js", dir: MOCHITESTS_DIR }); 9 10 addAccessibleTask( 11 ` 12 <div style="height: 100vh" id="one">one</div> 13 <div style="height: 100vh" id="two">two</div> 14 <div style="height: 100vh; width: 200vw; overflow: auto;" id="three"> 15 <div style="height: 300%;">three</div> 16 </div> 17 <textarea id="textarea" rows="1">a 18 b 19 c</textarea> 20 `, 21 async function (browser, accDoc) { 22 let onScrolling = waitForEvents([ 23 [EVENT_SCROLLING, accDoc], 24 [EVENT_SCROLLING_END, accDoc], 25 ]); 26 await SpecialPowers.spawn(browser, [], () => { 27 content.location.hash = "#two"; 28 }); 29 let [scrollEvent1, scrollEndEvent1] = await onScrolling; 30 scrollEvent1.QueryInterface(nsIAccessibleScrollingEvent); 31 Assert.greaterOrEqual( 32 scrollEvent1.maxScrollY, 33 scrollEvent1.scrollY, 34 "scrollY is within max" 35 ); 36 scrollEndEvent1.QueryInterface(nsIAccessibleScrollingEvent); 37 Assert.greaterOrEqual( 38 scrollEndEvent1.maxScrollY, 39 scrollEndEvent1.scrollY, 40 "scrollY is within max" 41 ); 42 43 onScrolling = waitForEvents([ 44 [EVENT_SCROLLING, accDoc], 45 [EVENT_SCROLLING_END, accDoc], 46 ]); 47 await SpecialPowers.spawn(browser, [], () => { 48 content.location.hash = "#three"; 49 }); 50 let [scrollEvent2, scrollEndEvent2] = await onScrolling; 51 scrollEvent2.QueryInterface(nsIAccessibleScrollingEvent); 52 Assert.greater( 53 scrollEvent2.scrollY, 54 scrollEvent1.scrollY, 55 `${scrollEvent2.scrollY} > ${scrollEvent1.scrollY}` 56 ); 57 scrollEndEvent2.QueryInterface(nsIAccessibleScrollingEvent); 58 Assert.greaterOrEqual( 59 scrollEndEvent2.maxScrollY, 60 scrollEndEvent2.scrollY, 61 "scrollY is within max" 62 ); 63 64 onScrolling = waitForEvents([ 65 [EVENT_SCROLLING, accDoc], 66 [EVENT_SCROLLING_END, accDoc], 67 ]); 68 await SpecialPowers.spawn(browser, [], () => { 69 content.scrollTo(10, 0); 70 }); 71 let [scrollEvent3, scrollEndEvent3] = await onScrolling; 72 scrollEvent3.QueryInterface(nsIAccessibleScrollingEvent); 73 Assert.greaterOrEqual( 74 scrollEvent3.maxScrollX, 75 scrollEvent3.scrollX, 76 "scrollX is within max" 77 ); 78 scrollEndEvent3.QueryInterface(nsIAccessibleScrollingEvent); 79 Assert.greaterOrEqual( 80 scrollEndEvent3.maxScrollX, 81 scrollEndEvent3.scrollX, 82 "scrollY is within max" 83 ); 84 Assert.greater( 85 scrollEvent3.scrollX, 86 scrollEvent2.scrollX, 87 `${scrollEvent3.scrollX} > ${scrollEvent2.scrollX}` 88 ); 89 90 // non-doc scrolling 91 onScrolling = waitForEvents([ 92 [EVENT_SCROLLING, "three"], 93 [EVENT_SCROLLING_END, "three"], 94 ]); 95 await SpecialPowers.spawn(browser, [], () => { 96 content.document.querySelector("#three").scrollTo(0, 10); 97 }); 98 let [scrollEvent4, scrollEndEvent4] = await onScrolling; 99 scrollEvent4.QueryInterface(nsIAccessibleScrollingEvent); 100 Assert.greaterOrEqual( 101 scrollEvent4.maxScrollY, 102 scrollEvent4.scrollY, 103 "scrollY is within max" 104 ); 105 scrollEndEvent4.QueryInterface(nsIAccessibleScrollingEvent); 106 Assert.greaterOrEqual( 107 scrollEndEvent4.maxScrollY, 108 scrollEndEvent4.scrollY, 109 "scrollY is within max" 110 ); 111 112 // textarea scrolling 113 info("Moving textarea caret to c"); 114 onScrolling = waitForEvents([ 115 [EVENT_SCROLLING, "textarea"], 116 [EVENT_SCROLLING_END, "textarea"], 117 ]); 118 await invokeContentTask(browser, [], () => { 119 const textareaDom = content.document.getElementById("textarea"); 120 textareaDom.focus(); 121 textareaDom.selectionStart = 4; 122 }); 123 await onScrolling; 124 } 125 ); 126 127 // Verify that the scrolling start event is fired for an anchor change. 128 addAccessibleTask( 129 ` 130 <p>a</p> 131 <p>b</p> 132 <p id="c">c</p> 133 `, 134 async function (browser) { 135 let onScrollingStart = waitForEvent(EVENT_SCROLLING_START, "c"); 136 await SpecialPowers.spawn(browser, [], () => { 137 content.location.hash = "#c"; 138 }); 139 await onScrollingStart; 140 }, 141 { chrome: true, topLevel: true } 142 ); 143 144 // Ensure that a scrollable, focused non-interactive element receives a 145 // scrolling start event when an anchor jump to that element is triggered. 146 addAccessibleTask( 147 ` 148 <div style="height: 100vh; width: 100vw; overflow: auto;" id="scrollable"> 149 <h1 style="height: 300%;" id="inside-scrollable">test</h1> 150 </div> 151 `, 152 async function (browser) { 153 let onScrollingStart = waitForEvent( 154 EVENT_SCROLLING_START, 155 "inside-scrollable" 156 ); 157 await invokeContentTask(browser, [], () => { 158 const scrollable = content.document.getElementById("scrollable"); 159 scrollable.focus(); 160 content.location.hash = "#inside-scrollable"; 161 }); 162 await onScrollingStart; 163 }, 164 { chrome: true, topLevel: true, iframe: true, remoteIframe: true } 165 ); 166 167 /** 168 * Test that slow loading pages fire scrolling start events correctly. 169 */ 170 add_task(async function testSlowLoad() { 171 // We use add_task because this document won't fire a doc load complete event 172 // until it is fully loaded. 173 const scriptUrl = 174 "https://example.com/browser/accessible/tests/browser/events/slow_doc.sjs"; 175 info("Testing first (already in tree when anchor jump occurs)"); 176 let url = `${scriptUrl}?second#:~:text=first`; 177 let focused = waitForEvent( 178 EVENT_FOCUS, 179 evt => 180 evt.accessible.role == ROLE_DOCUMENT && evt.accessibleDocument.URL == url 181 ); 182 await BrowserTestUtils.withNewTab( 183 { url, gBrowser, waitForLoad: false }, 184 async function () { 185 await focused; 186 // At this point, the document contains only "first". 187 info("Finishing load"); 188 let scrolled = waitForEvent( 189 EVENT_SCROLLING_START, 190 evt => evt.accessible.name == "first" 191 ); 192 await fetch(`${scriptUrl}?scriptFinish`); 193 info("Wait for scroll"); 194 await scrolled; 195 } 196 ); 197 198 info("Testing second (container already in tree when anchor jump occurs)"); 199 url = `${scriptUrl}?secondInContainer#:~:text=second`; 200 focused = waitForEvent( 201 EVENT_FOCUS, 202 evt => 203 evt.accessible.role == ROLE_DOCUMENT && evt.accessibleDocument.URL == url 204 ); 205 await BrowserTestUtils.withNewTab( 206 { url, gBrowser, waitForLoad: false }, 207 async function () { 208 await focused; 209 // At this point, the document contains only "first". 210 info("Finishing load"); 211 let scrolled = waitForEvent( 212 EVENT_SCROLLING_START, 213 evt => evt.accessible.name == "second" 214 ); 215 await fetch(`${scriptUrl}?scriptFinish`); 216 await scrolled; 217 } 218 ); 219 220 info("Testing second (not in tree when anchor jump occurs)"); 221 url = `${scriptUrl}?second#:~:text=second`; 222 focused = waitForEvent( 223 EVENT_FOCUS, 224 evt => 225 evt.accessible.role == ROLE_DOCUMENT && evt.accessibleDocument.URL == url 226 ); 227 await BrowserTestUtils.withNewTab( 228 { url, gBrowser, waitForLoad: false }, 229 async function () { 230 await focused; 231 // At this point, the document contains only "first". 232 info("Finishing load"); 233 let scrolled = waitForEvent( 234 EVENT_SCROLLING_START, 235 evt => evt.accessible.name == "second" 236 ); 237 await fetch(`${scriptUrl}?scriptFinish`); 238 await scrolled; 239 } 240 ); 241 242 info("Testing jump while in background"); 243 url = `${scriptUrl}?second#:~:text=second`; 244 focused = waitForEvent( 245 EVENT_FOCUS, 246 evt => 247 evt.accessible.role == ROLE_DOCUMENT && evt.accessibleDocument.URL == url 248 ); 249 await BrowserTestUtils.withNewTab( 250 { url, gBrowser, waitForLoad: false }, 251 async function () { 252 await focused; 253 // At this point, the document contains only "first". 254 info("Opening second tab in foreground"); 255 const secondUrl = "about:mozilla"; 256 focused = waitForEvent( 257 EVENT_FOCUS, 258 evt => 259 evt.accessible.role == ROLE_DOCUMENT && 260 evt.accessibleDocument.URL == secondUrl 261 ); 262 let secondTab = await BrowserTestUtils.openNewForegroundTab({ 263 url: secondUrl, 264 gBrowser, 265 }); 266 await focused; 267 // We shouldn't get a scrolling start event until focus returns to the 268 // first document. 269 let events = waitForEvents({ 270 expected: [[EVENT_SHOW, "second"]], 271 unexpected: [ 272 [EVENT_SCROLLING_START, evt => evt.accessible.name == "second"], 273 ], 274 }); 275 info("Finishing load"); 276 await fetch(`${scriptUrl}?scriptFinish`); 277 await events; 278 info("Closing second tab"); 279 events = waitForEvents([ 280 [ 281 EVENT_FOCUS, 282 evt => 283 evt.accessible.role == ROLE_DOCUMENT && 284 evt.accessibleDocument.URL == url, 285 ], 286 [EVENT_SCROLLING_START, evt => evt.accessible.name == "second"], 287 ]); 288 BrowserTestUtils.removeTab(secondTab); 289 await events; 290 } 291 ); 292 });