tor-browser

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

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 });