diff --git a/system-addon/lib/ActivityStream.jsm b/system-addon/lib/ActivityStream.jsm index c220b926b..e405a47c4 100644 --- a/system-addon/lib/ActivityStream.jsm +++ b/system-addon/lib/ActivityStream.jsm @@ -19,83 +19,75 @@ const {TopSitesFeed} = Cu.import("resource://activity-stream/lib/TopSitesFeed.js const REASON_ADDON_UNINSTALL = 6; -const PREFS_CONFIG = [ - { - name: "default.sites", +const PREFS_CONFIG = new Map([ + ["default.sites", { title: "Comma-separated list of default top sites to fill in behind visited sites", value: "https://www.facebook.com/,https://www.youtube.com/,https://www.amazon.com/,https://www.yahoo.com/,https://www.ebay.com/,https://twitter.com/" - }, - // When you add a feed pref here: - // 1. The pref should be prefixed with "feeds." - // 2. The init property should be a function that instantiates your Feed - { - name: "feeds.localization", - title: "Initialize strings and detect locale for Activity Stream", - value: true, - init: () => new LocalizationFeed() - }, - { - name: "feeds.newtabinit", - title: "Sends a copy of the state to each new tab that is opened", - value: true, - init: () => new NewTabInit() - }, - { - name: "feeds.places", - title: "Listens for and relays various Places-related events", - value: true, - init: () => new PlacesFeed() - }, - { - name: "feeds.prefs", - title: "Preferences", - value: true, - init: () => new PrefsFeed(PREFS_CONFIG.map(pref => pref.name)) - }, - { - name: "feeds.telemetry", - title: "Relays telemetry-related actions to TelemetrySender", - value: true, - init: () => new TelemetryFeed() - }, - { - name: "feeds.topsites", - title: "Queries places and gets metadata for Top Sites section", - value: true, - init: () => new TopSitesFeed() - }, - { - name: "showSearch", + }], + ["showSearch", { title: "Show the Search bar on the New Tab page", value: true + }], + ["showTopSites", { + title: "Show the Top Sites section on the New Tab page", + value: true + }], + ["telemetry", { + title: "Enable system error and usage data collection", + value: false + }], + ["telemetry.log", { + title: "Log telemetry events in the console", + value: false + }], + ["telemetry.ping.endpoint", { + title: "Telemetry server endpoint", + value: "https://tiles.services.mozilla.com/v3/links/activity-stream" + }] +]); + +const FEEDS_CONFIG = new Map(); +for (const {name, factory, title, value} of [ + { + name: "localization", + factory: () => new LocalizationFeed(), + title: "Initialize strings and detect locale for Activity Stream", + value: true }, { - name: "showTopSites", - title: "Show the Top Sites section on the New Tab page", + name: "newtabinit", + factory: () => new NewTabInit(), + title: "Sends a copy of the state to each new tab that is opened", + value: true + }, + { + name: "places", + factory: () => new PlacesFeed(), + title: "Listens for and relays various Places-related events", + value: true + }, + { + name: "prefs", + factory: () => new PrefsFeed(PREFS_CONFIG), + title: "Preferences", value: true }, { name: "telemetry", - title: "Enable system error and usage data collection", - value: false + factory: () => new TelemetryFeed(), + title: "Relays telemetry-related actions to TelemetrySender", + value: true }, { - name: "telemetry.log", - title: "Log telemetry events in the console", - value: false - }, - { - name: "telemetry.ping.endpoint", - title: "Telemetry server endpoint", - value: "https://tiles.services.mozilla.com/v3/links/activity-stream" - } -]; - -const feeds = {}; -for (const pref of PREFS_CONFIG) { - if (pref.name.startsWith("feeds.")) { - feeds[pref.name] = pref.init; + name: "topsites", + factory: () => new TopSitesFeed(), + title: "Queries places and gets metadata for Top Sites section", + value: true } +]) { + const pref = `feeds.${name}`; + FEEDS_CONFIG.set(pref, factory); + PREFS_CONFIG.set(pref, {title, value}); } this.ActivityStream = class ActivityStream { @@ -112,7 +104,7 @@ this.ActivityStream = class ActivityStream { this.initialized = false; this.options = options; this.store = new Store(); - this.feeds = feeds; + this.feeds = FEEDS_CONFIG; this._defaultPrefs = new DefaultPrefs(PREFS_CONFIG); } init() { diff --git a/system-addon/lib/ActivityStreamPrefs.jsm b/system-addon/lib/ActivityStreamPrefs.jsm index f5dcba529..3cd8a29b0 100644 --- a/system-addon/lib/ActivityStreamPrefs.jsm +++ b/system-addon/lib/ActivityStreamPrefs.jsm @@ -18,10 +18,23 @@ this.Prefs = class Prefs extends Preferences { constructor(branch = ACTIVITY_STREAM_PREF_BRANCH) { super({branch}); this._branchName = branch; + this._branchObservers = new Map(); } get branchName() { return this._branchName; } + ignoreBranch(listener) { + const observer = this._branchObservers.get(listener); + this._prefBranch.removeObserver(this._branchName, observer); + this._branchObservers.delete(listener); + } + observeBranch(listener) { + const observer = (subject, topic, pref) => { + listener.onPrefChanged(pref, this.get(pref)); + }; + this._prefBranch.addObserver("", observer); + this._branchObservers.set(listener, observer); + } }; this.DefaultPrefs = class DefaultPrefs { @@ -29,8 +42,8 @@ this.DefaultPrefs = class DefaultPrefs { /** * DefaultPrefs - A helper for setting and resetting default prefs for the add-on * - * @param {Array} config An array of configuration objects with the following properties: - * {string} .name The name of the pref + * @param {Map} config A Map with {string} key of the pref name and {object} + * value with the following pref properties: * {string} .title (optional) A description of the pref * {bool|string|number} .value The default value for the pref * @param {string} branch (optional) The pref branch (defaults to ACTIVITY_STREAM_PREF_BRANCH) @@ -64,8 +77,8 @@ this.DefaultPrefs = class DefaultPrefs { * init - Set default prefs for all prefs in the config */ init() { - for (const pref of this._config) { - this._setDefaultPref(pref.name, pref.value); + for (const pref of this._config.keys()) { + this._setDefaultPref(pref, this._config.get(pref).value); } } @@ -73,8 +86,8 @@ this.DefaultPrefs = class DefaultPrefs { * reset - Resets all user-defined prefs for prefs in ._config to their defaults */ reset() { - for (const pref of this._config) { - this.branch.clearUserPref(pref.name); + for (const name of this._config.keys()) { + this.branch.clearUserPref(name); } } }; diff --git a/system-addon/lib/PrefsFeed.jsm b/system-addon/lib/PrefsFeed.jsm index f0c0beb3a..640bd9c23 100644 --- a/system-addon/lib/PrefsFeed.jsm +++ b/system-addon/lib/PrefsFeed.jsm @@ -9,24 +9,21 @@ const {actionCreators: ac, actionTypes: at} = Cu.import("resource://activity-str const {Prefs} = Cu.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm", {}); this.PrefsFeed = class PrefsFeed { - constructor(prefNames) { - this._prefNames = prefNames; + constructor(prefMap) { + this._prefMap = prefMap; this._prefs = new Prefs(); - this._observers = new Map(); } onPrefChanged(name, value) { - this.store.dispatch(ac.BroadcastToContent({type: at.PREF_CHANGED, data: {name, value}})); + if (this._prefMap.has(name)) { + this.store.dispatch(ac.BroadcastToContent({type: at.PREF_CHANGED, data: {name, value}})); + } } init() { - const values = {}; + this._prefs.observeBranch(this); - // Set up listeners for each activity stream pref - for (const name of this._prefNames) { - const handler = value => { - this.onPrefChanged(name, value); - }; - this._observers.set(name, handler, this); - this._prefs.observe(name, handler); + // Get the initial value of each activity stream pref + const values = {}; + for (const name of this._prefMap.keys()) { values[name] = this._prefs.get(name); } @@ -34,10 +31,7 @@ this.PrefsFeed = class PrefsFeed { this.store.dispatch(ac.BroadcastToContent({type: at.PREFS_INITIAL_VALUES, data: values})); } removeListeners() { - for (const name of this._prefNames) { - this._prefs.ignore(name, this._observers.get(name)); - } - this._observers.clear(); + this._prefs.ignoreBranch(this); } onAction(action) { switch (action.type) { diff --git a/system-addon/lib/Store.jsm b/system-addon/lib/Store.jsm index fde31b07e..f337363ca 100644 --- a/system-addon/lib/Store.jsm +++ b/system-addon/lib/Store.jsm @@ -31,9 +31,7 @@ this.Store = class Store { this[method] = (...args) => this._store[method](...args); } this.feeds = new Map(); - this._feedFactories = null; this._prefs = new Prefs(); - this._prefHandlers = new Map(); this._messageChannel = new ActivityStreamMessageChannel({dispatch: this.dispatch}); this._store = redux.createStore( redux.combineReducers(reducers), @@ -64,7 +62,7 @@ this.Store = class Store { * passed to Store.init */ initFeed(feedName) { - const feed = this._feedFactories[feedName](); + const feed = this._feedFactories.get(feedName)(); feed.store = this; this.feeds.set(feedName, feed); } @@ -87,41 +85,34 @@ this.Store = class Store { } /** - * maybeStartFeedAndListenForPrefChanges - Listen for pref changes that turn a - * feed off/on, and as long as that pref was not explicitly set to - * false, initialize the feed immediately. - * - * @param {string} name The name of a feed, as defined in the object passed - * to Store.init + * onPrefChanged - Listener for handling feed changes. */ - maybeStartFeedAndListenForPrefChanges(prefName) { - // Create a listener that turns the feed off/on based on changes - // to the pref, and cache it so we can unlisten on shut-down. - const onPrefChanged = isEnabled => (isEnabled ? this.initFeed(prefName) : this.uninitFeed(prefName)); - this._prefHandlers.set(prefName, onPrefChanged); - this._prefs.observe(prefName, onPrefChanged); - - // TODO: This should propbably be done in a generic pref manager for Activity Stream. - // If the pref is true, start the feed immediately. - if (this._prefs.get(prefName)) { - this.initFeed(prefName); + onPrefChanged(name, value) { + if (this._feedFactories.has(name)) { + if (value) { + this.initFeed(name); + } else { + this.uninitFeed(name); + } } } /** * init - Initializes the ActivityStreamMessageChannel channel, and adds feeds. * - * @param {array} feedConstructors An array of configuration objects for feeds - * each with .name (the name of the pref for the feed) and .init, - * a function that returns an instance of the feed + * @param {Map} feedFactories A Map of feeds with the name of the pref for + * the feed as the key and a function that + * constructs an instance of the feed. */ - init(feedConstructors) { - if (feedConstructors) { - this._feedFactories = feedConstructors; - for (const pref of Object.keys(feedConstructors)) { - this.maybeStartFeedAndListenForPrefChanges(pref); + init(feedFactories) { + this._feedFactories = feedFactories; + for (const pref of feedFactories.keys()) { + if (this._prefs.get(pref)) { + this.initFeed(pref); } } + + this._prefs.observeBranch(this); this._messageChannel.createChannel(); } @@ -133,10 +124,9 @@ this.Store = class Store { */ uninit() { this.feeds.forEach(feed => this.uninitFeed(feed)); - this._prefHandlers.forEach((handler, pref) => this._prefs.ignore(pref, handler)); - this._prefHandlers.clear(); - this._feedFactories = null; this.feeds.clear(); + this._feedFactories = null; + this._prefs.ignoreBranch(this); this._messageChannel.destroyChannel(); } }; diff --git a/system-addon/test/unit/lib/ActivityStream.test.js b/system-addon/test/unit/lib/ActivityStream.test.js index a4486c561..e2573bf34 100644 --- a/system-addon/test/unit/lib/ActivityStream.test.js +++ b/system-addon/test/unit/lib/ActivityStream.test.js @@ -83,27 +83,27 @@ describe("ActivityStream", () => { }); describe("feeds", () => { it("should create a Localization feed", () => { - const feed = as.feeds["feeds.localization"](); + const feed = as.feeds.get("feeds.localization")(); assert.instanceOf(feed, Fake); }); it("should create a NewTabInit feed", () => { - const feed = as.feeds["feeds.newtabinit"](); + const feed = as.feeds.get("feeds.newtabinit")(); assert.instanceOf(feed, Fake); }); it("should create a Places feed", () => { - const feed = as.feeds["feeds.places"](); + const feed = as.feeds.get("feeds.places")(); assert.instanceOf(feed, Fake); }); it("should create a TopSites feed", () => { - const feed = as.feeds["feeds.topsites"](); + const feed = as.feeds.get("feeds.topsites")(); assert.instanceOf(feed, Fake); }); it("should create a Telemetry feed", () => { - const feed = as.feeds["feeds.telemetry"](); + const feed = as.feeds.get("feeds.telemetry")(); assert.instanceOf(feed, Fake); }); it("should create a Prefs feed", () => { - const feed = as.feeds["feeds.prefs"](); + const feed = as.feeds.get("feeds.prefs")(); assert.instanceOf(feed, Fake); }); }); diff --git a/system-addon/test/unit/lib/ActivityStreamPrefs.test.js b/system-addon/test/unit/lib/ActivityStreamPrefs.test.js index c60a125df..77dcc3b83 100644 --- a/system-addon/test/unit/lib/ActivityStreamPrefs.test.js +++ b/system-addon/test/unit/lib/ActivityStreamPrefs.test.js @@ -1,30 +1,75 @@ const ACTIVITY_STREAM_PREF_BRANCH = "browser.newtabpage.activity-stream."; const {Prefs, DefaultPrefs} = require("lib/ActivityStreamPrefs.jsm"); -const TEST_PREF_CONFIG = [ - {name: "foo", value: true}, - {name: "bar", value: "BAR"}, - {name: "baz", value: 1} -]; +const TEST_PREF_CONFIG = new Map([ + ["foo", {value: true}], + ["bar", {value: "BAR"}], + ["baz", {value: 1}] +]); describe("ActivityStreamPrefs", () => { describe("Prefs", () => { + let p; + beforeEach(() => { + p = new Prefs(); + }); it("should have get, set, and observe methods", () => { - const p = new Prefs(); assert.property(p, "get"); assert.property(p, "set"); assert.property(p, "observe"); }); describe(".branchName", () => { it("should return the activity stream branch by default", () => { - const p = new Prefs(); assert.equal(p.branchName, ACTIVITY_STREAM_PREF_BRANCH); }); it("should return the custom branch name if it was passed to the constructor", () => { - const p = new Prefs("foo"); + p = new Prefs("foo"); assert.equal(p.branchName, "foo"); }); }); + describe("#observeBranch", () => { + let listener; + beforeEach(() => { + p._prefBranch = {addObserver: sinon.stub()}; + listener = {onPrefChanged: sinon.stub()}; + p.observeBranch(listener); + }); + it("should add an observer", () => { + assert.calledOnce(p._prefBranch.addObserver); + }); + it("should store the listener", () => { + assert.equal(p._branchObservers.size, 1); + assert.ok(p._branchObservers.has(listener)); + }); + it("should call listener's onPrefChanged", () => { + p._branchObservers.get(listener)(); + + assert.calledOnce(listener.onPrefChanged); + }); + }); + describe("#ignoreBranch", () => { + let listener; + beforeEach(() => { + p._prefBranch = { + addObserver: sinon.stub(), + removeObserver: sinon.stub() + }; + listener = {}; + p.observeBranch(listener); + }); + it("should remove the observer", () => { + p.ignoreBranch(listener); + + assert.calledOnce(p._prefBranch.addObserver); + }); + it("should remove the listener", () => { + assert.equal(p._branchObservers.size, 1); + + p.ignoreBranch(listener); + + assert.equal(p._branchObservers.size, 0); + }); + }); }); describe("DefaultPrefs", () => { @@ -54,8 +99,8 @@ describe("ActivityStreamPrefs", () => { const defaultPrefs = new DefaultPrefs(TEST_PREF_CONFIG); sinon.spy(defaultPrefs.branch, "clearUserPref"); defaultPrefs.reset(); - for (const pref of TEST_PREF_CONFIG) { - assert.calledWith(defaultPrefs.branch.clearUserPref, pref.name); + for (const name of TEST_PREF_CONFIG.keys()) { + assert.calledWith(defaultPrefs.branch.clearUserPref, name); } }); }); diff --git a/system-addon/test/unit/lib/PrefsFeed.test.js b/system-addon/test/unit/lib/PrefsFeed.test.js index af7974bfb..d47a7477e 100644 --- a/system-addon/test/unit/lib/PrefsFeed.test.js +++ b/system-addon/test/unit/lib/PrefsFeed.test.js @@ -1,18 +1,20 @@ const {PrefsFeed} = require("lib/PrefsFeed.jsm"); const {actionTypes: at, actionCreators: ac} = require("common/Actions.jsm"); -const FAKE_PREFS = [{name: "foo", value: 1}, {name: "bar", value: 2}]; +const FAKE_PREFS = new Map([["foo", {value: 1}], ["bar", {value: 2}]]); describe("PrefsFeed", () => { let feed; beforeEach(() => { - feed = new PrefsFeed(FAKE_PREFS.map(p => p.name)); + feed = new PrefsFeed(FAKE_PREFS); feed.store = {dispatch: sinon.spy()}; feed._prefs = { - get: sinon.spy(item => FAKE_PREFS.filter(p => p.name === item)[0].value), + get: sinon.spy(item => FAKE_PREFS.get(item).value), set: sinon.spy(), observe: sinon.spy(), - ignore: sinon.spy() + observeBranch: sinon.spy(), + ignore: sinon.spy(), + ignoreBranch: sinon.spy() }; }); it("should set a pref when a SET_PREF action is received", () => { @@ -25,27 +27,15 @@ describe("PrefsFeed", () => { assert.equal(feed.store.dispatch.firstCall.args[0].type, at.PREFS_INITIAL_VALUES); assert.deepEqual(feed.store.dispatch.firstCall.args[0].data, {foo: 1, bar: 2}); }); - it("should add one observer per pref on init", () => { + it("should add one branch observer on init", () => { feed.onAction({type: at.INIT}); - FAKE_PREFS.forEach(pref => { - assert.calledWith(feed._prefs.observe, pref.name); - assert.isTrue(feed._observers.has(pref.name)); - }); + assert.calledOnce(feed._prefs.observeBranch); + assert.calledWith(feed._prefs.observeBranch, feed); }); - it("should call onPrefChanged when an observer is called", () => { - sinon.stub(feed, "onPrefChanged"); - feed.onAction({type: at.INIT}); - const handlerForFoo = feed._observers.get("foo"); - - handlerForFoo(true); - - assert.calledWith(feed.onPrefChanged, "foo", true); - }); - it("should remove all observers on uninit", () => { + it("should remove the branch observer on uninit", () => { feed.onAction({type: at.UNINIT}); - FAKE_PREFS.forEach(pref => { - assert.calledWith(feed._prefs.ignore, pref.name); - }); + assert.calledOnce(feed._prefs.ignoreBranch); + assert.calledWith(feed._prefs.ignoreBranch, feed); }); it("should send a PREF_CHANGED action when onPrefChanged is called", () => { feed.onPrefChanged("foo", 2); diff --git a/system-addon/test/unit/lib/Store.test.js b/system-addon/test/unit/lib/Store.test.js index f7cd7fb7f..c72fe33af 100644 --- a/system-addon/test/unit/lib/Store.test.js +++ b/system-addon/test/unit/lib/Store.test.js @@ -43,8 +43,8 @@ describe("Store", () => { describe("#initFeed", () => { it("should add an instance of the feed to .feeds", () => { class Foo {} - store._prefs.set("foo", false); - store.init({foo: () => new Foo()}); + store._prefs.set("foo", true); + store.init(new Map([["foo", () => new Foo()]])); store.initFeed("foo"); assert.isTrue(store.feeds.has("foo"), "foo is set"); @@ -52,7 +52,7 @@ describe("Store", () => { }); it("should add a .store property to the feed", () => { class Foo {} - store._feedFactories = {foo: () => new Foo()}; + store._feedFactories = new Map([["foo", () => new Foo()]]); store.initFeed("foo"); assert.propertyVal(store.feeds.get("foo"), "store", store); @@ -70,7 +70,7 @@ describe("Store", () => { feed = {uninit: sinon.spy()}; return feed; } - store._feedFactories = {foo: createFeed}; + store._feedFactories = new Map([["foo", createFeed]]); store.initFeed("foo"); store.uninitFeed("foo"); @@ -79,7 +79,7 @@ describe("Store", () => { }); it("should remove the feed from .feeds", () => { class Foo {} - store._feedFactories = {foo: () => new Foo()}; + store._feedFactories = new Map([["foo", () => new Foo()]]); store.initFeed("foo"); store.uninitFeed("foo"); @@ -87,69 +87,70 @@ describe("Store", () => { assert.isFalse(store.feeds.has("foo"), "foo is not in .feeds"); }); }); - describe("maybeStartFeedAndListenForPrefChanges", () => { + describe("onPrefChanged", () => { beforeEach(() => { sinon.stub(store, "initFeed"); sinon.stub(store, "uninitFeed"); - }); - it("should initialize the feed if the Pref is set to true", () => { - store._prefs.set("foo", true); - store.maybeStartFeedAndListenForPrefChanges("foo"); - assert.calledWith(store.initFeed, "foo"); - }); - it("should not initialize the feed if the Pref is set to false", () => { store._prefs.set("foo", false); - store.maybeStartFeedAndListenForPrefChanges("foo"); + store.init(new Map([["foo", () => ({})]])); + }); + it("should initialize the feed if called with true", () => { + store.onPrefChanged("foo", true); + + assert.calledWith(store.initFeed, "foo"); + assert.notCalled(store.uninitFeed); + }); + it("should uninitialize the feed if called with false", () => { + store.onPrefChanged("foo", false); + + assert.calledWith(store.uninitFeed, "foo"); assert.notCalled(store.initFeed); }); - it("should observe the pref", () => { - sinon.stub(store._prefs, "observe"); - store.maybeStartFeedAndListenForPrefChanges("foo"); - assert.calledWith(store._prefs.observe, "foo", store._prefHandlers.get("foo")); - }); - describe("handler", () => { - let handler; - beforeEach(() => { - store.maybeStartFeedAndListenForPrefChanges("foo"); - handler = store._prefHandlers.get("foo"); - }); - it("should initialize the feed if called with true", () => { - handler(true); - assert.calledWith(store.initFeed, "foo"); - }); - it("should uninitialize the feed if called with false", () => { - handler(false); - assert.calledWith(store.uninitFeed, "foo"); - }); + it("should do nothing if not an expected feed", () => { + store.onPrefChanged("bar", false); + + assert.notCalled(store.initFeed); + assert.notCalled(store.uninitFeed); }); }); describe("#init", () => { - it("should call .maybeStartFeedAndListenForPrefChanges with each key", () => { - sinon.stub(store, "maybeStartFeedAndListenForPrefChanges"); - store.init({foo: () => {}, bar: () => {}}); - assert.calledWith(store.maybeStartFeedAndListenForPrefChanges, "foo"); - assert.calledWith(store.maybeStartFeedAndListenForPrefChanges, "bar"); + it("should call .initFeed with each key", () => { + sinon.stub(store, "initFeed"); + store._prefs.set("foo", true); + store._prefs.set("bar", true); + store.init(new Map([["foo", () => {}], ["bar", () => {}]])); + assert.calledWith(store.initFeed, "foo"); + assert.calledWith(store.initFeed, "bar"); + }); + it("should not initialize the feed if the Pref is set to false", () => { + sinon.stub(store, "initFeed"); + store._prefs.set("foo", false); + store.init(new Map([["foo", () => {}]])); + assert.notCalled(store.initFeed); + }); + it("should observe the pref branch", () => { + sinon.stub(store._prefs, "observeBranch"); + store.init(new Map()); + assert.calledOnce(store._prefs.observeBranch); + assert.calledWith(store._prefs.observeBranch, store); }); it("should initialize the ActivityStreamMessageChannel channel", () => { - store.init(); + store.init(new Map()); assert.calledOnce(store._messageChannel.createChannel); }); }); describe("#uninit", () => { - it("should clear .feeds, ._prefHandlers, and ._feedFactories", () => { + it("should clear .feeds and ._feedFactories", () => { store._prefs.set("a", true); - store._prefs.set("b", true); - store._prefs.set("c", true); - store.init({ - a: () => ({}), - b: () => ({}), - c: () => ({}) - }); + store.init(new Map([ + ["a", () => ({})], + ["b", () => ({})], + ["c", () => ({})] + ])); store.uninit(); assert.equal(store.feeds.size, 0); - assert.equal(store._prefHandlers.size, 0); assert.isNull(store._feedFactories); }); it("should destroy the ActivityStreamMessageChannel channel", () => { @@ -171,7 +172,7 @@ describe("Store", () => { const action = {type: "FOO"}; store._prefs.set("sub", true); - store.init({sub: () => sub}); + store.init(new Map([["sub", () => sub]])); dispatch(action); diff --git a/system-addon/test/unit/utils.js b/system-addon/test/unit/utils.js index 492a31925..ca4a4e99f 100644 --- a/system-addon/test/unit/utils.js +++ b/system-addon/test/unit/utils.js @@ -104,6 +104,9 @@ FakePrefs.prototype = { delete this.observers[prefName]; } }, + _prefBranch: {}, + observeBranch(listener) {}, + ignoreBranch(listener) {}, prefs: {}, get(prefName) { return this.prefs[prefName]; },