ActivityStream.test.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. import {CONTENT_MESSAGE_TYPE} from "common/Actions.jsm";
  2. import injector from "inject!lib/ActivityStream.jsm";
  3. describe("ActivityStream", () => {
  4. let sandbox;
  5. let as;
  6. let ActivityStream;
  7. let PREFS_CONFIG;
  8. function Fake() {}
  9. function FakeStore() {
  10. return {init: () => {}, uninit: () => {}, feeds: {get: () => {}}};
  11. }
  12. beforeEach(() => {
  13. sandbox = sinon.createSandbox();
  14. ({ActivityStream, PREFS_CONFIG} = injector({
  15. "lib/Store.jsm": {Store: FakeStore},
  16. "lib/AboutPreferences.jsm": {AboutPreferences: Fake},
  17. "lib/NewTabInit.jsm": {NewTabInit: Fake},
  18. "lib/PlacesFeed.jsm": {PlacesFeed: Fake},
  19. "lib/PrefsFeed.jsm": {PrefsFeed: Fake},
  20. "lib/SectionsManager.jsm": {SectionsFeed: Fake},
  21. "lib/SystemTickFeed.jsm": {SystemTickFeed: Fake},
  22. "lib/TelemetryFeed.jsm": {TelemetryFeed: Fake},
  23. "lib/FaviconFeed.jsm": {FaviconFeed: Fake},
  24. "lib/TopSitesFeed.jsm": {TopSitesFeed: Fake},
  25. "lib/TopStoriesFeed.jsm": {TopStoriesFeed: Fake},
  26. "lib/HighlightsFeed.jsm": {HighlightsFeed: Fake},
  27. "lib/ASRouterFeed.jsm": {ASRouterFeed: Fake},
  28. "lib/DiscoveryStreamFeed.jsm": {DiscoveryStreamFeed: Fake},
  29. }));
  30. as = new ActivityStream();
  31. sandbox.stub(as.store, "init");
  32. sandbox.stub(as.store, "uninit");
  33. sandbox.stub(as._defaultPrefs, "init");
  34. });
  35. afterEach(() => sandbox.restore());
  36. it("should exist", () => {
  37. assert.ok(ActivityStream);
  38. });
  39. it("should initialize with .initialized=false", () => {
  40. assert.isFalse(as.initialized, ".initialized");
  41. });
  42. describe("#init", () => {
  43. beforeEach(() => {
  44. as.init();
  45. });
  46. it("should initialize default prefs", () => {
  47. assert.calledOnce(as._defaultPrefs.init);
  48. });
  49. it("should set .initialized to true", () => {
  50. assert.isTrue(as.initialized, ".initialized");
  51. });
  52. it("should call .store.init", () => {
  53. assert.calledOnce(as.store.init);
  54. });
  55. it("should pass to Store an INIT event for content", () => {
  56. as.init();
  57. const [, action] = as.store.init.firstCall.args;
  58. assert.equal(action.meta.to, CONTENT_MESSAGE_TYPE);
  59. });
  60. it("should pass to Store an UNINIT event", () => {
  61. as.init();
  62. const [, , action] = as.store.init.firstCall.args;
  63. assert.equal(action.type, "UNINIT");
  64. });
  65. });
  66. describe("#uninit", () => {
  67. beforeEach(() => {
  68. as.init();
  69. as.uninit();
  70. });
  71. it("should set .initialized to false", () => {
  72. assert.isFalse(as.initialized, ".initialized");
  73. });
  74. it("should call .store.uninit", () => {
  75. assert.calledOnce(as.store.uninit);
  76. });
  77. });
  78. describe("feeds", () => {
  79. it("should create a NewTabInit feed", () => {
  80. const feed = as.feeds.get("feeds.newtabinit")();
  81. assert.instanceOf(feed, Fake);
  82. });
  83. it("should create a Places feed", () => {
  84. const feed = as.feeds.get("feeds.places")();
  85. assert.instanceOf(feed, Fake);
  86. });
  87. it("should create a TopSites feed", () => {
  88. const feed = as.feeds.get("feeds.topsites")();
  89. assert.instanceOf(feed, Fake);
  90. });
  91. it("should create a Telemetry feed", () => {
  92. const feed = as.feeds.get("feeds.telemetry")();
  93. assert.instanceOf(feed, Fake);
  94. });
  95. it("should create a Prefs feed", () => {
  96. const feed = as.feeds.get("feeds.prefs")();
  97. assert.instanceOf(feed, Fake);
  98. });
  99. it("should create a section feed for each section in PREFS_CONFIG", () => {
  100. // If new sections are added, their feeds will have to be added to the
  101. // list of injected feeds above for this test to pass
  102. let feedCount = 0;
  103. for (const pref of PREFS_CONFIG.keys()) {
  104. if (pref.search(/^feeds\.section\.[^.]+$/) === 0) {
  105. const feed = as.feeds.get(pref)();
  106. assert.instanceOf(feed, Fake);
  107. feedCount++;
  108. }
  109. }
  110. assert.isAbove(feedCount, 0);
  111. });
  112. it("should create a AboutPreferences feed", () => {
  113. const feed = as.feeds.get("feeds.aboutpreferences")();
  114. assert.instanceOf(feed, Fake);
  115. });
  116. it("should create a SectionsFeed", () => {
  117. const feed = as.feeds.get("feeds.sections")();
  118. assert.instanceOf(feed, Fake);
  119. });
  120. it("should create a SystemTick feed", () => {
  121. const feed = as.feeds.get("feeds.systemtick")();
  122. assert.instanceOf(feed, Fake);
  123. });
  124. it("should create a Favicon feed", () => {
  125. const feed = as.feeds.get("feeds.favicon")();
  126. assert.instanceOf(feed, Fake);
  127. });
  128. it("should create a ASRouter feed", () => {
  129. const feed = as.feeds.get("feeds.asrouterfeed")();
  130. assert.instanceOf(feed, Fake);
  131. });
  132. it("should create a DiscoveryStreamFeed feed", () => {
  133. const feed = as.feeds.get("feeds.discoverystreamfeed")();
  134. assert.instanceOf(feed, Fake);
  135. });
  136. });
  137. describe("_migratePref", () => {
  138. it("should migrate a pref if the user has set a custom value", () => {
  139. sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true);
  140. sandbox.stub(global.Services.prefs, "getPrefType").returns("integer");
  141. sandbox.stub(global.Services.prefs, "getIntPref").returns(10);
  142. as._migratePref("oldPrefName", result => assert.equal(10, result));
  143. });
  144. it("should not migrate a pref if the user has not set a custom value", () => {
  145. // we bailed out early so we don't check the pref type later
  146. sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(false);
  147. sandbox.stub(global.Services.prefs, "getPrefType");
  148. as._migratePref("oldPrefName");
  149. assert.notCalled(global.Services.prefs.getPrefType);
  150. });
  151. it("should use the proper pref getter for each type", () => {
  152. sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true);
  153. // Integer
  154. sandbox.stub(global.Services.prefs, "getIntPref");
  155. sandbox.stub(global.Services.prefs, "getPrefType").returns("integer");
  156. as._migratePref("oldPrefName", () => {});
  157. assert.calledWith(global.Services.prefs.getIntPref, "oldPrefName");
  158. // Boolean
  159. sandbox.stub(global.Services.prefs, "getBoolPref");
  160. global.Services.prefs.getPrefType.returns("boolean");
  161. as._migratePref("oldPrefName", () => {});
  162. assert.calledWith(global.Services.prefs.getBoolPref, "oldPrefName");
  163. // String
  164. sandbox.stub(global.Services.prefs, "getStringPref");
  165. global.Services.prefs.getPrefType.returns("string");
  166. as._migratePref("oldPrefName", () => {});
  167. assert.calledWith(global.Services.prefs.getStringPref, "oldPrefName");
  168. });
  169. it("should clear the old pref after setting the new one", () => {
  170. sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true);
  171. sandbox.stub(global.Services.prefs, "clearUserPref");
  172. sandbox.stub(global.Services.prefs, "getPrefType").returns("integer");
  173. as._migratePref("oldPrefName", () => {});
  174. assert.calledWith(global.Services.prefs.clearUserPref, "oldPrefName");
  175. });
  176. });
  177. describe("_updateDynamicPrefs topstories default value", () => {
  178. it("should be false with no geo/locale", () => {
  179. as._updateDynamicPrefs();
  180. assert.isFalse(PREFS_CONFIG.get("feeds.section.topstories").value);
  181. });
  182. it("should be false with unexpected geo", () => {
  183. sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true);
  184. sandbox.stub(global.Services.prefs, "getStringPref").returns("NOGEO");
  185. as._updateDynamicPrefs();
  186. assert.isFalse(PREFS_CONFIG.get("feeds.section.topstories").value);
  187. });
  188. it("should be false with expected geo and unexpected locale", () => {
  189. sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true);
  190. sandbox.stub(global.Services.prefs, "getStringPref").returns("US");
  191. sandbox.stub(global.Services.locale, "appLocaleAsLangTag").get(() => "no-LOCALE");
  192. as._updateDynamicPrefs();
  193. assert.isFalse(PREFS_CONFIG.get("feeds.section.topstories").value);
  194. });
  195. it("should be true with expected geo and locale", () => {
  196. sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true);
  197. sandbox.stub(global.Services.prefs, "getStringPref").returns("US");
  198. sandbox.stub(global.Services.locale, "appLocaleAsLangTag").get(() => "en-US");
  199. as._updateDynamicPrefs();
  200. assert.isTrue(PREFS_CONFIG.get("feeds.section.topstories").value);
  201. });
  202. it("should be false after expected geo and locale then unexpected", () => {
  203. sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true);
  204. sandbox.stub(global.Services.prefs, "getStringPref")
  205. .onFirstCall()
  206. .returns("US")
  207. .onSecondCall()
  208. .returns("NOGEO");
  209. sandbox.stub(global.Services.locale, "appLocaleAsLangTag").get(() => "en-US");
  210. as._updateDynamicPrefs();
  211. as._updateDynamicPrefs();
  212. assert.isFalse(PREFS_CONFIG.get("feeds.section.topstories").value);
  213. });
  214. });
  215. describe("_updateDynamicPrefs topstories delayed default value", () => {
  216. let clock;
  217. beforeEach(() => {
  218. clock = sinon.useFakeTimers();
  219. // Have addObserver cause prefHasUserValue to now return true then observe
  220. sandbox.stub(global.Services.prefs, "addObserver").callsFake((pref, obs) => {
  221. sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true);
  222. setTimeout(() => obs.observe(null, "nsPref:changed", pref)); // eslint-disable-line max-nested-callbacks
  223. });
  224. });
  225. afterEach(() => clock.restore());
  226. it("should set false with unexpected geo", () => {
  227. sandbox.stub(global.Services.prefs, "getStringPref").returns("NOGEO");
  228. as._updateDynamicPrefs();
  229. clock.tick(1);
  230. assert.isFalse(PREFS_CONFIG.get("feeds.section.topstories").value);
  231. });
  232. it("should set true with expected geo and locale", () => {
  233. sandbox.stub(global.Services.prefs, "getStringPref").returns("US");
  234. sandbox.stub(global.Services.locale, "appLocaleAsLangTag").get(() => "en-US");
  235. as._updateDynamicPrefs();
  236. clock.tick(1);
  237. assert.isTrue(PREFS_CONFIG.get("feeds.section.topstories").value);
  238. });
  239. });
  240. describe("telemetry reporting on init failure", () => {
  241. it("should send a ping on init error", () => {
  242. as = new ActivityStream();
  243. const telemetry = {handleUndesiredEvent: sandbox.spy()};
  244. sandbox.stub(as.store, "init").throws();
  245. sandbox.stub(as.store.feeds, "get").returns(telemetry);
  246. try {
  247. as.init();
  248. } catch (e) {
  249. }
  250. assert.calledOnce(telemetry.handleUndesiredEvent);
  251. });
  252. });
  253. describe("searchs shortcuts shouldPin pref", () => {
  254. const SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF = "improvesearch.topSiteSearchShortcuts.searchEngines";
  255. let stub;
  256. beforeEach(() => {
  257. sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true);
  258. stub = sandbox.stub(global.Services.prefs, "getStringPref");
  259. });
  260. it("should be an empty string when no geo is available", () => {
  261. as._updateDynamicPrefs();
  262. assert.equal(PREFS_CONFIG.get(SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF).value, "");
  263. });
  264. it("should be 'baidu' in China", () => {
  265. stub.returns("CN");
  266. as._updateDynamicPrefs();
  267. assert.equal(PREFS_CONFIG.get(SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF).value, "baidu");
  268. });
  269. it("should be 'yandex' in Russia, Belarus, Kazakhstan, and Turkey", () => {
  270. const geos = ["BY", "KZ", "RU", "TR"];
  271. for (const geo of geos) {
  272. stub.returns(geo);
  273. as._updateDynamicPrefs();
  274. assert.equal(PREFS_CONFIG.get(SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF).value, "yandex");
  275. }
  276. });
  277. it("should be 'google,amazon' in Germany, France, the UK, Japan, Italy, and the US", () => {
  278. const geos = ["DE", "FR", "GB", "IT", "JP", "US"];
  279. for (const geo of geos) {
  280. stub.returns(geo);
  281. as._updateDynamicPrefs();
  282. assert.equal(PREFS_CONFIG.get(SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF).value, "google,amazon");
  283. }
  284. });
  285. it("should be 'google' elsewhere", () => {
  286. // A selection of other geos
  287. const geos = ["BR", "CA", "ES", "ID", "IN"];
  288. for (const geo of geos) {
  289. stub.returns(geo);
  290. as._updateDynamicPrefs();
  291. assert.equal(PREFS_CONFIG.get(SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF).value, "google");
  292. }
  293. });
  294. });
  295. });