summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/keyboard/browser_toolbarKeyNav.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/test/keyboard/browser_toolbarKeyNav.js')
-rw-r--r--browser/base/content/test/keyboard/browser_toolbarKeyNav.js641
1 files changed, 641 insertions, 0 deletions
diff --git a/browser/base/content/test/keyboard/browser_toolbarKeyNav.js b/browser/base/content/test/keyboard/browser_toolbarKeyNav.js
new file mode 100644
index 0000000000..7fb67a6a91
--- /dev/null
+++ b/browser/base/content/test/keyboard/browser_toolbarKeyNav.js
@@ -0,0 +1,641 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Test browser toolbar keyboard navigation.
+ * These tests assume the default browser configuration for toolbars unless
+ * otherwise specified.
+ */
+
+const PERMISSIONS_PAGE =
+ "https://example.com/browser/browser/base/content/test/permissions/permissions.html";
+const afterUrlBarButton = "save-to-pocket-button";
+
+// The DevEdition has the DevTools button in the toolbar by default. Remove it
+// to prevent branch-specific rules what button should be focused.
+function resetToolbarWithoutDevEditionButtons() {
+ CustomizableUI.reset();
+ CustomizableUI.removeWidgetFromArea("developer-button");
+}
+
+function AddHomeBesideReload() {
+ CustomizableUI.addWidgetToArea(
+ "home-button",
+ "nav-bar",
+ CustomizableUI.getPlacementOfWidget("stop-reload-button").position + 1
+ );
+}
+
+function RemoveHomeButton() {
+ CustomizableUI.removeWidgetFromArea("home-button");
+}
+
+function AddOldMenuSideButtons() {
+ // Make the FxA button visible even though we're signed out.
+ // We'll use oldfxastatus to restore the old state.
+ document.documentElement.setAttribute(
+ "oldfxastatus",
+ document.documentElement.getAttribute("fxastatus")
+ );
+ document.documentElement.setAttribute("fxastatus", "signed_in");
+ // The FxA button is supposed to be last, add these buttons before it.
+ CustomizableUI.addWidgetToArea(
+ "library-button",
+ "nav-bar",
+ CustomizableUI.getWidgetIdsInArea("nav-bar").length - 2
+ );
+ CustomizableUI.addWidgetToArea(
+ "sidebar-button",
+ "nav-bar",
+ CustomizableUI.getWidgetIdsInArea("nav-bar").length - 2
+ );
+ CustomizableUI.addWidgetToArea(
+ "unified-extensions-button",
+ "nav-bar",
+ CustomizableUI.getWidgetIdsInArea("nav-bar").length - 2
+ );
+}
+
+function RemoveOldMenuSideButtons() {
+ CustomizableUI.removeWidgetFromArea("library-button");
+ CustomizableUI.removeWidgetFromArea("sidebar-button");
+ document.documentElement.setAttribute(
+ "fxastatus",
+ document.documentElement.getAttribute("oldfxastatus")
+ );
+ document.documentElement.removeAttribute("oldfxastatus");
+}
+
+function startFromUrlBar(aWindow = window) {
+ aWindow.gURLBar.focus();
+ is(
+ aWindow.document.activeElement,
+ aWindow.gURLBar.inputField,
+ "URL bar focused for start of test"
+ );
+}
+
+// The Reload button is disabled for a short time even after the page finishes
+// loading. Wait for it to be enabled.
+async function waitUntilReloadEnabled() {
+ let button = document.getElementById("reload-button");
+ await TestUtils.waitForCondition(() => !button.disabled);
+}
+
+// Opens a new, blank tab, executes a task and closes the tab.
+function withNewBlankTab(taskFn) {
+ return BrowserTestUtils.withNewTab("about:blank", async function () {
+ // For a blank tab, the Reload button should be disabled. However, when we
+ // open about:blank with BrowserTestUtils.withNewTab, this is unreliable.
+ // Therefore, explicitly disable the reload command.
+ // We disable the command (rather than disabling the button directly) so the
+ // button will be updated correctly for future page loads.
+ document.getElementById("Browser:Reload").setAttribute("disabled", "true");
+ await taskFn();
+ });
+}
+
+function removeFirefoxViewButton() {
+ CustomizableUI.removeWidgetFromArea("firefox-view-button");
+}
+
+const BOOKMARKS_COUNT = 100;
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.toolbars.keyboard_navigation", true],
+ ["accessibility.tabfocus", 7],
+ ],
+ });
+ resetToolbarWithoutDevEditionButtons();
+
+ await PlacesUtils.bookmarks.eraseEverything();
+ // Add bookmarks.
+ let bookmarks = new Array(BOOKMARKS_COUNT);
+ for (let i = 0; i < BOOKMARKS_COUNT; ++i) {
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ bookmarks[i] = { url: `http://test.places.${i}/` };
+ }
+ await PlacesUtils.bookmarks.insertTree({
+ guid: PlacesUtils.bookmarks.toolbarGuid,
+ children: bookmarks,
+ });
+
+ // The page actions button is not normally visible, so we must
+ // unhide it.
+ BrowserPageActions.mainButtonNode.style.visibility = "visible";
+ registerCleanupFunction(() => {
+ BrowserPageActions.mainButtonNode.style.removeProperty("visibility");
+ });
+});
+
+// Test tab stops with no page loaded.
+add_task(async function testTabStopsNoPageWithHomeButton() {
+ AddHomeBesideReload();
+ await withNewBlankTab(async function () {
+ startFromUrlBar();
+ await expectFocusAfterKey("Shift+Tab", "home-button");
+ await expectFocusAfterKey("Shift+Tab", "tabs-newtab-button");
+ await expectFocusAfterKey("Shift+Tab", gBrowser.selectedTab);
+ await expectFocusAfterKey("Tab", "tabs-newtab-button");
+ await expectFocusAfterKey("Tab", "home-button");
+ await expectFocusAfterKey("Tab", gURLBar.inputField);
+ await expectFocusAfterKey("Tab", afterUrlBarButton);
+ await expectFocusAfterKey("Tab", gBrowser.selectedBrowser);
+ });
+ RemoveHomeButton();
+});
+
+async function doTestTabStopsPageLoaded(aPageActionsVisible) {
+ info(`doTestTabStopsPageLoaded(${aPageActionsVisible})`);
+
+ BrowserPageActions.mainButtonNode.style.visibility = aPageActionsVisible
+ ? "visible"
+ : "";
+ await BrowserTestUtils.withNewTab("https://example.com", async function () {
+ await waitUntilReloadEnabled();
+ startFromUrlBar();
+ await expectFocusAfterKey(
+ "Shift+Tab",
+ "tracking-protection-icon-container"
+ );
+ await expectFocusAfterKey("Shift+Tab", "reload-button");
+ await expectFocusAfterKey("Shift+Tab", "tabs-newtab-button");
+ await expectFocusAfterKey("Shift+Tab", gBrowser.selectedTab);
+ await expectFocusAfterKey("Tab", "tabs-newtab-button");
+ await expectFocusAfterKey("Tab", "reload-button");
+ await expectFocusAfterKey("Tab", "tracking-protection-icon-container");
+ await expectFocusAfterKey("Tab", gURLBar.inputField);
+ await expectFocusAfterKey(
+ "Tab",
+ aPageActionsVisible ? "pageActionButton" : "star-button-box"
+ );
+ await expectFocusAfterKey("Tab", afterUrlBarButton);
+ await expectFocusAfterKey("Tab", gBrowser.selectedBrowser);
+ });
+}
+
+// Test tab stops with a page loaded.
+add_task(async function testTabStopsPageLoaded() {
+ is(
+ BrowserPageActions.mainButtonNode.style.visibility,
+ "visible",
+ "explicitly shown at the beginning of test"
+ );
+ await doTestTabStopsPageLoaded(false);
+ await doTestTabStopsPageLoaded(true);
+});
+
+// Test tab stops with a notification anchor visible.
+// The notification anchor should not get its own tab stop.
+add_task(async function testTabStopsWithNotification() {
+ await BrowserTestUtils.withNewTab(
+ PERMISSIONS_PAGE,
+ async function (aBrowser) {
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+ // Request a permission.
+ BrowserTestUtils.synthesizeMouseAtCenter("#geo", {}, aBrowser);
+ await popupShown;
+ startFromUrlBar();
+ // If the notification anchor were in the tab order, the next shift+tab
+ // would focus it instead of #tracking-protection-icon-container.
+ await expectFocusAfterKey(
+ "Shift+Tab",
+ "tracking-protection-icon-container"
+ );
+ }
+ );
+});
+
+// Test tab stops with the Bookmarks toolbar visible.
+add_task(async function testTabStopsWithBookmarksToolbar() {
+ await BrowserTestUtils.withNewTab("about:blank", async function () {
+ CustomizableUI.setToolbarVisibility("PersonalToolbar", true);
+ startFromUrlBar();
+ await expectFocusAfterKey("Tab", afterUrlBarButton);
+ await expectFocusAfterKey("Tab", "PersonalToolbar", true);
+ await expectFocusAfterKey("Tab", gBrowser.selectedBrowser);
+
+ // Make sure the Bookmarks toolbar is no longer tabbable once hidden.
+ CustomizableUI.setToolbarVisibility("PersonalToolbar", false);
+ startFromUrlBar();
+ await expectFocusAfterKey("Tab", afterUrlBarButton);
+ await expectFocusAfterKey("Tab", gBrowser.selectedBrowser);
+ });
+});
+
+// Test a focusable toolbartabstop which has no navigable buttons.
+add_task(async function testTabStopNoButtons() {
+ await withNewBlankTab(async function () {
+ // The Back, Forward and Reload buttons are all currently disabled.
+ // The Home button is the only other button at that tab stop.
+ CustomizableUI.removeWidgetFromArea("home-button");
+ startFromUrlBar();
+ await expectFocusAfterKey("Shift+Tab", "tabs-newtab-button");
+ await expectFocusAfterKey("Tab", gURLBar.inputField);
+ resetToolbarWithoutDevEditionButtons();
+ AddHomeBesideReload();
+ // Make sure the button is reachable now that it has been re-added.
+ await expectFocusAfterKey("Shift+Tab", "home-button", true);
+ RemoveHomeButton();
+ });
+});
+
+// Test that right/left arrows move through toolbarbuttons.
+// This also verifies that:
+// 1. Right/left arrows do nothing when at the edges; and
+// 2. The overflow menu button can't be reached by right arrow when it isn't
+// visible.
+add_task(async function testArrowsToolbarbuttons() {
+ AddOldMenuSideButtons();
+ await BrowserTestUtils.withNewTab("about:blank", async function () {
+ startFromUrlBar();
+ await expectFocusAfterKey("Tab", afterUrlBarButton);
+ EventUtils.synthesizeKey("KEY_ArrowLeft");
+ is(
+ document.activeElement.id,
+ afterUrlBarButton,
+ "ArrowLeft at end of button group does nothing"
+ );
+ await expectFocusAfterKey("ArrowRight", "library-button");
+ await expectFocusAfterKey("ArrowRight", "sidebar-button");
+ await expectFocusAfterKey("ArrowRight", "unified-extensions-button");
+ await expectFocusAfterKey("ArrowRight", "fxa-toolbar-menu-button");
+ // This next check also confirms that the overflow menu button is skipped,
+ // since it is currently invisible.
+ await expectFocusAfterKey("ArrowRight", "PanelUI-menu-button");
+ EventUtils.synthesizeKey("KEY_ArrowRight");
+ is(
+ document.activeElement.id,
+ "PanelUI-menu-button",
+ "ArrowRight at end of button group does nothing"
+ );
+ await expectFocusAfterKey("ArrowLeft", "fxa-toolbar-menu-button");
+ await expectFocusAfterKey("ArrowLeft", "unified-extensions-button");
+ await expectFocusAfterKey("ArrowLeft", "sidebar-button");
+ await expectFocusAfterKey("ArrowLeft", "library-button");
+ });
+ RemoveOldMenuSideButtons();
+});
+
+// Test that right/left arrows move through buttons which aren't toolbarbuttons
+// but have role="button".
+add_task(async function testArrowsRoleButton() {
+ await BrowserTestUtils.withNewTab("https://example.com", async function () {
+ startFromUrlBar();
+ await expectFocusAfterKey("Tab", "pageActionButton");
+ await expectFocusAfterKey("ArrowRight", "star-button-box");
+ await expectFocusAfterKey("ArrowLeft", "pageActionButton");
+ });
+});
+
+// Test that right/left arrows do not land on disabled buttons.
+add_task(async function testArrowsDisabledButtons() {
+ await BrowserTestUtils.withNewTab(
+ "https://example.com",
+ async function (aBrowser) {
+ await waitUntilReloadEnabled();
+ startFromUrlBar();
+ await expectFocusAfterKey(
+ "Shift+Tab",
+ "tracking-protection-icon-container"
+ );
+ // Back and Forward buttons are disabled.
+ await expectFocusAfterKey("Shift+Tab", "reload-button");
+ EventUtils.synthesizeKey("KEY_ArrowLeft");
+ is(
+ document.activeElement.id,
+ "reload-button",
+ "ArrowLeft on Reload button when prior buttons disabled does nothing"
+ );
+
+ BrowserTestUtils.loadURIString(aBrowser, "https://example.com/2");
+ await BrowserTestUtils.browserLoaded(aBrowser);
+ await waitUntilReloadEnabled();
+ startFromUrlBar();
+ await expectFocusAfterKey(
+ "Shift+Tab",
+ "tracking-protection-icon-container"
+ );
+ await expectFocusAfterKey("Shift+Tab", "back-button");
+ // Forward button is still disabled.
+ await expectFocusAfterKey("ArrowRight", "reload-button");
+ }
+ );
+});
+
+// Test that right arrow reaches the overflow menu button when it is visible.
+add_task(async function testArrowsOverflowButton() {
+ AddOldMenuSideButtons();
+ await BrowserTestUtils.withNewTab("about:blank", async function () {
+ // Move something to the overflow menu to make the button appear.
+ CustomizableUI.addWidgetToArea(
+ "home-button",
+ CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
+ );
+ startFromUrlBar();
+ await expectFocusAfterKey("Tab", afterUrlBarButton);
+ await expectFocusAfterKey("ArrowRight", "library-button");
+ await expectFocusAfterKey("ArrowRight", "sidebar-button");
+ await expectFocusAfterKey("ArrowRight", "unified-extensions-button");
+ await expectFocusAfterKey("ArrowRight", "fxa-toolbar-menu-button");
+ await expectFocusAfterKey("ArrowRight", "nav-bar-overflow-button");
+ // Make sure the button is not reachable once it is invisible again.
+ await expectFocusAfterKey("ArrowRight", "PanelUI-menu-button");
+ resetToolbarWithoutDevEditionButtons();
+ // Flush layout so its invisibility can be detected.
+ document.getElementById("nav-bar-overflow-button").clientWidth;
+ // We reset the toolbar above so the unified extensions button is now the
+ // "last" button.
+ await expectFocusAfterKey("ArrowLeft", "unified-extensions-button");
+ await expectFocusAfterKey("ArrowLeft", "fxa-toolbar-menu-button");
+ });
+ RemoveOldMenuSideButtons();
+});
+
+// Test that toolbar keyboard navigation doesn't interfere with PanelMultiView
+// keyboard navigation.
+// We do this by opening the Library menu and ensuring that pressing left arrow
+// does nothing.
+add_task(async function testArrowsInPanelMultiView() {
+ AddOldMenuSideButtons();
+ let button = document.getElementById("library-button");
+ forceFocus(button);
+ EventUtils.synthesizeKey(" ");
+ let view = document.getElementById("appMenu-libraryView");
+ let focused = BrowserTestUtils.waitForEvent(view, "focus", true);
+ let focusEvt = await focused;
+ ok(true, "Focus inside Library menu after toolbar button pressed");
+ EventUtils.synthesizeKey("KEY_ArrowLeft");
+ is(
+ document.activeElement,
+ focusEvt.target,
+ "ArrowLeft inside panel does nothing"
+ );
+ let hidden = BrowserTestUtils.waitForEvent(document, "popuphidden", true);
+ view.closest("panel").hidePopup();
+ await hidden;
+ RemoveOldMenuSideButtons();
+});
+
+// Test that right/left arrows move in the expected direction for RTL locales.
+add_task(async function testArrowsRtl() {
+ AddOldMenuSideButtons();
+ await SpecialPowers.pushPrefEnv({ set: [["intl.l10n.pseudo", "bidi"]] });
+ // window.RTL_UI doesn't update in existing windows when this pref is changed,
+ // so we need to test in a new window.
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+ startFromUrlBar(win);
+ await expectFocusAfterKey("Tab", afterUrlBarButton, false, win);
+ EventUtils.synthesizeKey("KEY_ArrowRight", {}, win);
+ is(
+ win.document.activeElement.id,
+ afterUrlBarButton,
+ "ArrowRight at end of button group does nothing"
+ );
+ await expectFocusAfterKey("ArrowLeft", "library-button", false, win);
+ await expectFocusAfterKey("ArrowLeft", "sidebar-button", false, win);
+ await BrowserTestUtils.closeWindow(win);
+ await SpecialPowers.popPrefEnv();
+ RemoveOldMenuSideButtons();
+});
+
+// Test that right arrow reaches the overflow menu button on the Bookmarks
+// toolbar when it is visible.
+add_task(async function testArrowsBookmarksOverflowButton() {
+ let toolbar = gNavToolbox.querySelector("#PersonalToolbar");
+ // Third parameter is 'persist' and true is the default.
+ // Fourth parameter is 'animated' and we want no animation.
+ setToolbarVisibility(toolbar, true, true, false);
+ Assert.ok(!toolbar.collapsed, "toolbar should be visible");
+
+ await BrowserTestUtils.waitForEvent(
+ toolbar,
+ "BookmarksToolbarVisibilityUpdated"
+ );
+ let items = document.getElementById("PlacesToolbarItems").children;
+ let lastVisible;
+ for (let item of items) {
+ if (item.style.visibility == "hidden") {
+ break;
+ }
+ lastVisible = item;
+ }
+ forceFocus(lastVisible);
+ await expectFocusAfterKey("ArrowRight", "PlacesChevron");
+ setToolbarVisibility(toolbar, false, true, false);
+});
+
+registerCleanupFunction(async function () {
+ CustomizableUI.reset();
+ await PlacesUtils.bookmarks.eraseEverything();
+});
+
+// Test that when a toolbar button opens a panel, closing the panel restores
+// focus to the button which opened it.
+add_task(async function testPanelCloseRestoresFocus() {
+ AddOldMenuSideButtons();
+ await withNewBlankTab(async function () {
+ // We can't use forceFocus because that removes focusability immediately.
+ // Instead, we must let ToolbarKeyboardNavigator handle this properly.
+ startFromUrlBar();
+ await expectFocusAfterKey("Tab", afterUrlBarButton);
+ await expectFocusAfterKey("ArrowRight", "library-button");
+ let view = document.getElementById("appMenu-libraryView");
+ let shown = BrowserTestUtils.waitForEvent(view, "ViewShown");
+ EventUtils.synthesizeKey(" ");
+ await shown;
+ let hidden = BrowserTestUtils.waitForEvent(document, "popuphidden", true);
+ view.closest("panel").hidePopup();
+ await hidden;
+ is(
+ document.activeElement.id,
+ "library-button",
+ "Focus restored to Library button after panel closed"
+ );
+ });
+ RemoveOldMenuSideButtons();
+});
+
+// Test that the arrow key works in the group of the
+// 'tracking-protection-icon-container' and the 'identity-box'.
+add_task(async function testArrowKeyForTPIconContainerandIdentityBox() {
+ await BrowserTestUtils.withNewTab(
+ "https://example.com",
+ async function (browser) {
+ // Simulate geo sharing so the permission box shows
+ gBrowser.updateBrowserSharing(browser, { geo: true });
+ await waitUntilReloadEnabled();
+ startFromUrlBar();
+ await expectFocusAfterKey(
+ "Shift+Tab",
+ "tracking-protection-icon-container"
+ );
+ await expectFocusAfterKey("ArrowRight", "identity-icon-box");
+ await expectFocusAfterKey("ArrowRight", "identity-permission-box");
+ await expectFocusAfterKey("ArrowLeft", "identity-icon-box");
+ await expectFocusAfterKey(
+ "ArrowLeft",
+ "tracking-protection-icon-container"
+ );
+ gBrowser.updateBrowserSharing(browser, { geo: false });
+ }
+ );
+});
+
+// Test navigation by typed characters.
+add_task(async function testCharacterNavigation() {
+ AddHomeBesideReload();
+ AddOldMenuSideButtons();
+ await BrowserTestUtils.withNewTab("https://example.com", async function () {
+ await waitUntilReloadEnabled();
+ startFromUrlBar();
+ await expectFocusAfterKey("Tab", "pageActionButton");
+ await expectFocusAfterKey("h", "home-button");
+ // There's no button starting with "hs", so pressing s should do nothing.
+ EventUtils.synthesizeKey("s");
+ is(
+ document.activeElement.id,
+ "home-button",
+ "home-button still focused after s pressed"
+ );
+ // Escape should reset the search.
+ EventUtils.synthesizeKey("KEY_Escape");
+ // Now that the search is reset, pressing s should focus Save to Pocket.
+ await expectFocusAfterKey("s", "save-to-pocket-button");
+ // Pressing i makes the search "si", so it should focus Sidebars.
+ await expectFocusAfterKey("i", "sidebar-button");
+ // Reset the search.
+ EventUtils.synthesizeKey("KEY_Escape");
+ await expectFocusAfterKey("s", "save-to-pocket-button");
+ // Pressing s again should find the next button starting with s: Sidebars.
+ await expectFocusAfterKey("s", "sidebar-button");
+ });
+ RemoveHomeButton();
+ RemoveOldMenuSideButtons();
+});
+
+// Test that toolbar character navigation doesn't trigger in PanelMultiView for
+// a panel anchored to the toolbar.
+// We do this by opening the Library menu and ensuring that pressing s
+// does nothing.
+// This test should be removed if PanelMultiView implements character
+// navigation.
+add_task(async function testCharacterInPanelMultiView() {
+ AddOldMenuSideButtons();
+ let button = document.getElementById("library-button");
+ forceFocus(button);
+ let view = document.getElementById("appMenu-libraryView");
+ let focused = BrowserTestUtils.waitForEvent(view, "focus", true);
+ EventUtils.synthesizeKey(" ");
+ let focusEvt = await focused;
+ ok(true, "Focus inside Library menu after toolbar button pressed");
+ EventUtils.synthesizeKey("s");
+ is(document.activeElement, focusEvt.target, "s inside panel does nothing");
+ let hidden = BrowserTestUtils.waitForEvent(document, "popuphidden", true);
+ view.closest("panel").hidePopup();
+ await hidden;
+ RemoveOldMenuSideButtons();
+});
+
+// Test tab stops after the search bar is added.
+add_task(async function testTabStopsAfterSearchBarAdded() {
+ AddOldMenuSideButtons();
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.search.widget.inNavBar", 1]],
+ });
+ await withNewBlankTab(async function () {
+ startFromUrlBar();
+ await expectFocusAfterKey("Tab", "searchbar", true);
+ await expectFocusAfterKey("Tab", afterUrlBarButton);
+ await expectFocusAfterKey("ArrowRight", "library-button");
+ });
+ await SpecialPowers.popPrefEnv();
+ RemoveOldMenuSideButtons();
+});
+
+// Test tab navigation when the Firefox View button is present
+// and when the button is not present.
+add_task(async function testFirefoxViewButtonNavigation() {
+ // Add enough tabs so that the new-tab-button appears in the toolbar
+ // and the tabs-newtab-button is hidden.
+ await BrowserTestUtils.overflowTabs(registerCleanupFunction, window);
+
+ // Assert that Firefox View button receives focus when tab navigating
+ // forward from the end of web content.
+ // Additionally, ensure that focus is not trapped between the
+ // selected tab and the new-tab button.
+ // Finally, assert that focus is restored to web content when
+ // navigating backwards from the Firefox View button.
+ await BrowserTestUtils.withNewTab(
+ PERMISSIONS_PAGE,
+ async function (aBrowser) {
+ await SpecialPowers.spawn(aBrowser, [], async () => {
+ content.document.querySelector("#camera").focus();
+ });
+
+ await expectFocusAfterKey("Tab", "firefox-view-button");
+ let selectedTab = document.querySelector("tab[selected]");
+ await expectFocusAfterKey("Tab", selectedTab);
+ await expectFocusAfterKey("Tab", "new-tab-button");
+ await expectFocusAfterKey("Shift+Tab", selectedTab);
+ await expectFocusAfterKey("Shift+Tab", "firefox-view-button");
+
+ // Moving from toolbar back into content
+ EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
+ await SpecialPowers.spawn(aBrowser, [], async () => {
+ let activeElement = content.document.activeElement;
+ let expectedElement = content.document.querySelector("#camera");
+ is(
+ activeElement,
+ expectedElement,
+ "Focus should be returned to the 'camera' button"
+ );
+ });
+ }
+ );
+
+ // Assert that the selected tab receives focus before the new-tab button
+ // if there is no Firefox View button.
+ // Additionally, assert that navigating backwards from the selected tab
+ // restores focus to the last element in the web content.
+ await BrowserTestUtils.withNewTab(
+ PERMISSIONS_PAGE,
+ async function (aBrowser) {
+ removeFirefoxViewButton();
+
+ await SpecialPowers.spawn(aBrowser, [], async () => {
+ content.document.querySelector("#camera").focus();
+ });
+
+ let selectedTab = document.querySelector("tab[selected]");
+ await expectFocusAfterKey("Tab", selectedTab);
+ await expectFocusAfterKey("Tab", "new-tab-button");
+ await expectFocusAfterKey("Shift+Tab", selectedTab);
+
+ // Moving from toolbar back into content
+ EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
+ await SpecialPowers.spawn(aBrowser, [], async () => {
+ let activeElement = content.document.activeElement;
+ let expectedElement = content.document.querySelector("#camera");
+ is(
+ activeElement,
+ expectedElement,
+ "Focus should be returned to the 'camera' button"
+ );
+ });
+ }
+ );
+
+ // Clean up extra tabs
+ while (gBrowser.tabs.length > 1) {
+ BrowserTestUtils.removeTab(gBrowser.tabs[0]);
+ }
+ CustomizableUI.reset();
+});