tor-browser

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

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:
Mbrowser/extensions/newtab/lib/PrefsFeed.sys.mjs | 20++++++++++++--------
Mbrowser/extensions/newtab/test/unit/lib/PrefsFeed.test.js | 23+++++++++++++++++++++++
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 });