browser_panel_keyboard_navigation.js (9369B)
1 "use strict"; 2 3 /** 4 * Test keyboard navigation in the app menu panel. 5 */ 6 7 const kHelpButtonId = "appMenu-help-button2"; 8 9 function getEnabledNavigableElementsForView(panelView) { 10 return Array.from( 11 panelView.querySelectorAll("button,toolbarbutton,menulist,.text-link") 12 ).filter(element => { 13 let bounds = element.getBoundingClientRect(); 14 return !element.disabled && bounds.width > 0 && bounds.height > 0; 15 }); 16 } 17 18 add_task(async function testUpDownKeys() { 19 await gCUITestUtils.openMainMenu(); 20 21 let buttons = getEnabledNavigableElementsForView(PanelUI.mainView); 22 23 for (let button of buttons) { 24 if (button.disabled) { 25 continue; 26 } 27 EventUtils.synthesizeKey("KEY_ArrowDown"); 28 Assert.equal( 29 document.commandDispatcher.focusedElement, 30 button, 31 "The correct button should be focused after navigating downward" 32 ); 33 } 34 35 EventUtils.synthesizeKey("KEY_ArrowDown"); 36 Assert.equal( 37 document.commandDispatcher.focusedElement, 38 buttons[0], 39 "Pressing upwards should cycle around and select the first button again" 40 ); 41 42 for (let i = buttons.length - 1; i >= 0; --i) { 43 let button = buttons[i]; 44 if (button.disabled) { 45 continue; 46 } 47 EventUtils.synthesizeKey("KEY_ArrowUp"); 48 Assert.equal( 49 document.commandDispatcher.focusedElement, 50 button, 51 "The first button should be focused after navigating upward" 52 ); 53 } 54 55 await gCUITestUtils.hideMainMenu(); 56 }); 57 58 add_task(async function testHomeEndKeys() { 59 await gCUITestUtils.openMainMenu(); 60 61 let buttons = getEnabledNavigableElementsForView(PanelUI.mainView); 62 let enabledButtons = buttons.filter(btn => !btn.disabled); 63 let firstButton = enabledButtons[0]; 64 let lastButton = enabledButtons.pop(); 65 66 Assert.notEqual(firstButton, lastButton, "There is more than one button"); 67 68 EventUtils.synthesizeKey("KEY_End"); 69 Assert.equal( 70 document.commandDispatcher.focusedElement, 71 lastButton, 72 "The last button should be focused after pressing End" 73 ); 74 75 EventUtils.synthesizeKey("KEY_Home"); 76 Assert.equal( 77 document.commandDispatcher.focusedElement, 78 firstButton, 79 "The first button should be focused after pressing Home" 80 ); 81 82 await gCUITestUtils.hideMainMenu(); 83 }); 84 85 add_task(async function testEnterKeyBehaviors() { 86 await gCUITestUtils.openMainMenu(); 87 88 let buttons = getEnabledNavigableElementsForView(PanelUI.mainView); 89 90 // Navigate to the 'Help' button, which points to a subview. 91 EventUtils.synthesizeKey("KEY_ArrowUp"); 92 let focusedElement = document.commandDispatcher.focusedElement; 93 Assert.equal( 94 focusedElement, 95 buttons[buttons.length - 1], 96 "The last button should be focused after navigating upward" 97 ); 98 99 // Make sure the Help button is in focus. 100 while ( 101 !focusedElement || 102 !focusedElement.id || 103 focusedElement.id != kHelpButtonId 104 ) { 105 EventUtils.synthesizeKey("KEY_ArrowUp"); 106 focusedElement = document.commandDispatcher.focusedElement; 107 } 108 EventUtils.synthesizeKey("KEY_Enter"); 109 110 let helpView = document.getElementById("PanelUI-helpView"); 111 await BrowserTestUtils.waitForEvent(helpView, "ViewShown"); 112 113 let helpButtons = getEnabledNavigableElementsForView(helpView); 114 Assert.ok( 115 helpButtons[0].classList.contains("subviewbutton-back"), 116 "First button in help view should be a back button" 117 ); 118 119 // For posterity, check navigating the subview using up/ down arrow keys as well. 120 // When opening a subview, the first control *after* the Back button gets 121 // focus. 122 EventUtils.synthesizeKey("KEY_ArrowUp"); 123 focusedElement = document.commandDispatcher.focusedElement; 124 Assert.equal( 125 focusedElement, 126 helpButtons[0], 127 "The Back button should be focused after navigating upward" 128 ); 129 for (let i = helpButtons.length - 1; i >= 0; --i) { 130 let button = helpButtons[i]; 131 if (button.disabled) { 132 continue; 133 } 134 EventUtils.synthesizeKey("KEY_ArrowUp"); 135 focusedElement = document.commandDispatcher.focusedElement; 136 Assert.equal( 137 focusedElement, 138 button, 139 "The previous button should be focused after navigating upward" 140 ); 141 } 142 143 // Make sure the back button is in focus again. 144 while (focusedElement != helpButtons[0]) { 145 EventUtils.synthesizeKey("KEY_ArrowDown"); 146 focusedElement = document.commandDispatcher.focusedElement; 147 } 148 149 // The first button is the back button. Hittin Enter should navigate us back. 150 let promise = BrowserTestUtils.waitForEvent(PanelUI.mainView, "ViewShown"); 151 EventUtils.synthesizeKey("KEY_Enter"); 152 await promise; 153 154 // Let's test a 'normal' command button. 155 focusedElement = document.commandDispatcher.focusedElement; 156 const kFindButtonId = "appMenu-find-button2"; 157 while ( 158 !focusedElement || 159 !focusedElement.id || 160 focusedElement.id != kFindButtonId 161 ) { 162 EventUtils.synthesizeKey("KEY_ArrowUp"); 163 focusedElement = document.commandDispatcher.focusedElement; 164 } 165 let findBarPromise = gBrowser.isFindBarInitialized() 166 ? null 167 : BrowserTestUtils.waitForEvent(gBrowser.selectedTab, "TabFindInitialized"); 168 Assert.equal( 169 focusedElement.id, 170 kFindButtonId, 171 "Find button should be selected" 172 ); 173 174 await gCUITestUtils.hidePanelMultiView(PanelUI.panel, () => 175 EventUtils.synthesizeKey("KEY_Enter") 176 ); 177 178 await findBarPromise; 179 Assert.ok(!gFindBar.hidden, "Findbar should have opened"); 180 gFindBar.close(); 181 }); 182 183 add_task(async function testLeftRightKeys() { 184 await gCUITestUtils.openMainMenu(); 185 186 // Navigate to the 'Help' button, which points to a subview. 187 let focusedElement = document.commandDispatcher.focusedElement; 188 while ( 189 !focusedElement || 190 !focusedElement.id || 191 focusedElement.id != kHelpButtonId 192 ) { 193 EventUtils.synthesizeKey("KEY_ArrowUp"); 194 focusedElement = document.commandDispatcher.focusedElement; 195 } 196 Assert.equal( 197 focusedElement.id, 198 kHelpButtonId, 199 "The last button should be focused after navigating upward" 200 ); 201 202 // Hitting ArrowRight on a button that points to a subview should navigate us 203 // there. 204 EventUtils.synthesizeKey("KEY_ArrowRight"); 205 let helpView = document.getElementById("PanelUI-helpView"); 206 await BrowserTestUtils.waitForEvent(helpView, "ViewShown"); 207 208 // Hitting ArrowLeft should navigate us back. 209 let promise = BrowserTestUtils.waitForEvent(PanelUI.mainView, "ViewShown"); 210 EventUtils.synthesizeKey("KEY_ArrowLeft"); 211 await promise; 212 213 focusedElement = document.commandDispatcher.focusedElement; 214 Assert.equal( 215 focusedElement.id, 216 kHelpButtonId, 217 "Help button should be focused again now that we're back in the main view" 218 ); 219 220 await gCUITestUtils.hideMainMenu(); 221 }); 222 223 add_task(async function testTabKey() { 224 await gCUITestUtils.openMainMenu(); 225 226 let buttons = getEnabledNavigableElementsForView(PanelUI.mainView); 227 228 for (let button of buttons) { 229 if (button.disabled) { 230 continue; 231 } 232 EventUtils.synthesizeKey("KEY_Tab"); 233 Assert.equal( 234 document.commandDispatcher.focusedElement, 235 button, 236 "The correct button should be focused after tabbing" 237 ); 238 } 239 240 EventUtils.synthesizeKey("KEY_Tab"); 241 Assert.equal( 242 document.commandDispatcher.focusedElement, 243 buttons[0], 244 "Pressing tab should cycle around and select the first button again" 245 ); 246 247 for (let i = buttons.length - 1; i >= 0; --i) { 248 let button = buttons[i]; 249 if (button.disabled) { 250 continue; 251 } 252 EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true }); 253 Assert.equal( 254 document.commandDispatcher.focusedElement, 255 button, 256 "The correct button should be focused after shift + tabbing" 257 ); 258 } 259 260 EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true }); 261 Assert.equal( 262 document.commandDispatcher.focusedElement, 263 buttons[buttons.length - 1], 264 "Pressing shift + tab should cycle around and select the last button again" 265 ); 266 267 await gCUITestUtils.hideMainMenu(); 268 }); 269 270 add_task(async function testInterleavedTabAndArrowKeys() { 271 await gCUITestUtils.openMainMenu(); 272 273 let buttons = getEnabledNavigableElementsForView(PanelUI.mainView); 274 let tab = false; 275 276 for (let button of buttons) { 277 if (button.disabled) { 278 continue; 279 } 280 if (tab) { 281 EventUtils.synthesizeKey("KEY_Tab"); 282 } else { 283 EventUtils.synthesizeKey("KEY_ArrowDown"); 284 } 285 tab = !tab; 286 } 287 288 Assert.equal( 289 document.commandDispatcher.focusedElement, 290 buttons[buttons.length - 1], 291 "The last button should be focused after a mix of Tab and ArrowDown" 292 ); 293 294 await gCUITestUtils.hideMainMenu(); 295 }); 296 297 add_task(async function testSpaceDownAfterTabNavigation() { 298 await gCUITestUtils.openMainMenu(); 299 300 let buttons = getEnabledNavigableElementsForView(PanelUI.mainView); 301 let button; 302 303 for (button of buttons) { 304 if (button.disabled) { 305 continue; 306 } 307 EventUtils.synthesizeKey("KEY_Tab"); 308 if (button.id == kHelpButtonId) { 309 break; 310 } 311 } 312 313 Assert.equal( 314 document.commandDispatcher.focusedElement, 315 button, 316 "Help button should be focused after tabbing to it." 317 ); 318 319 // Pressing down space on a button that points to a subview should navigate us 320 // there, before keyup. 321 EventUtils.synthesizeKey(" ", { type: "keydown" }); 322 let helpView = document.getElementById("PanelUI-helpView"); 323 await BrowserTestUtils.waitForEvent(helpView, "ViewShown"); 324 325 await gCUITestUtils.hideMainMenu(); 326 });