diff options
Diffstat (limited to 'browser/components/firefoxview/tests/browser/browser_opentabs_pinned_tabs.js')
-rw-r--r-- | browser/components/firefoxview/tests/browser/browser_opentabs_pinned_tabs.js | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/browser/components/firefoxview/tests/browser/browser_opentabs_pinned_tabs.js b/browser/components/firefoxview/tests/browser/browser_opentabs_pinned_tabs.js new file mode 100644 index 0000000000..d74812bca5 --- /dev/null +++ b/browser/components/firefoxview/tests/browser/browser_opentabs_pinned_tabs.js @@ -0,0 +1,481 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +let pageWithAlert = + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com/browser/browser/base/content/test/tabPrompts/openPromptOffTimeout.html"; +let pageWithSound = + "http://mochi.test:8888/browser/dom/base/test/file_audioLoop.html"; + +function cleanup() { + // Cleanup + while (gBrowser.tabs.length > 1) { + BrowserTestUtils.removeTab(gBrowser.tabs[1]); + } +} + +const arrowDown = async tabList => { + info("Arrow down"); + EventUtils.synthesizeKey("KEY_ArrowDown", {}); + await tabList.getUpdateComplete(); +}; +const arrowUp = async tabList => { + info("Arrow up"); + EventUtils.synthesizeKey("KEY_ArrowUp", {}); + await tabList.getUpdateComplete(); +}; +const arrowRight = async tabList => { + info("Arrow right"); + EventUtils.synthesizeKey("KEY_ArrowRight", {}); + await tabList.getUpdateComplete(); +}; +const arrowLeft = async tabList => { + info("Arrow left"); + EventUtils.synthesizeKey("KEY_ArrowLeft", {}); + await tabList.getUpdateComplete(); +}; + +add_task(async function test_pin_unpin_open_tab() { + await withFirefoxView({}, async browser => { + const { document } = browser.contentWindow; + await navigateToViewAndWait(document, "opentabs"); + + let openTabs = document.querySelector("view-opentabs[name=opentabs]"); + await openTabs.updateComplete; + await TestUtils.waitForCondition( + () => openTabs.viewCards[0].tabList.rowEls.length + ); + await openTabs.openTabsTarget.readyWindowsPromise; + let card = openTabs.viewCards[0]; + let openTabEl = card.tabList.rowEls[0]; + let tabChangeRaised = BrowserTestUtils.waitForEvent( + NonPrivateTabs, + "TabChange" + ); + + // Pin tab + EventUtils.synthesizeMouseAtCenter( + openTabEl.secondaryButtonEl, + {}, + content + ); + await TestUtils.waitForCondition(() => card.tabContextMenu.panelList); + let panelList = card.tabContextMenu.panelList; + await BrowserTestUtils.waitForEvent(panelList, "shown"); + info("The context menu is shown when clicking the tab's 'more' button"); + + let pinTabPanelItem = panelList.querySelector( + "panel-item[data-l10n-id=fxviewtabrow-pin-tab]" + ); + + await clearAllParentTelemetryEvents(); + let contextMenuEvent = [ + [ + "firefoxview_next", + "context_menu", + "tabs", + undefined, + { menu_action: "pin-tab", data_type: "opentabs" }, + ], + ]; + tabChangeRaised = BrowserTestUtils.waitForEvent( + NonPrivateTabs, + "TabChange" + ); + + // Unpin tab + EventUtils.synthesizeMouseAtCenter(pinTabPanelItem, {}, content); + info("Pin Tab context menu option clicked."); + + await tabChangeRaised; + await openTabs.updateComplete; + + let pinnedTab = card.tabList.rowEls[0]; + await TestUtils.waitForCondition(() => + pinnedTab.indicators.includes("pinned") + ); + + // Check aria roles + let listWrapper = card.tabList.shadowRoot.querySelector(".fxview-tab-list"); + ok( + Array.from(listWrapper.classList).includes("pinned"), + "The tab list has the 'pinned' class as expected." + ); + + Assert.strictEqual( + listWrapper.getAttribute("role"), + "tablist", + "The list wrapper has an aria-role of 'tablist'" + ); + Assert.strictEqual( + pinnedTab.pinnedTabButtonEl.getAttribute("role"), + "tab", + "The pinned tab's button element has a role of 'tab'" + ); + + // Open context menu + EventUtils.synthesizeMouseAtCenter( + pinnedTab, + { type: "contextmenu" }, + content + ); + await TestUtils.waitForCondition(() => card.tabContextMenu.panelList); + panelList = card.tabContextMenu.panelList; + await BrowserTestUtils.waitForEvent(panelList, "shown"); + info("The context menu is shown when right clicking the pinned tab"); + + let unpinTabPanelItem = panelList.querySelector( + "panel-item[data-l10n-id=fxviewtabrow-unpin-tab]" + ); + + await clearAllParentTelemetryEvents(); + contextMenuEvent = [ + [ + "firefoxview_next", + "context_menu", + "tabs", + undefined, + { menu_action: "unpin-tab", data_type: "opentabs" }, + ], + ]; + tabChangeRaised = BrowserTestUtils.waitForEvent( + NonPrivateTabs, + "TabChange" + ); + + // Unpin tab + EventUtils.synthesizeMouseAtCenter(unpinTabPanelItem, {}, content); + info("Unpin Tab context menu option clicked."); + + await tabChangeRaised; + await openTabs.updateComplete; + await telemetryEvent(contextMenuEvent); + }); + cleanup(); +}); + +add_task(async function test_indicator_pinned_tabs_with_keyboard() { + await add_new_tab(URLs[0]); + await add_new_tab(URLs[1]); + await add_new_tab(pageWithSound); + await withFirefoxView({}, async browser => { + const { document } = browser.contentWindow; + await navigateToViewAndWait(document, "opentabs"); + + let openTabs = document.querySelector("view-opentabs[name=opentabs]"); + await openTabs.updateComplete; + await TestUtils.waitForCondition( + () => openTabs.viewCards[0].tabList.rowEls.length + ); + await openTabs.openTabsTarget.readyWindowsPromise; + setSortOption(openTabs, "tabStripOrder"); + let card = openTabs.viewCards[0]; + + let openedTab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + pageWithAlert, + true + ); + let openedTabGotAttentionPromise = BrowserTestUtils.waitForAttribute( + "attention", + openedTab + ); + + await switchToFxViewTab(); + + await openedTabGotAttentionPromise; + + let tabChangeRaised = BrowserTestUtils.waitForEvent( + NonPrivateTabs, + "TabChange" + ); + + // Pin 2 of 5 tabs + browser.ownerGlobal.gBrowser.tabs.forEach((tab, i) => { + if (i > 2) { + browser.ownerGlobal.gBrowser.pinTab(tab); + } + }); + + await tabChangeRaised; + await openTabs.updateComplete; + + let soundPlayingPinnedTab = card.tabList.rowEls[0]; + let attentionPinnedTab = card.tabList.rowEls[1]; + let firstUnpinnedTab = card.tabList.rowEls[2]; + let secondUnpinnedTab = card.tabList.rowEls[3]; + + // Check soundplaying indicator + ok( + soundPlayingPinnedTab.indicators.includes("pinned") && + soundPlayingPinnedTab.indicators.includes("soundplaying") && + soundPlayingPinnedTab.mediaButtonEl, + "The first pinned tab has the 'sound playing' indicator." + ); + + soundPlayingPinnedTab.pinnedTabButtonEl.focus(); + ok( + isActiveElement(soundPlayingPinnedTab.pinnedTabButtonEl), + "Focus should be on the first pinned tab's button element." + ); + info("First pinned tab has focus"); + + // Test mute/unmute + EventUtils.synthesizeKey("m", { ctrlKey: true }); + await TestUtils.waitForCondition(() => + soundPlayingPinnedTab.indicators.includes("muted") + ); + EventUtils.synthesizeKey("m", { ctrlKey: true }); + await TestUtils.waitForCondition( + () => !soundPlayingPinnedTab.indicators.includes("muted") + ); + + await arrowRight(card.tabList); + ok( + isActiveElement(attentionPinnedTab.pinnedTabButtonEl), + "Focus should be on the second pinned tab's button element." + ); + + // Check notification dot indicator + ok( + attentionPinnedTab.indicators.includes("pinned") && + attentionPinnedTab.indicators.includes("attention") && + Array.from( + attentionPinnedTab.shadowRoot.querySelector( + ".fxview-tab-row-favicon-wrapper" + ).classList + ).includes("attention"), + "The second pinned tab has the 'attention' indicator." + ); + + await arrowDown(card.tabList); + ok( + isActiveElement(firstUnpinnedTab.mainEl), + "Focus should be on the first unpinned tab's main/link element." + ); + + await arrowRight(card.tabList); + ok( + isActiveElement(firstUnpinnedTab.secondaryButtonEl), + "Focus should be on the first unpinned tab's secondary/more button element." + ); + + await arrowUp(card.tabList); + ok( + isActiveElement(attentionPinnedTab.pinnedTabButtonEl), + "Focus should be on the second pinned tab's button element." + ); + + await arrowRight(card.tabList); + ok( + isActiveElement(firstUnpinnedTab.secondaryButtonEl), + "Focus should be on the first unpinned tab's secondary/more button element." + ); + + await arrowUp(card.tabList); + ok( + isActiveElement(attentionPinnedTab.pinnedTabButtonEl), + "Focus should be on the second pinned tab's button element." + ); + + await arrowLeft(card.tabList); + ok( + isActiveElement(soundPlayingPinnedTab.pinnedTabButtonEl), + "Focus should be on the first pinned tab's button element." + ); + + await arrowDown(card.tabList); + ok( + isActiveElement(firstUnpinnedTab.secondaryButtonEl), + "Focus should be on the first unpinned tab's secondary/more button element." + ); + + await arrowDown(card.tabList); + ok( + isActiveElement(secondUnpinnedTab.secondaryButtonEl), + "Focus should be on the second unpinned tab's secondary/more button element." + ); + + // Switch back to other tab to close prompt before cleanup + await BrowserTestUtils.switchTab(gBrowser, openedTab); + EventUtils.synthesizeKey("KEY_Enter", {}); + }); + cleanup(); +}); + +add_task(async function test_mute_unmute_pinned_tab() { + await withFirefoxView({}, async browser => { + const { document } = browser.contentWindow; + await navigateToViewAndWait(document, "opentabs"); + + let openTabs = document.querySelector("view-opentabs[name=opentabs]"); + await openTabs.updateComplete; + await TestUtils.waitForCondition( + () => openTabs.viewCards[0].tabList.rowEls.length + ); + await openTabs.openTabsTarget.readyWindowsPromise; + let card = openTabs.viewCards[0]; + let openTabEl = card.tabList.rowEls[0]; + let tabChangeRaised = BrowserTestUtils.waitForEvent( + NonPrivateTabs, + "TabChange" + ); + + // Mute tab + // We intentionally turn off this a11y check, because the following click + // is purposefully targeting a not focusable button within a pinned tab + // control. A keyboard-only user could mute/unmute this pinned tab via the + // context menu, while we do not want to create an additional, unnecessary + // tabstop for this control, therefore this rule check shall be ignored by + // a11y_checks suite. + AccessibilityUtils.setEnv({ focusableRule: false }); + EventUtils.synthesizeMouseAtCenter(openTabEl.mediaButtonEl, {}, content); + AccessibilityUtils.resetEnv(); + info("Mute Tab button clicked."); + + tabChangeRaised = BrowserTestUtils.waitForEvent( + NonPrivateTabs, + "TabChange" + ); + + await tabChangeRaised; + await openTabs.updateComplete; + + let mutedTab = card.tabList.rowEls[0]; + await TestUtils.waitForCondition(() => + mutedTab.indicators.includes("muted") + ); + + // Unmute tab + // We intentionally turn off this a11y check, because the following click + // is purposefully targeting a not focusable button within a pinned tab + // control. A keyboard-only user could mute/unmute this pinned tab via the + // context menu, while we do not want to create an additional, unnecessary + // tabstop for this control, therefore this rule check shall be ignored by + // a11y_checks suite. + AccessibilityUtils.setEnv({ focusableRule: false }); + EventUtils.synthesizeMouseAtCenter(openTabEl.mediaButtonEl, {}, content); + AccessibilityUtils.resetEnv(); + info("Unmute Tab button clicked."); + + tabChangeRaised = BrowserTestUtils.waitForEvent( + NonPrivateTabs, + "TabChange" + ); + + await tabChangeRaised; + await openTabs.updateComplete; + + let unmutedTab = card.tabList.rowEls[0]; + await TestUtils.waitForCondition( + () => !unmutedTab.indicators.includes("muted") + ); + }); + cleanup(); +}); + +add_task(async function test_mute_unmute_with_context_menu() { + await withFirefoxView({}, async browser => { + const { document } = browser.contentWindow; + await navigateToViewAndWait(document, "opentabs"); + + let openTabs = document.querySelector("view-opentabs[name=opentabs]"); + await openTabs.updateComplete; + await TestUtils.waitForCondition( + () => openTabs.viewCards[0].tabList.rowEls.length + ); + await openTabs.openTabsTarget.readyWindowsPromise; + let card = openTabs.viewCards[0]; + let openTabEl = card.tabList.rowEls[0]; + let tabChangeRaised = BrowserTestUtils.waitForEvent( + NonPrivateTabs, + "TabChange" + ); + + // Mute tab + EventUtils.synthesizeMouseAtCenter( + openTabEl.pinnedTabButtonEl, + { type: "contextmenu" }, + content + ); + await TestUtils.waitForCondition(() => card.tabContextMenu.panelList); + let panelList = card.tabContextMenu.panelList; + await BrowserTestUtils.waitForEvent(panelList, "shown"); + info("The context menu is shown when clicking the tab's 'more' button"); + + let pinTabPanelItem = panelList.querySelector( + "panel-item[data-l10n-id=fxviewtabrow-mute-tab]" + ); + + await clearAllParentTelemetryEvents(); + let contextMenuEvent = [ + [ + "firefoxview_next", + "context_menu", + "tabs", + undefined, + { menu_action: "mute-tab", data_type: "opentabs" }, + ], + ]; + tabChangeRaised = BrowserTestUtils.waitForEvent( + NonPrivateTabs, + "TabChange" + ); + + // Mute tab + EventUtils.synthesizeMouseAtCenter(pinTabPanelItem, {}, content); + info("Mute Tab context menu option clicked."); + + await tabChangeRaised; + await openTabs.updateComplete; + + let mutedTab = card.tabList.rowEls[0]; + await TestUtils.waitForCondition(() => + mutedTab.indicators.includes("muted") + ); + + // Open context menu + EventUtils.synthesizeMouseAtCenter( + mutedTab, + { type: "contextmenu" }, + content + ); + await TestUtils.waitForCondition(() => card.tabContextMenu.panelList); + panelList = card.tabContextMenu.panelList; + await BrowserTestUtils.waitForEvent(panelList, "shown"); + info("The context menu is shown when right clicking the pinned tab"); + + let unmuteTabPanelItem = panelList.querySelector( + "panel-item[data-l10n-id=fxviewtabrow-unmute-tab]" + ); + + await clearAllParentTelemetryEvents(); + contextMenuEvent = [ + [ + "firefoxview_next", + "context_menu", + "tabs", + undefined, + { menu_action: "unmute-tab", data_type: "opentabs" }, + ], + ]; + tabChangeRaised = BrowserTestUtils.waitForEvent( + NonPrivateTabs, + "TabChange" + ); + + // Unpin tab + EventUtils.synthesizeMouseAtCenter(unmuteTabPanelItem, {}, content); + info("Unmute Tab context menu option clicked."); + + await tabChangeRaised; + await openTabs.updateComplete; + await telemetryEvent(contextMenuEvent); + + let unmutedTab = card.tabList.rowEls[0]; + await TestUtils.waitForCondition( + () => !unmutedTab.indicators.includes("muted") + ); + }); + cleanup(); +}); |