diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 7e8672677617..64050b25e2a1 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -538,6 +538,9 @@ pref("browser.urlbar.shortcuts.history", true); pref("browser.urlbar.eventTelemetry.enabled", false); +// Whether search engagement telemetry should be recorded. +pref("browser.urlbar.searchEngagementTelemetry.enabled", false); + // When we send events to Urlbar extensions, we wait this amount of time in // milliseconds for them to respond before timing out. pref("browser.urlbar.extension.timeout", 400); diff --git a/browser/components/urlbar/UrlbarController.sys.mjs b/browser/components/urlbar/UrlbarController.sys.mjs index ca0c01185439..2f375f678f87 100644 --- a/browser/components/urlbar/UrlbarController.sys.mjs +++ b/browser/components/urlbar/UrlbarController.sys.mjs @@ -1167,7 +1167,9 @@ class TelemetryEvent { `${method} event: ${JSON.stringify(eventInfo)}` ); - Glean.urlbar[method].record(eventInfo); + if (lazy.UrlbarPrefs.get("searchEngagementTelemetryEnabled")) { + Glean.urlbar[method].record(eventInfo); + } } #getInteractionType( @@ -1346,18 +1348,33 @@ class TelemetryEvent { }; #beginObservingPingPrefs() { - for (const p of Object.keys(this.#PING_PREFS)) { - this.onPrefChanged(p); - } + this.onPrefChanged("searchEngagementTelemetry.enabled"); lazy.UrlbarPrefs.addObserver(this); } onPrefChanged(pref) { + if (pref === "searchEngagementTelemetry.enabled") { + for (const p of Object.keys(this.#PING_PREFS)) { + this.onPrefChanged(p); + } + return; + } + + if (!lazy.UrlbarPrefs.get("searchEngagementTelemetryEnabled")) { + return; + } + const metric = this.#PING_PREFS[pref]; if (metric) { metric.set(lazy.UrlbarPrefs.get(pref)); } } + onNimbusChanged(variable) { + if (variable === "searchEngagementTelemetryEnabled") { + this.onPrefChanged("searchEngagementTelemetry.enabled"); + } + } + #previousSearchWordsSet = null; } diff --git a/browser/components/urlbar/UrlbarPrefs.sys.mjs b/browser/components/urlbar/UrlbarPrefs.sys.mjs index 5a25017755a0..22131f36209e 100644 --- a/browser/components/urlbar/UrlbarPrefs.sys.mjs +++ b/browser/components/urlbar/UrlbarPrefs.sys.mjs @@ -129,6 +129,10 @@ const PREF_URLBAR_DEFAULTS = new Map([ // Applies URL highlighting and other styling to the text in the urlbar input. ["formatting.enabled", true], + // Whether search engagement telemetry should be recorded. This pref is a + // fallback for the Nimbus variable `searchEngagementTelemetryEnabled`. + ["searchEngagementTelemetry.enabled", false], + // Interval time until taking pause impression telemetry. ["searchEngagementTelemetry.pauseImpressionIntervalMs", 1000], diff --git a/browser/components/urlbar/metrics.yaml b/browser/components/urlbar/metrics.yaml index 82c520ab01cc..161f1ec39d93 100644 --- a/browser/components/urlbar/metrics.yaml +++ b/browser/components/urlbar/metrics.yaml @@ -12,7 +12,6 @@ $tags: urlbar: abandonment: - disabled: true type: event description: Recorded when the user abandons a search (blurring the urlbar). extra_keys: @@ -130,7 +129,6 @@ urlbar: - fx-search-telemetry@mozilla.com expires: never engagement: - disabled: true type: event description: Recorded when the user executes an action on a result. extra_keys: @@ -325,7 +323,6 @@ urlbar: - fx-search-telemetry@mozilla.com expires: never impression: - disabled: true type: event description: Recorded when urlbar results are shown to the user. extra_keys: diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser.ini b/browser/components/urlbar/tests/engagementTelemetry/browser/browser.ini index 3debdf4bcccf..4e66293a3044 100644 --- a/browser/components/urlbar/tests/engagementTelemetry/browser/browser.ini +++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser.ini @@ -8,6 +8,7 @@ support-files = head-groups.js head-interaction.js head-n_chars_n_words.js + head-preferences.js head-sap.js head-search_mode.js ../../browser-tips/head.js @@ -22,6 +23,7 @@ skip-if = [browser_glean_telemetry_abandonment_interaction_persisted_search_terms_disabled.js] [browser_glean_telemetry_abandonment_interaction_persisted_search_terms_enabled.js] [browser_glean_telemetry_abandonment_n_chars_n_words.js] +[browser_glean_telemetry_abandonment_preferences.js] [browser_glean_telemetry_abandonment_sap.js] [browser_glean_telemetry_abandonment_search_mode.js] [browser_glean_telemetry_abandonment_tips.js] @@ -31,6 +33,7 @@ skip-if = [browser_glean_telemetry_engagement_interaction_persisted_search_terms_disabled.js] [browser_glean_telemetry_engagement_interaction_persisted_search_terms_enabled.js] [browser_glean_telemetry_engagement_n_chars_n_words.js] +[browser_glean_telemetry_engagement_preferences.js] [browser_glean_telemetry_engagement_sap.js] [browser_glean_telemetry_engagement_search_mode.js] [browser_glean_telemetry_engagement_selected_result.js] diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_preferences.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_preferences.js new file mode 100644 index 000000000000..757455c3d23a --- /dev/null +++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_preferences.js @@ -0,0 +1,42 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test the Glean telemetry behavior with its preferences. + +add_setup(async function() { + await initPreferencesTest(); +}); + +add_task(async function enabled() { + await doSearchEngagementTelemetryTest({ + enabled: true, + trigger: () => doBlur(), + assert: () => assertAbandonmentTelemetry([{ sap: "urlbar_newtab" }]), + }); +}); + +add_task(async function disabled() { + await doSearchEngagementTelemetryTest({ + enabled: false, + trigger: () => doBlur(), + assert: () => assertAbandonmentTelemetry([]), + }); +}); + +add_task(async function nimbusEnabled() { + await doNimbusTest({ + enabled: true, + trigger: () => doBlur(), + assert: () => assertAbandonmentTelemetry([{ sap: "urlbar_newtab" }]), + }); +}); + +add_task(async function nimbusDisabled() { + await doNimbusTest({ + enabled: false, + trigger: () => doBlur(), + assert: () => assertAbandonmentTelemetry([]), + }); +}); diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_tips.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_tips.js index 6c1db84fbe53..db54d3a340da 100644 --- a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_tips.js +++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_abandonment_tips.js @@ -11,12 +11,9 @@ Services.scriptloader.loadSubScript( ); add_setup(async function() { - Services.fog.setMetricsFeatureConfig( - JSON.stringify({ "urlbar.abandonment": false }) - ); - await SpecialPowers.pushPrefEnv({ set: [ + ["browser.urlbar.searchEngagementTelemetry.enabled", true], ["browser.urlbar.searchTips.test.ignoreShowLimits", true], ["browser.urlbar.showSearchTerms.featureGate", true], ], @@ -33,7 +30,6 @@ add_setup(async function() { await Services.search.moveEngine(engine, 0); registerCleanupFunction(async function() { - Services.fog.setMetricsFeatureConfig("{}"); await SpecialPowers.popPrefEnv(); await Services.search.setDefault( originalDefaultEngine, diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_preferences.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_preferences.js new file mode 100644 index 000000000000..f1d9f33bd8c3 --- /dev/null +++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_preferences.js @@ -0,0 +1,42 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test the Glean telemetry behavior with its preferences. + +add_setup(async function() { + await initPreferencesTest(); +}); + +add_task(async function enabled() { + await doSearchEngagementTelemetryTest({ + enabled: true, + trigger: () => doEnter(), + assert: () => assertEngagementTelemetry([{ sap: "urlbar_newtab" }]), + }); +}); + +add_task(async function disabled() { + await doSearchEngagementTelemetryTest({ + enabled: false, + trigger: () => doEnter(), + assert: () => assertEngagementTelemetry([]), + }); +}); + +add_task(async function nimbusEnabled() { + await doNimbusTest({ + enabled: true, + trigger: () => doEnter(), + assert: () => assertEngagementTelemetry([{ sap: "urlbar_newtab" }]), + }); +}); + +add_task(async function nimbusDisabled() { + await doNimbusTest({ + enabled: false, + trigger: () => doEnter(), + assert: () => assertEngagementTelemetry([]), + }); +}); diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_tips.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_tips.js index bd10fd94bc94..dbc39e8fab17 100644 --- a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_tips.js +++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_engagement_tips.js @@ -17,15 +17,13 @@ ChromeUtils.defineESModuleGetters(this, { add_setup(async function() { makeProfileResettable(); - Services.fog.setMetricsFeatureConfig( - JSON.stringify({ "urlbar.engagement": false }) - ); await SpecialPowers.pushPrefEnv({ - set: [["browser.urlbar.quickactions.enabled", false]], + set: [ + ["browser.urlbar.searchEngagementTelemetry.enabled", true], + ["browser.urlbar.quickactions.enabled", false], + ], }); - registerCleanupFunction(async function() { - Services.fog.setMetricsFeatureConfig("{}"); await SpecialPowers.popPrefEnv(); }); }); diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_preferences.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_preferences.js index d17b37fd1858..404b8da7a960 100644 --- a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_preferences.js +++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_impression_preferences.js @@ -6,7 +6,41 @@ // Test the impression telemetry behavior with its preferences. add_setup(async function() { - await setup(); + await initPreferencesTest(); +}); + +add_task(async function enabled() { + await doSearchEngagementTelemetryTest({ + enabled: true, + trigger: () => waitForPauseImpression(), + assert: () => + assertImpressionTelemetry([{ reason: "pause", sap: "urlbar_newtab" }]), + }); +}); + +add_task(async function disabled() { + await doSearchEngagementTelemetryTest({ + enabled: false, + trigger: () => waitForPauseImpression(), + assert: () => assertImpressionTelemetry([]), + }); +}); + +add_task(async function nimbusEnabled() { + await doNimbusTest({ + enabled: true, + trigger: () => waitForPauseImpression(), + assert: () => + assertImpressionTelemetry([{ reason: "pause", sap: "urlbar_newtab" }]), + }); +}); + +add_task(async function nimbusDisabled() { + await doNimbusTest({ + enabled: false, + trigger: () => waitForPauseImpression(), + assert: () => assertImpressionTelemetry([]), + }); }); add_task(async function pauseImpressionIntervalMs() { @@ -16,6 +50,7 @@ add_task(async function pauseImpressionIntervalMs() { ); await SpecialPowers.pushPrefEnv({ set: [ + ["browser.urlbar.searchEngagementTelemetry.enabled", true], [ "browser.urlbar.searchEngagementTelemetry.pauseImpressionIntervalMs", originalInterval + additionalInterval, diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_record_preferences.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_record_preferences.js index 0e7bdd02ce54..45df8070074e 100644 --- a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_record_preferences.js +++ b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_record_preferences.js @@ -6,18 +6,22 @@ // Test for preference telemetry. add_setup(async function() { + // Simulate initialization for TelemetryEvent. + // 1. Turn browser.urlbar.searchEngagementTelemetry.enabled on. + // 2. Remove all Glean data. + // 3. Call onPrefChanged() that will be called from TelemetryEvent constructor. + await SpecialPowers.pushPrefEnv({ + set: [["browser.urlbar.searchEngagementTelemetry.enabled", true]], + }); await Services.fog.testFlushAllChildren(); Services.fog.testResetFOG(); - - // Create a new window in order to initialize TelemetryEvent of - // UrlbarController. - const win = await BrowserTestUtils.openNewBrowserWindow(); - registerCleanupFunction(async function() { - await BrowserTestUtils.closeWindow(win); - }); + gURLBar.controller.engagementEvent.onPrefChanged( + "searchEngagementTelemetry.enabled" + ); }); add_task(async function prefMaxRichResults() { + Assert.ok(UrlbarPrefs.get("maxRichResults"), "Sanity check"); Assert.equal( Glean.urlbar.prefMaxResults.testGetValue(), UrlbarPrefs.get("maxRichResults"), @@ -52,3 +56,66 @@ add_task(async function prefSuggestTopsites() { "Record prefSuggestTopsites when the suggest.topsites pref is updated" ); }); + +add_task(async function searchEngagementTelemetryEnabled() { + info("Disable search engagement telemetry"); + await SpecialPowers.pushPrefEnv({ + set: [["browser.urlbar.searchEngagementTelemetry.enabled", false]], + }); + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.urlbar.suggest.topsites", !UrlbarPrefs.get("suggest.topsites")], + ["browser.urlbar.maxRichResults", 100], + ], + }); + Assert.notEqual( + Glean.urlbar.prefMaxResults.testGetValue(), + UrlbarPrefs.get("maxRichResults"), + "Did not record prefMaxResults" + ); + Assert.notEqual( + Glean.urlbar.prefSuggestTopsites.testGetValue(), + UrlbarPrefs.get("suggest.topsites"), + "Did not record prefSuggestTopsites" + ); + + info("Enable search engagement telemetry"); + await SpecialPowers.pushPrefEnv({ + set: [["browser.urlbar.searchEngagementTelemetry.enabled", true]], + }); + Assert.equal( + Glean.urlbar.prefMaxResults.testGetValue(), + UrlbarPrefs.get("maxRichResults"), + "Update prefMaxResults when search engagement telemetry is enabled" + ); + Assert.equal( + Glean.urlbar.prefSuggestTopsites.testGetValue(), + UrlbarPrefs.get("suggest.topsites"), + "Update prefSuggestTopsites when search engagement telemetry is enabled" + ); +}); + +add_task(async function nimbusSearchEngagementTelemetryEnabled() { + info("Disable search engagement telemetry"); + await SpecialPowers.pushPrefEnv({ + set: [["browser.urlbar.searchEngagementTelemetry.enabled", false]], + }); + + info("Enable search engagement telemetry from Nimbus"); + // eslint-disable-next-line mozilla/valid-lazy + const doCleanup = await lazy.UrlbarTestUtils.initNimbusFeature({ + searchEngagementTelemetryEnabled: true, + }); + Assert.equal( + Glean.urlbar.prefMaxResults.testGetValue(), + UrlbarPrefs.get("maxRichResults"), + "Update prefMaxResults when search engagement telemetry is enabled" + ); + Assert.equal( + Glean.urlbar.prefSuggestTopsites.testGetValue(), + UrlbarPrefs.get("suggest.topsites"), + "Update prefSuggestTopsites when search engagement telemetry is enabled" + ); + + doCleanup(); +}); diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/head-preferences.js b/browser/components/urlbar/tests/engagementTelemetry/browser/head-preferences.js new file mode 100644 index 000000000000..95330f507160 --- /dev/null +++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head-preferences.js @@ -0,0 +1,36 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* import-globals-from head.js */ + +async function doSearchEngagementTelemetryTest({ trigger, assert, enabled }) { + await SpecialPowers.pushPrefEnv({ + set: [["browser.urlbar.searchEngagementTelemetry.enabled", enabled]], + }); + + await doTest(async browser => { + await openPopup("https://example.com"); + + await trigger(); + await assert(); + }); + + await SpecialPowers.popPrefEnv(); +} + +async function doNimbusTest({ trigger, assert, enabled }) { + const doCleanup = await setupNimbus({ + searchEngagementTelemetryEnabled: enabled, + }); + + await doTest(async browser => { + await openPopup("https://example.com"); + + await trigger(); + await assert(); + }); + + doCleanup(); +} diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/head.js b/browser/components/urlbar/tests/engagementTelemetry/browser/head.js index 0d42372a1e00..0ea4e6c09afa 100644 --- a/browser/components/urlbar/tests/engagementTelemetry/browser/head.js +++ b/browser/components/urlbar/tests/engagementTelemetry/browser/head.js @@ -179,15 +179,6 @@ async function doPasteAndGo(data) { async function doTest(testFn) { await Services.fog.testFlushAllChildren(); Services.fog.testResetFOG(); - // Enable recording telemetry for abandonment, engagement and impression. - Services.fog.setMetricsFeatureConfig( - JSON.stringify({ - "urlbar.abandonment": false, - "urlbar.engagement": false, - "urlbar.impression": false, - }) - ); - gURLBar.controller.engagementEvent.reset(); await PlacesUtils.history.clear(); await PlacesUtils.bookmarks.eraseEverything(); @@ -198,11 +189,7 @@ async function doTest(testFn) { await QuickSuggest.blockedSuggestions._test_readyPromise; await updateTopSites(() => true); - try { - await BrowserTestUtils.withNewTab(gBrowser, testFn); - } finally { - Services.fog.setMetricsFeatureConfig("{}"); - } + await BrowserTestUtils.withNewTab(gBrowser, testFn); } async function initGroupTest() { @@ -232,6 +219,15 @@ async function initNCharsAndNWordsTest() { await setup(); } +async function initPreferencesTest() { + /* import-globals-from head-preferences.js */ + Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/browser/components/urlbar/tests/engagementTelemetry/browser/head-preferences.js", + this + ); + await setup(); +} + async function initSapTest() { /* import-globals-from head-sap.js */ Services.scriptloader.loadSubScript( diff --git a/browser/components/urlbar/tests/unit/test_UrlbarPrefs.js b/browser/components/urlbar/tests/unit/test_UrlbarPrefs.js index c681aca38743..80a4c37b08f3 100644 --- a/browser/components/urlbar/tests/unit/test_UrlbarPrefs.js +++ b/browser/components/urlbar/tests/unit/test_UrlbarPrefs.js @@ -358,7 +358,7 @@ add_task(function initializeShowSearchSuggestionsFirstPref() { // Tests whether observer.onNimbusChanged works. add_task(async function onNimbusChanged() { Services.prefs.setBoolPref( - "browser.urlbar.autoFill.adaptiveHistory.enabled", + "browser.urlbar.searchEngagementTelemetry.enabled", false ); @@ -387,11 +387,11 @@ add_task(async function onNimbusChanged() { UrlbarPrefs.addObserver(observer); const doCleanup = await UrlbarTestUtils.initNimbusFeature({ - autoFillAdaptiveHistoryEnabled: true, + searchEngagementTelemetryEnabled: true, }); Assert.equal(observer.prefChangedList.length, 0); Assert.ok( - observer.nimbusChangedList.includes("autoFillAdaptiveHistoryEnabled") + observer.nimbusChangedList.includes("searchEngagementTelemetryEnabled") ); doCleanup(); }); @@ -399,10 +399,10 @@ add_task(async function onNimbusChanged() { // Tests whether observer.onPrefChanged works. add_task(async function onPrefChanged() { const doCleanup = await UrlbarTestUtils.initNimbusFeature({ - autoFillAdaptiveHistoryEnabled: false, + searchEngagementTelemetryEnabled: false, }); Services.prefs.setBoolPref( - "browser.urlbar.autoFill.adaptiveHistory.enabled", + "browser.urlbar.searchEngagementTelemetry.enabled", false ); @@ -434,16 +434,19 @@ add_task(async function onPrefChanged() { UrlbarPrefs.addObserver(observer); Services.prefs.setBoolPref( - "browser.urlbar.autoFill.adaptiveHistory.enabled", + "browser.urlbar.searchEngagementTelemetry.enabled", true ); await deferred.promise; Assert.equal(observer.prefChangedList.length, 1); - Assert.equal(observer.prefChangedList[0], "autoFill.adaptiveHistory.enabled"); + Assert.equal( + observer.prefChangedList[0], + "searchEngagementTelemetry.enabled" + ); Assert.equal(observer.nimbusChangedList.length, 0); Services.prefs.clearUserPref( - "browser.urlbar.autoFill.adaptiveHistory.enabled" + "browser.urlbar.searchEngagementTelemetry.enabled" ); doCleanup(); }); diff --git a/toolkit/components/nimbus/FeatureManifest.yaml b/toolkit/components/nimbus/FeatureManifest.yaml index 471ff306e6c8..a28d84a48ecc 100644 --- a/toolkit/components/nimbus/FeatureManifest.yaml +++ b/toolkit/components/nimbus/FeatureManifest.yaml @@ -222,6 +222,10 @@ urlbar: type: boolean setPref: browser.urlbar.resultMenu description: Enable the per-result three-dot menu with options such as Dismiss and Learn More. + searchEngagementTelemetryEnabled: + type: boolean + fallbackPref: browser.urlbar.searchEngagementTelemetry.enabled + description: Whether search engagement telemetry should be enabled. showSearchTermsFeatureGate: type: boolean fallbackPref: browser.urlbar.showSearchTerms.featureGate