tor-browser

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

commit 66e30688d50b2101eaf3e18555b9f55d6e9644b8
parent bd23533d0a55a0bac72d9d5cda68b79f9b4c769b
Author: Stephen Thompson <sthompson@mozilla.com>
Date:   Tue, 23 Dec 2025 15:40:43 +0000

Bug 2001752 - count interactions with list all tabs menu items r=mconley,tabbrowser-reviewers,nsharpley

- "Close all duplicate tabs"
- "Search tabs"
- "Tabs from other devices"

The `allTabsMenu` does not have its own labeled counter under `browser/modules` that hooks into the existing BrowserUsageTelemetry data recording. It would be possible to create a labeled counter that fits into BrowserUsageTelemetry and captures lots of interactions in the "list all tabs" menu, but at this time there are only specific questions about the usage of specific items in that menu. Additionally, the "list all tabs" menu is frequently discussed as a UI surface that will go away, so this metrics code may not live a super long time...

Differential Revision: https://phabricator.services.mozilla.com/D275346

Diffstat:
Mbrowser/components/tabbrowser/content/browser-allTabsMenu.js | 5+++++
Mbrowser/components/tabbrowser/metrics.yaml | 19+++++++++++++++++++
Mbrowser/components/tabbrowser/test/browser/tabs/browser.toml | 2++
Abrowser/components/tabbrowser/test/browser/tabs/browser_list_all_tabs_telemetry.js | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/components/tabbrowser/test/browser/tabs/browser_tab_manager_synced_tabs.js | 33+++++++++++++++++++++++++++++++++
5 files changed, 162 insertions(+), 0 deletions(-)

diff --git a/browser/components/tabbrowser/content/browser-allTabsMenu.js b/browser/components/tabbrowser/content/browser-allTabsMenu.js @@ -117,9 +117,13 @@ var gTabsPanel = { let { PanelUI } = target.ownerGlobal; switch (target.id) { case "allTabsMenu-searchTabs": + Glean.browserUiInteraction.listAllTabsAction.search_tabs.add(1); this.searchTabs(); break; case "allTabsMenu-closeDuplicateTabs": + Glean.browserUiInteraction.listAllTabsAction.close_all_duplicates.add( + 1 + ); gBrowser.removeAllDuplicateTabs(); break; case "allTabsMenu-containerTabsButton": @@ -129,6 +133,7 @@ var gTabsPanel = { PanelUI.showSubView(this.kElements.hiddenTabsView, target); break; case "allTabsMenu-syncedTabs": + Glean.browserUiInteraction.listAllTabsAction.tabs_from_devices.add(1); SidebarController.show("viewTabsSidebar"); break; case "allTabsMenu-groupsViewShowMore": diff --git a/browser/components/tabbrowser/metrics.yaml b/browser/components/tabbrowser/metrics.yaml @@ -132,6 +132,25 @@ browser.ui.interaction: expires: never telemetry_mirror: BROWSER_UI_INTERACTION_ALL_TABS_PANEL_ENTRYPOINT + list_all_tabs_action: + type: labeled_counter + description: > + Records how often users interact with any top-level menu option in the + "List All Tabs" menu. + bugs: + - https://bugzil.la/2001752 + data_reviews: + - https://bugzil.la/2001752 + data_sensitivity: + - interaction + notification_emails: + - sthompson@mozilla.com + expires: never + labels: + - close_all_duplicates # "Close all duplicate tabs" menu item + - tabs_from_devices # "Tabs from other devices" menu item + - search_tabs # "Search tabs" menu item + tab_movement: type: labeled_counter description: > diff --git a/browser/components/tabbrowser/test/browser/tabs/browser.toml b/browser/components/tabbrowser/test/browser/tabs/browser.toml @@ -202,6 +202,8 @@ skip-if = [ "os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # Bug 1904826 ] +["browser_list_all_tabs_telemetry.js"] + ["browser_long_data_url_label_truncation.js"] tags = "vertical-tabs" diff --git a/browser/components/tabbrowser/test/browser/tabs/browser_list_all_tabs_telemetry.js b/browser/components/tabbrowser/test/browser/tabs/browser_list_all_tabs_telemetry.js @@ -0,0 +1,103 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +async function resetTelemetry() { + await Services.fog.testFlushAllChildren(); + Services.fog.testResetFOG(); +} + +add_setup(async () => { + await resetTelemetry(); +}); + +registerCleanupFunction(async () => { + await resetTelemetry(); +}); + +add_task(async function test_list_all_tabs_telemetry_close_duplicate_tabs() { + // Prevent a confirmation message from showing up during the test because + // this test doesn't need to exercise that functionality. + await SpecialPowers.pushPrefEnv({ + set: [["browser.tabs.haveShownCloseAllDuplicateTabsWarning", true]], + }); + + // Create 2 tabs with the same URL so that there are duplicate tabs present. + await Promise.all([addTab(), addTab()]); + + window.gTabsPanel.init(); + + Assert.equal( + Glean.browserUiInteraction.listAllTabsAction.close_all_duplicates.testGetValue(), + undefined, + "interaction count for close duplicate tabs starts unset" + ); + + const button = window.document.getElementById("alltabs-button"); + + const allTabsView = window.document.getElementById("allTabsMenu-allTabsView"); + const allTabsPopupShownPromise = BrowserTestUtils.waitForEvent( + allTabsView, + "ViewShown" + ); + button.click(); + await allTabsPopupShownPromise; + + const closeDuplicateTabsButton = window.document.getElementById( + "allTabsMenu-closeDuplicateTabs" + ); + closeDuplicateTabsButton.click(); + + await BrowserTestUtils.waitForCondition(() => { + return ( + Glean.browserUiInteraction.listAllTabsAction.close_all_duplicates.testGetValue() == + 1 + ); + }, "Wait for metric to increment"); + Assert.equal( + Glean.browserUiInteraction.listAllTabsAction.close_all_duplicates.testGetValue(), + 1, + "interaction count for close duplicate tabs should be 1 after clicking on the menu item" + ); + + BrowserTestUtils.removeTab(gBrowser.tabs[1]); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async function test_list_all_tabs_telemetry_search_tabs() { + window.gTabsPanel.init(); + + Assert.equal( + Glean.browserUiInteraction.listAllTabsAction.search_tabs.testGetValue(), + undefined, + "interaction count for search tabs starts unset" + ); + + const button = window.document.getElementById("alltabs-button"); + + const allTabsView = window.document.getElementById("allTabsMenu-allTabsView"); + const allTabsPopupShownPromise = BrowserTestUtils.waitForEvent( + allTabsView, + "ViewShown" + ); + button.click(); + await allTabsPopupShownPromise; + + const searchTabsButton = window.document.getElementById( + "allTabsMenu-searchTabs" + ); + searchTabsButton.click(); + + await BrowserTestUtils.waitForCondition(() => { + return ( + Glean.browserUiInteraction.listAllTabsAction.search_tabs.testGetValue() == + 1 + ); + }, "Wait for metric to increment"); + Assert.equal( + Glean.browserUiInteraction.listAllTabsAction.search_tabs.testGetValue(), + 1, + "interaction count for search tabs should be 1 after clicking on the menu item" + ); +}); diff --git a/browser/components/tabbrowser/test/browser/tabs/browser_tab_manager_synced_tabs.js b/browser/components/tabbrowser/test/browser/tabs/browser_tab_manager_synced_tabs.js @@ -1,4 +1,16 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +async function resetTelemetry() { + await Services.fog.testFlushAllChildren(); + Services.fog.testResetFOG(); +} + add_setup(async function () { + await resetTelemetry(); + const previous = PlacesUIUtils.shouldShowTabsFromOtherComputersMenuitem; registerCleanupFunction(async () => { @@ -8,9 +20,18 @@ add_setup(async function () { PlacesUIUtils.shouldShowTabsFromOtherComputersMenuitem = () => true; }); +registerCleanupFunction(async () => { + await resetTelemetry(); +}); + add_task(async function tab_manager_synced_tabs() { let win = await BrowserTestUtils.openNewBrowserWindow(); win.gTabsPanel.init(); + Assert.equal( + Glean.browserUiInteraction.listAllTabsAction.tabs_from_devices.testGetValue(), + undefined, + "interaction count for tabs from other devices starts unset" + ); let button = win.document.getElementById("alltabs-button"); let allTabsView = win.document.getElementById("allTabsMenu-allTabsView"); @@ -36,5 +57,17 @@ add_task(async function tab_manager_synced_tabs() { "Synced tabs side bar is being displayed" ); + await BrowserTestUtils.waitForCondition(() => { + return ( + Glean.browserUiInteraction.listAllTabsAction.tabs_from_devices.testGetValue() == + 1 + ); + }, "Wait for metric to increment"); + Assert.equal( + Glean.browserUiInteraction.listAllTabsAction.tabs_from_devices.testGetValue(), + 1, + "interaction count for tabs from other devices should be 1 after clicking on the menu item" + ); + await BrowserTestUtils.closeWindow(win); });