browser_backforward_userinteraction.js (11339B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const TEST_PAGE = 7 getRootDirectory(gTestPath).replace( 8 "chrome://mochitests/content", 9 "https://example.com" 10 ) + "dummy_page.html"; 11 const IFRAME_PAGE = 12 getRootDirectory(gTestPath).replace( 13 "chrome://mochitests/content", 14 "https://example.com" 15 ) + "dummy_iframe_page.html"; 16 17 async function assertMenulist(entries, baseURL = TEST_PAGE) { 18 // Wait for the session data to be flushed before continuing the test 19 await new Promise(resolve => 20 SessionStore.getSessionHistory(gBrowser.selectedTab, resolve) 21 ); 22 23 let backButton = document.getElementById("back-button"); 24 let contextMenu = document.getElementById("backForwardMenu"); 25 26 info("waiting for the history menu to open"); 27 28 let popupShownPromise = BrowserTestUtils.waitForEvent( 29 contextMenu, 30 "popupshown" 31 ); 32 EventUtils.synthesizeMouseAtCenter(backButton, { 33 type: "contextmenu", 34 button: 2, 35 }); 36 await popupShownPromise; 37 38 ok(true, "history menu opened"); 39 40 let nodes = contextMenu.childNodes; 41 42 is( 43 nodes.length, 44 entries.length, 45 "Has the expected number of contextMenu entries" 46 ); 47 48 for (let i = 0; i < entries.length; i++) { 49 let node = nodes[i]; 50 is( 51 node.getAttribute("uri").replace(/[?|#]/, "!"), 52 baseURL + "!entry=" + entries[i], 53 "contextMenu node has the correct uri" 54 ); 55 } 56 57 let popupHiddenPromise = BrowserTestUtils.waitForEvent( 58 contextMenu, 59 "popuphidden" 60 ); 61 contextMenu.hidePopup(); 62 await popupHiddenPromise; 63 } 64 65 // There are different ways of loading a page, but they should exhibit roughly the same 66 // back-forward behavior for the purpose of requiring user interaction. Thus, we 67 // have a utility function that runs the same test with a parameterized method of loading 68 // new URLs. 69 async function runTopLevelTest(loadMethod, useHashes = false) { 70 let p = useHashes ? "#" : "?"; 71 72 // Test with both pref on and off 73 for (let requireUserInteraction of [true, false]) { 74 Services.prefs.setBoolPref( 75 "browser.navigation.requireUserInteraction", 76 requireUserInteraction 77 ); 78 79 let tab = await BrowserTestUtils.openNewForegroundTab( 80 gBrowser, 81 TEST_PAGE + p + "entry=0" 82 ); 83 let browser = tab.linkedBrowser; 84 // Add some user interaction to entry 0 85 await BrowserTestUtils.synthesizeMouse( 86 "body", 87 0, 88 0, 89 {}, 90 browser.browsingContext, 91 true 92 ); 93 94 assertBackForwardState(false, false); 95 96 await loadMethod(TEST_PAGE + p + "entry=1"); 97 98 assertBackForwardState(true, false); 99 await assertMenulist([1, 0]); 100 101 await loadMethod(TEST_PAGE + p + "entry=2"); 102 103 assertBackForwardState(true, false); 104 await assertMenulist(requireUserInteraction ? [2, 0] : [2, 1, 0]); 105 106 await loadMethod(TEST_PAGE + p + "entry=3"); 107 108 info("Adding user interaction for entry=3"); 109 // Add some user interaction to entry 3 110 await BrowserTestUtils.synthesizeMouse( 111 "body", 112 0, 113 0, 114 {}, 115 browser.browsingContext, 116 true 117 ); 118 119 assertBackForwardState(true, false); 120 await assertMenulist(requireUserInteraction ? [3, 0] : [3, 2, 1, 0]); 121 122 await loadMethod(TEST_PAGE + p + "entry=4"); 123 124 assertBackForwardState(true, false); 125 await assertMenulist(requireUserInteraction ? [4, 3, 0] : [4, 3, 2, 1, 0]); 126 127 info("Adding user interaction for entry=4"); 128 // Add some user interaction to entry 4 129 await BrowserTestUtils.synthesizeMouse( 130 "body", 131 0, 132 0, 133 {}, 134 browser.browsingContext, 135 true 136 ); 137 138 await loadMethod(TEST_PAGE + p + "entry=5"); 139 140 assertBackForwardState(true, false); 141 await assertMenulist( 142 requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0] 143 ); 144 145 await goBack(TEST_PAGE + p + "entry=4"); 146 await goBack(TEST_PAGE + p + "entry=3"); 147 148 if (!requireUserInteraction) { 149 await goBack(TEST_PAGE + p + "entry=2"); 150 await goBack(TEST_PAGE + p + "entry=1"); 151 } 152 153 assertBackForwardState(true, true); 154 await assertMenulist( 155 requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0] 156 ); 157 158 await goBack(TEST_PAGE + p + "entry=0"); 159 160 assertBackForwardState(false, true); 161 162 if (!requireUserInteraction) { 163 await goForward(TEST_PAGE + p + "entry=1"); 164 await goForward(TEST_PAGE + p + "entry=2"); 165 } 166 167 await goForward(TEST_PAGE + p + "entry=3"); 168 169 assertBackForwardState(true, true); 170 await assertMenulist( 171 requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0] 172 ); 173 174 await goForward(TEST_PAGE + p + "entry=4"); 175 176 assertBackForwardState(true, true); 177 await assertMenulist( 178 requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0] 179 ); 180 181 await goForward(TEST_PAGE + p + "entry=5"); 182 183 assertBackForwardState(true, false); 184 await assertMenulist( 185 requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0] 186 ); 187 188 BrowserTestUtils.removeTab(tab); 189 } 190 191 Services.prefs.clearUserPref("browser.navigation.requireUserInteraction"); 192 } 193 194 async function runIframeTest(loadMethod) { 195 // Test with both pref on and off 196 for (let requireUserInteraction of [true, false]) { 197 Services.prefs.setBoolPref( 198 "browser.navigation.requireUserInteraction", 199 requireUserInteraction 200 ); 201 202 // First test the boring case where we only have one iframe. 203 let tab = await BrowserTestUtils.openNewForegroundTab( 204 gBrowser, 205 IFRAME_PAGE + "?entry=0" 206 ); 207 let browser = tab.linkedBrowser; 208 // Add some user interaction to entry 0 209 await BrowserTestUtils.synthesizeMouse( 210 "body", 211 0, 212 0, 213 {}, 214 browser.browsingContext, 215 true 216 ); 217 218 assertBackForwardState(false, false); 219 220 await loadMethod(TEST_PAGE + "?sub_entry=1", "frame1"); 221 222 assertBackForwardState(true, false); 223 await assertMenulist([0, 0], IFRAME_PAGE); 224 225 await loadMethod(TEST_PAGE + "?sub_entry=2", "frame1"); 226 227 assertBackForwardState(true, false); 228 await assertMenulist( 229 requireUserInteraction ? [0, 0] : [0, 0, 0], 230 IFRAME_PAGE 231 ); 232 233 let bc = await SpecialPowers.spawn(browser, [], function () { 234 return content.document.getElementById("frame1").browsingContext; 235 }); 236 237 // Add some user interaction to sub entry 2 238 await BrowserTestUtils.synthesizeMouse("body", 0, 0, {}, bc, true); 239 240 await loadMethod(TEST_PAGE + "?sub_entry=3", "frame1"); 241 242 assertBackForwardState(true, false); 243 await assertMenulist( 244 requireUserInteraction ? [0, 0, 0] : [0, 0, 0, 0], 245 IFRAME_PAGE 246 ); 247 248 await loadMethod(TEST_PAGE + "?sub_entry=4", "frame1"); 249 250 assertBackForwardState(true, false); 251 await assertMenulist( 252 requireUserInteraction ? [0, 0, 0] : [0, 0, 0, 0, 0], 253 IFRAME_PAGE 254 ); 255 256 if (!requireUserInteraction) { 257 await goBack(TEST_PAGE + "?sub_entry=3", true); 258 } 259 260 await goBack(TEST_PAGE + "?sub_entry=2", true); 261 262 assertBackForwardState(true, true); 263 await assertMenulist( 264 requireUserInteraction ? [0, 0, 0] : [0, 0, 0, 0, 0], 265 IFRAME_PAGE 266 ); 267 268 await loadMethod(IFRAME_PAGE + "?entry=1"); 269 270 assertBackForwardState(true, false); 271 await assertMenulist( 272 requireUserInteraction ? [1, 0, 0] : [1, 0, 0, 0], 273 IFRAME_PAGE 274 ); 275 276 BrowserTestUtils.removeTab(tab); 277 278 // Two iframes, now we're talking. 279 tab = await BrowserTestUtils.openNewForegroundTab( 280 gBrowser, 281 IFRAME_PAGE + "?entry=0" 282 ); 283 browser = tab.linkedBrowser; 284 // Add some user interaction to entry 0 285 await BrowserTestUtils.synthesizeMouse( 286 "body", 287 0, 288 0, 289 {}, 290 browser.browsingContext, 291 true 292 ); 293 294 await loadMethod(IFRAME_PAGE + "?entry=1"); 295 296 assertBackForwardState(true, false); 297 await assertMenulist(requireUserInteraction ? [1, 0] : [1, 0], IFRAME_PAGE); 298 299 // Add some user interaction to frame 1. 300 bc = await SpecialPowers.spawn(browser, [], function () { 301 return content.document.getElementById("frame1").browsingContext; 302 }); 303 await BrowserTestUtils.synthesizeMouse("body", 0, 0, {}, bc, true); 304 305 // Add some user interaction to frame 2. 306 bc = await SpecialPowers.spawn(browser, [], function () { 307 return content.document.getElementById("frame2").browsingContext; 308 }); 309 await BrowserTestUtils.synthesizeMouse("body", 0, 0, {}, bc, true); 310 311 // Navigate frame 2. 312 await loadMethod(TEST_PAGE + "?sub_entry=1", "frame2"); 313 314 assertBackForwardState(true, false); 315 await assertMenulist( 316 requireUserInteraction ? [1, 1, 0] : [1, 1, 0], 317 IFRAME_PAGE 318 ); 319 320 // Add some user interaction to frame 1, again. 321 bc = await SpecialPowers.spawn(browser, [], function () { 322 return content.document.getElementById("frame1").browsingContext; 323 }); 324 await BrowserTestUtils.synthesizeMouse("body", 0, 0, {}, bc, true); 325 326 // Navigate frame 2, again. 327 await loadMethod(TEST_PAGE + "?sub_entry=2", "frame2"); 328 329 assertBackForwardState(true, false); 330 await assertMenulist( 331 requireUserInteraction ? [1, 1, 1, 0] : [1, 1, 1, 0], 332 IFRAME_PAGE 333 ); 334 335 await goBack(TEST_PAGE + "?sub_entry=1", true); 336 337 assertBackForwardState(true, true); 338 await assertMenulist( 339 requireUserInteraction ? [1, 1, 1, 0] : [1, 1, 1, 0], 340 IFRAME_PAGE 341 ); 342 343 await goBack(TEST_PAGE + "?sub_entry=0", true); 344 345 assertBackForwardState(true, true); 346 await assertMenulist( 347 requireUserInteraction ? [1, 1, 1, 0] : [1, 1, 1, 0], 348 IFRAME_PAGE 349 ); 350 351 BrowserTestUtils.removeTab(tab); 352 } 353 354 Services.prefs.clearUserPref("browser.navigation.requireUserInteraction"); 355 } 356 357 // Test that when the pref is flipped, we are skipping history 358 // entries without user interaction when following links with hash URIs. 359 add_task(async function test_hashURI() { 360 async function followLinkHash(url) { 361 info(`Creating and following a link to ${url}`); 362 let browser = gBrowser.selectedBrowser; 363 let loaded = BrowserTestUtils.waitForLocationChange(gBrowser, url); 364 await SpecialPowers.spawn(browser, [url], function (url) { 365 let a = content.document.createElement("a"); 366 a.href = url; 367 content.document.body.appendChild(a); 368 a.click(); 369 }); 370 await loaded; 371 info(`Loaded ${url}`); 372 } 373 374 await runTopLevelTest(followLinkHash, true); 375 }); 376 377 // Test that when the pref is flipped, we are skipping history 378 // entries without user interaction when using history.pushState. 379 add_task(async function test_pushState() { 380 await runTopLevelTest(pushState); 381 }); 382 383 // Test that when the pref is flipped, we are skipping history 384 // entries without user interaction when following a link. 385 add_task(async function test_followLink() { 386 await runTopLevelTest(followLink); 387 }); 388 389 // Test that when the pref is flipped, we are skipping history 390 // entries without user interaction when navigating inside an iframe 391 // using history.pushState. 392 add_task(async function test_iframe_pushState() { 393 await runIframeTest(pushState); 394 }); 395 396 // Test that when the pref is flipped, we are skipping history 397 // entries without user interaction when navigating inside an iframe 398 // by following links. 399 add_task(async function test_iframe_followLink() { 400 await runIframeTest(followLink); 401 });