tor-browser

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

browser_popupNotification_keyboard.js (9323B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 function test() {
      6  waitForExplicitFinish();
      7 
      8  ok(PopupNotifications, "PopupNotifications object exists");
      9  ok(PopupNotifications.panel, "PopupNotifications panel exists");
     10 
     11  // Force tabfocus for all elements on OSX.
     12  SpecialPowers.pushPrefEnv({
     13    set: [
     14      ["accessibility.tabfocus", 7],
     15      ["browser.urlbar.scotchBonnet.enableOverride", true],
     16    ],
     17  }).then(setup);
     18 }
     19 
     20 // Focusing on notification icon buttons is handled by the ToolbarKeyboardNavigator
     21 // component and arrow keys (see browser/base/content/browser-toolbarKeyNav.js).
     22 async function focusNotificationAnchor(anchor) {
     23  // To happen focus event on urlbar, remove the focus once.
     24  // We intentionally turn off this a11y check, because the following click is
     25  // purposefully targeting a non-interactive element.
     26  AccessibilityUtils.setEnv({ mustHaveAccessibleRule: false });
     27  EventUtils.synthesizeMouseAtCenter(document.getElementById("browser"), {});
     28  AccessibilityUtils.resetEnv();
     29  await BrowserTestUtils.waitForCondition(() =>
     30    document.activeElement.closest("#browser")
     31  );
     32 
     33  // Move focus to left side button of urlbar.
     34  EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {});
     35  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
     36 
     37  // Move focus to the target.
     38  while (document.activeElement !== anchor) {
     39    EventUtils.synthesizeKey("ArrowRight");
     40  }
     41 }
     42 
     43 var tests = [
     44  // Test that for persistent notifications,
     45  // the secondary action is triggered by pressing the escape key.
     46  {
     47    id: "Test#1",
     48    run() {
     49      this.notifyObj = new BasicNotification(this.id);
     50      this.notifyObj.options.persistent = true;
     51      showNotification(this.notifyObj);
     52    },
     53    onShown(popup) {
     54      checkPopup(popup, this.notifyObj);
     55      EventUtils.synthesizeKey("KEY_Escape");
     56    },
     57    onHidden() {
     58      ok(!this.notifyObj.mainActionClicked, "mainAction was not clicked");
     59      ok(this.notifyObj.secondaryActionClicked, "secondaryAction was clicked");
     60      ok(
     61        !this.notifyObj.dismissalCallbackTriggered,
     62        "dismissal callback wasn't triggered"
     63      );
     64      ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
     65      is(
     66        this.notifyObj.mainActionSource,
     67        undefined,
     68        "shouldn't have a main action source."
     69      );
     70      is(
     71        this.notifyObj.secondaryActionSource,
     72        "esc-press",
     73        "secondary action should be from ESC key press"
     74      );
     75    },
     76  },
     77  // Test that for non-persistent notifications, the escape key dismisses the notification.
     78  {
     79    id: "Test#2",
     80    run() {
     81      this.notifyObj = new BasicNotification(this.id);
     82      this.notification = showNotification(this.notifyObj);
     83    },
     84    onShown(popup) {
     85      checkPopup(popup, this.notifyObj);
     86      EventUtils.synthesizeKey("KEY_Escape");
     87    },
     88    onHidden() {
     89      ok(!this.notifyObj.mainActionClicked, "mainAction was not clicked");
     90      ok(
     91        !this.notifyObj.secondaryActionClicked,
     92        "secondaryAction was not clicked"
     93      );
     94      ok(
     95        this.notifyObj.dismissalCallbackTriggered,
     96        "dismissal callback triggered"
     97      );
     98      ok(
     99        !this.notifyObj.removedCallbackTriggered,
    100        "removed callback was not triggered"
    101      );
    102      is(
    103        this.notifyObj.mainActionSource,
    104        undefined,
    105        "shouldn't have a main action source."
    106      );
    107      is(
    108        this.notifyObj.secondaryActionSource,
    109        undefined,
    110        "shouldn't have a secondary action source."
    111      );
    112      this.notification.remove();
    113    },
    114  },
    115  // Test that the space key on an anchor element focuses an active notification
    116  {
    117    id: "Test#3",
    118    run() {
    119      this.notifyObj = new BasicNotification(this.id);
    120      this.notifyObj.anchorID = "geo-notification-icon";
    121      this.notifyObj.addOptions({
    122        persistent: true,
    123      });
    124      this.notification = showNotification(this.notifyObj);
    125    },
    126    async onShown(popup) {
    127      checkPopup(popup, this.notifyObj);
    128      let anchor = document.getElementById(this.notifyObj.anchorID);
    129      await focusNotificationAnchor(anchor);
    130      EventUtils.sendString(" ");
    131      is(document.activeElement, popup.children[0].closebutton);
    132      this.notification.remove();
    133    },
    134    onHidden() {},
    135  },
    136  // Test that you can switch between active notifications with the space key
    137  // and that the notification is focused on selection.
    138  {
    139    id: "Test#4",
    140    async run() {
    141      let notifyObj1 = new BasicNotification(this.id);
    142      notifyObj1.id += "_1";
    143      notifyObj1.anchorID = "default-notification-icon";
    144      notifyObj1.addOptions({
    145        hideClose: true,
    146        checkbox: {
    147          label: "Test that elements inside the panel can be focused",
    148        },
    149        persistent: true,
    150      });
    151      let opened = waitForNotificationPanel();
    152      let notification1 = showNotification(notifyObj1);
    153      await opened;
    154 
    155      let notifyObj2 = new BasicNotification(this.id);
    156      notifyObj2.id += "_2";
    157      notifyObj2.anchorID = "geo-notification-icon";
    158      notifyObj2.addOptions({
    159        persistent: true,
    160      });
    161      opened = waitForNotificationPanel();
    162      let notification2 = showNotification(notifyObj2);
    163      let popup = await opened;
    164 
    165      // Make sure notification 2 is visible
    166      checkPopup(popup, notifyObj2);
    167 
    168      // Activate the anchor for notification 1 and wait until it's shown.
    169      let anchor = document.getElementById(notifyObj1.anchorID);
    170      await focusNotificationAnchor(anchor);
    171      is(document.activeElement, anchor);
    172      opened = waitForNotificationPanel();
    173      EventUtils.sendString(" ");
    174      popup = await opened;
    175      checkPopup(popup, notifyObj1);
    176 
    177      is(document.activeElement, popup.children[0].checkbox);
    178 
    179      // Activate the anchor for notification 2 and wait until it's shown.
    180      anchor = document.getElementById(notifyObj2.anchorID);
    181      await focusNotificationAnchor(anchor);
    182      is(document.activeElement, anchor);
    183      opened = waitForNotificationPanel();
    184      EventUtils.sendString(" ");
    185      popup = await opened;
    186      checkPopup(popup, notifyObj2);
    187 
    188      is(document.activeElement, popup.children[0].closebutton);
    189 
    190      notification1.remove();
    191      notification2.remove();
    192      goNext();
    193    },
    194  },
    195  // Test that passing the autofocus option will focus an opened notification.
    196  {
    197    id: "Test#5",
    198    run() {
    199      this.notifyObj = new BasicNotification(this.id);
    200      this.notifyObj.anchorID = "geo-notification-icon";
    201      this.notifyObj.addOptions({
    202        autofocus: true,
    203      });
    204      this.notification = showNotification(this.notifyObj);
    205    },
    206    onShown(popup) {
    207      checkPopup(popup, this.notifyObj);
    208 
    209      // Initial focus on open is null because a panel itself
    210      // can not be focused, next tab focus will be inside the panel.
    211      is(Services.focus.focusedElement, null);
    212 
    213      EventUtils.synthesizeKey("KEY_Tab");
    214      is(Services.focus.focusedElement, popup.children[0].closebutton);
    215      dismissNotification(popup);
    216    },
    217    async onHidden() {
    218      // Focus the urlbar to check that it stays focused.
    219      gURLBar.focus();
    220 
    221      // Show another notification and make sure it's not autofocused.
    222      let notifyObj = new BasicNotification(this.id);
    223      notifyObj.id += "_2";
    224      notifyObj.anchorID = "default-notification-icon";
    225 
    226      let opened = waitForNotificationPanel();
    227      let notification = showNotification(notifyObj);
    228      let popup = await opened;
    229      checkPopup(popup, notifyObj);
    230 
    231      // Check that the urlbar is still focused.
    232      is(Services.focus.focusedElement, gURLBar.inputField);
    233 
    234      this.notification.remove();
    235      notification.remove();
    236    },
    237  },
    238  // Test that focus is not moved out of a content element if autofocus is not set.
    239  {
    240    id: "Test#6",
    241    async run() {
    242      let id = this.id;
    243      await BrowserTestUtils.withNewTab(
    244        "data:text/html,<input id='test-input'/>",
    245        async function (browser) {
    246          let notifyObj = new BasicNotification(id);
    247          await SpecialPowers.spawn(browser, [], function () {
    248            content.document.getElementById("test-input").focus();
    249          });
    250 
    251          let opened = waitForNotificationPanel();
    252          let notification = showNotification(notifyObj);
    253          await opened;
    254 
    255          // Check that the focused element in the chrome window
    256          // is either the browser in case we're running on e10s
    257          // or the input field in case of non-e10s.
    258          if (gMultiProcessBrowser) {
    259            is(Services.focus.focusedElement, browser);
    260          } else {
    261            is(
    262              Services.focus.focusedElement,
    263              browser.contentDocument.getElementById("test-input")
    264            );
    265          }
    266 
    267          // Check that the input field is still focused inside the browser.
    268          await SpecialPowers.spawn(browser, [], function () {
    269            is(
    270              content.document.activeElement,
    271              content.document.getElementById("test-input")
    272            );
    273          });
    274 
    275          notification.remove();
    276        }
    277      );
    278      goNext();
    279    },
    280  },
    281 ];