registerCleanupFunction(() => { SidebarUI.hide(); }); /** * Helper function that opens a sidebar switcher panel popup menu * @returns Promise that resolves when the switcher panel popup is shown * without any action from a user/test */ function showSwitcherPanelPromise() { return new Promise(resolve => { SidebarUI._switcherPanel.addEventListener( "popupshown", () => { resolve(); }, { once: true } ); SidebarUI.showSwitcherPanel(); }); } /** * Helper function that waits for a sidebar switcher panel's "popupshown" event * @returns Promise which resolves when the popup menu is opened */ async function waitForSwitcherPopupShown() { return BrowserTestUtils.waitForEvent(SidebarUI._switcherPanel, "popupshown"); } /** * Helper function that sends a mouse click to a specific menu item or a key * event to a active menu item of the sidebar switcher menu popup. Provide a * querySelector parameter when a click behavior is needed. * @param {String} [querySelector=null] An HTML attribute of the menu item * to be clicked * @returns Promise that resolves when both the menu popup is hidden and * the sidebar itself is focused */ function pickSwitcherMenuitem(querySelector = null) { let sidebarPopup = document.querySelector("#sidebarMenu-popup"); let hideSwitcherPanelPromise = Promise.all([ BrowserTestUtils.waitForEvent(window, "SidebarFocused"), BrowserTestUtils.waitForEvent(sidebarPopup, "popuphidden"), ]); if (querySelector) { document.querySelector(querySelector).click(); } else { EventUtils.synthesizeKey("KEY_Enter", {}); } return hideSwitcherPanelPromise; } /** * Helper function to test a key handling of sidebar menu popup items used to * access a specific sidebar * @param {String} key Event.key to open the switcher menu popup * @param {String} sidebarTitle Title of the sidebar that is to be activated * during the test (capitalized one word versions), * i.e. "History" or "Tabs" */ async function testSidebarMenuKeyToggle(key, sidebarTitle) { info(`Testing "${key}" key handling of sidebar menu popup items to access ${sidebarTitle} sidebar`); Assert.ok(SidebarUI.isOpen, "Sidebar is open"); let sidebarSwitcher = document.querySelector("#sidebar-switcher-target"); let sidebar = document.getElementById("sidebar"); let searchBox = sidebar.firstElementChild; // If focus is on the search field (i.e. on the History sidebar), // or if the focus is on the awesomebar (bug 1835899), // move it to the switcher target: if (searchBox && searchBox.matches(":focus")) { EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true, repeat: 2 }); } else if (!sidebarSwitcher.matches(":focus")) { sidebarSwitcher.focus(); } Assert.equal( document.activeElement, sidebarSwitcher, "The sidebar switcher target button is focused" ); Assert.ok( sidebarSwitcher.matches(":focus"), "The sidebar switcher target button is focused" ); Assert.equal( SidebarUI._switcherPanel.state, "closed", "Sidebar menu popup is closed" ); let promisePopupShown = waitForSwitcherPopupShown(); // Activate sidebar switcher target to open its sidebar menu popup: EventUtils.synthesizeKey(key, {}); await promisePopupShown; Assert.equal( SidebarUI._switcherPanel.state, "open", "Sidebar menu popup is open" ); info("Testing keyboard navigation between sidebar menu popup controls"); let arrowDown = async (menuitemId, msg) => { let menuItemActive = BrowserTestUtils.waitForEvent( SidebarUI._switcherPanel, "DOMMenuItemActive" ); EventUtils.synthesizeKey("KEY_ArrowDown", {}); await menuItemActive; Assert.ok( document.getElementById(menuitemId).hasAttribute("_moz-menuactive"), msg ); }; // Move to the first sidebar switcher option: await arrowDown( "sidebar-switcher-bookmarks", "The 1st sidebar menu item (Bookmarks) is active" ); // Move to the next sidebar switcher option: await arrowDown( "sidebar-switcher-history", "The 2nd sidebar menu item (History) is active" ); if (sidebarTitle === "Tabs") { await arrowDown( "sidebar-switcher-tabs", "The 3rd sidebar menu item (Synced Tabs) is active" ); } // Activate the tested sidebar switcher option to open the tested sidebar: let sidebarShown = BrowserTestUtils.waitForEvent(window, "SidebarShown"); await pickSwitcherMenuitem(/* querySelector = */ null); await sidebarShown; info("Testing keyboard navigation when a sidebar menu popup is closed"); Assert.equal( SidebarUI._switcherPanel.state, "closed", "Sidebar menu popup is closed" ); // Test the sidebar panel is updated Assert.equal( SidebarUI._box.getAttribute("sidebarcommand"), `view${sidebarTitle}Sidebar` /* e.g. "viewHistorySidebar" */, `${sidebarTitle} sidebar loaded` ); Assert.equal( SidebarUI.currentID, `view${sidebarTitle}Sidebar` /* e.g. "viewHistorySidebar" */, `${sidebarTitle}'s current ID is updated to a target view` ); } add_task(async function markup() { // If a sidebar is already open, close it. if (!document.getElementById("sidebar-box").hidden) { Assert.ok( false, "Unexpected sidebar found - a previous test failed to cleanup correctly" ); SidebarUI.hide(); } let sidebarPopup = document.querySelector("#sidebarMenu-popup"); let sidebarSwitcher = document.querySelector("#sidebar-switcher-target"); let sidebarTitle = document.querySelector("#sidebar-title"); info("Test default markup of the sidebar switcher control"); Assert.equal( sidebarSwitcher.tagName, "toolbarbutton", "Sidebar switcher target control is a toolbarbutton" ); Assert.equal( sidebarSwitcher.children[1], sidebarTitle, "Sidebar switcher target control has a child label element" ); Assert.equal( sidebarTitle.tagName, "label", "Sidebar switcher target control has a label element (that is expected to provide its accessible name" ); Assert.equal( sidebarSwitcher.getAttribute("aria-expanded"), "false", "Sidebar switcher button is collapsed by default" ); info("Test dynamic changes in the markup of the sidebar switcher control"); await SidebarUI.show("viewBookmarksSidebar"); await showSwitcherPanelPromise(); Assert.equal( sidebarSwitcher.getAttribute("aria-expanded"), "true", "Sidebar switcher button is expanded when a sidebar menu is shown" ); let waitForPopupHidden = BrowserTestUtils.waitForEvent( sidebarPopup, "popuphidden" ); // Close on Escape anywhere EventUtils.synthesizeKey("KEY_Escape", {}); await waitForPopupHidden; Assert.equal( sidebarSwitcher.getAttribute("aria-expanded"), "false", "Sidebar switcher button is collapsed when a sidebar menu is dismissed" ); SidebarUI.hide(); }); add_task(async function keynav() { // If a sidebar is already open, close it. if (SidebarUI.isOpen) { Assert.ok( false, "Unexpected sidebar found - a previous test failed to cleanup correctly" ); SidebarUI.hide(); } await SidebarUI.show("viewBookmarksSidebar"); await testSidebarMenuKeyToggle("KEY_Enter", "History"); await testSidebarMenuKeyToggle(" ", "Tabs"); SidebarUI.hide(); }); add_task(async function mouse() { // If a sidebar is already open, close it. if (!document.getElementById("sidebar-box").hidden) { Assert.ok( false, "Unexpected sidebar found - a previous test failed to cleanup correctly" ); SidebarUI.hide(); } let sidebar = document.querySelector("#sidebar-box"); await SidebarUI.show("viewBookmarksSidebar"); await showSwitcherPanelPromise(); await pickSwitcherMenuitem("#sidebar-switcher-history"); Assert.equal( sidebar.getAttribute("sidebarcommand"), "viewHistorySidebar", "History sidebar loaded" ); await showSwitcherPanelPromise(); await pickSwitcherMenuitem("#sidebar-switcher-tabs"); Assert.equal( sidebar.getAttribute("sidebarcommand"), "viewTabsSidebar", "Tabs sidebar loaded" ); await showSwitcherPanelPromise(); await pickSwitcherMenuitem("#sidebar-switcher-bookmarks"); Assert.equal( sidebar.getAttribute("sidebarcommand"), "viewBookmarksSidebar", "Bookmarks sidebar loaded" ); });