ActivityStream.test.js (34938B)
1 import { CONTENT_MESSAGE_TYPE } from "common/Actions.mjs"; 2 import { 3 ActivityStream, 4 PREFS_CONFIG, 5 csvPrefHasValue, 6 } from "lib/ActivityStream.sys.mjs"; 7 import { GlobalOverrider } from "test/unit/utils"; 8 9 import { DEFAULT_SITES } from "lib/DefaultSites.sys.mjs"; 10 import { AboutPreferences } from "lib/AboutPreferences.sys.mjs"; 11 import { DefaultPrefs } from "lib/ActivityStreamPrefs.sys.mjs"; 12 import { NewTabInit } from "lib/NewTabInit.sys.mjs"; 13 import { SectionsFeed } from "lib/SectionsManager.sys.mjs"; 14 import { RecommendationProvider } from "lib/RecommendationProvider.sys.mjs"; 15 import { PlacesFeed } from "lib/PlacesFeed.sys.mjs"; 16 import { PrefsFeed } from "lib/PrefsFeed.sys.mjs"; 17 import { SystemTickFeed } from "lib/SystemTickFeed.sys.mjs"; 18 import { TelemetryFeed } from "lib/TelemetryFeed.sys.mjs"; 19 import { FaviconFeed } from "lib/FaviconFeed.sys.mjs"; 20 import { TopSitesFeed } from "lib/TopSitesFeed.sys.mjs"; 21 import { TopStoriesFeed } from "lib/TopStoriesFeed.sys.mjs"; 22 import { HighlightsFeed } from "lib/HighlightsFeed.sys.mjs"; 23 import { DiscoveryStreamFeed } from "lib/DiscoveryStreamFeed.sys.mjs"; 24 25 import { PersistentCache } from "lib/PersistentCache.sys.mjs"; 26 import { DownloadsManager } from "lib/DownloadsManager.sys.mjs"; 27 28 describe("ActivityStream", () => { 29 let sandbox; 30 let as; 31 function FakeStore() { 32 return { init: () => {}, uninit: () => {}, feeds: { get: () => {} } }; 33 } 34 35 let globals; 36 beforeEach(() => { 37 globals = new GlobalOverrider(); 38 globals.set({ 39 Store: FakeStore, 40 41 DEFAULT_SITES, 42 AboutPreferences, 43 DefaultPrefs, 44 NewTabActorRegistry: { init: () => {} }, 45 NewTabInit, 46 SectionsFeed, 47 RecommendationProvider, 48 PlacesFeed, 49 PrefsFeed, 50 SystemTickFeed, 51 TelemetryFeed, 52 FaviconFeed, 53 TopSitesFeed, 54 TopStoriesFeed, 55 HighlightsFeed, 56 DiscoveryStreamFeed, 57 58 PersistentCache, 59 DownloadsManager, 60 }); 61 62 as = new ActivityStream(); 63 sandbox = sinon.createSandbox(); 64 sandbox.stub(as.store, "init"); 65 sandbox.stub(as.store, "uninit"); 66 sandbox.stub(as._defaultPrefs, "init"); 67 PREFS_CONFIG.get("feeds.system.topstories").value = undefined; 68 }); 69 70 afterEach(() => { 71 sandbox.restore(); 72 globals.restore(); 73 }); 74 75 it("should exist", () => { 76 assert.ok(ActivityStream); 77 }); 78 it("should initialize with .initialized=false", () => { 79 assert.isFalse(as.initialized, ".initialized"); 80 }); 81 describe("#init", () => { 82 beforeEach(() => { 83 as.init(); 84 }); 85 it("should initialize default prefs", () => { 86 assert.calledOnce(as._defaultPrefs.init); 87 }); 88 it("should set .initialized to true", () => { 89 assert.isTrue(as.initialized, ".initialized"); 90 }); 91 it("should call .store.init", () => { 92 assert.calledOnce(as.store.init); 93 }); 94 it("should pass to Store an INIT event for content", () => { 95 as.init(); 96 97 const [, action] = as.store.init.firstCall.args; 98 assert.equal(action.meta.to, CONTENT_MESSAGE_TYPE); 99 }); 100 it("should pass to Store an UNINIT event", () => { 101 as.init(); 102 103 const [, , action] = as.store.init.firstCall.args; 104 assert.equal(action.type, "UNINIT"); 105 }); 106 it("should call addObserver for the app locales", () => { 107 sandbox.stub(global.Services.obs, "addObserver"); 108 as.init(); 109 assert.calledWith( 110 global.Services.obs.addObserver, 111 as, 112 "intl:app-locales-changed" 113 ); 114 }); 115 }); 116 describe("#uninit", () => { 117 beforeEach(() => { 118 as.init(); 119 as.uninit(); 120 }); 121 it("should set .initialized to false", () => { 122 assert.isFalse(as.initialized, ".initialized"); 123 }); 124 it("should call .store.uninit", () => { 125 assert.calledOnce(as.store.uninit); 126 }); 127 it("should call removeObserver for the region", () => { 128 sandbox.stub(global.Services.obs, "removeObserver"); 129 as.geo = ""; 130 as.uninit(); 131 assert.calledWith( 132 global.Services.obs.removeObserver, 133 as, 134 global.Region.REGION_TOPIC 135 ); 136 }); 137 it("should call removeObserver for the app locales", () => { 138 sandbox.stub(global.Services.obs, "removeObserver"); 139 as.uninit(); 140 assert.calledWith( 141 global.Services.obs.removeObserver, 142 as, 143 "intl:app-locales-changed" 144 ); 145 }); 146 }); 147 describe("#observe", () => { 148 it("should call _updateDynamicPrefs from observe", () => { 149 sandbox.stub(as, "_updateDynamicPrefs"); 150 as.observe(undefined, global.Region.REGION_TOPIC); 151 assert.calledOnce(as._updateDynamicPrefs); 152 }); 153 }); 154 describe("feeds", () => { 155 it("should create a NewTabInit feed", () => { 156 const feed = as.feeds.get("feeds.newtabinit")(); 157 assert.ok(feed, "feed should exist"); 158 }); 159 it("should create a Places feed", () => { 160 const feed = as.feeds.get("feeds.places")(); 161 assert.ok(feed, "feed should exist"); 162 }); 163 it("should create a TopSites feed", () => { 164 const feed = as.feeds.get("feeds.system.topsites")(); 165 assert.ok(feed, "feed should exist"); 166 }); 167 it("should create a Telemetry feed", () => { 168 const feed = as.feeds.get("feeds.telemetry")(); 169 assert.ok(feed, "feed should exist"); 170 }); 171 it("should create a Prefs feed", () => { 172 const feed = as.feeds.get("feeds.prefs")(); 173 assert.ok(feed, "feed should exist"); 174 }); 175 it("should create a HighlightsFeed feed", () => { 176 const feed = as.feeds.get("feeds.section.highlights")(); 177 assert.ok(feed, "feed should exist"); 178 }); 179 it("should create a TopStoriesFeed feed", () => { 180 const feed = as.feeds.get("feeds.system.topstories")(); 181 assert.ok(feed, "feed should exist"); 182 }); 183 it("should create a AboutPreferences feed", () => { 184 const feed = as.feeds.get("feeds.aboutpreferences")(); 185 assert.ok(feed, "feed should exist"); 186 }); 187 it("should create a SectionsFeed", () => { 188 const feed = as.feeds.get("feeds.sections")(); 189 assert.ok(feed, "feed should exist"); 190 }); 191 it("should create a SystemTick feed", () => { 192 const feed = as.feeds.get("feeds.systemtick")(); 193 assert.ok(feed, "feed should exist"); 194 }); 195 it("should create a Favicon feed", () => { 196 const feed = as.feeds.get("feeds.favicon")(); 197 assert.ok(feed, "feed should exist"); 198 }); 199 it("should create a RecommendationProvider feed", () => { 200 const feed = as.feeds.get("feeds.recommendationprovider")(); 201 assert.ok(feed, "feed should exist"); 202 }); 203 it("should create a DiscoveryStreamFeed feed", () => { 204 const feed = as.feeds.get("feeds.discoverystreamfeed")(); 205 assert.ok(feed, "feed should exist"); 206 }); 207 }); 208 describe("_migratePref", () => { 209 it("should migrate a pref if the user has set a custom value", () => { 210 sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true); 211 sandbox.stub(global.Services.prefs, "getPrefType").returns("integer"); 212 sandbox.stub(global.Services.prefs, "getIntPref").returns(10); 213 as._migratePref("oldPrefName", result => assert.equal(10, result)); 214 }); 215 it("should not migrate a pref if the user has not set a custom value", () => { 216 // we bailed out early so we don't check the pref type later 217 sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(false); 218 sandbox.stub(global.Services.prefs, "getPrefType"); 219 as._migratePref("oldPrefName"); 220 assert.notCalled(global.Services.prefs.getPrefType); 221 }); 222 it("should use the proper pref getter for each type", () => { 223 sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true); 224 225 // Integer 226 sandbox.stub(global.Services.prefs, "getIntPref"); 227 sandbox.stub(global.Services.prefs, "getPrefType").returns("integer"); 228 as._migratePref("oldPrefName", () => {}); 229 assert.calledWith(global.Services.prefs.getIntPref, "oldPrefName"); 230 231 // Boolean 232 sandbox.stub(global.Services.prefs, "getBoolPref"); 233 global.Services.prefs.getPrefType.returns("boolean"); 234 as._migratePref("oldPrefName", () => {}); 235 assert.calledWith(global.Services.prefs.getBoolPref, "oldPrefName"); 236 237 // String 238 sandbox.stub(global.Services.prefs, "getStringPref"); 239 global.Services.prefs.getPrefType.returns("string"); 240 as._migratePref("oldPrefName", () => {}); 241 assert.calledWith(global.Services.prefs.getStringPref, "oldPrefName"); 242 }); 243 it("should clear the old pref after setting the new one", () => { 244 sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true); 245 sandbox.stub(global.Services.prefs, "clearUserPref"); 246 sandbox.stub(global.Services.prefs, "getPrefType").returns("integer"); 247 as._migratePref("oldPrefName", () => {}); 248 assert.calledWith(global.Services.prefs.clearUserPref, "oldPrefName"); 249 }); 250 }); 251 describe("csvPrefHasValue", () => { 252 let getStringPrefStub; 253 beforeEach(() => { 254 getStringPrefStub = sandbox.stub(global.Services.prefs, "getStringPref"); 255 sandbox.stub(global.Region, "home").get(() => "CA"); 256 sandbox 257 .stub(global.Services.locale, "appLocaleAsBCP47") 258 .get(() => "en-CA"); 259 }); 260 it("throws an error when the pref argument is not a string", () => { 261 assert.throws( 262 () => csvPrefHasValue(0, "foo"), 263 Error, 264 "The stringPrefName argument is not a string" 265 ); 266 }); 267 it("returns true if pref contains test value", () => { 268 getStringPrefStub.withArgs("example.csvPref").returns("foo,bar"); 269 const featureCheck = csvPrefHasValue("example.csvPref", "foo"); 270 assert.isTrue(featureCheck); 271 }); 272 it("returns false if pref contains test value", () => { 273 getStringPrefStub.withArgs("example.csvPref").returns("foo,bar"); 274 const featureCheck = csvPrefHasValue("example.csvPref", "baz"); 275 assert.isFalse(featureCheck); 276 }); 277 it("returns false if pref value returns empty", () => { 278 getStringPrefStub.withArgs("example.csvPref").returns(""); 279 const featureCheck = csvPrefHasValue("example.csvPref", "foo"); 280 assert.isFalse(featureCheck); 281 }); 282 it("returns false if test value is blank", () => { 283 getStringPrefStub.withArgs("example.csvPref").returns("foo,bar"); 284 const featureCheck = csvPrefHasValue("example.csvPref", ""); 285 assert.isFalse(featureCheck); 286 }); 287 }); 288 describe("showWeather", () => { 289 let stub; 290 let getStringPrefStub; 291 const FEATURE_ENABLED_PREF = "system.showWeather"; 292 const REGION_WEATHER_CONFIG = 293 "browser.newtabpage.activity-stream.discoverystream.region-weather-config"; 294 const LOCALE_WEATHER_CONFIG = 295 "browser.newtabpage.activity-stream.discoverystream.locale-weather-config"; 296 beforeEach(() => { 297 stub = sandbox.stub(global.Region, "home"); 298 299 sandbox 300 .stub(global.Services.locale, "appLocaleAsBCP47") 301 .get(() => "en-US"); 302 303 getStringPrefStub = sandbox.stub(global.Services.prefs, "getStringPref"); 304 305 // Set default regions 306 getStringPrefStub.withArgs(REGION_WEATHER_CONFIG).returns("US, CA"); 307 308 // Set default locales 309 getStringPrefStub 310 .withArgs(LOCALE_WEATHER_CONFIG) 311 .returns("en-US,en-GB,en-CA"); 312 }); 313 it("should turn off when region and locale are not set", () => { 314 stub.get(() => ""); 315 sandbox.stub(global.Services.locale, "appLocaleAsBCP47").get(() => ""); 316 as._updateDynamicPrefs(); 317 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 318 }); 319 it("should turn off when region is not set", () => { 320 stub.get(() => ""); 321 as._updateDynamicPrefs(); 322 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 323 }); 324 it("should turn on when region is supported", () => { 325 stub.get(() => "US"); 326 as._updateDynamicPrefs(); 327 assert.isTrue(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 328 }); 329 it("should turn off when region is not supported", () => { 330 stub.get(() => "JP"); 331 as._updateDynamicPrefs(); 332 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 333 }); 334 it("should turn off when locale is not set", () => { 335 stub.get(() => "US"); 336 sandbox.stub(global.Services.locale, "appLocaleAsBCP47").get(() => ""); 337 as._updateDynamicPrefs(); 338 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 339 }); 340 it("should turn on when locale is supported", () => { 341 stub.get(() => "US"); 342 sandbox 343 .stub(global.Services.locale, "appLocaleAsBCP47") 344 .get(() => "en-US"); 345 as._updateDynamicPrefs(); 346 assert.isTrue(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 347 }); 348 it("should turn off when locale is not supported", () => { 349 stub.get(() => "US"); 350 sandbox.stub(global.Services.locale, "appLocaleAsBCP47").get(() => "fr"); 351 as._updateDynamicPrefs(); 352 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 353 }); 354 it("should turn off when region and locale are both not supported", () => { 355 stub.get(() => "FR"); 356 sandbox.stub(global.Services.locale, "appLocaleAsBCP47").get(() => "fr"); 357 as._updateDynamicPrefs(); 358 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 359 }); 360 }); 361 describe("showTopicsSelection", () => { 362 let stub; 363 let getStringPrefStub; 364 const FEATURE_ENABLED_PREF = "discoverystream.topicSelection.enabled"; 365 const REGION_TOPICS_CONFIG = 366 "browser.newtabpage.activity-stream.discoverystream.topicSelection.region-topics-config"; 367 const LOCALE_TOPICS_CONFIG = 368 "browser.newtabpage.activity-stream.discoverystream.topicSelection.locale-topics-config"; 369 beforeEach(() => { 370 stub = sandbox.stub(global.Region, "home"); 371 372 sandbox 373 .stub(global.Services.locale, "appLocaleAsBCP47") 374 .get(() => "en-US"); 375 376 getStringPrefStub = sandbox.stub(global.Services.prefs, "getStringPref"); 377 378 // Set default regions 379 getStringPrefStub.withArgs(REGION_TOPICS_CONFIG).returns("US, CA"); 380 381 // Set default locales 382 getStringPrefStub 383 .withArgs(LOCALE_TOPICS_CONFIG) 384 .returns("en-US,en-GB,en-CA"); 385 }); 386 it("should turn off when region and locale are not set", () => { 387 stub.get(() => ""); 388 sandbox.stub(global.Services.locale, "appLocaleAsBCP47").get(() => ""); 389 as._updateDynamicPrefs(); 390 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 391 }); 392 it("should turn off when region is not set", () => { 393 stub.get(() => ""); 394 as._updateDynamicPrefs(); 395 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 396 }); 397 it("should turn on when region is supported", () => { 398 stub.get(() => "US"); 399 as._updateDynamicPrefs(); 400 assert.isTrue(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 401 }); 402 it("should turn off when region is not supported", () => { 403 stub.get(() => "JP"); 404 as._updateDynamicPrefs(); 405 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 406 }); 407 it("should turn off when locale is not set", () => { 408 stub.get(() => "US"); 409 sandbox.stub(global.Services.locale, "appLocaleAsBCP47").get(() => ""); 410 as._updateDynamicPrefs(); 411 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 412 }); 413 it("should turn on when locale is supported", () => { 414 stub.get(() => "US"); 415 sandbox 416 .stub(global.Services.locale, "appLocaleAsBCP47") 417 .get(() => "en-US"); 418 as._updateDynamicPrefs(); 419 assert.isTrue(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 420 }); 421 it("should turn off when locale is not supported", () => { 422 stub.get(() => "US"); 423 sandbox.stub(global.Services.locale, "appLocaleAsBCP47").get(() => "fr"); 424 as._updateDynamicPrefs(); 425 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 426 }); 427 it("should turn off when region and locale are both not supported", () => { 428 stub.get(() => "FR"); 429 sandbox.stub(global.Services.locale, "appLocaleAsBCP47").get(() => "fr"); 430 as._updateDynamicPrefs(); 431 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 432 }); 433 }); 434 describe("showTopicLabels", () => { 435 let stub; 436 let getStringPrefStub; 437 const FEATURE_ENABLED_PREF = "discoverystream.topicLabels.enabled"; 438 const REGION_TOPIC_LABEL_CONFIG = 439 "browser.newtabpage.activity-stream.discoverystream.topicLabels.region-topic-label-config"; 440 const LOCALE_TOPIC_LABEL_CONFIG = 441 "browser.newtabpage.activity-stream.discoverystream.topicLabels.locale-topic-label-config"; 442 beforeEach(() => { 443 stub = sandbox.stub(global.Region, "home"); 444 445 sandbox 446 .stub(global.Services.locale, "appLocaleAsBCP47") 447 .get(() => "en-US"); 448 449 getStringPrefStub = sandbox.stub(global.Services.prefs, "getStringPref"); 450 451 // Set default regions 452 getStringPrefStub.withArgs(REGION_TOPIC_LABEL_CONFIG).returns("US, CA"); 453 454 // Set default locales 455 getStringPrefStub 456 .withArgs(LOCALE_TOPIC_LABEL_CONFIG) 457 .returns("en-US,en-GB,en-CA"); 458 }); 459 it("should turn off when region and locale are not set", () => { 460 stub.get(() => ""); 461 sandbox.stub(global.Services.locale, "appLocaleAsBCP47").get(() => ""); 462 as._updateDynamicPrefs(); 463 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 464 }); 465 it("should turn off when region is not set", () => { 466 stub.get(() => ""); 467 as._updateDynamicPrefs(); 468 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 469 }); 470 it("should turn on when region is supported", () => { 471 stub.get(() => "US"); 472 as._updateDynamicPrefs(); 473 assert.isTrue(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 474 }); 475 it("should turn off when region is not supported", () => { 476 stub.get(() => "JP"); 477 as._updateDynamicPrefs(); 478 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 479 }); 480 it("should turn off when locale is not set", () => { 481 stub.get(() => "US"); 482 sandbox.stub(global.Services.locale, "appLocaleAsBCP47").get(() => ""); 483 as._updateDynamicPrefs(); 484 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 485 }); 486 it("should turn on when locale is supported", () => { 487 stub.get(() => "US"); 488 sandbox 489 .stub(global.Services.locale, "appLocaleAsBCP47") 490 .get(() => "en-US"); 491 as._updateDynamicPrefs(); 492 assert.isTrue(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 493 }); 494 it("should turn off when locale is not supported", () => { 495 stub.get(() => "US"); 496 sandbox.stub(global.Services.locale, "appLocaleAsBCP47").get(() => "fr"); 497 as._updateDynamicPrefs(); 498 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 499 }); 500 it("should turn off when region and locale are both not supported", () => { 501 stub.get(() => "FR"); 502 sandbox.stub(global.Services.locale, "appLocaleAsBCP47").get(() => "fr"); 503 as._updateDynamicPrefs(); 504 assert.isFalse(PREFS_CONFIG.get(FEATURE_ENABLED_PREF).value); 505 }); 506 }); 507 describe("discoverystream.region-basic-layout config", () => { 508 let getStringPrefStub; 509 beforeEach(() => { 510 getStringPrefStub = sandbox.stub(global.Services.prefs, "getStringPref"); 511 sandbox.stub(global.Region, "home").get(() => "CA"); 512 sandbox 513 .stub(global.Services.locale, "appLocaleAsBCP47") 514 .get(() => "en-CA"); 515 }); 516 it("should enable 7 row layout pref if no basic config is set and no geo is set", () => { 517 getStringPrefStub 518 .withArgs( 519 "browser.newtabpage.activity-stream.discoverystream.region-basic-config" 520 ) 521 .returns(""); 522 sandbox.stub(global.Region, "home").get(() => ""); 523 524 as._updateDynamicPrefs(); 525 526 assert.isFalse( 527 PREFS_CONFIG.get("discoverystream.region-basic-layout").value 528 ); 529 }); 530 it("should enable 1 row layout pref based on region layout pref", () => { 531 getStringPrefStub 532 .withArgs( 533 "browser.newtabpage.activity-stream.discoverystream.region-basic-config" 534 ) 535 .returns("CA"); 536 537 as._updateDynamicPrefs(); 538 539 assert.isTrue( 540 PREFS_CONFIG.get("discoverystream.region-basic-layout").value 541 ); 542 }); 543 it("should enable 7 row layout pref based on region layout pref", () => { 544 getStringPrefStub 545 .withArgs( 546 "browser.newtabpage.activity-stream.discoverystream.region-basic-config" 547 ) 548 .returns(""); 549 550 as._updateDynamicPrefs(); 551 552 assert.isFalse( 553 PREFS_CONFIG.get("discoverystream.region-basic-layout").value 554 ); 555 }); 556 }); 557 describe("_updateDynamicPrefs topstories default value", () => { 558 let getVariableStub; 559 let getBoolPrefStub; 560 let appLocaleAsBCP47Stub; 561 beforeEach(() => { 562 getVariableStub = sandbox.stub( 563 global.NimbusFeatures.pocketNewtab, 564 "getVariable" 565 ); 566 appLocaleAsBCP47Stub = sandbox.stub( 567 global.Services.locale, 568 "appLocaleAsBCP47" 569 ); 570 571 getBoolPrefStub = sandbox.stub(global.Services.prefs, "getBoolPref"); 572 getBoolPrefStub 573 .withArgs("browser.newtabpage.activity-stream.feeds.section.topstories") 574 .returns(true); 575 576 appLocaleAsBCP47Stub.get(() => "en-US"); 577 578 sandbox.stub(global.Region, "home").get(() => "US"); 579 580 getVariableStub.withArgs("regionStoriesConfig").returns("US,CA"); 581 }); 582 it("should be false with no geo/locale", () => { 583 appLocaleAsBCP47Stub.get(() => ""); 584 sandbox.stub(global.Region, "home").get(() => ""); 585 586 as._updateDynamicPrefs(); 587 588 assert.isFalse(PREFS_CONFIG.get("feeds.system.topstories").value); 589 }); 590 it("should be false with no geo but an allowed locale", () => { 591 appLocaleAsBCP47Stub.get(() => ""); 592 sandbox.stub(global.Region, "home").get(() => ""); 593 appLocaleAsBCP47Stub.get(() => "en-US"); 594 getVariableStub 595 .withArgs("localeListConfig") 596 .returns("en-US,en-CA,en-GB") 597 // We only have this pref set to trigger a close to real situation. 598 .withArgs( 599 "browser.newtabpage.activity-stream.discoverystream.region-stories-block" 600 ) 601 .returns("FR"); 602 603 as._updateDynamicPrefs(); 604 605 assert.isFalse(PREFS_CONFIG.get("feeds.system.topstories").value); 606 }); 607 it("should be false with unexpected geo", () => { 608 sandbox.stub(global.Region, "home").get(() => "NOGEO"); 609 610 as._updateDynamicPrefs(); 611 612 assert.isFalse(PREFS_CONFIG.get("feeds.system.topstories").value); 613 }); 614 it("should be false with expected geo and unexpected locale", () => { 615 appLocaleAsBCP47Stub.get(() => "no-LOCALE"); 616 617 as._updateDynamicPrefs(); 618 619 assert.isFalse(PREFS_CONFIG.get("feeds.system.topstories").value); 620 }); 621 it("should be true with expected geo and locale", () => { 622 as._updateDynamicPrefs(); 623 assert.isTrue(PREFS_CONFIG.get("feeds.system.topstories").value); 624 }); 625 it("should be false after expected geo and locale then unexpected", () => { 626 sandbox 627 .stub(global.Region, "home") 628 .onFirstCall() 629 .get(() => "US") 630 .onSecondCall() 631 .get(() => "NOGEO"); 632 633 as._updateDynamicPrefs(); 634 as._updateDynamicPrefs(); 635 636 assert.isFalse(PREFS_CONFIG.get("feeds.system.topstories").value); 637 }); 638 it("should be true with updated pref change", () => { 639 appLocaleAsBCP47Stub.get(() => "en-GB"); 640 sandbox.stub(global.Region, "home").get(() => "GB"); 641 getVariableStub.withArgs("regionStoriesConfig").returns("GB"); 642 643 as._updateDynamicPrefs(); 644 645 assert.isTrue(PREFS_CONFIG.get("feeds.system.topstories").value); 646 }); 647 it("should be true with allowed locale in non US region", () => { 648 appLocaleAsBCP47Stub.get(() => "en-CA"); 649 sandbox.stub(global.Region, "home").get(() => "DE"); 650 getVariableStub.withArgs("localeListConfig").returns("en-US,en-CA,en-GB"); 651 652 as._updateDynamicPrefs(); 653 654 assert.isTrue(PREFS_CONFIG.get("feeds.system.topstories").value); 655 }); 656 }); 657 describe("_updateDynamicPrefs topstories delayed default value", () => { 658 let clock; 659 beforeEach(() => { 660 clock = sinon.useFakeTimers(); 661 662 // Have addObserver cause prefHasUserValue to now return true then observe 663 sandbox.stub(global.Services.obs, "addObserver").callsFake(() => { 664 setTimeout(() => { 665 Services.obs.notifyObservers("US", "browser-region-updated"); 666 }); 667 }); 668 }); 669 afterEach(() => clock.restore()); 670 671 it("should set false with unexpected geo", () => { 672 sandbox 673 .stub(global.Services.prefs, "getStringPref") 674 .withArgs("browser.search.region") 675 .returns("NOGEO"); 676 677 as._updateDynamicPrefs(); 678 679 clock.tick(1); 680 681 assert.isFalse(PREFS_CONFIG.get("feeds.system.topstories").value); 682 }); 683 it("should set true with expected geo and locale", () => { 684 sandbox 685 .stub(global.NimbusFeatures.pocketNewtab, "getVariable") 686 .withArgs("regionStoriesConfig") 687 .returns("US"); 688 689 sandbox.stub(global.Services.prefs, "getBoolPref").returns(true); 690 sandbox 691 .stub(global.Services.locale, "appLocaleAsBCP47") 692 .get(() => "en-US"); 693 694 as._updateDynamicPrefs(); 695 clock.tick(1); 696 697 assert.isTrue(PREFS_CONFIG.get("feeds.system.topstories").value); 698 }); 699 it("should not change default even with expected geo and locale", () => { 700 as._defaultPrefs.set("feeds.system.topstories", false); 701 sandbox 702 .stub(global.Services.prefs, "getStringPref") 703 .withArgs( 704 "browser.newtabpage.activity-stream.discoverystream.region-stories-config" 705 ) 706 .returns("US"); 707 708 sandbox 709 .stub(global.Services.locale, "appLocaleAsBCP47") 710 .get(() => "en-US"); 711 712 as._updateDynamicPrefs(); 713 clock.tick(1); 714 715 assert.isFalse(PREFS_CONFIG.get("feeds.system.topstories").value); 716 }); 717 it("should set false with geo blocked", () => { 718 sandbox 719 .stub(global.Services.prefs, "getStringPref") 720 .withArgs( 721 "browser.newtabpage.activity-stream.discoverystream.region-stories-config" 722 ) 723 .returns("US") 724 .withArgs( 725 "browser.newtabpage.activity-stream.discoverystream.region-stories-block" 726 ) 727 .returns("US"); 728 729 sandbox.stub(global.Services.prefs, "getBoolPref").returns(true); 730 sandbox 731 .stub(global.Services.locale, "appLocaleAsBCP47") 732 .get(() => "en-US"); 733 734 as._updateDynamicPrefs(); 735 clock.tick(1); 736 737 assert.isFalse(PREFS_CONFIG.get("feeds.system.topstories").value); 738 }); 739 }); 740 describe("searchs shortcuts shouldPin pref", () => { 741 const SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF = 742 "improvesearch.topSiteSearchShortcuts.searchEngines"; 743 let stub; 744 745 beforeEach(() => { 746 stub = sandbox.stub(global.Region, "home"); 747 }); 748 749 it("should be an empty string when no geo is available", () => { 750 stub.get(() => ""); 751 as._updateDynamicPrefs(); 752 assert.equal( 753 PREFS_CONFIG.get(SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF).value, 754 "" 755 ); 756 }); 757 758 it("should be 'baidu' in China", () => { 759 stub.get(() => "CN"); 760 as._updateDynamicPrefs(); 761 assert.equal( 762 PREFS_CONFIG.get(SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF).value, 763 "baidu" 764 ); 765 }); 766 767 it("should be 'yandex' in Russia, Belarus, Kazakhstan, and Turkey", () => { 768 const geos = ["BY", "KZ", "RU", "TR"]; 769 for (const geo of geos) { 770 stub.get(() => geo); 771 as._updateDynamicPrefs(); 772 assert.equal( 773 PREFS_CONFIG.get(SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF).value, 774 "yandex" 775 ); 776 } 777 }); 778 779 it("should be 'google,amazon' in Germany, France, the UK, Japan, Italy, and the US", () => { 780 const geos = ["DE", "FR", "GB", "IT", "JP", "US"]; 781 for (const geo of geos) { 782 stub.returns(geo); 783 as._updateDynamicPrefs(); 784 assert.equal( 785 PREFS_CONFIG.get(SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF).value, 786 "google,amazon" 787 ); 788 } 789 }); 790 791 it("should be 'google' elsewhere", () => { 792 // A selection of other geos 793 const geos = ["BR", "CA", "ES", "ID", "IN"]; 794 for (const geo of geos) { 795 stub.get(() => geo); 796 as._updateDynamicPrefs(); 797 assert.equal( 798 PREFS_CONFIG.get(SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF).value, 799 "google" 800 ); 801 } 802 }); 803 }); 804 805 describe("proxying images", () => { 806 let registerStub; 807 let unregisterStub; 808 809 beforeEach(() => { 810 registerStub = sandbox.stub(as, "registerNetworkProxy"); 811 unregisterStub = sandbox.stub(as, "unregisterNetworkProxy"); 812 }); 813 814 describe("#init", () => { 815 it("should call registerNetworkProxy during init", () => { 816 as.init(); 817 assert.calledOnce(registerStub); 818 }); 819 }); 820 821 describe("#uninit", () => { 822 it("should call unregisterNetworkProxy during uninit", () => { 823 as.init(); 824 as.uninit(); 825 assert.calledOnce(unregisterStub); 826 }); 827 }); 828 829 describe("#getImageProxyConfig", () => { 830 beforeEach(() => { 831 as.initialized = true; 832 }); 833 834 it("should return null when proxy config is missing", () => { 835 as.store = { 836 getState: () => ({ 837 Prefs: { 838 values: {}, 839 }, 840 }), 841 }; 842 843 const config = as.getImageProxyConfig(); 844 assert.isNull(config); 845 }); 846 847 it("should return null when proxy is disabled", () => { 848 as.store = { 849 getState: () => ({ 850 Prefs: { 851 values: { 852 trainhopConfig: { 853 imageProxy: { 854 enabled: false, 855 proxyHost: "proxy.example.com", 856 proxyPort: 443, 857 proxyAuthHeader: "auth", 858 }, 859 }, 860 "discoverystream.sections.personalization.inferred.enabled": true, 861 }, 862 }, 863 }), 864 }; 865 866 const config = as.getImageProxyConfig(); 867 assert.isNull(config); 868 }); 869 870 it("should return null when required fields are missing", () => { 871 as.store = { 872 getState: () => ({ 873 Prefs: { 874 values: { 875 trainhopConfig: { 876 imageProxy: { 877 enabled: true, 878 proxyHost: "proxy.example.com", 879 }, 880 }, 881 "discoverystream.sections.personalization.inferred.enabled": true, 882 }, 883 }, 884 }), 885 }; 886 887 const config = as.getImageProxyConfig(); 888 assert.isNull(config); 889 }); 890 891 it("should return null when inferred personalization is disabled", () => { 892 as.store = { 893 getState: () => ({ 894 Prefs: { 895 values: { 896 trainhopConfig: { 897 imageProxy: { 898 enabled: true, 899 proxyHost: "proxy.example.com", 900 proxyPort: 443, 901 proxyAuthHeader: "auth", 902 }, 903 }, 904 "discoverystream.sections.personalization.inferred.enabled": false, 905 "discoverystream.imageProxy.enabled": true, 906 }, 907 }, 908 }), 909 }; 910 911 const config = as.getImageProxyConfig(); 912 assert.isNull(config); 913 }); 914 915 it("should return valid config when properly configured", () => { 916 as.store = { 917 getState: () => ({ 918 Prefs: { 919 values: { 920 trainhopConfig: { 921 imageProxy: { 922 enabled: true, 923 proxyHost: "host", 924 proxyPort: 1124, 925 proxyAuthHeader: "123", 926 connectionIsolationKey: "isolation-key", 927 failoverProxy: "failover.example.com", 928 imageProxyHosts: "host1.com,host2.com,host3.com", 929 }, 930 }, 931 "discoverystream.sections.personalization.inferred.enabled": true, 932 "discoverystream.imageProxy.enabled": true, 933 }, 934 }, 935 }), 936 }; 937 938 const config = as.getImageProxyConfig(); 939 assert.ok(config); 940 }); 941 }); 942 943 describe("#applyFilter", () => { 944 let mockChannel; 945 let mockCallback; 946 let mockProxyInfo; 947 let mockBrowser; 948 let mockCustomProxyInfo; 949 let getConfigStub; 950 let AboutNewTabParent; 951 952 beforeEach(() => { 953 mockCallback = { onProxyFilterResult: sandbox.stub() }; 954 mockProxyInfo = {}; 955 mockCustomProxyInfo = {}; 956 mockBrowser = {}; 957 958 mockChannel = { 959 URI: { host: "example.com", scheme: "https" }, 960 loadInfo: { 961 browsingContext: { top: { embedderElement: mockBrowser } }, 962 }, 963 }; 964 965 getConfigStub = sandbox.stub(as, "getImageProxyConfig"); 966 967 AboutNewTabParent = { loadedTabs: new Set([mockBrowser]) }; 968 globals.set({ 969 AboutNewTabParent, 970 ProxyService: { 971 newProxyInfo: sandbox.stub().returns(mockCustomProxyInfo), 972 }, 973 }); 974 }); 975 976 it("should pass through original proxy when config is null", () => { 977 getConfigStub.returns(null); 978 979 as.applyFilter(mockChannel, mockProxyInfo, mockCallback); 980 981 assert.calledOnce(mockCallback.onProxyFilterResult); 982 assert.calledWith(mockCallback.onProxyFilterResult, mockProxyInfo); 983 }); 984 985 it("should apply proxy for matching HTTPS host from newtab", () => { 986 const config = { 987 imageProxyHosts: ["example.com", "other.com"], 988 proxyHost: "proxy.example.com", 989 proxyPort: 443, 990 proxyAuthHeader: "Bearer token", 991 connectionIsolationKey: "key", 992 failoverProxy: "failover.example.com", 993 }; 994 getConfigStub.returns(config); 995 996 as.applyFilter(mockChannel, mockProxyInfo, mockCallback); 997 998 assert.calledOnce(global.ProxyService.newProxyInfo); 999 assert.calledWith( 1000 global.ProxyService.newProxyInfo, 1001 "https", 1002 config.proxyHost, 1003 config.proxyPort, 1004 config.proxyAuthHeader, 1005 config.connectionIsolationKey, 1006 0, 1007 5000, 1008 config.failoverProxy 1009 ); 1010 1011 assert.calledOnce(mockCallback.onProxyFilterResult); 1012 assert.calledWith( 1013 mockCallback.onProxyFilterResult, 1014 mockCustomProxyInfo 1015 ); 1016 }); 1017 }); 1018 }); 1019 });