tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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>