tor-browser

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

commit 8d325ea75a0d9fb4ce81d212192bbd2e19173f95
parent a2775ed162980e13ab13eb1e05d208cf3b398f75
Author: Drew Willcoxon <adw@mozilla.com>
Date:   Thu, 23 Oct 2025 22:32:05 +0000

Bug 1995362 - Part 1: Core changes: Reconcile online Suggest with the new online-enabled pref. r=daisuke,Standard8,urlbar-reviewers

This is part 1 of 5 and is the core set of changes for the new online Suggest
pref. There are actually two prefs:

```
browser.urlbar.quicksuggest.online.available
browser.urlbar.quicksuggest.online.enabled
```

From this point on, in order for `SuggestBackendMerino` to actually make its
online Suggest fetch, both prefs must be true. The `available` pref is false by
default. In later work, we will update `QuickSuggest` init to set it to true for
users who have accepted Terms of Use and whose region-locales should receive
online Suggest. We can also use the `quickSuggestOnlineAvailable` Nimbus
variable introduced in this revision to deliver online availability. The
`enabled` pref defaults to true for all users, regardless of region-locale, and
will map directly to the new online checkbox in the settings UI, which we'll
also handle in later work. Please see the bug for further discussion.

Once all the patches in this stack land, the old pref,
`browser.urlbar.quicksuggest.dataCollection.enabled`, won't be used at all
anymore (aside from a few isolated cases we can handle in separate bugs), which
means people who are currently opted in to online Suggest will stop getting
online Suggest until we ship new online (OHTTP) to them and they accept the
Terms of Use. This revision (and patch stack) keeps the pref in `firefox.js` for
now however because it's used by Nimbus targeting filters that are currently
used by some live experiments.

Depends on D269441

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

Diffstat:
Mbrowser/app/profile/firefox.js | 32++++++++++++++++++++++++--------
Mbrowser/components/urlbar/QuickSuggest.sys.mjs | 7++-----
Mbrowser/components/urlbar/UrlbarPrefs.sys.mjs | 16+++++++++++++++-
Mbrowser/components/urlbar/docs/firefox-suggest-telemetry.rst | 4++++
Mbrowser/components/urlbar/docs/preferences.rst | 13+++++++++++--
Mbrowser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs | 26+++++++++++++++-----------
Mbrowser/components/urlbar/private/SuggestBackendMerino.sys.mjs | 6+++---
Mbrowser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_realtime_optin_engagement.js | 13++++++++-----
Mbrowser/components/urlbar/tests/quicksuggest/QuickSuggestTestUtils.sys.mjs | 18++++++++++--------
Mbrowser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest.js | 12+++++++++---
Mbrowser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_configuration.js | 178-------------------------------------------------------------------------------
Mbrowser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_merinoSessions.js | 5++++-
Mbrowser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_optin.js | 28++++++++++++++--------------
Mbrowser/components/urlbar/tests/quicksuggest/browser/browser_telemetry_environment.js | 11+----------
Mbrowser/components/urlbar/tests/quicksuggest/unit/head.js | 5+++--
Mbrowser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest.js | 6++++--
Mbrowser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_addons.js | 8++++----
Abrowser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_defaultPrefs.js | 204+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_merino.js | 84++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mbrowser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_merinoSessions.js | 3++-
Dbrowser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_offlineDefault.js | 217-------------------------------------------------------------------------------
Mbrowser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_relevanceRanking.js | 4++--
Mbrowser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_yelp_realtime.js | 5+++--
Mbrowser/components/urlbar/tests/quicksuggest/unit/xpcshell.toml | 6+++---
Mtoolkit/components/nimbus/FeatureManifest.yaml | 8+++++---
25 files changed, 401 insertions(+), 518 deletions(-)

diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js @@ -479,20 +479,36 @@ pref("browser.urlbar.suggest.quicksuggest.nonsponsored", false, sticky); // default-branch values, the user is enrolled in over time. pref("browser.urlbar.suggest.quicksuggest.sponsored", false, sticky); +// TODO: Remove this pref, which is the old opt-in pref for online Firefox +// Suggest. We need to keep it for now because some live Nimbus experiments use +// a targeting filter that depends on it. Original comment below. +// // Whether data collection is enabled for quick suggest results in the urlbar. // This pref is exposed to the user in the UI, and it's sticky so that its // user-branch value persists regardless of whatever Firefox Suggest scenarios, // with their various default-branch values, the user is enrolled in over time. pref("browser.urlbar.quicksuggest.dataCollection.enabled", false, sticky); -// Whether quick suggest retrives online suggestions from Merino via Oblivious -// HTTP (OHTTP). This functionality is being enabled in a future release. Note, -// that even if this is preference enabled, the feature may not be available -// - there are other prefs that control if the feature is available or not. -// When the feature is enabled, the pref will also be exposed to the user in the -// UI and it's sticky so that its user-branch value persists regardless of -// whatever Firefox Suggest scenarios, with their various default-brnch values, -// the user is enrolled in over time. +// Whether online Firefox Suggest is available to the user. This is only +// relevant when Suggest overall is enabled [1]. When true, a checkbox will be +// shown in the settings UI allowing to the user to toggle online Suggest. +// +// [1] browser.urlbar.quicksuggest.enabled +pref("browser.urlbar.quicksuggest.online.available", false); + +// Whether Firefox Suggest retrieves online suggestions from Merino. This pref +// is only relevant when Suggest overall is enabled [1] and online Suggest is +// available to the user [2]; otherwise online suggestions are disabled. In +// addition, when the relevant Oblivious HTTP (OHTTP) prefs [3, 4] are set, +// online suggestions will be fetched over OHTTP. +// +// This pref corresponds to the online Suggest checkbox in the settings UI. It's +// sticky so that user choice is preserved regardless of its default value. +// +// [1] browser.urlbar.quicksuggest.enabled +// [2] browser.urlbar.quicksuggest.online.available +// [3] browser.urlbar.merino.ohttpConfigURL +// [4] browser.urlbar.merino.ohttpRelayURL pref("browser.urlbar.quicksuggest.online.enabled", true, sticky); // Whether the Firefox Suggest contextual opt-in result is enabled. diff --git a/browser/components/urlbar/QuickSuggest.sys.mjs b/browser/components/urlbar/QuickSuggest.sys.mjs @@ -62,10 +62,7 @@ const EN_LOCALES = ["en-CA", "en-GB", "en-US", "en-ZA"]; const SUGGEST_PREFS = Object.freeze({ // Prefs related to Suggest overall // - // Please update `test_quicksuggest_offlineDefault.js` when you change these. - "quicksuggest.dataCollection.enabled": { - nimbusVariableIfExposedInUi: "quickSuggestDataCollectionEnabled", - }, + // Please update `test_quicksuggest_defaultPrefs.js` when you change these. "quicksuggest.enabled": { defaultValues: { DE: [["de", ...EN_LOCALES], true], @@ -107,7 +104,7 @@ const SUGGEST_PREFS = Object.freeze({ // Prefs related to individual features // - // Please update `test_quicksuggest_offlineDefault.js` when you change these. + // Please update `test_quicksuggest_defaultPrefs.js` when you change these. "addons.featureGate": { defaultValues: { US: [EN_LOCALES, true], diff --git a/browser/components/urlbar/UrlbarPrefs.sys.mjs b/browser/components/urlbar/UrlbarPrefs.sys.mjs @@ -292,7 +292,9 @@ const PREF_URLBAR_DEFAULTS = /** @type {PreferenceDefinition[]} */ ([ // impression. ["quicksuggest.contextualOptIn.impressionDaysLimit", 5], - // Whether the user has opted in to data collection for quick suggest. + // TODO: Remove this pref, which is the old opt-in pref for online Firefox + // Suggest. We need to keep it for now because some live Nimbus experiments + // use a targeting filter that depends on it. ["quicksuggest.dataCollection.enabled", false], // Comma-separated list of Suggest dynamic suggestion types to enable. @@ -338,6 +340,18 @@ const PREF_URLBAR_DEFAULTS = /** @type {PreferenceDefinition[]} */ ([ // Whether Suggest will use the ML backend in addition to Rust. ["quicksuggest.mlEnabled", false], + // NOTE: You should most likely access this pref via its Nimbus variable + // instead: `UrlbarPrefs.get("quickSuggestOnlineAvailable"). It's listed here + // mainly so tests can access it easily via `UrlbarPrefs`. + // + // Whether online Suggest is available to the user. This is only relevant when + // Suggest overall is enabled. + ["quicksuggest.online.available", false], + + // Whether online Suggest is enabled for the user. This is only relevant when + // Suggest overall is enabled and online Suggest is available to the user. + ["quicksuggest.online.enabled", true], + // The last time (as seconds) the user selected 'Not Now' on Realtime // suggestion opt-in result. ["quicksuggest.realtimeOptIn.notNowTimeSeconds", 0], diff --git a/browser/components/urlbar/docs/firefox-suggest-telemetry.rst b/browser/components/urlbar/docs/firefox-suggest-telemetry.rst @@ -1331,7 +1331,11 @@ Changelog Firefox 94.0.2 Introduced. [Bug 1735976_] + Firefox 146.0 + Removed. [Bug 1995362_] + .. _1735976: https://bugzilla.mozilla.org/show_bug.cgi?id=1735976 +.. _1995362: https://bugzilla.mozilla.org/show_bug.cgi?id=1995362 browser.urlbar.suggest.quicksuggest ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/browser/components/urlbar/docs/preferences.rst b/browser/components/urlbar/docs/preferences.rst @@ -171,8 +171,17 @@ browser.urlbar.quicksuggest.enabled (boolean, default: false) the individual prefs ``browser.urlbar.suggest.quicksuggest.nonsponsored`` and ``browser.urlbar.suggest.quicksuggest.sponsored``. -browser.urlbar.quicksuggest.dataCollection.enabled (boolean, default: false) - Whether data collection is enabled for quick suggest results. +browser.urlbar.quicksuggest.online.available (boolean, default: false) + Whether online Firefox Suggest is available to the user. This is only + relevant when Suggest overall is enabled. When true, a checkbox will be + shown in the settings UI allowing to the user to toggle online Suggest. + +browser.urlbar.quicksuggest.online.enabled (boolean, default: true) + Whether Firefox Suggest retrieves online suggestions from Merino. This pref + is only relevant when Suggest overall is enabled and online Suggest is + available to the user; otherwise online suggestions are disabled. In + addition, when the relevant Oblivious HTTP (OHTTP) Merino prefs are set, + online suggestions will be fetched over OHTTP. browser.urlbar.richSuggestions.tail (boolean, default: true) If true, we show tail search suggestions when available. diff --git a/browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs b/browser/components/urlbar/private/RealtimeSuggestProvider.sys.mjs @@ -139,7 +139,8 @@ export class RealtimeSuggestProvider extends SuggestProvider { "quicksuggest.realtimeOptIn.dismissTypes", "quicksuggest.realtimeOptIn.notNowTimeSeconds", "quicksuggest.realtimeOptIn.notNowReshowAfterPeriodDays", - "quicksuggest.dataCollection.enabled", + "quickSuggestOnlineAvailable", + "quicksuggest.online.enabled", this.featureGatePref, this.suggestPref, @@ -164,15 +165,18 @@ export class RealtimeSuggestProvider extends SuggestProvider { } get shouldEnable() { - if (!lazy.UrlbarPrefs.get(this.featureGatePref)) { - // The feature gate is disabled. Don't show opt-in or online suggestions - // for this realtime type. + if ( + !lazy.UrlbarPrefs.get(this.featureGatePref) || + !lazy.UrlbarPrefs.get("quickSuggestOnlineAvailable") + ) { + // The feature gate is disabled or online suggestions aren't available. + // Don't show opt-in or online suggestions for this realtime type. return false; } - if (lazy.UrlbarPrefs.get("quicksuggest.dataCollection.enabled")) { - // The user opted in to online suggestions. Show this realtime type if - // they didn't disable it. + if (lazy.UrlbarPrefs.get("quicksuggest.online.enabled")) { + // Online suggestions are enabled. Show this realtime type if the user + // didn't disable it. return lazy.UrlbarPrefs.get(this.suggestPref); } @@ -256,9 +260,9 @@ export class RealtimeSuggestProvider extends SuggestProvider { } filterSuggestions(suggestions) { - // The Rust opt-in suggestion can continue to be matched after the user opts - // in, so always return only Merino suggestions after opt in. - if (lazy.UrlbarPrefs.get("quicksuggest.dataCollection.enabled")) { + // The Rust opt-in suggestion can always be matched regardless of whether + // online is enabled, so return only Merino suggestions when it is enabled. + if (lazy.UrlbarPrefs.get("quicksuggest.online.enabled")) { return suggestions.filter(s => s.source == "merino"); } return suggestions; @@ -560,7 +564,7 @@ export class RealtimeSuggestProvider extends SuggestProvider { onOptInEngagement(queryContext, controller, details, _searchString) { switch (details.selType) { case "opt_in": - lazy.UrlbarPrefs.set("quicksuggest.dataCollection.enabled", true); + lazy.UrlbarPrefs.set("quicksuggest.online.enabled", true); controller.input.startQuery({ allowAutofill: false }); break; case "not_now": { diff --git a/browser/components/urlbar/private/SuggestBackendMerino.sys.mjs b/browser/components/urlbar/private/SuggestBackendMerino.sys.mjs @@ -16,12 +16,12 @@ ChromeUtils.defineESModuleGetters(lazy, { */ /** - * The Suggest Merino backend. This backend is enabled when the user opts in to - * Merino, also called "online" Suggest. + * The Suggest Merino backend. This backend is enabled when online Suggest is + * available to the user and enabled. */ export class SuggestBackendMerino extends SuggestBackend { get enablingPreferences() { - return ["quicksuggest.dataCollection.enabled"]; + return ["quickSuggestOnlineAvailable", "quicksuggest.online.enabled"]; } /** diff --git a/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_realtime_optin_engagement.js b/browser/components/urlbar/tests/engagementTelemetry/browser/browser_glean_telemetry_realtime_optin_engagement.js @@ -37,11 +37,14 @@ add_setup(async function () { ], }, ], - prefs: [["market.featureGate", true]], + prefs: [ + ["quicksuggest.online.available", true], + ["market.featureGate", true], + ], }); registerCleanupFunction(() => { - UrlbarPrefs.clear("quicksuggest.dataCollection.enabled"); + UrlbarPrefs.clear("quicksuggest.online.enabled"); UrlbarPrefs.clear("quicksuggest.dynamicSuggestionTypes"); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.dismissTypes"); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.notNowTimeSeconds"); @@ -51,7 +54,7 @@ add_setup(async function () { }); add_task(async function opt_in() { - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); UrlbarPrefs.set("suggest.realtimeOptIn", true); await doTest(async () => { @@ -73,7 +76,7 @@ add_task(async function opt_in() { }); add_task(async function not_now_and_dismiss() { - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); UrlbarPrefs.set("suggest.realtimeOptIn", true); await doTest(async () => { @@ -126,7 +129,7 @@ add_task(async function not_now_and_dismiss() { }); add_task(async function not_interested() { - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); UrlbarPrefs.set("suggest.realtimeOptIn", true); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.dismissTypes"); diff --git a/browser/components/urlbar/tests/quicksuggest/QuickSuggestTestUtils.sys.mjs b/browser/components/urlbar/tests/quicksuggest/QuickSuggestTestUtils.sys.mjs @@ -189,10 +189,10 @@ class _QuickSuggestTestUtils { * the record should be added to. Defaults to "quicksuggest-other". * @param {Array} [options.merinoSuggestions] * Array of Merino suggestion objects. If given, this function will start - * the mock Merino server and set `quicksuggest.dataCollection.enabled` to - * true so that `UrlbarProviderQuickSuggest` will fetch suggestions from it. - * Otherwise Merino will not serve suggestions, but you can still set up - * Merino without using this function by using `MerinoTestUtils` directly. + * the mock Merino server and set appropriate online prefs so that Suggest + * will fetch suggestions from it. Otherwise Merino will not serve + * suggestions, but you can still set up Merino without using this function + * by using `MerinoTestUtils` directly. * @param {object} [options.config] * The Suggest configuration object. This should not be the full remote * settings record; only pass the object that should be set to the nested @@ -280,7 +280,8 @@ class _QuickSuggestTestUtils { this.#log("ensureQuickSuggestInit", "Setting up Merino server"); await lazy.MerinoTestUtils.server.start(); lazy.MerinoTestUtils.server.response.body.suggestions = merinoSuggestions; - lazy.UrlbarPrefs.set("quicksuggest.dataCollection.enabled", true); + lazy.UrlbarPrefs.set("quicksuggest.online.available", true); + lazy.UrlbarPrefs.set("quicksuggest.online.enabled", true); this.#log("ensureQuickSuggestInit", "Done setting up Merino server"); } @@ -303,7 +304,7 @@ class _QuickSuggestTestUtils { return cleanup; } - async #uninitQuickSuggest(prefs, clearDataCollectionEnabled) { + async #uninitQuickSuggest(prefs, clearOnlinePrefs) { this.#log("#uninitQuickSuggest", "Started"); // Reset prefs, which can cause the Rust backend to start syncing. Wait for @@ -316,8 +317,9 @@ class _QuickSuggestTestUtils { this.#log("#uninitQuickSuggest", "Stopping remote settings server"); await this.#remoteSettingsServer.stop(); - if (clearDataCollectionEnabled) { - lazy.UrlbarPrefs.clear("quicksuggest.dataCollection.enabled"); + if (clearOnlinePrefs) { + lazy.UrlbarPrefs.clear("quicksuggest.online.available"); + lazy.UrlbarPrefs.clear("quicksuggest.online.enabled"); } await lazy.QuickSuggest.rustBackend._test_setRemoteSettingsService(null); diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest.js @@ -62,7 +62,7 @@ add_setup(async function () { }); // Disable Merino so we trigger only remote settings suggestions. - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); await SpecialPowers.pushPrefEnv({ set: [["browser.urlbar.suggest.engines", false]], @@ -287,7 +287,10 @@ add_task(async function resultMenu_manage_nonSponsored() { add_task(async function resultMenu_manage_navigational() { // Enable Merino. await SpecialPowers.pushPrefEnv({ - set: [["browser.urlbar.quicksuggest.dataCollection.enabled", true]], + set: [ + ["browser.urlbar.quicksuggest.online.available", true], + ["browser.urlbar.quicksuggest.online.enabled", true], + ], }); MerinoTestUtils.server.response.body.suggestions = [ @@ -306,7 +309,10 @@ add_task(async function resultMenu_manage_navigational() { add_task(async function resultMenu_manage_dynamicWikipedia() { // Enable Merino. await SpecialPowers.pushPrefEnv({ - set: [["browser.urlbar.quicksuggest.dataCollection.enabled", true]], + set: [ + ["browser.urlbar.quicksuggest.online.available", true], + ["browser.urlbar.quicksuggest.online.enabled", true], + ], }); MerinoTestUtils.server.response.body.suggestions = [ MERINO_DYNAMIC_WIKIPEDIA_SUGGESTION, diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_configuration.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_configuration.js @@ -268,184 +268,6 @@ add_task(async function () { }); }); -// Initial state: -// * Data collection on by default and user left them on -// -// 1. First enrollment: -// * Data collection forced off -// -// Expected: -// * Data collection off -// -// 2. User turns on data collection -// 3. Second enrollment: -// * Data collection forced off again -// -// Expected: -// * Data collection remains on -add_task(async function () { - await checkEnrollments( - [ - { - initialPrefsToSet: { - defaultBranch: { - "quicksuggest.dataCollection.enabled": true, - }, - }, - valueOverrides: { - quickSuggestDataCollectionEnabled: false, - }, - expectedPrefs: { - defaultBranch: { - "quicksuggest.dataCollection.enabled": false, - }, - }, - }, - ], - [ - { - initialPrefsToSet: { - userBranch: { - "quicksuggest.dataCollection.enabled": true, - }, - }, - valueOverrides: { - quickSuggestDataCollectionEnabled: false, - }, - expectedPrefs: { - defaultBranch: { - "quicksuggest.dataCollection.enabled": false, - }, - userBranch: { - "quicksuggest.dataCollection.enabled": true, - }, - }, - }, - ] - ); -}); - -// Initial state: -// * Data collection on by default but user turned it off -// -// Enrollment: -// * Data collection forced on -// -// Expected: -// * Data collection remains off -add_task(async function () { - await checkEnrollments({ - initialPrefsToSet: { - defaultBranch: { - "quicksuggest.dataCollection.enabled": true, - }, - userBranch: { - "quicksuggest.dataCollection.enabled": false, - }, - }, - valueOverrides: { - quickSuggestDataCollectionEnabled: true, - }, - expectedPrefs: { - defaultBranch: { - "quicksuggest.dataCollection.enabled": true, - }, - userBranch: { - "quicksuggest.dataCollection.enabled": false, - }, - }, - }); -}); - -// Initial state: -// * Data collection off by default and user left it off -// -// 1. First enrollment: -// * Data collection forced on -// -// Expected: -// * Data collection on -// -// 2. User turns off data collection -// 3. Second enrollment: -// * Data collection forced on again -// -// Expected: -// * Data collection remains off -add_task(async function () { - await checkEnrollments( - [ - { - initialPrefsToSet: { - defaultBranch: { - "quicksuggest.dataCollection.enabled": false, - }, - }, - valueOverrides: { - quickSuggestDataCollectionEnabled: true, - }, - expectedPrefs: { - defaultBranch: { - "quicksuggest.dataCollection.enabled": true, - }, - }, - }, - ], - [ - { - initialPrefsToSet: { - userBranch: { - "quicksuggest.dataCollection.enabled": false, - }, - }, - valueOverrides: { - quickSuggestDataCollectionEnabled: true, - }, - expectedPrefs: { - defaultBranch: { - "quicksuggest.dataCollection.enabled": false, - }, - userBranch: { - "quicksuggest.dataCollection.enabled": false, - }, - }, - }, - ] - ); -}); - -// Initial state: -// * Data collection off by default but user turned it on -// -// Enrollment: -// * Data collection forced off -// -// Expected: -// * Data collection remains on -add_task(async function () { - await checkEnrollments({ - initialPrefsToSet: { - defaultBranch: { - "quicksuggest.dataCollection.enabled": false, - }, - userBranch: { - "quicksuggest.dataCollection.enabled": true, - }, - }, - valueOverrides: { - quickSuggestDataCollectionEnabled: false, - }, - expectedPrefs: { - defaultBranch: { - "quicksuggest.dataCollection.enabled": false, - }, - userBranch: { - "quicksuggest.dataCollection.enabled": true, - }, - }, - }); -}); - /** * Tests one or more enrollments. Sets an initial set of prefs on the default * and/or user branches, enrolls in a mock Nimbus experiment, checks expected diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_merinoSessions.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_merinoSessions.js @@ -11,7 +11,10 @@ add_setup(async function () { await SpecialPowers.pushPrefEnv({ - set: [["browser.urlbar.quicksuggest.dataCollection.enabled", true]], + set: [ + ["browser.urlbar.quicksuggest.online.available", true], + ["browser.urlbar.quicksuggest.online.enabled", true], + ], }); await PlacesUtils.history.clear(); diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_optin.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_realtime_optin.js @@ -55,7 +55,7 @@ add_setup(async function () { registerCleanupFunction(async () => { UrlbarPrefs.clear("suggest.realtimeOptIn"); - UrlbarPrefs.clear("quicksuggest.dataCollection.enabled"); + UrlbarPrefs.clear("quicksuggest.online.enabled"); // Make sure all ingest is done before finishing. await QuickSuggestTestUtils.forceSync(); @@ -82,7 +82,7 @@ add_task(async function messages() { }); async function doMessagesTest({ input, expected }) { - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); let { element } = await openRealtimeSuggestion({ input }); let title = element.row.querySelector(".urlbarView-title"); @@ -93,7 +93,7 @@ async function doMessagesTest({ input, expected }) { Assert.equal(description.textContent, expected.description); await UrlbarTestUtils.promisePopupClose(window); - UrlbarPrefs.clear("quicksuggest.dataCollection.enabled"); + UrlbarPrefs.clear("quicksuggest.online.enabled"); } add_task(async function optIn_mouse() { @@ -110,11 +110,11 @@ async function doOptInTest(useKeyboard) { "Sanity check: MarketSuggestions is enabled initially" ); - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); Assert.ok( QuickSuggest.getFeature("MarketSuggestions").isEnabled, - "MarketSuggestions remains enabled after disabling quicksuggest.dataCollection.enabled" + "MarketSuggestions remains enabled after disabling quicksuggest.online.enabled" ); let { element, result } = await openRealtimeSuggestion({ input: "stock" }); @@ -162,7 +162,7 @@ async function doOptInTest(useKeyboard) { window, 1 ); - Assert.ok(UrlbarPrefs.get("quicksuggest.dataCollection.enabled")); + Assert.ok(UrlbarPrefs.get("quicksuggest.online.enabled")); Assert.equal(merinoResult.payload.source, "merino"); Assert.equal(merinoResult.payload.provider, "polygon"); Assert.equal(merinoResult.payload.dynamicType, "market"); @@ -175,11 +175,11 @@ async function doOptInTest(useKeyboard) { "MarketSuggestions remains enabled opting in" ); - UrlbarPrefs.clear("quicksuggest.dataCollection.enabled"); + UrlbarPrefs.clear("quicksuggest.online.enabled"); Assert.ok( QuickSuggest.getFeature("MarketSuggestions").isEnabled, - "MarketSuggestions remains enabled after clearing quicksuggest.dataCollection.enabled" + "MarketSuggestions remains enabled after clearing quicksuggest.online.enabled" ); } @@ -189,7 +189,7 @@ add_task(async function dismiss() { "Sanity check: MarketSuggestions is enabled initially" ); - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.notNowTimeSeconds"); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.notNowTypes"); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.dismissTypes"); @@ -308,7 +308,7 @@ add_task(async function dismiss() { "MarketSuggestions remains disabled simulating passage of 1000 days" ); - UrlbarPrefs.clear("quicksuggest.dataCollection.enabled"); + UrlbarPrefs.clear("quicksuggest.online.enabled"); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.notNowTimeSeconds"); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.notNowTypes"); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.dismissTypes"); @@ -330,7 +330,7 @@ add_task(async function dismiss_with_another_type() { "Sanity check: MarketSuggestions is enabled initially" ); - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.notNowTimeSeconds"); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.notNowTypes"); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.dismissTypes"); @@ -405,7 +405,7 @@ add_task(async function dismiss_with_another_type() { await assertOptInVisibility({ input: "stock", expectedVisibility: true }); - UrlbarPrefs.clear("quicksuggest.dataCollection.enabled"); + UrlbarPrefs.clear("quicksuggest.online.enabled"); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.notNowTimeSeconds"); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.notNowTypes"); UrlbarPrefs.clear("quicksuggest.realtimeOptIn.dismissTypes"); @@ -423,7 +423,7 @@ add_task(async function not_interested() { "Sanity check: MarketSuggestions is enabled initially" ); - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); UrlbarPrefs.set("suggest.realtimeOptIn", true); info("Click on dropdown button"); @@ -461,7 +461,7 @@ add_task(async function not_interested() { info("Any realtime type suggestion never be shown"); await assertOptInVisibility({ input: "stock", expectedVisibility: false }); - UrlbarPrefs.clear("quicksuggest.dataCollection.enabled"); + UrlbarPrefs.clear("quicksuggest.online.enabled"); UrlbarPrefs.clear("suggest.realtimeOptIn"); Assert.ok( diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_telemetry_environment.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_telemetry_environment.js @@ -23,11 +23,6 @@ add_task(async function sponsoredToggled() { doToggleTest("suggest.quicksuggest.sponsored"); }); -// Toggles the `quicksuggest.dataCollection.enabled` pref. -add_task(async function dataCollectionToggled() { - doToggleTest("quicksuggest.dataCollection.enabled"); -}); - function doToggleTest(pref) { let enabled = UrlbarPrefs.get(pref); Assert.equal( @@ -82,11 +77,7 @@ add_task(async function telemetryEnvironmentOnStartup() { // array here. Assert.deepEqual( prefs.sort(), - [ - "quicksuggest.dataCollection.enabled", - "suggest.quicksuggest.nonsponsored", - "suggest.quicksuggest.sponsored", - ], + ["suggest.quicksuggest.nonsponsored", "suggest.quicksuggest.sponsored"], "Expected startup prefs" ); diff --git a/browser/components/urlbar/tests/quicksuggest/unit/head.js b/browser/components/urlbar/tests/quicksuggest/unit/head.js @@ -113,6 +113,7 @@ async function doMigrateTest({ let initialDefaultBranch = { "suggest.quicksuggest.nonsponsored": false, "suggest.quicksuggest.sponsored": false, + // This pref is obsolete but it's used by old migrations that we still test. "quicksuggest.dataCollection.enabled": false, }; for (let name of Object.keys(initialDefaultBranch)) { @@ -626,7 +627,7 @@ async function doOneShowLessFrequentlyTest({ // mock Merino server will always return whatever suggestion it's told to // return regardless of the search string. That means Merino will return a // suggestion for a keyword that's smaller than the first full word. - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); // Set Nimbus variables and RS config. let cleanUpNimbus = await UrlbarTestUtils.initNimbusFeature(nimbus); @@ -701,7 +702,7 @@ async function doOneShowLessFrequentlyTest({ await cleanUpNimbus(); UrlbarPrefs.clear(showLessFrequentlyCountPref); - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", true); + UrlbarPrefs.clear("quicksuggest.online.enabled"); } /** diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest.js @@ -2113,7 +2113,8 @@ add_task(async function online_wikipedia_disabled() { }); async function doMerinoTest(callback) { - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); await MerinoTestUtils.server.start(); MerinoTestUtils.server.response.body.suggestions = MERINO_SUGGESTIONS; @@ -2121,7 +2122,8 @@ async function doMerinoTest(callback) { await callback(); await MerinoTestUtils.server.stop(); - UrlbarPrefs.clear("quicksuggest.dataCollection.enabled"); + UrlbarPrefs.clear("quicksuggest.online.available"); + UrlbarPrefs.clear("quicksuggest.online.enabled"); } add_task(async function mergeRustProviderConstraints() { diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_addons.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_addons.js @@ -428,7 +428,7 @@ add_task(async function remoteSettings() { ]; // Disable Merino so we trigger only remote settings suggestions. - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); for (let { input, expected } of testCases) { await check_results({ @@ -440,7 +440,7 @@ add_task(async function remoteSettings() { }); } - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", true); + UrlbarPrefs.clear("quicksuggest.online.enabled"); }); add_task(async function merinoIsTopPick() { @@ -484,7 +484,7 @@ add_task(async function merinoIsTopPick() { // Tests the "Not relevant" command: a dismissed suggestion shouldn't be added. add_task(async function notRelevant() { // Disable Merino suggestions to make this task simpler. - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); await doDismissOneTest({ result: makeExpectedResult({ @@ -509,7 +509,7 @@ add_task(async function notRelevant() { ], }); - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", true); + UrlbarPrefs.clear("quicksuggest.online.enabled"); }); // Tests the "Not interested" command: all addon suggestions should be disabled diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_defaultPrefs.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_defaultPrefs.js @@ -0,0 +1,204 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests that Suggest is enabled by default for appropriate region-locales and +// disabled by default everywhere else. + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + Preferences: "resource://gre/modules/Preferences.sys.mjs", +}); + +const EN_LOCALES = ["en-CA", "en-GB", "en-US", "en-ZA"]; + +// Expected prefs when Suggest is disabled. +const EXPECTED_PREFS_SUGGEST_DISABLED = { + "quicksuggest.enabled": false, + "quicksuggest.online.available": false, + "quicksuggest.online.enabled": true, + "quicksuggest.settingsUi": QuickSuggest.SETTINGS_UI.NONE, + "suggest.quicksuggest.nonsponsored": false, + "suggest.quicksuggest.sponsored": false, + "addons.featureGate": false, + "amp.featureGate": false, + "importantDates.featureGate": false, + "mdn.featureGate": false, + "weather.featureGate": false, + "wikipedia.featureGate": false, + "yelp.featureGate": false, +}; + +// Expected prefs for native locales in EU countries (e.g., `de` locale in +// Germany). +const EXPECTED_PREFS_EU_NATIVE = { + ...EXPECTED_PREFS_SUGGEST_DISABLED, + "quicksuggest.enabled": true, + "quicksuggest.settingsUi": QuickSuggest.SETTINGS_UI.OFFLINE_ONLY, + "suggest.quicksuggest.nonsponsored": true, + "suggest.quicksuggest.sponsored": true, + "importantDates.featureGate": true, + "weather.featureGate": true, +}; + +// Expected prefs for `en` locales in EU countries (e.g., `en-US` locale in +// Germany). +const EXPECTED_PREFS_EU_EN = { + ...EXPECTED_PREFS_SUGGEST_DISABLED, + "quicksuggest.enabled": true, + "importantDates.featureGate": true, +}; + +// Base set of expected prefs for countries where an `en` locale is native +// (e.g., US, UK). These countries will have slightly different actual expected +// prefs, which is why this is a base set. +const EXPECTED_PREFS_BASE_EN_NATIVE = { + ...EXPECTED_PREFS_SUGGEST_DISABLED, + "quicksuggest.enabled": true, + "quicksuggest.settingsUi": QuickSuggest.SETTINGS_UI.OFFLINE_ONLY, + "suggest.quicksuggest.nonsponsored": true, + "suggest.quicksuggest.sponsored": true, + "amp.featureGate": true, + "importantDates.featureGate": true, + "weather.featureGate": true, + "wikipedia.featureGate": true, +}; + +// Region -> locale -> expected prefs when Suggest is enabled +const EXPECTED_PREFS_BY_LOCALE_BY_REGION = { + DE: { + de: EXPECTED_PREFS_EU_NATIVE, + ...Object.fromEntries( + EN_LOCALES.map(locale => [locale, EXPECTED_PREFS_EU_EN]) + ), + }, + FR: { + fr: EXPECTED_PREFS_EU_NATIVE, + ...Object.fromEntries( + EN_LOCALES.map(locale => [locale, EXPECTED_PREFS_EU_EN]) + ), + }, + GB: Object.fromEntries( + EN_LOCALES.map(locale => [locale, EXPECTED_PREFS_BASE_EN_NATIVE]) + ), + IT: { + it: EXPECTED_PREFS_EU_NATIVE, + ...Object.fromEntries( + EN_LOCALES.map(locale => [locale, EXPECTED_PREFS_EU_EN]) + ), + }, + US: Object.fromEntries( + EN_LOCALES.map(locale => [ + locale, + { + ...EXPECTED_PREFS_BASE_EN_NATIVE, + "addons.featureGate": true, + "mdn.featureGate": true, + "yelp.featureGate": true, + }, + ]) + ), +}; + +add_setup(async () => { + await UrlbarTestUtils.initNimbusFeature(); +}); + +add_task(async function test() { + let tests = [ + // Regions/locales where Suggest should be enabled to some extent + { region: "DE", locale: "de" }, + { region: "DE", locale: "en-GB" }, + { region: "DE", locale: "en-US" }, + + { region: "FR", locale: "fr" }, + { region: "FR", locale: "en-GB" }, + { region: "FR", locale: "en-US" }, + + { region: "GB", locale: "en-US" }, + { region: "GB", locale: "en-CA" }, + { region: "GB", locale: "en-GB" }, + + { region: "IT", locale: "it" }, + { region: "IT", locale: "en-GB" }, + { region: "IT", locale: "en-US" }, + + { region: "US", locale: "en-US" }, + { region: "US", locale: "en-CA" }, + { region: "US", locale: "en-GB" }, + + // Regions/locales where Suggest should be completely disabled + { region: "CA", locale: "en-US" }, + { region: "CA", locale: "en-CA" }, + { region: "GB", locale: "de" }, + { region: "US", locale: "de" }, + ]; + + for (let { locale, region } of tests) { + await doTest({ locale, region }); + } +}); + +/** + * Sets the app's locale and region, reinitializes Suggest, and asserts that the + * pref values are correct. + * + * @param {object} options + * Options object. + * @param {string} options.locale + * The locale to simulate. + * @param {string} options.region + * The "home" region to simulate. + */ +async function doTest({ locale, region }) { + let expectedPrefs = + EXPECTED_PREFS_BY_LOCALE_BY_REGION[region]?.[locale] ?? + EXPECTED_PREFS_SUGGEST_DISABLED; + + let defaults = new Preferences({ + branch: "browser.urlbar.", + defaultBranch: true, + }); + + // Setup: Clear any user values and save original default-branch values. + let originalDefaults = {}; + for (let name of Object.keys(expectedPrefs)) { + Services.prefs.clearUserPref("browser.urlbar." + name); + originalDefaults[name] = defaults.get(name); + } + + // Set the region and locale, call the function, check the pref values. + await QuickSuggestTestUtils.withRegionAndLocale({ + region, + locale, + callback: async () => { + for (let [name, value] of Object.entries(expectedPrefs)) { + // Check the default-branch value. + Assert.strictEqual( + defaults.get(name), + value, + `Default pref value for ${name}, locale ${locale}, region ${region}` + ); + + // For good measure, also check the return value of `UrlbarPrefs.get` + // since we use it everywhere. The value should be the same as the + // default-branch value. + UrlbarPrefs.get( + name, + value, + `UrlbarPrefs.get() value for ${name}, locale ${locale}, region ${region}` + ); + } + }, + }); + + // Teardown: Restore original default-branch values for the next task. + for (let [name, originalDefault] of Object.entries(originalDefaults)) { + if (originalDefault === undefined) { + Services.prefs.deleteBranch("browser.urlbar." + name); + } else { + defaults.set(name, originalDefault); + } + } +} diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_merino.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_merino.js @@ -11,9 +11,6 @@ ChromeUtils.defineESModuleGetters(this, { "moz-src:///browser/components/urlbar/private/AmpSuggestions.sys.mjs", }); -// relative to `browser.urlbar` -const PREF_DATA_COLLECTION_ENABLED = "quicksuggest.dataCollection.enabled"; - const SEARCH_STRING = "frab"; const { DEFAULT_SUGGESTION_SCORE } = UrlbarProviderQuickSuggest; @@ -62,7 +59,8 @@ add_setup(async () => { add_task(async function merinoDisabled() { let mockEndpointUrl = UrlbarPrefs.get("merino.endpointURL"); UrlbarPrefs.set("merino.endpointURL", ""); - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); // Clear the remote settings suggestions so that if Merino is actually queried // -- which would be a bug -- we don't accidentally mask the Merino suggestion @@ -83,24 +81,31 @@ add_task(async function merinoDisabled() { await resetRemoteSettingsData(); }); -// Tests with Merino enabled but with data collection disabled. Results should -// not be fetched from Merino in that case. -add_task(async function dataCollectionDisabled() { - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, false); - +// Results should be fetched from Merino only when online is both available and +// enabled. +add_task(async function onlineAvailableAndEnabled() { // Clear the remote settings suggestions so that if Merino is actually queried // -- which would be a bug -- we don't accidentally mask the Merino suggestion // by also matching an RS suggestion with the same or higher score. await QuickSuggestTestUtils.setRemoteSettingsRecords([]); - let context = createContext(SEARCH_STRING, { - providers: [UrlbarProviderQuickSuggest.name], - isPrivate: false, - }); - await check_results({ - context, - matches: [], - }); + for (let onlineAvailable of [false, true]) { + for (let onlineEnabled of [false, true]) { + UrlbarPrefs.set("quicksuggest.online.available", onlineAvailable); + UrlbarPrefs.set("quicksuggest.online.enabled", onlineEnabled); + + await check_results({ + context: createContext(SEARCH_STRING, { + providers: [UrlbarProviderQuickSuggest.name], + isPrivate: false, + }), + matches: + onlineAvailable && onlineEnabled + ? [EXPECTED_MERINO_URLBAR_RESULT] + : [], + }); + } + } await resetRemoteSettingsData(); }); @@ -108,7 +113,8 @@ add_task(async function dataCollectionDisabled() { // When the Merino suggestion has a higher score than the remote settings // suggestion, the Merino suggestion should be used. add_task(async function higherScore() { - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); MerinoTestUtils.server.response.body.suggestions[0].score = 2 * DEFAULT_SUGGESTION_SCORE; @@ -129,7 +135,8 @@ add_task(async function higherScore() { // When the Merino suggestion has a lower score than the remote settings // suggestion, the remote settings suggestion should be used. add_task(async function lowerScore() { - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); MerinoTestUtils.server.response.body.suggestions[0].score = DEFAULT_SUGGESTION_SCORE / 2; @@ -150,7 +157,8 @@ add_task(async function lowerScore() { // When remote settings doesn't return a suggestion but Merino does, the Merino // suggestion should be used. add_task(async function noSuggestion_remoteSettings() { - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); let context = createContext("this doesn't match remote settings", { providers: [UrlbarProviderQuickSuggest.name], @@ -168,7 +176,8 @@ add_task(async function noSuggestion_remoteSettings() { // When Merino doesn't return a suggestion but remote settings does, the remote // settings suggestion should be used. add_task(async function noSuggestion_merino() { - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); MerinoTestUtils.server.response.body.suggestions = []; @@ -188,7 +197,8 @@ add_task(async function noSuggestion_merino() { // When Merino returns multiple suggestions, the one with the largest score // should be used. add_task(async function multipleMerinoSuggestions() { - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); MerinoTestUtils.server.response.body.suggestions = [ { @@ -266,7 +276,8 @@ add_task(async function multipleMerinoSuggestions() { // Timestamp templates in URLs should be replaced with real timestamps. add_task(async function timestamps() { - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); // Set up the Merino response with template URLs. let suggestion = MerinoTestUtils.server.response.body.suggestions[0]; @@ -309,11 +320,13 @@ add_task(async function timestamps() { merinoClient().resetSession(); }); -// When both suggestion types are disabled but data collection is enabled, we -// should still send requests to Merino, and the requests should include an -// empty `providers` to tell Merino not to fetch any suggestions. -add_task(async function suggestedDisabled_dataCollectionEnabled() { - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); +// When both suggestion types are disabled but online is enabled, we should +// still send requests to Merino, and the requests should include an empty +// `providers` to tell Merino not to fetch any suggestions. +add_task(async function suggestedDisabled_onlineEnabled() { + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); + UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", false); UrlbarPrefs.set("suggest.quicksuggest.sponsored", false); @@ -346,7 +359,8 @@ add_task(async function suggestedDisabled_dataCollectionEnabled() { // Tests dismissals of managed Merino suggestions (suggestions that are managed // by a `SuggestFeature`). add_task(async function dismissals_managed() { - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); // Set up a single Merino AMP suggestion with a unique URL. let url = "https://example.com/merino-amp-url"; @@ -417,7 +431,8 @@ add_task(async function dismissals_managed() { // Tests dismissals of unmanaged Merino suggestions (suggestions that are not // managed by a `SuggestFeature`). add_task(async function dismissals_unmanaged_1() { - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); let provider = "some-unknown-merino-provider"; let tests = [ @@ -563,7 +578,8 @@ add_task(async function dismissals_unmanaged_1() { // managed by a `SuggestFeature`) that all have the same URL but different // original URLs and dismissal keys. add_task(async function dismissals_unmanaged_2() { - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); let provider = "some-unknown-merino-provider"; @@ -743,7 +759,8 @@ add_task(async function dismissals_unmanaged_2() { // Tests a Merino suggestion that is a top pick/best match. add_task(async function bestMatch() { - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); // Set up a suggestion with `is_top_pick` and an unknown provider so that // UrlbarProviderQuickSuggest will make a default result for it. @@ -827,7 +844,8 @@ async function doUnmanagedTest({ pref, suggestion }) { UrlbarPrefs.set("suggest.quicksuggest.sponsored", true); await QuickSuggestTestUtils.forceSync(); - UrlbarPrefs.set(PREF_DATA_COLLECTION_ENABLED, true); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); MerinoTestUtils.server.response.body.suggestions = [suggestion]; let expectedResult = { diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_merinoSessions.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_merinoSessions.js @@ -11,7 +11,8 @@ add_setup(async () => { await QuickSuggestTestUtils.ensureQuickSuggestInit({ prefs: [ ["suggest.quicksuggest.sponsored", true], - ["quicksuggest.dataCollection.enabled", true], + ["quicksuggest.online.available", true], + ["quicksuggest.online.enabled", true], ], }); }); diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_offlineDefault.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_offlineDefault.js @@ -1,217 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Tests that Suggest is enabled by default for appropriate locales and disabled -// by default everywhere else. (When Suggest is enabled by default, "offline" -// suggestions are enabled but Merino is not, hence "offline" default.) - -"use strict"; - -ChromeUtils.defineESModuleGetters(this, { - Preferences: "resource://gre/modules/Preferences.sys.mjs", -}); - -const EN_LOCALES = ["en-CA", "en-GB", "en-US", "en-ZA"]; - -// Expected prefs when Suggest is disabled. -const EXPECTED_PREFS_SUGGEST_DISABLED = { - "quicksuggest.enabled": false, - "quicksuggest.dataCollection.enabled": false, - "quicksuggest.settingsUi": QuickSuggest.SETTINGS_UI.NONE, - "suggest.quicksuggest.nonsponsored": false, - "suggest.quicksuggest.sponsored": false, - "addons.featureGate": false, - "amp.featureGate": false, - "importantDates.featureGate": false, - "mdn.featureGate": false, - "weather.featureGate": false, - "wikipedia.featureGate": false, - "yelp.featureGate": false, -}; - -// Expected prefs for native locales in EU countries (e.g., `de` locale in Germany). -const EXPECTED_PREFS_EU_NATIVE = { - "quicksuggest.enabled": true, - "quicksuggest.dataCollection.enabled": false, - "quicksuggest.settingsUi": QuickSuggest.SETTINGS_UI.OFFLINE_ONLY, - "suggest.quicksuggest.nonsponsored": true, - "suggest.quicksuggest.sponsored": true, - "addons.featureGate": false, - "amp.featureGate": false, - "importantDates.featureGate": true, - "mdn.featureGate": false, - "weather.featureGate": true, - "wikipedia.featureGate": false, - "yelp.featureGate": false, -}; - -// Expected prefs for `en` locales in EU countries (e.g., `en-US` locale in -// Germany). -const EXPECTED_PREFS_EU_EN = { - ...EXPECTED_PREFS_SUGGEST_DISABLED, - "quicksuggest.enabled": true, - "importantDates.featureGate": true, -}; - -// Region -> locale -> expected prefs when Suggest is enabled -const EXPECTED_PREFS_BY_LOCALE_BY_REGION = { - DE: { - de: EXPECTED_PREFS_EU_NATIVE, - ...Object.fromEntries( - EN_LOCALES.map(locale => [locale, EXPECTED_PREFS_EU_EN]) - ), - }, - FR: { - fr: EXPECTED_PREFS_EU_NATIVE, - ...Object.fromEntries( - EN_LOCALES.map(locale => [locale, EXPECTED_PREFS_EU_EN]) - ), - }, - GB: Object.fromEntries( - EN_LOCALES.map(locale => [ - locale, - { - "quicksuggest.enabled": true, - "quicksuggest.dataCollection.enabled": false, - "quicksuggest.settingsUi": QuickSuggest.SETTINGS_UI.OFFLINE_ONLY, - "suggest.quicksuggest.nonsponsored": true, - "suggest.quicksuggest.sponsored": true, - "addons.featureGate": false, - "amp.featureGate": true, - "importantDates.featureGate": true, - "mdn.featureGate": false, - "weather.featureGate": true, - "wikipedia.featureGate": true, - "yelp.featureGate": false, - }, - ]) - ), - IT: { - it: EXPECTED_PREFS_EU_NATIVE, - ...Object.fromEntries( - EN_LOCALES.map(locale => [locale, EXPECTED_PREFS_EU_EN]) - ), - }, - US: Object.fromEntries( - EN_LOCALES.map(locale => [ - locale, - { - "quicksuggest.enabled": true, - "quicksuggest.dataCollection.enabled": false, - "quicksuggest.settingsUi": QuickSuggest.SETTINGS_UI.OFFLINE_ONLY, - "suggest.quicksuggest.nonsponsored": true, - "suggest.quicksuggest.sponsored": true, - "addons.featureGate": true, - "amp.featureGate": true, - "importantDates.featureGate": true, - "mdn.featureGate": true, - "weather.featureGate": true, - "wikipedia.featureGate": true, - "yelp.featureGate": true, - }, - ]) - ), -}; - -add_setup(async () => { - await UrlbarTestUtils.initNimbusFeature(); -}); - -add_task(async function test() { - let tests = [ - // Regions/locales where Suggest should be enabled to some extent - { region: "DE", locale: "de" }, - { region: "DE", locale: "en-GB" }, - { region: "DE", locale: "en-US" }, - - { region: "FR", locale: "fr" }, - { region: "FR", locale: "en-GB" }, - { region: "FR", locale: "en-US" }, - - { region: "GB", locale: "en-US" }, - { region: "GB", locale: "en-CA" }, - { region: "GB", locale: "en-GB" }, - - { region: "IT", locale: "it" }, - { region: "IT", locale: "en-GB" }, - { region: "IT", locale: "en-US" }, - - { region: "US", locale: "en-US" }, - { region: "US", locale: "en-CA" }, - { region: "US", locale: "en-GB" }, - - // Regions/locales where Suggest should be completely disabled - { region: "CA", locale: "en-US" }, - { region: "CA", locale: "en-CA" }, - { region: "GB", locale: "de" }, - { region: "US", locale: "de" }, - ]; - - for (let { locale, region } of tests) { - await doTest({ locale, region }); - } -}); - -/** - * Sets the app's locale and region, reinitializes Suggest, and asserts that the - * pref values are correct. - * - * @param {object} options - * Options object. - * @param {string} options.locale - * The locale to simulate. - * @param {string} options.region - * The "home" region to simulate. - */ -async function doTest({ locale, region }) { - let expectedPrefs = - EXPECTED_PREFS_BY_LOCALE_BY_REGION[region]?.[locale] ?? - EXPECTED_PREFS_SUGGEST_DISABLED; - - let defaults = new Preferences({ - branch: "browser.urlbar.", - defaultBranch: true, - }); - - // Setup: Clear any user values and save original default-branch values. - let originalDefaults = {}; - for (let name of Object.keys(expectedPrefs)) { - Services.prefs.clearUserPref("browser.urlbar." + name); - originalDefaults[name] = defaults.get(name); - } - - // Set the region and locale, call the function, check the pref values. - await QuickSuggestTestUtils.withRegionAndLocale({ - region, - locale, - callback: async () => { - for (let [name, value] of Object.entries(expectedPrefs)) { - // Check the default-branch value. - Assert.strictEqual( - defaults.get(name), - value, - `Default pref value for ${name}, locale ${locale}, region ${region}` - ); - - // For good measure, also check the return value of `UrlbarPrefs.get` - // since we use it everywhere. The value should be the same as the - // default-branch value. - UrlbarPrefs.get( - name, - value, - `UrlbarPrefs.get() value for ${name}, locale ${locale}, region ${region}` - ); - } - }, - }); - - // Teardown: Restore original default-branch values for the next task. - for (let [name, originalDefault] of Object.entries(originalDefaults)) { - if (originalDefault === undefined) { - Services.prefs.deleteBranch("browser.urlbar." + name); - } else { - defaults.set(name, originalDefault); - } - } -} diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_relevanceRanking.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_relevanceRanking.js @@ -321,7 +321,7 @@ add_task(async function offline_default_mode_end2end() { async function doOfflineTest({ mode, expectedResultArgs }) { // Turn off Merino. - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.enabled", false); Services.prefs.setStringPref(PREF_RANKING_MODE, mode); @@ -371,7 +371,7 @@ async function doOfflineTest({ mode, expectedResultArgs }) { }); Services.prefs.clearUserPref(PREF_RANKING_MODE); - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", true); + UrlbarPrefs.clear("quicksuggest.online.enabled"); sandbox.restore(); } diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_yelp_realtime.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_yelp_realtime.js @@ -194,7 +194,7 @@ add_task(async function opt_in_on_opt_in_prompt() { }); info("Check the prefs after triggering"); - Assert.ok(UrlbarPrefs.get("quicksuggest.dataCollection.enabled")); + Assert.ok(UrlbarPrefs.get("quicksuggest.online.enabled")); info("Check the result after triggering"); await check_results({ @@ -358,7 +358,8 @@ add_task(async function not_interested_on_opt_in_prompt() { function setupOptInPromptTest() { UrlbarPrefs.set("suggest.realtimeOptIn", true); - UrlbarPrefs.set("quicksuggest.dataCollection.enabled", false); + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", false); UrlbarPrefs.set("quicksuggest.realtimeOptIn.dismissTypes", ""); UrlbarPrefs.set("quicksuggest.realtimeOptIn.notNowTimeSeconds", 0); UrlbarPrefs.set("quicksuggest.realtimeOptIn.notNowTypes", ""); diff --git a/browser/components/urlbar/tests/quicksuggest/unit/xpcshell.toml b/browser/components/urlbar/tests/quicksuggest/unit/xpcshell.toml @@ -17,6 +17,9 @@ requesttimeoutfactor = 2 # Slow on Linux ["test_quicksuggest_addons.js"] +["test_quicksuggest_defaultPrefs.js"] +requesttimeoutfactor = 2 # Slow on Linux and Windows + ["test_quicksuggest_dynamicSuggestions.js"] ["test_quicksuggest_exposures.js"] @@ -48,9 +51,6 @@ skip-if = ["true"] # Bug 1880214 ["test_quicksuggest_migrate_v4.js"] -["test_quicksuggest_offlineDefault.js"] -requesttimeoutfactor = 2 # Slow on Linux and Windows - ["test_quicksuggest_relevanceRanking.js"] ["test_quicksuggest_remoteSettingsFilter.js"] diff --git a/toolkit/components/nimbus/FeatureManifest.yaml b/toolkit/components/nimbus/FeatureManifest.yaml @@ -432,9 +432,6 @@ urlbar: branch: default pref: browser.urlbar.quicksuggest.contextualOptIn.impressionDaysLimit description: Days until dismiss the Firefox Suggest contextual opt-in result after first impression. - quickSuggestDataCollectionEnabled: - type: boolean - description: Whether data collection should be enabled by default. If this variable is specified, it will override the value implied by the scenario. It will never override the user's local preference to disable (or enable) data collection, if the user has already toggled that preference. quickSuggestDynamicSuggestionTypes: type: string setPref: @@ -492,6 +489,11 @@ urlbar: description: >- The index of non-sponsored QuickSuggest results within the general group. A negative index is relative to the end of the group + quickSuggestOnlineAvailable: + type: boolean + fallbackPref: browser.urlbar.quicksuggest.online.available + description: >- + Whether online Suggest should be made available to the user. quickSuggestRankingMode: type: string fallbackPref: browser.urlbar.quicksuggest.rankingMode