browser_documentnavigation.js (12253B)
1 /* 2 * This test checks that focus is adjusted properly in a browser when pressing F6 and Shift+F6. 3 * There are additional tests in dom/tests/mochitest/chrome/test_focus_docnav.xul which test 4 * non-browser cases. 5 */ 6 7 var testPage1 = 8 "data:text/html,<html id='html1'><body id='body1'><button id='button1'>Tab 1</button></body></html>"; 9 var testPage2 = 10 "data:text/html,<html id='html2'><body id='body2'><button id='button2'>Tab 2</button></body></html>"; 11 var testPage3 = 12 "data:text/html,<html id='html3'><body id='body3' contenteditable='true'><button id='button3'>Tab 3</button></body></html>"; 13 14 var fm = Services.focus; 15 16 async function expectFocusOnF6( 17 backward, 18 expectedDocument, 19 expectedElement, 20 onContent, 21 desc 22 ) { 23 if (onContent) { 24 let success = await SpecialPowers.spawn( 25 gBrowser.selectedBrowser, 26 [expectedElement], 27 async function (expectedElementId) { 28 content.lastResult = ""; 29 let contentExpectedElement = 30 content.document.getElementById(expectedElementId); 31 if (!contentExpectedElement) { 32 // Element not found, so look in the child frames. 33 for (let f = 0; f < content.frames.length; f++) { 34 if (content.frames[f].document.getElementById(expectedElementId)) { 35 contentExpectedElement = content.frames[f].document; 36 break; 37 } 38 } 39 } else if (contentExpectedElement.localName == "html") { 40 contentExpectedElement = contentExpectedElement.ownerDocument; 41 } 42 43 if (!contentExpectedElement) { 44 return null; 45 } 46 47 contentExpectedElement.addEventListener( 48 "focus", 49 function () { 50 let details = 51 Services.focus.focusedWindow.document.documentElement.id; 52 if (Services.focus.focusedElement) { 53 details += "," + Services.focus.focusedElement.id; 54 } 55 56 // Assign the result to a temporary place, to be used 57 // by the next spawn call. 58 content.lastResult = details; 59 }, 60 { capture: true, once: true } 61 ); 62 63 return !!contentExpectedElement; 64 } 65 ); 66 67 ok(success, "expected element " + expectedElement + " was found"); 68 69 EventUtils.synthesizeKey("VK_F6", { shiftKey: backward }); 70 71 let expected = expectedDocument; 72 if (!expectedElement.startsWith("html")) { 73 expected += "," + expectedElement; 74 } 75 76 let result = await SpecialPowers.spawn( 77 gBrowser.selectedBrowser, 78 [], 79 async () => { 80 await ContentTaskUtils.waitForCondition(() => content.lastResult); 81 return content.lastResult; 82 } 83 ); 84 is(result, expected, desc + " child focus matches"); 85 } else { 86 let focusPromise = BrowserTestUtils.waitForEvent(window, "focus", true); 87 EventUtils.synthesizeKey("VK_F6", { shiftKey: backward }); 88 await focusPromise; 89 } 90 91 if (typeof expectedElement == "string") { 92 expectedElement = fm.focusedWindow.document.getElementById(expectedElement); 93 } 94 95 if (gMultiProcessBrowser && onContent) { 96 expectedDocument = "main-window"; 97 expectedElement = gBrowser.selectedBrowser; 98 } 99 100 is( 101 fm.focusedWindow.document.documentElement.id, 102 expectedDocument, 103 desc + " document matches" 104 ); 105 is( 106 fm.focusedElement, 107 expectedElement, 108 desc + 109 " element matches (wanted: " + 110 expectedElement.id + 111 " got: " + 112 fm.focusedElement.id + 113 ")" 114 ); 115 } 116 117 // Load a page and navigate between it and the chrome window. 118 add_task(async function () { 119 let page1Promise = BrowserTestUtils.browserLoaded( 120 gBrowser.selectedBrowser, 121 false, 122 testPage1 123 ); 124 BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, testPage1); 125 await page1Promise; 126 127 // When the urlbar is focused, pressing F6 should focus the root of the content page. 128 gURLBar.focus(); 129 await expectFocusOnF6( 130 false, 131 "html1", 132 "html1", 133 true, 134 "basic focus content page" 135 ); 136 137 // When the content is focused, pressing F6 should focus the urlbar. 138 await expectFocusOnF6( 139 false, 140 "main-window", 141 gURLBar.inputField, 142 false, 143 "basic focus content page urlbar" 144 ); 145 146 // When a button in content is focused, pressing F6 should focus the urlbar. 147 await expectFocusOnF6( 148 false, 149 "html1", 150 "html1", 151 true, 152 "basic focus content page with button focused" 153 ); 154 155 await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { 156 return content.document.getElementById("button1").focus(); 157 }); 158 159 await expectFocusOnF6( 160 false, 161 "main-window", 162 gURLBar.inputField, 163 false, 164 "basic focus content page with button focused urlbar" 165 ); 166 167 // The document root should be focused, not the button 168 await expectFocusOnF6( 169 false, 170 "html1", 171 "html1", 172 true, 173 "basic focus again content page with button focused" 174 ); 175 176 // Check to ensure that the root element is focused 177 await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { 178 Assert.equal( 179 content.document.activeElement, 180 content.document.documentElement, 181 "basic focus again content page with button focused child root is focused" 182 ); 183 }); 184 }); 185 186 // Open a second tab. Document focus should skip the background tab. 187 add_task(async function () { 188 await BrowserTestUtils.openNewForegroundTab(gBrowser, testPage2); 189 190 await expectFocusOnF6( 191 false, 192 "main-window", 193 gURLBar.inputField, 194 false, 195 "basic focus content page and second tab urlbar" 196 ); 197 await expectFocusOnF6( 198 false, 199 "html2", 200 "html2", 201 true, 202 "basic focus content page with second tab" 203 ); 204 205 BrowserTestUtils.removeTab(gBrowser.selectedTab); 206 }); 207 208 // Shift+F6 should navigate backwards. There's only one document here so the effect 209 // is the same. 210 add_task(async function () { 211 gURLBar.focus(); 212 await expectFocusOnF6( 213 true, 214 "html1", 215 "html1", 216 true, 217 "back focus content page" 218 ); 219 await expectFocusOnF6( 220 true, 221 "main-window", 222 gURLBar.inputField, 223 false, 224 "back focus content page urlbar" 225 ); 226 }); 227 228 // Open the sidebar and navigate between the sidebar, content and top-level window 229 add_task(async function () { 230 let sidebar = document.getElementById("sidebar"); 231 232 let loadPromise = BrowserTestUtils.waitForEvent(sidebar, "load", true); 233 SidebarController.toggle("viewBookmarksSidebar"); 234 await loadPromise; 235 236 gURLBar.focus(); 237 await expectFocusOnF6( 238 false, 239 "bookmarksPanel", 240 sidebar.contentDocument 241 .getElementById("search-box") 242 .shadowRoot.querySelector("input"), 243 false, 244 "focus with sidebar open sidebar" 245 ); 246 await expectFocusOnF6( 247 false, 248 "html1", 249 "html1", 250 true, 251 "focus with sidebar open content" 252 ); 253 await expectFocusOnF6( 254 false, 255 "main-window", 256 gURLBar.inputField, 257 false, 258 "focus with sidebar urlbar" 259 ); 260 261 // Now go backwards 262 await expectFocusOnF6( 263 true, 264 "html1", 265 "html1", 266 true, 267 "back focus with sidebar open content" 268 ); 269 270 // Bug 2006225: sidebar.revamp introduces a regression where the "X" button receives 271 // focus instead of the search input. 272 let expectedSidebarFocusElement = Services.prefs.getBoolPref("sidebar.revamp") 273 ? sidebar.contentDocument 274 .getElementById("sidebar-panel-close") 275 .shadowRoot.querySelector("#main-button") 276 : sidebar.contentDocument 277 .getElementById("search-box") 278 .shadowRoot.querySelector("input"); 279 await expectFocusOnF6( 280 true, 281 "bookmarksPanel", 282 expectedSidebarFocusElement, 283 false, 284 "back focus with sidebar open sidebar" 285 ); 286 await expectFocusOnF6( 287 true, 288 "main-window", 289 gURLBar.inputField, 290 false, 291 "back focus with sidebar urlbar" 292 ); 293 294 SidebarController.toggle("viewBookmarksSidebar"); 295 }); 296 297 // Navigate when the downloads panel is open 298 add_task(async function test_download_focus() { 299 await pushPrefs( 300 ["accessibility.tabfocus", 7], 301 ["browser.download.autohideButton", false], 302 ["security.dialog_enable_delay", 0] 303 ); 304 await promiseButtonShown("downloads-button"); 305 306 let popupShownPromise = BrowserTestUtils.waitForEvent( 307 document, 308 "popupshown", 309 true 310 ); 311 EventUtils.synthesizeMouseAtCenter( 312 document.getElementById("downloads-button"), 313 {} 314 ); 315 await popupShownPromise; 316 317 gURLBar.focus(); 318 await expectFocusOnF6( 319 false, 320 "main-window", 321 document.getElementById("downloadsHistory"), 322 false, 323 "focus with downloads panel open panel" 324 ); 325 await expectFocusOnF6( 326 false, 327 "html1", 328 "html1", 329 true, 330 "focus with downloads panel open" 331 ); 332 await expectFocusOnF6( 333 false, 334 "main-window", 335 gURLBar.inputField, 336 false, 337 "focus downloads panel open urlbar" 338 ); 339 340 // Now go backwards 341 await expectFocusOnF6( 342 true, 343 "html1", 344 "html1", 345 true, 346 "back focus with downloads panel open" 347 ); 348 await expectFocusOnF6( 349 true, 350 "main-window", 351 document.getElementById("downloadsHistory"), 352 false, 353 "back focus with downloads panel open" 354 ); 355 await expectFocusOnF6( 356 true, 357 "main-window", 358 gURLBar.inputField, 359 false, 360 "back focus downloads panel open urlbar" 361 ); 362 363 let downloadsPopup = document.getElementById("downloadsPanel"); 364 let popupHiddenPromise = BrowserTestUtils.waitForEvent( 365 downloadsPopup, 366 "popuphidden", 367 true 368 ); 369 downloadsPopup.hidePopup(); 370 await popupHiddenPromise; 371 }); 372 373 // Navigation with a contenteditable body 374 add_task(async function () { 375 await BrowserTestUtils.openNewForegroundTab(gBrowser, testPage3); 376 377 // The body should be focused when it is editable, not the root. 378 gURLBar.focus(); 379 await expectFocusOnF6( 380 false, 381 "html3", 382 "body3", 383 true, 384 "focus with contenteditable body" 385 ); 386 await expectFocusOnF6( 387 false, 388 "main-window", 389 gURLBar.inputField, 390 false, 391 "focus with contenteditable body urlbar" 392 ); 393 394 // Now go backwards 395 396 await expectFocusOnF6( 397 false, 398 "html3", 399 "body3", 400 true, 401 "back focus with contenteditable body" 402 ); 403 await expectFocusOnF6( 404 false, 405 "main-window", 406 gURLBar.inputField, 407 false, 408 "back focus with contenteditable body urlbar" 409 ); 410 411 BrowserTestUtils.removeTab(gBrowser.selectedTab); 412 }); 413 414 // Navigation with a frameset loaded 415 add_task(async function () { 416 await BrowserTestUtils.openNewForegroundTab( 417 gBrowser, 418 "http://mochi.test:8888/browser/browser/base/content/test/general/file_documentnavigation_frameset.html" 419 ); 420 421 gURLBar.focus(); 422 await expectFocusOnF6( 423 false, 424 "htmlframe1", 425 "htmlframe1", 426 true, 427 "focus on frameset frame 0" 428 ); 429 await expectFocusOnF6( 430 false, 431 "htmlframe2", 432 "htmlframe2", 433 true, 434 "focus on frameset frame 1" 435 ); 436 await expectFocusOnF6( 437 false, 438 "htmlframe3", 439 "htmlframe3", 440 true, 441 "focus on frameset frame 2" 442 ); 443 await expectFocusOnF6( 444 false, 445 "htmlframe4", 446 "htmlframe4", 447 true, 448 "focus on frameset frame 3" 449 ); 450 await expectFocusOnF6( 451 false, 452 "main-window", 453 gURLBar.inputField, 454 false, 455 "focus on frameset frame urlbar" 456 ); 457 458 await expectFocusOnF6( 459 true, 460 "htmlframe4", 461 "htmlframe4", 462 true, 463 "back focus on frameset frame 3" 464 ); 465 await expectFocusOnF6( 466 true, 467 "htmlframe3", 468 "htmlframe3", 469 true, 470 "back focus on frameset frame 2" 471 ); 472 await expectFocusOnF6( 473 true, 474 "htmlframe2", 475 "htmlframe2", 476 true, 477 "back focus on frameset frame 1" 478 ); 479 await expectFocusOnF6( 480 true, 481 "htmlframe1", 482 "htmlframe1", 483 true, 484 "back focus on frameset frame 0" 485 ); 486 await expectFocusOnF6( 487 true, 488 "main-window", 489 gURLBar.inputField, 490 false, 491 "back focus on frameset frame urlbar" 492 ); 493 494 BrowserTestUtils.removeTab(gBrowser.selectedTab); 495 }); 496 497 // XXXndeakin add tests for browsers inside of panels 498 499 function promiseButtonShown(id) { 500 let dwu = window.windowUtils; 501 return TestUtils.waitForCondition(() => { 502 let target = document.getElementById(id); 503 let bounds = dwu.getBoundsWithoutFlushing(target); 504 return bounds.width > 0 && bounds.height > 0; 505 }, `Waiting for button ${id} to have non-0 size`); 506 }