diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index 08f0993d9b3d5..45f9a53e3dd2f 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -1646,6 +1646,8 @@ BrowserGlue.prototype = { ProcessHangMonitor.init(); + UrlbarPrefs.maybeEnableOfflineQuickSuggest(); + // A channel for "remote troubleshooting" code... let channel = new WebChannel( "remote-troubleshooting", diff --git a/browser/components/preferences/privacy.js b/browser/components/preferences/privacy.js index 9631ef45981db..c60f9d18de8fd 100644 --- a/browser/components/preferences/privacy.js +++ b/browser/components/preferences/privacy.js @@ -1925,13 +1925,15 @@ var gPrivacyPane = { * Initializes the address bar section. */ _initAddressBar() { - // Update the Firefox Suggest section on Nimbus changes. - this._updateFirefoxSuggestSection = this._updateFirefoxSuggestSection.bind( - this - ); - NimbusFeatures.urlbar.onUpdate(this._updateFirefoxSuggestSection); + // Update the Firefox Suggest section on Nimbus changes. Note that + // `onUpdate` passes the Nimbus feature name as its first arg but that is + // not the arg that `_updateFirefoxSuggestSection` expects, so we do not + // want to pass it on. + this._firefoxSuggestNimbusUpdate = () => + this._updateFirefoxSuggestSection(); + NimbusFeatures.urlbar.onUpdate(this._firefoxSuggestNimbusUpdate); window.addEventListener("unload", () => - NimbusFeatures.urlbar.off(this._updateFirefoxSuggestSection) + NimbusFeatures.urlbar.off(this._firefoxSuggestNimbusUpdate) ); // Set up the sponsored checkbox. When the main checkbox is checked, the diff --git a/browser/components/preferences/tests/browser_privacy_firefoxSuggest.js b/browser/components/preferences/tests/browser_privacy_firefoxSuggest.js index 64c62ef9d3206..17df667b205f5 100644 --- a/browser/components/preferences/tests/browser_privacy_firefoxSuggest.js +++ b/browser/components/preferences/tests/browser_privacy_firefoxSuggest.js @@ -53,7 +53,7 @@ add_task(async function() { await doVisibilityTest({ initialDefaultBranchValue: undefined, initialUserBranchValue: undefined, - initialExpectedVisibility: false, + initialExpectedVisibility: true, newDefaultBranchValue: false, newUserBranchValue: false, newExpectedVisibility: false, @@ -86,7 +86,7 @@ add_task(async function() { await doVisibilityTest({ initialDefaultBranchValue: undefined, initialUserBranchValue: undefined, - initialExpectedVisibility: false, + initialExpectedVisibility: true, newDefaultBranchValue: true, newUserBranchValue: undefined, newExpectedVisibility: true, @@ -97,7 +97,7 @@ add_task(async function() { await doVisibilityTest({ initialDefaultBranchValue: undefined, initialUserBranchValue: undefined, - initialExpectedVisibility: false, + initialExpectedVisibility: true, newDefaultBranchValue: undefined, newUserBranchValue: true, newExpectedVisibility: true, @@ -133,7 +133,7 @@ add_task(async function() { initialExpectedVisibility: false, newDefaultBranchValue: true, newUserBranchValue: undefined, - newExpectedVisibility: true, + newExpectedVisibility: false, }); }); diff --git a/browser/components/urlbar/UrlbarPrefs.jsm b/browser/components/urlbar/UrlbarPrefs.jsm index 23f175b2f342e..c42c70ff6ecd8 100644 --- a/browser/components/urlbar/UrlbarPrefs.jsm +++ b/browser/components/urlbar/UrlbarPrefs.jsm @@ -19,6 +19,7 @@ const { XPCOMUtils } = ChromeUtils.import( XPCOMUtils.defineLazyModuleGetters(this, { NimbusFeatures: "resource://nimbus/ExperimentAPI.jsm", + Region: "resource://gre/modules/Region.jsm", UrlbarUtils: "resource:///modules/UrlbarUtils.jsm", }); @@ -525,6 +526,38 @@ class Preferences { ); } + /** + * Depending on certain conditions [1], possibly enables on the default prefs + * branch the Firefox Suggest "offline" scenario, which means Firefox Suggest + * (quick suggest) will be fully enabled by default without showing onboarding + * and without sending data to Mozilla [2]. Users can opt out in the prefs UI, + * which will set overriding prefs on the user branch. Note that values set + * programatically on the default branch like this do not persist across app + * restarts, so this needs to be called on every startup until these pref + * values are codified in firefox.js. + * + * [1] Currently the conditions are: the user's home region must be US and + * their locale must be en-* + * + * [2] In contrast, the "online" scenario sends data to Mozilla and requires + * user opt-in via onboarding before Firefox Suggest is fully enabled. + */ + async maybeEnableOfflineQuickSuggest() { + // `Region.home` is null before init finishes, so await it. + await Region.init(); + if ( + Region.home == "US" && + Services.locale.appLocaleAsBCP47.substring(0, 2) == "en" + ) { + let prefs = Services.prefs.getDefaultBranch("browser.urlbar."); + prefs.setBoolPref("quicksuggest.enabled", true); + prefs.setCharPref("quicksuggest.scenario", "offline"); + prefs.setBoolPref("quicksuggest.shouldShowOnboardingDialog", false); + prefs.setBoolPref("suggest.quicksuggest", true); + prefs.setBoolPref("suggest.quicksuggest.sponsored", true); + } + } + /** * Adds a preference observer. Observers are held weakly. * diff --git a/browser/components/urlbar/UrlbarQuickSuggest.jsm b/browser/components/urlbar/UrlbarQuickSuggest.jsm index 18ee919b14dcc..dac0dfd922096 100644 --- a/browser/components/urlbar/UrlbarQuickSuggest.jsm +++ b/browser/components/urlbar/UrlbarQuickSuggest.jsm @@ -300,6 +300,33 @@ class Suggestions { * are saved locally. */ async _ensureAttachmentsDownloaded() { + // Make sure we don't re-enter this method, which can happen due to a cycle + // created by our remote settings sync listener as follows: + // + // Pref change -> onPrefChanged -> onEnabledUpdate -> _setupRemoteSettings + // -> _ensureAttachmentsDownloaded -> this._rs.get -> RemoteSettingsClient + // calls sync on itself -> RemoteSettingsClient emits a sync event -> + // _onSettingsSync -> _ensureAttachmentsDownloaded + // + // Because RemoteSettingsClient awaits when it emits its sync event, we get + // a deadlock in that call stack. Quick suggest will not be able to complete + // initialization and return suggestions until something else causes it to + // fetch the data again. Restarting the app also fixes it because it seems + // RemoteSettingsClient takes a different code path on initialization after + // restart, presumably because the data was successfully downloaded and + // cached before the deadlock. + if (this._ensureAttachmentsDownloadedRunning) { + return; + } + this._ensureAttachmentsDownloadedRunning = true; + try { + await this._ensureAttachmentsDownloadedHelper(); + } finally { + this._ensureAttachmentsDownloadedRunning = false; + } + } + + async _ensureAttachmentsDownloadedHelper() { log.info("_ensureAttachmentsDownloaded started"); let dataOpts = { useCache: true }; let data = await this._rs.get({ filters: { type: "data" } }); diff --git a/browser/components/urlbar/UrlbarView.jsm b/browser/components/urlbar/UrlbarView.jsm index 5824bcd561cf9..fd90ea75b3429 100644 --- a/browser/components/urlbar/UrlbarView.jsm +++ b/browser/components/urlbar/UrlbarView.jsm @@ -2171,7 +2171,7 @@ class UrlbarView { ); } - if (UrlbarPrefs.get("quicksuggest.enabled")) { + if (UrlbarPrefs.get("quickSuggestEnabled")) { idArgs.push({ id: "urlbar-result-action-sponsored" }); } diff --git a/browser/components/urlbar/tests/UrlbarTestUtils.jsm b/browser/components/urlbar/tests/UrlbarTestUtils.jsm index 8269f5c54dca9..a1e12f065b451 100644 --- a/browser/components/urlbar/tests/UrlbarTestUtils.jsm +++ b/browser/components/urlbar/tests/UrlbarTestUtils.jsm @@ -21,10 +21,12 @@ XPCOMUtils.defineLazyModuleGetters(this, { PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm", Services: "resource://gre/modules/Services.jsm", setTimeout: "resource://gre/modules/Timer.jsm", + sinon: "resource://testing-common/Sinon.jsm", TestUtils: "resource://testing-common/TestUtils.jsm", UrlbarController: "resource:///modules/UrlbarController.jsm", UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm", UrlbarProvider: "resource:///modules/UrlbarUtils.jsm", + UrlbarQuickSuggest: "resource:///modules/UrlbarQuickSuggest.jsm", UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.jsm", UrlbarUtils: "resource:///modules/UrlbarUtils.jsm", }); @@ -843,6 +845,33 @@ var UrlbarTestUtils = { }); return doExperimentCleanup; }, + + /** + * Waits for quick suggest initialization to finish, ensures its data will not + * be updated again during the test, and also optionally sets it up with mock + * data. + * + * @param {array} [data] + * Array of quick suggest data objects. If not given, then this function + * won't set up any mock data. + */ + async ensureQuickSuggestInit(data = null) { + this._testScope?.info("Awaiting UrlbarQuickSuggest.init"); + await UrlbarQuickSuggest.init(); + this._testScope?.info("Done awaiting UrlbarQuickSuggest.init"); + let sandbox = sinon.createSandbox(); + sandbox.stub(UrlbarQuickSuggest, "_ensureAttachmentsDownloadedHelper"); + this._testScope?.registerCleanupFunction(() => sandbox.restore()); + if (data) { + this._testScope?.info( + "Awaiting UrlbarQuickSuggest._processSuggestionsJSON" + ); + await UrlbarQuickSuggest._processSuggestionsJSON(data); + this._testScope?.info( + "Done awaiting UrlbarQuickSuggest._processSuggestionsJSON" + ); + } + }, }; UrlbarTestUtils.formHistory = { diff --git a/browser/components/urlbar/tests/browser/browser_quicksuggest.js b/browser/components/urlbar/tests/browser/browser_quicksuggest.js index 4277e5fc1c4e1..62247c029adef 100644 --- a/browser/components/urlbar/tests/browser/browser_quicksuggest.js +++ b/browser/components/urlbar/tests/browser/browser_quicksuggest.js @@ -57,41 +57,27 @@ async function assertNoQuickSuggestResults(win = window) { add_task(async function init() { await PlacesUtils.history.clear(); + await PlacesUtils.bookmarks.eraseEverything(); await UrlbarTestUtils.formHistory.clear(); - Services.prefs.clearUserPref(SEEN_DIALOG_PREF); - Services.prefs.clearUserPref("browser.urlbar.quicksuggest.seenRestarts"); - - let doExperimentCleanup = await UrlbarTestUtils.enrollExperiment({ - valueOverrides: { - quickSuggestEnabled: true, - quickSuggestShouldShowOnboardingDialog: true, - }, - }); - - await UrlbarQuickSuggest.init(); - await UrlbarQuickSuggest._processSuggestionsJSON(TEST_DATA); - let onEnabled = UrlbarQuickSuggest.onEnabledUpdate; - UrlbarQuickSuggest.onEnabledUpdate = () => {}; - - registerCleanupFunction(async function() { - await doExperimentCleanup(); - UrlbarQuickSuggest.onEnabledUpdate = onEnabled; - - // The onboarding test task causes prefs to be set, so clear them when done - // so we leave a blank slate for other tests. - UrlbarPrefs.clear("suggest.quicksuggest"); - UrlbarPrefs.clear("suggest.quicksuggest.sponsored"); - UrlbarPrefs.clear("quicksuggest.shouldShowOnboardingDialog"); - UrlbarPrefs.clear("quicksuggest.showedOnboardingDialog"); - UrlbarPrefs.clear("quicksuggest.seenRestarts"); - }); + await UrlbarTestUtils.ensureQuickSuggestInit(TEST_DATA); }); -// Tests the onboarding dialog. This task must run first because it fully -// enables the feature (both sponsored and non-sponsored suggestions) by virtue -// of showing the onboarding. add_task(async function test_onboarding() { + // Set up prefs so that onboarding will be shown. + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.urlbar.quicksuggest.shouldShowOnboardingDialog", true], + [ + "browser.urlbar.quicksuggest.quicksuggest.showedOnboardingDialog", + false, + ], + ["browser.urlbar.quicksuggest.seenRestarts", 0], + ["browser.urlbar.suggest.quicksuggest", false], + ["browser.urlbar.suggest.quicksuggest.sponsored", false], + ], + }); + await UrlbarTestUtils.promiseAutocompleteResultPopup({ window, value: "fra", @@ -119,6 +105,13 @@ add_task(async function test_onboarding() { info("Waiting for dialog and pref change"); await Promise.all([dialogPromise, prefPromise]); + + await SpecialPowers.popPrefEnv(); + + // Clear prefs that are set by virtue of showing and accepting the onboarding. + UrlbarPrefs.clear("quicksuggest.shouldShowOnboardingDialog"); + UrlbarPrefs.clear("quicksuggest.showedOnboardingDialog"); + UrlbarPrefs.clear("quicksuggest.seenRestarts"); }); // Tests a sponsored result and keyword highlighting. diff --git a/browser/components/urlbar/tests/browser/browser_quicksuggest_configuration.js b/browser/components/urlbar/tests/browser/browser_quicksuggest_configuration.js index 7144e3716c74b..840d0c7f20516 100644 --- a/browser/components/urlbar/tests/browser/browser_quicksuggest_configuration.js +++ b/browser/components/urlbar/tests/browser/browser_quicksuggest_configuration.js @@ -16,18 +16,27 @@ const SHOWED_ONBOARDING_DIALOG_PREF = const SEEN_RESTART_PREF = "browser.urlbar.quicksuggest.seenRestarts"; add_task(async function init() { - await UrlbarQuickSuggest.init(); - let onEnabled = UrlbarQuickSuggest.onEnabledUpdate; - UrlbarQuickSuggest.onEnabledUpdate = () => {}; - registerCleanupFunction(async function() { - UrlbarQuickSuggest.onEnabledUpdate = onEnabled; - }); + await UrlbarTestUtils.ensureQuickSuggestInit(); }); // The default is to wait for no browser restarts to show the onboarding dialog // on the first restart. This tests that we can override it by configuring the // `showOnboardingDialogOnNthRestart` add_task(async function test_override_wait_after_n_restarts() { + // Set up prefs so that onboarding will be shown. + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.urlbar.quicksuggest.shouldShowOnboardingDialog", true], + [ + "browser.urlbar.quicksuggest.quicksuggest.showedOnboardingDialog", + false, + ], + ["browser.urlbar.quicksuggest.seenRestarts", 0], + ["browser.urlbar.suggest.quicksuggest", false], + ["browser.urlbar.suggest.quicksuggest.sponsored", false], + ], + }); + await UrlbarTestUtils.withExperiment({ valueOverrides: { quickSuggestEnabled: true, @@ -58,6 +67,8 @@ add_task(async function test_override_wait_after_n_restarts() { await Promise.all([dialogPromise, prefPromise]); }, }); + + await SpecialPowers.popPrefEnv(); clearOnboardingPrefs(); }); diff --git a/browser/components/urlbar/tests/browser/browser_quicksuggest_indexes.js b/browser/components/urlbar/tests/browser/browser_quicksuggest_indexes.js index 48857e3b232df..ced6d73f433fb 100644 --- a/browser/components/urlbar/tests/browser/browser_quicksuggest_indexes.js +++ b/browser/components/urlbar/tests/browser/browser_quicksuggest_indexes.js @@ -65,24 +65,11 @@ add_task(async function init() { let oldDefaultEngine = await Services.search.getDefault(); await Services.search.setDefault(Services.search.getEngineByName("Example")); - await UrlbarQuickSuggest.init(); - let { _createTree } = UrlbarQuickSuggest; - UrlbarQuickSuggest._createTree = () => {}; - await UrlbarQuickSuggest._processSuggestionsJSON(TEST_DATA); - - await SpecialPowers.pushPrefEnv({ - set: [ - ["browser.urlbar.quicksuggest.enabled", true], - ["browser.urlbar.quicksuggest.shouldShowOnboardingDialog", false], - ["browser.urlbar.suggest.quicksuggest", true], - ["browser.urlbar.suggest.quicksuggest.sponsored", true], - ], - }); + await UrlbarTestUtils.ensureQuickSuggestInit(TEST_DATA); registerCleanupFunction(async () => { await PlacesUtils.history.clear(); Services.search.setDefault(oldDefaultEngine); - UrlbarQuickSuggest._createTree = _createTree; }); }); diff --git a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_quicksuggest.js b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_quicksuggest.js index 9bc419abfa14d..b2a81f297f4d4 100644 --- a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_quicksuggest.js +++ b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_quicksuggest.js @@ -57,17 +57,10 @@ add_task(async function init() { PartnerLinkAttribution._pingCentre, "sendStructuredIngestionPing" ); - sandbox.stub(UrlbarQuickSuggest, "_setupRemoteSettings").resolves(true); await PlacesUtils.history.clear(); + await PlacesUtils.bookmarks.eraseEverything(); await UrlbarTestUtils.formHistory.clear(); - await SpecialPowers.pushPrefEnv({ - set: [ - [EXPERIMENT_PREF, true], - ["browser.urlbar." + SUGGEST_PREF, true], - ["browser.urlbar.suggest.quicksuggest.sponsored", true], - ], - }); // Add a mock engine so we don't hit the network. await SearchTestUtils.installSearchExtension(); @@ -75,8 +68,7 @@ add_task(async function init() { Services.search.setDefault(Services.search.getEngineByName("Example")); // Set up Quick Suggest. - await UrlbarQuickSuggest.init(); - await UrlbarQuickSuggest._processSuggestionsJSON(TEST_DATA); + await UrlbarTestUtils.ensureQuickSuggestInit(TEST_DATA); UrlbarProviderQuickSuggest._helpUrl = TEST_HELP_URL; // Enable local telemetry recording for the duration of the test. diff --git a/browser/components/urlbar/tests/unit/test_quicksuggest.js b/browser/components/urlbar/tests/unit/test_quicksuggest.js index 8e088d9e13e51..a3609d78c57ae 100644 --- a/browser/components/urlbar/tests/unit/test_quicksuggest.js +++ b/browser/components/urlbar/tests/unit/test_quicksuggest.js @@ -90,9 +90,7 @@ add_task(async function init() { // Set up the remote settings client with the test data. Need to set the // `suggest.quicksuggest` pref to make `init` finish. UrlbarPrefs.set("suggest.quicksuggest", true); - await UrlbarQuickSuggest.init(); - await UrlbarQuickSuggest._processSuggestionsJSON(REMOTE_SETTINGS_DATA); - sinon.stub(UrlbarQuickSuggest, "onEnabledUpdate").get(() => {}); + await UrlbarTestUtils.ensureQuickSuggestInit(REMOTE_SETTINGS_DATA); }); // Tests with only non-sponsored suggestions enabled with a matching search diff --git a/browser/components/urlbar/tests/unit/test_quicksuggest_merino.js b/browser/components/urlbar/tests/unit/test_quicksuggest_merino.js index e506a2a4ab245..0bed029bddd67 100644 --- a/browser/components/urlbar/tests/unit/test_quicksuggest_merino.js +++ b/browser/components/urlbar/tests/unit/test_quicksuggest_merino.js @@ -48,9 +48,7 @@ add_task(async function init() { UrlbarPrefs.set(PREF_MERINO_ENDPOINT_URL, url.toString()); // Set up the remote settings client with the test data. - await UrlbarQuickSuggest.init(); - await UrlbarQuickSuggest._processSuggestionsJSON(REMOTE_SETTINGS_DATA); - UrlbarQuickSuggest.onEnabledUpdate = () => {}; + await UrlbarTestUtils.ensureQuickSuggestInit(REMOTE_SETTINGS_DATA); }); // Tests with Merino enabled and remote settings disabled. diff --git a/browser/components/urlbar/tests/unit/test_quicksuggest_offlineDefault.js b/browser/components/urlbar/tests/unit/test_quicksuggest_offlineDefault.js new file mode 100644 index 0000000000000..f64fa4105c4f6 --- /dev/null +++ b/browser/components/urlbar/tests/unit/test_quicksuggest_offlineDefault.js @@ -0,0 +1,154 @@ +/* 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 `UrlbarPrefs.maybeEnableOfflineQuickSuggest` in isolation. + +"use strict"; + +XPCOMUtils.defineLazyModuleGetters(this, { + Region: "resource://gre/modules/Region.jsm", +}); + +// All the prefs that `maybeEnableOfflineQuickSuggest` sets along with +// the expected default-branch values when offline is enabled and when it's not +// enabled. +const PREFS = [ + { + name: "browser.urlbar.quicksuggest.enabled", + get: "getBoolPref", + set: "setBoolPref", + expectedOfflineValue: true, + expectedOtherValue: false, + }, + { + name: "browser.urlbar.quicksuggest.scenario", + get: "getCharPref", + set: "setCharPref", + expectedOfflineValue: "offline", + expectedOtherValue: "history", + }, + { + name: "browser.urlbar.quicksuggest.shouldShowOnboardingDialog", + get: "getBoolPref", + set: "setBoolPref", + expectedOfflineValue: false, + expectedOtherValue: true, + }, + { + name: "browser.urlbar.suggest.quicksuggest", + get: "getBoolPref", + set: "setBoolPref", + expectedOfflineValue: true, + expectedOtherValue: false, + }, + { + name: "browser.urlbar.suggest.quicksuggest.sponsored", + get: "getBoolPref", + set: "setBoolPref", + expectedOfflineValue: true, + expectedOtherValue: false, + }, +]; + +add_task(async function test() { + let tests = [ + { locale: "en-US", home: "US", expectedOfflineDefault: true }, + { locale: "en-US", home: "CA", expectedOfflineDefault: false }, + { locale: "en-CA", home: "US", expectedOfflineDefault: true }, + { locale: "en-CA", home: "CA", expectedOfflineDefault: false }, + { locale: "en-GB", home: "US", expectedOfflineDefault: true }, + { locale: "en-GB", home: "GB", expectedOfflineDefault: false }, + { locale: "de", home: "US", expectedOfflineDefault: false }, + { locale: "de", home: "DE", expectedOfflineDefault: false }, + ]; + for (let { locale, home, expectedOfflineDefault } of tests) { + await doTest({ locale, home, expectedOfflineDefault }); + } +}); + +/** + * Sets the app's locale and region, calls + * `UrlbarPrefs.maybeEnableOfflineQuickSuggest`, and asserts that the pref + * values are correct. + * + * @param {string} options.locale + * The locale to simulate. + * @param {string} options.home + * The "home" region to simulate. + * @param {boolean} options.expectedOfflineDefault + * The expected value of whether offline should be enabled by default given + * the locale and region. + */ +async function doTest({ locale, home, expectedOfflineDefault }) { + // Setup: Clear any user values and save original default-branch values. + for (let pref of PREFS) { + Services.prefs.clearUserPref(pref.name); + pref.originalDefault = Services.prefs + .getDefaultBranch(pref.name) + [pref.get](""); + } + + // Set the region and locale, call the function, check the pref values. + Region._setHomeRegion(home, false); + await withLocales([locale], async () => { + await UrlbarPrefs.maybeEnableOfflineQuickSuggest(); + for (let { name, get, expectedOfflineValue, expectedOtherValue } of PREFS) { + let expectedValue = expectedOfflineDefault + ? expectedOfflineValue + : expectedOtherValue; + + // Check the default-branch value. + Assert.strictEqual( + Services.prefs.getDefaultBranch(name)[get](""), + expectedValue, + `Default pref value for ${name}, locale ${locale}, home ${home}` + ); + + // 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.replace("browser.urlbar.", ""), + expectedValue, + `UrlbarPrefs.get() value for ${name}, locale ${locale}, home ${home}` + ); + } + }); + + // Teardown: Restore original default-branch values for the next task. + for (let { name, originalDefault, set } of PREFS) { + if (originalDefault === undefined) { + Services.prefs.deleteBranch(name); + } else { + Services.prefs.getDefaultBranch(name)[set]("", originalDefault); + } + } +} + +/** + * Sets the app's locales, calls your callback, and resets locales. + * + * @param {array} locales + * An array of locale strings. The entire array will be set as the available + * locales, and the first locale in the array will be set as the requested + * locale. + * @param {function} callback + */ +async function withLocales(locales, callback) { + let available = Services.locale.availableLocales; + let requested = Services.locale.requestedLocales; + + Services.locale.availableLocales = locales; + Services.locale.requestedLocales = locales.slice(0, 1); + Assert.equal( + Services.locale.appLocaleAsBCP47, + locales[0], + "App locale is now " + locales[0] + ); + + await callback(); + + Services.locale.availableLocales = available; + Services.locale.requestedLocales = requested; +} diff --git a/browser/components/urlbar/tests/unit/xpcshell.ini b/browser/components/urlbar/tests/unit/xpcshell.ini index 01b4f62eb82af..0b7521c09021c 100644 --- a/browser/components/urlbar/tests/unit/xpcshell.ini +++ b/browser/components/urlbar/tests/unit/xpcshell.ini @@ -72,6 +72,7 @@ skip-if = !sync [test_quicksuggest.js] [test_quicksuggest_keywordtree.js] [test_quicksuggest_merino.js] +[test_quicksuggest_offlineDefault.js] [test_tokenizer.js] [test_trimming.js] [test_unitConversion.js]