test_menu_button.html (10310B)
1 <!DOCTYPE HTML> 2 <html> 3 <!-- 4 Test the menu-button component 5 --> 6 <head> 7 <meta charset="utf-8"> 8 <title>Test the menu-button component</title> 9 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> 10 <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> 11 <script type="module" src="chrome://browser/content/aboutlogins/components/menu-button.mjs"></script> 12 <script src="aboutlogins_common.js"></script> 13 14 <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> 15 </head> 16 <body> 17 <p id="display"> 18 </p> 19 <div id="content" style="display: none"> 20 <iframe id="templateFrame" src="chrome://browser/content/aboutlogins/aboutLogins.html" 21 sandbox="allow-same-origin"></iframe> 22 </div> 23 <pre id="test"> 24 </pre> 25 <script> 26 /** Test the menu-button component */ 27 28 let gMenuButton; 29 add_setup(async () => { 30 let templateFrame = document.getElementById("templateFrame"); 31 let displayEl = document.getElementById("display"); 32 await importDependencies(templateFrame, displayEl); 33 34 gMenuButton = document.createElement("menu-button"); 35 displayEl.appendChild(gMenuButton); 36 gMenuButton.style.marginInlineStart = "100px"; 37 38 isnot(document.activeElement, gMenuButton, "menu-button should not be focused by default"); 39 while (document.activeElement != gMenuButton) { 40 sendKey("TAB"); 41 await new Promise(resolve => requestAnimationFrame(resolve)); 42 } 43 }); 44 45 add_task(async function test_menu_click_button () { 46 let menu = gMenuButton.shadowRoot.querySelector(".menu"); 47 let menuButton = gMenuButton.shadowRoot.querySelector(".menu-button"); 48 ok(menu.hidden, "menu should be hidden before being clicked"); 49 await synthesizeMouseAtCenter(menuButton, {}); 50 await new Promise(resolve => requestAnimationFrame(resolve)); 51 ok(!menu.hidden, "menu should be visible after clicked"); 52 53 let menuListSeparators = gMenuButton.shadowRoot.querySelectorAll(".menuitem-separator"); 54 await synthesizeMouseAtCenter(menuListSeparators[0], {}); 55 await new Promise(resolve => requestAnimationFrame(resolve)); 56 ok(!menu.hidden, "menu should still be visible after menu separator has been clicked"); 57 58 let menuListButtons = gMenuButton.shadowRoot.querySelectorAll(".menuitem-button"); 59 await synthesizeMouseAtCenter(menuListButtons[0], {}); 60 await new Promise(resolve => requestAnimationFrame(resolve)); 61 ok(menu.hidden, "menu should be hidden after a button has been clicked"); 62 }); 63 64 add_task(async function test_menu_click_outside () { 65 let menu = gMenuButton.shadowRoot.querySelector(".menu"); 66 let menuButton = gMenuButton.shadowRoot.querySelector(".menu-button"); 67 ok(menu.hidden, "menu should be hidden before being clicked"); 68 await synthesizeMouseAtCenter(menuButton, {}); 69 await new Promise(resolve => requestAnimationFrame(resolve)); 70 ok(!menu.hidden, "menu should be visible after clicked"); 71 72 let menuListSeparators = gMenuButton.shadowRoot.querySelectorAll(".menuitem-separator"); 73 await synthesizeMouseAtCenter(menuListSeparators[0], {}); 74 await new Promise(resolve => requestAnimationFrame(resolve)); 75 ok(!menu.hidden, "menu should still be visible after menu separator has been clicked"); 76 77 let outsideEl = document.getElementById("test"); 78 await synthesizeMouseAtCenter(outsideEl, {}); 79 await new Promise(resolve => requestAnimationFrame(resolve)); 80 ok(menu.hidden, "menu should be hidden after a click outside of the menu has been clicked"); 81 82 for (let key of ["KEY_ArrowDown", "KEY_ArrowUp"]) { 83 synthesizeKey(key); 84 await new Promise(resolve => requestAnimationFrame(resolve)); 85 ok(menu.hidden, `menu should still be hidden when ${key} is entered`); 86 } 87 }); 88 89 add_task(async function test_menu_esc_after_click_disabled_item () { 90 let menu = gMenuButton.shadowRoot.querySelector(".menu"); 91 let menuButton = gMenuButton.shadowRoot.querySelector(".menu-button"); 92 ok(menu.hidden, "menu should be hidden before being clicked"); 93 await synthesizeMouseAtCenter(menuButton, {}); 94 await new Promise(resolve => requestAnimationFrame(resolve)); 95 ok(!menu.hidden, "menu should be visible after clicked"); 96 97 let menuListSeparators = gMenuButton.shadowRoot.querySelectorAll(".menuitem-separator"); 98 await synthesizeMouseAtCenter(menuListSeparators[0], {}); 99 await new Promise(resolve => requestAnimationFrame(resolve)); 100 ok(!menu.hidden, "menu should still be visible after menu separator has been clicked"); 101 102 sendKey("ESCAPE"); 103 await new Promise(resolve => requestAnimationFrame(resolve)); 104 ok(menu.hidden, "menu should be hidden after pressing 'escape'"); 105 }); 106 107 add_task(async function test_menu_open_close() { 108 is(document.activeElement, gMenuButton, "menu-button should be focused to start the test"); 109 110 let menu = gMenuButton.shadowRoot.querySelector(".menu"); 111 is(true, menu.hidden, "menu should be hidden before pressing 'space'"); 112 sendKey("SPACE"); 113 await new Promise(resolve => requestAnimationFrame(resolve)); 114 ok(!menu.hidden, "menu should be visible after pressing 'space'"); 115 116 sendKey("ESCAPE"); 117 await new Promise(resolve => requestAnimationFrame(resolve)); 118 ok(menu.hidden, "menu should be hidden after pressing 'escape'"); 119 is(gMenuButton.shadowRoot.activeElement, gMenuButton.shadowRoot.querySelector(".menu-button"), 120 "the .menu-button should be focused after closing the menu via keyboard"); 121 122 sendKey("RETURN"); 123 let firstVisibleItem = gMenuButton.shadowRoot.querySelector(".menuitem-button:not([hidden])"); 124 await SimpleTest.promiseWaitForCondition(() => firstVisibleItem.matches(":focus"), 125 "waiting for firstVisibleItem to get focus"); 126 127 ok(!menu.hidden, "menu should be visible after pressing 'return'"); 128 ok(firstVisibleItem.matches(":focus"), "firstVisibleItem should be focused after opening popup"); 129 130 synthesizeKey("VK_TAB", { shiftKey: true }); 131 await SimpleTest.promiseWaitForCondition(() => !firstVisibleItem.matches(":focus"), 132 "waiting for firstVisibleItem to lose focus"); 133 ok(!firstVisibleItem.matches(":focus"), "firstVisibleItem should lose focus after tabbing away from it"); 134 sendKey("TAB"); 135 await SimpleTest.promiseWaitForCondition(() => firstVisibleItem.matches(":focus"), 136 "waiting for firstVisibleItem to get focus again"); 137 ok(firstVisibleItem.matches(":focus"), "firstVisibleItem should be focused after tabbing to it again"); 138 sendKey("TAB"); // Import from file 139 sendKey("TAB"); // Export 140 sendKey("TAB"); // Remove All Logins 141 142 if (navigator.platform == "Win32" || navigator.platform == "MacIntel") { 143 // The Import menuitem is only visible on Windows/macOS, where we will need another Tab 144 // press to get to the Preferences item. 145 let preferencesItem = gMenuButton.shadowRoot.querySelector(".menuitem-preferences"); 146 sendKey("DOWN"); 147 await SimpleTest.promiseWaitForCondition(() => preferencesItem.matches(":focus"), 148 "waiting for preferencesItem to gain focus"); 149 ok(preferencesItem.matches(":focus"), `.menuitem-preferences should be now be focused (DOWN)`); 150 sendKey("UP"); 151 await SimpleTest.promiseWaitForCondition(() => !preferencesItem.matches(":focus"), 152 `waiting for preferencesItem to lose focus (UP)`); 153 ok(!preferencesItem.matches(":focus"), `.menuitem-preferences should lose focus after pressing up`); 154 155 sendKey("TAB"); 156 await SimpleTest.promiseWaitForCondition(() => preferencesItem.matches(":focus"), 157 "waiting for preferencesItem to get focus"); 158 ok(preferencesItem.matches(":focus"), ".menuitem-preferences should be focused after tabbing to it"); 159 } 160 161 let openPreferencesEvent = null; 162 ok(!menu.hidden, "menu should be visible before pressing 'space' on .menuitem-preferences"); 163 window.addEventListener( 164 "AboutLoginsOpenPreferences", 165 event => openPreferencesEvent = event, 166 {once: true} 167 ); 168 sendKey("SPACE"); 169 ok(openPreferencesEvent, "AboutLoginsOpenPreferences event should be dispatched after pressing 'space' on .menuitem-preferences"); 170 ok(menu.hidden, "menu should be hidden after pressing 'space' on .menuitem-preferences"); 171 172 // Clean up task 173 sendKey("TAB"); 174 synthesizeKey("VK_TAB", { shiftKey: true }); 175 }); 176 177 add_task(async function test_menu_keyboard_cycling() { 178 function waitForElementFocus(selector) { 179 return SimpleTest.promiseWaitForCondition( 180 () => gMenuButton.shadowRoot.querySelector(selector).matches(":focus"), 181 `waiting for ${selector} to be focused` 182 ); 183 } 184 185 function getFocusedMenuItem() { 186 return gMenuButton.shadowRoot.querySelector(".menuitem-button:focus"); 187 } 188 189 let allItems = [ 190 "menuitem-import-file", 191 "menuitem-export", 192 "menuitem-remove-all-logins", 193 "menuitem-preferences", 194 "menuitem-help", 195 ]; 196 if (navigator.platform == "Win32" || navigator.platform == "MacIntel") { 197 allItems = ["menuitem-import-browser", ...allItems]; 198 } 199 200 let menu = gMenuButton.shadowRoot.querySelector(".menu"); 201 202 is(document.activeElement, gMenuButton, "menu-button should be focused to start the test"); 203 is(true, menu.hidden, "menu should be hidden before pressing 'space'"); 204 205 sendKey("RETURN"); 206 207 await SimpleTest.promiseWaitForCondition(() => !menu.hidden, "waiting for menu to show"); 208 209 ok(!menu.hidden, "menu should be visible after pressing 'enter'"); 210 211 for (let item of allItems) { 212 await waitForElementFocus("." + item); 213 ok( 214 getFocusedMenuItem().classList.contains(item), 215 `.${item} should be selected after key is pressed` 216 ); 217 sendKey("DOWN"); 218 } 219 220 221 await waitForElementFocus("." + allItems[0]); 222 ok( 223 getFocusedMenuItem().classList.contains(allItems[0]), 224 "Focused item should not change if left arrow is pressed" 225 ) 226 sendKey("LEFT"); 227 228 await waitForElementFocus("." + allItems[0]); 229 ok( 230 getFocusedMenuItem().classList.contains(allItems[0]), 231 "Focused item should not change if right arrow is pressed" 232 ) 233 sendKey("RIGHT"); 234 235 await waitForElementFocus("." + allItems[0]); 236 ok( 237 getFocusedMenuItem().classList.contains(allItems[0]), 238 "Last item should cycle back to first item" 239 ); 240 241 sendKey("UP"); 242 243 let reversedItems = allItems.reverse(); 244 for (let item of reversedItems) { 245 await waitForElementFocus("." + item); 246 ok( 247 getFocusedMenuItem().classList.contains(item), 248 `.${item} should be selected after up key is pressed` 249 ); 250 sendKey("UP"); 251 } 252 }); 253 </script> 254 255 </body> 256 </html>