commit e692405da5787b7885238dd70fa07d1772e8c949
parent 0a13b56b7140c1e5577fe59f4d9ea160cf9931e6
Author: Nathan Barrett <nbarrett@mozilla.com>
Date: Fri, 12 Dec 2025 16:00:48 +0000
Bug 2005622 - Fetch trainhop config during startup in PrefsFeed r=mconley,home-newtab-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D276087
Diffstat:
2 files changed, 35 insertions(+), 8 deletions(-)
diff --git a/browser/extensions/newtab/lib/PrefsFeed.sys.mjs b/browser/extensions/newtab/lib/PrefsFeed.sys.mjs
@@ -101,13 +101,13 @@ export class PrefsFeed {
}
/**
- * Handler for when experiment data updates.
+ * Computes the trainhop config by processing all enrollments.
* Supports two formats:
* - Single payload: { type: "feature", payload: { "enabled": true, ... }}
* - Multi-payload: { type: "multi-payload", payload: [{ type: "feature", payload: { "enabled": true, ... }}] }
* Both formats output the same structure: { "feature": { "enabled": true, ... }}
*/
- onTrainhopExperimentUpdated() {
+ _getTrainhopConfig() {
const allEnrollments =
lazy.NimbusFeatures.newtabTrainhop.getAllEnrollments() || [];
@@ -134,12 +134,6 @@ export class PrefsFeed {
}
});
- // Combine all trainhop experiments keyed by type.
- // Rules for duplicates:
- // - Experiments take precedence over rollouts (this is expected).
- // - If multiple experiments or multiple rollouts exist for the same type,
- // only the first is kept. This is nondeterministic and considered an error;
- // those experiments/rollouts should be relaunched.
const valueObj = {};
enrollmentsToProcess.reduce((accumulator, currentValue) => {
if (currentValue?.value?.type) {
@@ -155,6 +149,15 @@ export class PrefsFeed {
return accumulator;
}, {});
+ return valueObj;
+ }
+
+ /**
+ * Handler for when experiment data updates.
+ */
+ onTrainhopExperimentUpdated() {
+ const valueObj = this._getTrainhopConfig();
+
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
@@ -336,6 +339,7 @@ export class PrefsFeed {
lazy.NimbusFeatures.newtabSmartShortcuts.getAllVariables() || {};
values.widgetsConfig =
lazy.NimbusFeatures.newtabWidgets.getAllVariables() || {};
+ values.trainhopConfig = this._getTrainhopConfig();
this._setBoolPref(values, "logowordmark.alwaysVisible", false);
this._setBoolPref(values, "feeds.section.topstories", false);
this._setBoolPref(values, "discoverystream.enabled", false);
diff --git a/browser/extensions/newtab/test/unit/lib/PrefsFeed.test.js b/browser/extensions/newtab/test/unit/lib/PrefsFeed.test.js
@@ -90,6 +90,29 @@ describe("PrefsFeed", () => {
const [{ data }] = feed.store.dispatch.firstCall.args;
assert.deepEqual(data.featureConfig, { prefsButtonIcon: "icon-foo" });
});
+ it("should dispatch PREFS_INITIAL_VALUES with trainhopConfig", () => {
+ const testObject = {
+ meta: { isRollout: false },
+ value: {
+ type: "testExperiment",
+ payload: { enabled: true },
+ },
+ };
+ sandbox
+ .stub(global.NimbusFeatures.newtabTrainhop, "getAllEnrollments")
+ .returns([testObject]);
+
+ feed.onAction({ type: at.INIT });
+
+ assert.equal(
+ feed.store.dispatch.firstCall.args[0].type,
+ at.PREFS_INITIAL_VALUES
+ );
+ const [{ data }] = feed.store.dispatch.firstCall.args;
+ assert.deepEqual(data.trainhopConfig, {
+ testExperiment: { enabled: true },
+ });
+ });
it("should dispatch PREFS_INITIAL_VALUES with an empty object if no experiment is returned", () => {
sandbox.stub(global.NimbusFeatures.newtab, "getAllVariables").returns(null);
feed.onAction({ type: at.INIT });