зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1730618 - Allow Nimbus to enable Firefox Suggest online and override the offline default. r=mythmon,preferences-reviewers,mstriemer
This reworks the fix to bug 1729776. Currently Nimbus doesn't have a way to force the two suggestions prefs [1] on or off. That might seem surprising since we've run experiments already. Initially we defaulted the two prefs to true but we defaulted the separate feature-gate pref [2] to false, and it was the feature-gate pref we controlled via Nimbus. At some point we changed the defaults to false and then in Firefox flipped them to true after showing the onboarding dialog. As a result we've never needed to override the two suggestion prefs via Nimbus. The problem now is that we default-enable offline (for US en users), so we set all three prefs to true. For the online rollout, we need to keep the feature-gate pref enabled but disable the suggestion prefs, and there's no way to do that. My first idea was to add new Nimbus variables to override the two suggestion prefs. The prefs would keep their default true values but be overridden by Nimbus. But that doesn't work because there's no way for Firefox to tell whether the prefs are true because the user has opted in (overriding Nimbus) or because they still have their default values. Setting the prefs to true on the user branch doesn't have any effect because they're also true on the default branch. Or maybe there's a way I don't know about to force them to true on the user branch, but even if there were, it seems brittle to rely on a value being set on the user branch to distinguish between the two cases. (This is a potential problem for any prefs that are controlled by both Nimbus and the user. So far the prefs we've been using via Nimbus have all been hidden feature-gate-type things and implementation details.) We already have a `quickSuggestScenario` variable. We currently use it only to tell what we should send in the telemetry ping (bug 1729576) and whether some parts of the prefs UI should be shown. This revision makes it much more important by treating it as the source of truth for the user's scenario. It now determines the default values of related prefs, including the two suggestions prefs. The logic is: ``` If quickSuggestScenario is non-null: scenario = quickSuggestScenario Else (e.g., there's no rollout): If the user is US en: scenario = offline Else: scenario = history ``` After determining the scenario, it's set it as `browser.urlbar.quicksuggest.scenario` on the default branch. There's an existing pref observer in UrlbarPrefs, and I added a case for this pref so that when it's updated we also update all the other prefs that depend on the scenario. This way when the pref is set -- either due to Nimbus update or by changing it on about:config -- all the other prefs stay in sync. I kept the default value of `browser.urlbar.quicksuggest.scenario` but removed it as the fallback for `quickSuggestScenario`. If it still both had a default and remained the fallback, then it would be impossible to tell when Nimbus is trying to override it, because any fetch of the value from Nimbus would just return the fallback pref's value if there is no override. I considered instead removing the default value and keeping it as the fallback. The drawback of that is that unenrollments would not take effect until restart. I actually tried this approach first, and in tests, after mock experiments were unenrolled, the pref values remained what they were when the experiment was active. It might also be possible to not have the `browser.urlbar.quicksuggest.scenario` pref at all. We could call NimbusFeatures directly to get the scenario. However, currently we cache and access Nimbus variables through UrlbarPrefs, as we do with prefs, and I don't want to add an inconsistency. This revision also fixes bug 1730596 since it was easy to do given that I needed a way to prevent indirect recursive updates to the scenario, and I can use that for bug 1730596 too (the `_updatingFirefoxSuggestScenario` bool). [1] `browser.urlbar.suggest.quicksuggest` and `browser.urlbar.suggest.quicksuggest.sponsored` [2] `browser.urlbar.quicksuggest.enabled` Differential Revision: https://phabricator.services.mozilla.com/D125511
This commit is contained in:
Родитель
42fc576ab9
Коммит
f0b457683b
|
@ -1650,7 +1650,7 @@ BrowserGlue.prototype = {
|
||||||
|
|
||||||
ProcessHangMonitor.init();
|
ProcessHangMonitor.init();
|
||||||
|
|
||||||
UrlbarPrefs.maybeEnableOfflineQuickSuggest();
|
UrlbarPrefs.updateFirefoxSuggestScenario();
|
||||||
|
|
||||||
// A channel for "remote troubleshooting" code...
|
// A channel for "remote troubleshooting" code...
|
||||||
let channel = new WebChannel(
|
let channel = new WebChannel(
|
||||||
|
|
|
@ -1925,16 +1925,21 @@ var gPrivacyPane = {
|
||||||
* Initializes the address bar section.
|
* Initializes the address bar section.
|
||||||
*/
|
*/
|
||||||
_initAddressBar() {
|
_initAddressBar() {
|
||||||
// Update the Firefox Suggest section on Nimbus changes. Note that
|
// Update the Firefox Suggest section when Firefox Suggest's enabled status
|
||||||
// `onUpdate` passes the Nimbus feature name as its first arg but that is
|
// or scenario changes.
|
||||||
// not the arg that `_updateFirefoxSuggestSection` expects, so we do not
|
this._urlbarPrefObserver = {
|
||||||
// want to pass it on.
|
onPrefChanged: pref => {
|
||||||
this._firefoxSuggestNimbusUpdate = () =>
|
if (["quicksuggest.enabled", "quicksuggest.scenario"].includes(pref)) {
|
||||||
this._updateFirefoxSuggestSection();
|
this._updateFirefoxSuggestSection();
|
||||||
NimbusFeatures.urlbar.onUpdate(this._firefoxSuggestNimbusUpdate);
|
}
|
||||||
window.addEventListener("unload", () =>
|
},
|
||||||
NimbusFeatures.urlbar.off(this._firefoxSuggestNimbusUpdate)
|
};
|
||||||
);
|
UrlbarPrefs.addObserver(this._urlbarPrefObserver);
|
||||||
|
window.addEventListener("unload", () => {
|
||||||
|
// UrlbarPrefs holds a weak reference to our observer, which is why we
|
||||||
|
// don't remove it on unload.
|
||||||
|
this._urlbarPrefObserver = null;
|
||||||
|
});
|
||||||
|
|
||||||
// Set up the sponsored checkbox. When the main checkbox is checked, the
|
// Set up the sponsored checkbox. When the main checkbox is checked, the
|
||||||
// sponsored checkbox should be enabled and its checked status should
|
// sponsored checkbox should be enabled and its checked status should
|
||||||
|
@ -1989,7 +1994,7 @@ var gPrivacyPane = {
|
||||||
// The main checkbox description discusses data collection, which we
|
// The main checkbox description discusses data collection, which we
|
||||||
// perform only in the "online" scenario. Hide it otherwise.
|
// perform only in the "online" scenario. Hide it otherwise.
|
||||||
document.getElementById("firefoxSuggestSuggestionDescription").hidden =
|
document.getElementById("firefoxSuggestSuggestionDescription").hidden =
|
||||||
UrlbarPrefs.get("quickSuggestScenario") != "online";
|
UrlbarPrefs.get("quicksuggest.scenario") != "online";
|
||||||
// Show the container.
|
// Show the container.
|
||||||
this._updateFirefoxSuggestSponsoredCheckbox();
|
this._updateFirefoxSuggestSponsoredCheckbox();
|
||||||
container.removeAttribute("hidden");
|
container.removeAttribute("hidden");
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This module exports the UrlbarPrefs singleton, which manages preferences for
|
* This module exports the UrlbarPrefs singleton, which manages preferences for
|
||||||
* the urlbar. It also provides access to urlbar Nimbus features as if they are
|
* the urlbar. It also provides access to urlbar Nimbus variables as if they are
|
||||||
* preferences.
|
* preferences, but only for variables with fallback prefs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var EXPORTED_SYMBOLS = ["UrlbarPrefs", "UrlbarPrefsObserver"];
|
var EXPORTED_SYMBOLS = ["UrlbarPrefs", "UrlbarPrefsObserver"];
|
||||||
|
@ -447,6 +447,7 @@ class Preferences {
|
||||||
"keyword.enabled",
|
"keyword.enabled",
|
||||||
"suggest.searches",
|
"suggest.searches",
|
||||||
];
|
];
|
||||||
|
this._updatingFirefoxSuggestScenario = false;
|
||||||
NimbusFeatures.urlbar.onUpdate(() => this._onNimbusUpdate());
|
NimbusFeatures.urlbar.onUpdate(() => this._onNimbusUpdate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,37 +528,130 @@ class Preferences {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Depending on certain conditions [1], possibly enables on the default prefs
|
* Sets the appropriate Firefox Suggest scenario based on the current Nimbus
|
||||||
* branch the Firefox Suggest "offline" scenario, which means Firefox Suggest
|
* rollout (if any) and "hardcoded" rollouts (if any). The possible scenarios
|
||||||
* (quick suggest) will be fully enabled by default without showing onboarding
|
* are:
|
||||||
* 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
|
* history
|
||||||
* their locale must be en-*
|
* This is the scenario when the user is not in any rollouts. Firefox
|
||||||
*
|
* Suggest suggestions are disabled.
|
||||||
* [2] In contrast, the "online" scenario sends data to Mozilla and requires
|
* offline
|
||||||
* user opt-in via onboarding before Firefox Suggest is fully enabled.
|
* This is the scenario for the "offline" rollout. Firefox Suggest
|
||||||
|
* suggestions are enabled by default. Search strings and matching keywords
|
||||||
|
* are not included in related telemetry. The onboarding dialog is not
|
||||||
|
* shown.
|
||||||
|
* online
|
||||||
|
* This is the scenario for the "online" rollout. The onboarding dialog will
|
||||||
|
* be shown and the user must opt in to enable Firefox Suggest suggestions
|
||||||
|
* and related telemetry, which will include search strings and matching
|
||||||
|
* keywords.
|
||||||
*/
|
*/
|
||||||
async maybeEnableOfflineQuickSuggest() {
|
async updateFirefoxSuggestScenario() {
|
||||||
// `Region.home` is null before init finishes, so await it.
|
// Make sure we don't re-enter this method while updating prefs. (Updates to
|
||||||
|
// prefs that are fallbacks for Nimbus variables trigger the pref observer
|
||||||
|
// in Nimbus, which triggers our Nimbus `onUpdate` callback, which calls
|
||||||
|
// this method again.) We also want to avoid event telemetry that's recorded
|
||||||
|
// on updates to the `suggest` prefs since that telemetry is intended to
|
||||||
|
// capture toggles made by the user on about:preferences.
|
||||||
|
if (this._updatingFirefoxSuggestScenario) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this._updatingFirefoxSuggestScenario = true;
|
||||||
|
await this._updateFirefoxSuggestScenarioHelper();
|
||||||
|
} finally {
|
||||||
|
this._updatingFirefoxSuggestScenario = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _updateFirefoxSuggestScenarioHelper() {
|
||||||
|
// We need to pick a scenario. If the user is in a Nimbus rollout, then
|
||||||
|
// Nimbus will define it. Otherwise the user may be in a "hardcoded" rollout
|
||||||
|
// depending on their region and locale. Finally, if the user is not in any
|
||||||
|
// rollouts, then the scenario is "history", which means no Firefox Suggest
|
||||||
|
// suggestions should appear.
|
||||||
|
//
|
||||||
|
// IMPORTANT: This relies on the `quickSuggestScenario` variable not having
|
||||||
|
// a `fallbackPref`. If it did, and if there were no Nimbus override, then
|
||||||
|
// Nimbus would just return the pref's value. The logic here would
|
||||||
|
// incorrectly assume that the user is in a Nimbus rollout when in fact it
|
||||||
|
// would only be fetching the pref value. You might think, But wait, I can
|
||||||
|
// define a fallback as long as there's no default value for it in
|
||||||
|
// firefox.js. That would work initially, but if the user is ever unenrolled
|
||||||
|
// from a Nimbus rollout, the default value set here would persist until
|
||||||
|
// restart, meaning Firefox would effectively ignore the unenrollment until
|
||||||
|
// then.
|
||||||
|
let scenario = this._nimbus.quickSuggestScenario;
|
||||||
|
if (!scenario) {
|
||||||
await Region.init();
|
await Region.init();
|
||||||
if (
|
if (
|
||||||
Region.home == "US" &&
|
Region.home == "US" &&
|
||||||
Services.locale.appLocaleAsBCP47.substring(0, 2) == "en"
|
Services.locale.appLocaleAsBCP47.substring(0, 2) == "en"
|
||||||
) {
|
) {
|
||||||
let prefs = Services.prefs.getDefaultBranch("browser.urlbar.");
|
// offline rollout for en locales in the US region
|
||||||
prefs.setBoolPref("quicksuggest.enabled", true);
|
scenario = "offline";
|
||||||
prefs.setCharPref("quicksuggest.scenario", "offline");
|
} else {
|
||||||
prefs.setBoolPref("quicksuggest.shouldShowOnboardingDialog", false);
|
// no rollout
|
||||||
prefs.setBoolPref("suggest.quicksuggest", true);
|
scenario = "history";
|
||||||
prefs.setBoolPref("suggest.quicksuggest.sponsored", true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let defaults = Services.prefs.getDefaultBranch("browser.urlbar.");
|
||||||
|
defaults.setCharPref("quicksuggest.scenario", scenario);
|
||||||
|
// At this point, `onPrefChange` fires for the `quicksuggest.scenario`
|
||||||
|
// change and it calls `_syncFirefoxSuggestPrefsFromScenario`.
|
||||||
|
}
|
||||||
|
|
||||||
|
_syncFirefoxSuggestPrefsFromScenario() {
|
||||||
|
// Note: Setting a pref that's listed as a fallback for a Nimbus variable
|
||||||
|
// will trigger the pref observer inside Nimbus and cause all
|
||||||
|
// `Nimbus.urlbar.onUpdate` callbacks to be called. Inside this class we
|
||||||
|
// guard against that by using `_updatingFirefoxSuggestScenario`, but keep
|
||||||
|
// it in mind.
|
||||||
|
|
||||||
|
let scenario = this.get("quicksuggest.scenario");
|
||||||
|
let defaults = Services.prefs.getDefaultBranch("browser.urlbar.");
|
||||||
|
|
||||||
|
let enabled = false;
|
||||||
|
switch (scenario) {
|
||||||
|
case "history":
|
||||||
|
defaults.setBoolPref("quicksuggest.shouldShowOnboardingDialog", true);
|
||||||
|
defaults.setBoolPref("suggest.quicksuggest", false);
|
||||||
|
defaults.setBoolPref("suggest.quicksuggest.sponsored", false);
|
||||||
|
break;
|
||||||
|
case "offline":
|
||||||
|
enabled = true;
|
||||||
|
defaults.setBoolPref("quicksuggest.shouldShowOnboardingDialog", false);
|
||||||
|
defaults.setBoolPref("suggest.quicksuggest", true);
|
||||||
|
defaults.setBoolPref("suggest.quicksuggest.sponsored", true);
|
||||||
|
break;
|
||||||
|
case "online":
|
||||||
|
enabled = true;
|
||||||
|
defaults.setBoolPref("quicksuggest.shouldShowOnboardingDialog", true);
|
||||||
|
defaults.setBoolPref("suggest.quicksuggest", false);
|
||||||
|
defaults.setBoolPref("suggest.quicksuggest.sponsored", false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Cu.reportError(`Unrecognized Firefox Suggest scenario "${scenario}"`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set `quicksuggest.enabled` last so that if any observers depend on it
|
||||||
|
// specifically, all prefs will have been updated when they're called.
|
||||||
|
defaults.setBoolPref("quicksuggest.enabled", enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {boolean}
|
||||||
|
* Whether the Firefox Suggest scenario is being updated. While true,
|
||||||
|
* changes to related prefs should be ignored, depending on the observer.
|
||||||
|
* Telemetry intended to capture user changes to the prefs should not be
|
||||||
|
* recorded, for example.
|
||||||
|
*/
|
||||||
|
get updatingFirefoxSuggestScenario() {
|
||||||
|
return this._updatingFirefoxSuggestScenario;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a preference observer. Observers are held weakly.
|
* Adds a preference observer. Observers are held weakly.
|
||||||
*
|
*
|
||||||
|
@ -608,6 +702,9 @@ class Preferences {
|
||||||
|
|
||||||
// Some prefs may influence others.
|
// Some prefs may influence others.
|
||||||
switch (pref) {
|
switch (pref) {
|
||||||
|
case "quicksuggest.scenario":
|
||||||
|
this._syncFirefoxSuggestPrefsFromScenario();
|
||||||
|
return;
|
||||||
case "showSearchSuggestionsFirst":
|
case "showSearchSuggestionsFirst":
|
||||||
this.set(
|
this.set(
|
||||||
"resultGroups",
|
"resultGroups",
|
||||||
|
@ -635,6 +732,8 @@ class Preferences {
|
||||||
this._map.delete(key);
|
this._map.delete(key);
|
||||||
}
|
}
|
||||||
this.__nimbus = null;
|
this.__nimbus = null;
|
||||||
|
|
||||||
|
this.updateFirefoxSuggestScenario();
|
||||||
}
|
}
|
||||||
|
|
||||||
get _nimbus() {
|
get _nimbus() {
|
||||||
|
|
|
@ -270,7 +270,7 @@ class ProviderQuickSuggest extends UrlbarProvider {
|
||||||
|
|
||||||
let searchQuery = "";
|
let searchQuery = "";
|
||||||
let matchedKeywords = "";
|
let matchedKeywords = "";
|
||||||
let scenario = UrlbarPrefs.get("quickSuggestScenario");
|
let scenario = UrlbarPrefs.get("quicksuggest.scenario");
|
||||||
// Only collect the search query and matched keywords for "online" scenario.
|
// Only collect the search query and matched keywords for "online" scenario.
|
||||||
// For other scenarios, those fields are set as empty strings.
|
// For other scenarios, those fields are set as empty strings.
|
||||||
if (scenario === "online") {
|
if (scenario === "online") {
|
||||||
|
@ -318,18 +318,22 @@ class ProviderQuickSuggest extends UrlbarProvider {
|
||||||
onPrefChanged(pref) {
|
onPrefChanged(pref) {
|
||||||
switch (pref) {
|
switch (pref) {
|
||||||
case "suggest.quicksuggest":
|
case "suggest.quicksuggest":
|
||||||
|
if (!UrlbarPrefs.updatingFirefoxSuggestScenario) {
|
||||||
Services.telemetry.recordEvent(
|
Services.telemetry.recordEvent(
|
||||||
TELEMETRY_EVENT_CATEGORY,
|
TELEMETRY_EVENT_CATEGORY,
|
||||||
"enable_toggled",
|
"enable_toggled",
|
||||||
UrlbarPrefs.get(pref) ? "enabled" : "disabled"
|
UrlbarPrefs.get(pref) ? "enabled" : "disabled"
|
||||||
);
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "suggest.quicksuggest.sponsored":
|
case "suggest.quicksuggest.sponsored":
|
||||||
|
if (!UrlbarPrefs.updatingFirefoxSuggestScenario) {
|
||||||
Services.telemetry.recordEvent(
|
Services.telemetry.recordEvent(
|
||||||
TELEMETRY_EVENT_CATEGORY,
|
TELEMETRY_EVENT_CATEGORY,
|
||||||
"sponsored_toggled",
|
"sponsored_toggled",
|
||||||
UrlbarPrefs.get(pref) ? "enabled" : "disabled"
|
UrlbarPrefs.get(pref) ? "enabled" : "disabled"
|
||||||
);
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,19 +31,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
||||||
});
|
});
|
||||||
|
|
||||||
// This must be kept in sync with FeatureManifest.js. UrlbarPrefs.get() will
|
|
||||||
// throw an "unknown pref" error if a test enrolls in a mock experiment and hits
|
|
||||||
// a code path that accesses a Nimbus feature variable not defined here.
|
|
||||||
const DEFAULT_EXPERIMENT_FEATURE_VARIABLES = {
|
|
||||||
merinoEnabled: false,
|
|
||||||
quickSuggestEnabled: false,
|
|
||||||
quickSuggestNonSponsoredIndex: -1,
|
|
||||||
quickSuggestScenario: "history",
|
|
||||||
quickSuggestShouldShowOnboardingDialog: true,
|
|
||||||
quickSuggestShowOnboardingDialogAfterNRestarts: 0,
|
|
||||||
quickSuggestSponsoredIndex: -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
var UrlbarTestUtils = {
|
var UrlbarTestUtils = {
|
||||||
/**
|
/**
|
||||||
* This maps the categories used by the FX_URLBAR_SELECTED_RESULT_METHOD and
|
* This maps the categories used by the FX_URLBAR_SELECTED_RESULT_METHOD and
|
||||||
|
@ -823,13 +810,7 @@ var UrlbarTestUtils = {
|
||||||
* Enrolls in a mock Nimbus experiment.
|
* Enrolls in a mock Nimbus experiment.
|
||||||
*
|
*
|
||||||
* @param {object} [valueOverrides]
|
* @param {object} [valueOverrides]
|
||||||
* Individual feature variables to override. By default, feature variables
|
* Values for feature variables.
|
||||||
* take their values from DEFAULT_EXPERIMENT_FEATURE_VARIABLES. Overridden
|
|
||||||
* by `recipe`.
|
|
||||||
* @param {object} [recipe]
|
|
||||||
* If given, this recipe is used as is.
|
|
||||||
* @param {string} [name]
|
|
||||||
* The name of the experiment.
|
|
||||||
* @returns {function}
|
* @returns {function}
|
||||||
* The experiment cleanup function (async).
|
* The experiment cleanup function (async).
|
||||||
*/
|
*/
|
||||||
|
@ -838,10 +819,7 @@ var UrlbarTestUtils = {
|
||||||
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
|
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
|
||||||
enabled: true,
|
enabled: true,
|
||||||
featureId: "urlbar",
|
featureId: "urlbar",
|
||||||
value: Object.assign(
|
value: valueOverrides,
|
||||||
DEFAULT_EXPERIMENT_FEATURE_VARIABLES,
|
|
||||||
valueOverrides
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
return doExperimentCleanup;
|
return doExperimentCleanup;
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,10 +11,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
UrlbarQuickSuggest: "resource:///modules/UrlbarQuickSuggest.jsm",
|
UrlbarQuickSuggest: "resource:///modules/UrlbarQuickSuggest.jsm",
|
||||||
});
|
});
|
||||||
|
|
||||||
const SHOWED_ONBOARDING_DIALOG_PREF =
|
|
||||||
"browser.urlbar.quicksuggest.showedOnboardingDialog";
|
|
||||||
const SEEN_RESTART_PREF = "browser.urlbar.quicksuggest.seenRestarts";
|
|
||||||
|
|
||||||
add_task(async function init() {
|
add_task(async function init() {
|
||||||
await UrlbarTestUtils.ensureQuickSuggestInit();
|
await UrlbarTestUtils.ensureQuickSuggestInit();
|
||||||
});
|
});
|
||||||
|
@ -23,24 +19,17 @@ add_task(async function init() {
|
||||||
// on the first restart. This tests that we can override it by configuring the
|
// on the first restart. This tests that we can override it by configuring the
|
||||||
// `showOnboardingDialogOnNthRestart`
|
// `showOnboardingDialogOnNthRestart`
|
||||||
add_task(async function test_override_wait_after_n_restarts() {
|
add_task(async function test_override_wait_after_n_restarts() {
|
||||||
// Set up prefs so that onboarding will be shown.
|
// Set up non-Nimbus prefs related to showing the onboarding.
|
||||||
await SpecialPowers.pushPrefEnv({
|
await SpecialPowers.pushPrefEnv({
|
||||||
set: [
|
set: [
|
||||||
["browser.urlbar.quicksuggest.shouldShowOnboardingDialog", true],
|
["browser.urlbar.quicksuggest.showedOnboardingDialog", false],
|
||||||
[
|
|
||||||
"browser.urlbar.quicksuggest.quicksuggest.showedOnboardingDialog",
|
|
||||||
false,
|
|
||||||
],
|
|
||||||
["browser.urlbar.quicksuggest.seenRestarts", 0],
|
["browser.urlbar.quicksuggest.seenRestarts", 0],
|
||||||
["browser.urlbar.suggest.quicksuggest", false],
|
|
||||||
["browser.urlbar.suggest.quicksuggest.sponsored", false],
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
await UrlbarTestUtils.withExperiment({
|
await UrlbarTestUtils.withExperiment({
|
||||||
valueOverrides: {
|
valueOverrides: {
|
||||||
quickSuggestEnabled: true,
|
quickSuggestScenario: "online",
|
||||||
quickSuggestShouldShowOnboardingDialog: true,
|
|
||||||
// Wait for 1 browser restart
|
// Wait for 1 browser restart
|
||||||
quickSuggestShowOnboardingDialogAfterNRestarts: 1,
|
quickSuggestShowOnboardingDialogAfterNRestarts: 1,
|
||||||
},
|
},
|
||||||
|
@ -51,7 +40,7 @@ add_task(async function test_override_wait_after_n_restarts() {
|
||||||
{ isSubDialog: true }
|
{ isSubDialog: true }
|
||||||
).then(() => info("Saw dialog"));
|
).then(() => info("Saw dialog"));
|
||||||
let prefPromise = TestUtils.waitForPrefChange(
|
let prefPromise = TestUtils.waitForPrefChange(
|
||||||
SHOWED_ONBOARDING_DIALOG_PREF,
|
"browser.urlbar.quicksuggest.showedOnboardingDialog",
|
||||||
value => value === true
|
value => value === true
|
||||||
).then(() => info("Saw pref change"));
|
).then(() => info("Saw pref change"));
|
||||||
|
|
||||||
|
@ -73,16 +62,16 @@ add_task(async function test_override_wait_after_n_restarts() {
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(async function test_skip_onboarding_dialog() {
|
add_task(async function test_skip_onboarding_dialog() {
|
||||||
|
// Set up non-Nimbus prefs related to showing the onboarding.
|
||||||
await SpecialPowers.pushPrefEnv({
|
await SpecialPowers.pushPrefEnv({
|
||||||
set: [
|
set: [
|
||||||
["browser.urlbar.suggest.quicksuggest", false],
|
["browser.urlbar.quicksuggest.showedOnboardingDialog", false],
|
||||||
[SHOWED_ONBOARDING_DIALOG_PREF, false],
|
["browser.urlbar.quicksuggest.seenRestarts", 0],
|
||||||
[SEEN_RESTART_PREF, 0],
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
await UrlbarTestUtils.withExperiment({
|
await UrlbarTestUtils.withExperiment({
|
||||||
valueOverrides: {
|
valueOverrides: {
|
||||||
quickSuggestEnabled: true,
|
quickSuggestScenario: "online",
|
||||||
quickSuggestShouldShowOnboardingDialog: false,
|
quickSuggestShouldShowOnboardingDialog: false,
|
||||||
},
|
},
|
||||||
callback: async () => {
|
callback: async () => {
|
||||||
|
@ -92,7 +81,9 @@ add_task(async function test_skip_onboarding_dialog() {
|
||||||
await UrlbarQuickSuggest.maybeShowOnboardingDialog();
|
await UrlbarQuickSuggest.maybeShowOnboardingDialog();
|
||||||
}
|
}
|
||||||
Assert.ok(
|
Assert.ok(
|
||||||
!Services.prefs.getBoolPref(SHOWED_ONBOARDING_DIALOG_PREF),
|
!Services.prefs.getBoolPref(
|
||||||
|
"browser.urlbar.quicksuggest.showedOnboardingDialog"
|
||||||
|
),
|
||||||
"The showed onboarding dialog pref should not be set"
|
"The showed onboarding dialog pref should not be set"
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -151,11 +142,44 @@ add_task(async function test_scenario_online() {
|
||||||
quickSuggestScenario: "online",
|
quickSuggestScenario: "online",
|
||||||
},
|
},
|
||||||
callback: () => {
|
callback: () => {
|
||||||
Assert.equal(
|
assertScenarioPrefs({
|
||||||
UrlbarPrefs.get("quickSuggestScenario"),
|
urlbarPrefs: {
|
||||||
"online",
|
// prefs
|
||||||
"quickSuggestScenario online"
|
"quicksuggest.scenario": "online",
|
||||||
);
|
"quicksuggest.enabled": true,
|
||||||
|
"quicksuggest.shouldShowOnboardingDialog": true,
|
||||||
|
"suggest.quicksuggest": false,
|
||||||
|
"suggest.quicksuggest.sponsored": false,
|
||||||
|
|
||||||
|
// Nimbus variables
|
||||||
|
quickSuggestScenario: "online",
|
||||||
|
quickSuggestEnabled: true,
|
||||||
|
quickSuggestShouldShowOnboardingDialog: true,
|
||||||
|
},
|
||||||
|
defaults: [
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.quicksuggest.scenario",
|
||||||
|
value: "online",
|
||||||
|
getter: "getCharPref",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.quicksuggest.enabled",
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.quicksuggest.shouldShowOnboardingDialog",
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.suggest.quicksuggest",
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.suggest.quicksuggest.sponsored",
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -166,11 +190,44 @@ add_task(async function test_scenario_offline() {
|
||||||
quickSuggestScenario: "offline",
|
quickSuggestScenario: "offline",
|
||||||
},
|
},
|
||||||
callback: () => {
|
callback: () => {
|
||||||
Assert.equal(
|
assertScenarioPrefs({
|
||||||
UrlbarPrefs.get("quickSuggestScenario"),
|
urlbarPrefs: {
|
||||||
"offline",
|
// prefs
|
||||||
"quickSuggestScenario offline"
|
"quicksuggest.scenario": "offline",
|
||||||
);
|
"quicksuggest.enabled": true,
|
||||||
|
"quicksuggest.shouldShowOnboardingDialog": false,
|
||||||
|
"suggest.quicksuggest": true,
|
||||||
|
"suggest.quicksuggest.sponsored": true,
|
||||||
|
|
||||||
|
// Nimbus variables
|
||||||
|
quickSuggestScenario: "offline",
|
||||||
|
quickSuggestEnabled: true,
|
||||||
|
quickSuggestShouldShowOnboardingDialog: false,
|
||||||
|
},
|
||||||
|
defaults: [
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.quicksuggest.scenario",
|
||||||
|
value: "offline",
|
||||||
|
getter: "getCharPref",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.quicksuggest.enabled",
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.quicksuggest.shouldShowOnboardingDialog",
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.suggest.quicksuggest",
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.suggest.quicksuggest.sponsored",
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -181,15 +238,63 @@ add_task(async function test_scenario_history() {
|
||||||
quickSuggestScenario: "history",
|
quickSuggestScenario: "history",
|
||||||
},
|
},
|
||||||
callback: () => {
|
callback: () => {
|
||||||
Assert.equal(
|
assertScenarioPrefs({
|
||||||
UrlbarPrefs.get("quickSuggestScenario"),
|
urlbarPrefs: {
|
||||||
"history",
|
// prefs
|
||||||
"quickSuggestScenario history"
|
"quicksuggest.scenario": "history",
|
||||||
);
|
"quicksuggest.enabled": false,
|
||||||
|
"quicksuggest.shouldShowOnboardingDialog": true,
|
||||||
|
"suggest.quicksuggest": false,
|
||||||
|
"suggest.quicksuggest.sponsored": false,
|
||||||
|
|
||||||
|
// Nimbus variables
|
||||||
|
quickSuggestScenario: "history",
|
||||||
|
quickSuggestEnabled: false,
|
||||||
|
quickSuggestShouldShowOnboardingDialog: true,
|
||||||
|
},
|
||||||
|
defaults: [
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.quicksuggest.scenario",
|
||||||
|
value: "history",
|
||||||
|
getter: "getCharPref",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.quicksuggest.enabled",
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.quicksuggest.shouldShowOnboardingDialog",
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.suggest.quicksuggest",
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "browser.urlbar.suggest.quicksuggest.sponsored",
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function assertScenarioPrefs({ urlbarPrefs, defaults }) {
|
||||||
|
for (let [name, value] of Object.entries(urlbarPrefs)) {
|
||||||
|
Assert.equal(UrlbarPrefs.get(name), value, `UrlbarPrefs.get("${name}")`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let prefs = Services.prefs.getDefaultBranch("");
|
||||||
|
for (let { name, getter, value } of defaults) {
|
||||||
|
Assert.equal(
|
||||||
|
prefs[getter || "getBoolPref"](name),
|
||||||
|
value,
|
||||||
|
`Default branch pref: ${name}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function clearOnboardingPrefs() {
|
function clearOnboardingPrefs() {
|
||||||
UrlbarPrefs.clear("suggest.quicksuggest");
|
UrlbarPrefs.clear("suggest.quicksuggest");
|
||||||
UrlbarPrefs.clear("suggest.quicksuggest.sponsored");
|
UrlbarPrefs.clear("suggest.quicksuggest.sponsored");
|
||||||
|
|
|
@ -46,7 +46,7 @@ const TELEMETRY_EVENT_CATEGORY = "contextservices.quicksuggest";
|
||||||
const EXPERIMENT_PREF = "browser.urlbar.quicksuggest.enabled";
|
const EXPERIMENT_PREF = "browser.urlbar.quicksuggest.enabled";
|
||||||
const SUGGEST_PREF = "suggest.quicksuggest";
|
const SUGGEST_PREF = "suggest.quicksuggest";
|
||||||
|
|
||||||
const DEFAULT_SCENARIO = UrlbarPrefs.get("quickSuggestScenario");
|
const DEFAULT_SCENARIO = UrlbarPrefs.get("quicksuggest.scenario");
|
||||||
|
|
||||||
// Spy for the custom impression/click sender
|
// Spy for the custom impression/click sender
|
||||||
let spy;
|
let spy;
|
||||||
|
@ -111,11 +111,12 @@ add_task(async function impression_online() {
|
||||||
// Make sure Merino is disabled so we don't hit the network.
|
// Make sure Merino is disabled so we don't hit the network.
|
||||||
merinoEnabled: false,
|
merinoEnabled: false,
|
||||||
quickSuggestScenario: "online",
|
quickSuggestScenario: "online",
|
||||||
quickSuggestEnabled: true,
|
|
||||||
quickSuggestShouldShowOnboardingDialog: false,
|
quickSuggestShouldShowOnboardingDialog: false,
|
||||||
},
|
},
|
||||||
callback: async () => {
|
callback: async () => {
|
||||||
spy.resetHistory();
|
spy.resetHistory();
|
||||||
|
UrlbarPrefs.set("suggest.quicksuggest", true);
|
||||||
|
UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
|
||||||
await BrowserTestUtils.withNewTab("about:blank", async () => {
|
await BrowserTestUtils.withNewTab("about:blank", async () => {
|
||||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||||
window,
|
window,
|
||||||
|
@ -473,6 +474,57 @@ add_task(async function nimbusExposure() {
|
||||||
await doExperimentCleanup();
|
await doExperimentCleanup();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The contextservices.quicksuggest enable_toggled and sponsored_toggled events
|
||||||
|
// should not be recorded when the scenario changes.
|
||||||
|
add_task(async function updateScenarioNoEvents() {
|
||||||
|
// Make sure the prefs don't have user values that would mask the default
|
||||||
|
// values set below.
|
||||||
|
UrlbarPrefs.clear("quicksuggest.scenario");
|
||||||
|
UrlbarPrefs.clear("suggest.quicksuggest");
|
||||||
|
UrlbarPrefs.clear("suggest.quicksuggest.sponsored");
|
||||||
|
Services.telemetry.clearEvents();
|
||||||
|
|
||||||
|
// check initial defaults
|
||||||
|
let defaults = Services.prefs.getDefaultBranch("browser.urlbar.");
|
||||||
|
Assert.equal(
|
||||||
|
defaults.getCharPref("quicksuggest.scenario"),
|
||||||
|
"offline",
|
||||||
|
"Default scenario is offline initially"
|
||||||
|
);
|
||||||
|
Assert.ok(
|
||||||
|
defaults.getBoolPref("suggest.quicksuggest"),
|
||||||
|
"suggest.quicksuggest is true initially"
|
||||||
|
);
|
||||||
|
Assert.ok(
|
||||||
|
defaults.getBoolPref("suggest.quicksuggest.sponsored"),
|
||||||
|
"suggest.quicksuggest.sponsored is true initially"
|
||||||
|
);
|
||||||
|
|
||||||
|
// set online
|
||||||
|
defaults.setCharPref("quicksuggest.scenario", "online");
|
||||||
|
Assert.ok(
|
||||||
|
!defaults.getBoolPref("suggest.quicksuggest"),
|
||||||
|
"suggest.quicksuggest is false after setting online scenario"
|
||||||
|
);
|
||||||
|
Assert.ok(
|
||||||
|
!defaults.getBoolPref("suggest.quicksuggest.sponsored"),
|
||||||
|
"suggest.quicksuggest.sponsored is false after setting online scenario"
|
||||||
|
);
|
||||||
|
TelemetryTestUtils.assertEvents([]);
|
||||||
|
|
||||||
|
// set back to offline
|
||||||
|
defaults.setCharPref("quicksuggest.scenario", "offline");
|
||||||
|
Assert.ok(
|
||||||
|
defaults.getBoolPref("suggest.quicksuggest"),
|
||||||
|
"suggest.quicksuggest is true after setting offline again"
|
||||||
|
);
|
||||||
|
Assert.ok(
|
||||||
|
defaults.getBoolPref("suggest.quicksuggest.sponsored"),
|
||||||
|
"suggest.quicksuggest.sponsored is true after setting offline again"
|
||||||
|
);
|
||||||
|
TelemetryTestUtils.assertEvents([]);
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the values of all the Quick Suggest scalars.
|
* Checks the values of all the Quick Suggest scalars.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
// Tests `UrlbarPrefs.maybeEnableOfflineQuickSuggest` in isolation.
|
// Tests `UrlbarPrefs.updateFirefoxSuggestScenario` in isolation under the
|
||||||
|
// assumption that the offline scenario should be enabled by default for US en.
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
@ -10,8 +11,8 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
Region: "resource://gre/modules/Region.jsm",
|
Region: "resource://gre/modules/Region.jsm",
|
||||||
});
|
});
|
||||||
|
|
||||||
// All the prefs that `maybeEnableOfflineQuickSuggest` sets along with
|
// All the prefs that `updateFirefoxSuggestScenario` sets along with the
|
||||||
// the expected default-branch values when offline is enabled and when it's not
|
// expected default-branch values when offline is enabled and when it's not
|
||||||
// enabled.
|
// enabled.
|
||||||
const PREFS = [
|
const PREFS = [
|
||||||
{
|
{
|
||||||
|
@ -69,8 +70,8 @@ add_task(async function test() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the app's locale and region, calls
|
* Sets the app's locale and region, calls
|
||||||
* `UrlbarPrefs.maybeEnableOfflineQuickSuggest`, and asserts that the pref
|
* `UrlbarPrefs.updateFirefoxSuggestScenario`, and asserts that the pref values
|
||||||
* values are correct.
|
* are correct.
|
||||||
*
|
*
|
||||||
* @param {string} options.locale
|
* @param {string} options.locale
|
||||||
* The locale to simulate.
|
* The locale to simulate.
|
||||||
|
@ -92,7 +93,7 @@ async function doTest({ locale, home, expectedOfflineDefault }) {
|
||||||
// Set the region and locale, call the function, check the pref values.
|
// Set the region and locale, call the function, check the pref values.
|
||||||
Region._setHomeRegion(home, false);
|
Region._setHomeRegion(home, false);
|
||||||
await withLocales([locale], async () => {
|
await withLocales([locale], async () => {
|
||||||
await UrlbarPrefs.maybeEnableOfflineQuickSuggest();
|
await UrlbarPrefs.updateFirefoxSuggestScenario();
|
||||||
for (let { name, get, expectedOfflineValue, expectedOtherValue } of PREFS) {
|
for (let { name, get, expectedOfflineValue, expectedOtherValue } of PREFS) {
|
||||||
let expectedValue = expectedOfflineDefault
|
let expectedValue = expectedOfflineDefault
|
||||||
? expectedOfflineValue
|
? expectedOfflineValue
|
||||||
|
|
|
@ -38,8 +38,8 @@ const FeatureManifest = {
|
||||||
"Whether Remote Settings is enabled as a quick suggest source",
|
"Whether Remote Settings is enabled as a quick suggest source",
|
||||||
},
|
},
|
||||||
quickSuggestScenario: {
|
quickSuggestScenario: {
|
||||||
|
// IMPORTANT: This should not have a fallbackPref. See UrlbarPrefs.jsm.
|
||||||
type: "string",
|
type: "string",
|
||||||
fallbackPref: "browser.urlbar.quicksuggest.scenario",
|
|
||||||
description:
|
description:
|
||||||
"The Firefox Suggest scenario in which the user is enrolled",
|
"The Firefox Suggest scenario in which the user is enrolled",
|
||||||
enum: ["history", "offline", "online"],
|
enum: ["history", "offline", "online"],
|
||||||
|
|
Загрузка…
Ссылка в новой задаче