tor-browser

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

commit bfa706ff41f6b28cc38da589eb70e72f2636fe4a
parent bd16379fe164e4af2c1a00b0214054c6f24ac661
Author: Stephen Thompson <sthompson@mozilla.com>
Date:   Fri, 19 Dec 2025 02:04:59 +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 | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/components/tabbrowser/test/browser/tabs/browser_tab_manager_synced_tabs.js | 33+++++++++++++++++++++++++++++++++
5 files changed, 168 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,109 @@ +/* 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() { + const win = await BrowserTestUtils.openNewBrowserWindow(); + + // 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([addTabTo(win.gBrowser), addTabTo(win.gBrowser)]); + + win.gTabsPanel.init(); + + Assert.equal( + Glean.browserUiInteraction.listAllTabsAction.close_all_duplicates.testGetValue(), + undefined, + "interaction count for close duplicate tabs starts unset" + ); + + const button = win.document.getElementById("alltabs-button"); + + const allTabsView = win.document.getElementById("allTabsMenu-allTabsView"); + const allTabsPopupShownPromise = BrowserTestUtils.waitForEvent( + allTabsView, + "ViewShown" + ); + button.click(); + await allTabsPopupShownPromise; + + const closeDuplicateTabsButton = win.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" + ); + + await BrowserTestUtils.closeWindow(win); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async function test_list_all_tabs_telemetry_search_tabs() { + const win = await BrowserTestUtils.openNewBrowserWindow(); + + win.gTabsPanel.init(); + + Assert.equal( + Glean.browserUiInteraction.listAllTabsAction.search_tabs.testGetValue(), + undefined, + "interaction count for search tabs starts unset" + ); + + const button = win.document.getElementById("alltabs-button"); + + const allTabsView = win.document.getElementById("allTabsMenu-allTabsView"); + const allTabsPopupShownPromise = BrowserTestUtils.waitForEvent( + allTabsView, + "ViewShown" + ); + button.click(); + await allTabsPopupShownPromise; + + const searchTabsButton = win.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" + ); + + await BrowserTestUtils.closeWindow(win); +}); 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); });