tor-browser

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

AboutPreferences.test.js (12693B)


      1 /* global Services */
      2 import {
      3  AboutPreferences,
      4  PREFERENCES_LOADED_EVENT,
      5 } from "lib/AboutPreferences.sys.mjs";
      6 import { actionTypes as at, actionCreators as ac } from "common/Actions.mjs";
      7 import { GlobalOverrider } from "test/unit/utils";
      8 
      9 describe("AboutPreferences Feed", () => {
     10  let globals;
     11  let sandbox;
     12  let Sections;
     13  let DiscoveryStream;
     14  let instance;
     15 
     16  beforeEach(() => {
     17    globals = new GlobalOverrider();
     18    sandbox = globals.sandbox;
     19    Sections = [];
     20    DiscoveryStream = { config: { enabled: false } };
     21    instance = new AboutPreferences();
     22    instance.store = {
     23      dispatch: sandbox.stub(),
     24      getState: () => ({ Sections, DiscoveryStream }),
     25    };
     26    globals.set("NimbusFeatures", {
     27      newtab: { getAllVariables: sandbox.stub() },
     28    });
     29  });
     30  afterEach(() => {
     31    globals.restore();
     32  });
     33 
     34  describe("#onAction", () => {
     35    it("should call .init() on an INIT action", () => {
     36      const stub = sandbox.stub(instance, "init");
     37 
     38      instance.onAction({ type: at.INIT });
     39 
     40      assert.calledOnce(stub);
     41    });
     42    it("should call .uninit() on an UNINIT action", () => {
     43      const stub = sandbox.stub(instance, "uninit");
     44 
     45      instance.onAction({ type: at.UNINIT });
     46 
     47      assert.calledOnce(stub);
     48    });
     49    it("should call .openPreferences on SETTINGS_OPEN", () => {
     50      const action = {
     51        type: at.SETTINGS_OPEN,
     52        _target: { browser: { ownerGlobal: { openPreferences: sinon.spy() } } },
     53      };
     54      instance.onAction(action);
     55      assert.calledOnce(action._target.browser.ownerGlobal.openPreferences);
     56    });
     57    it("should call .BrowserAddonUI.openAddonsMgr with the extension id on OPEN_WEBEXT_SETTINGS", () => {
     58      const action = {
     59        type: at.OPEN_WEBEXT_SETTINGS,
     60        data: "foo",
     61        _target: {
     62          browser: {
     63            ownerGlobal: {
     64              BrowserAddonUI: { openAddonsMgr: sinon.spy() },
     65            },
     66          },
     67        },
     68      };
     69      instance.onAction(action);
     70      assert.calledWith(
     71        action._target.browser.ownerGlobal.BrowserAddonUI.openAddonsMgr,
     72        "addons://detail/foo"
     73      );
     74    });
     75  });
     76 
     77  describe("#observe", () => {
     78    let renderPreferenceSection;
     79    let toggleRestoreDefaults;
     80 
     81    beforeEach(() => {
     82      // Stub out All The Things
     83      renderPreferenceSection = sandbox.stub(
     84        instance,
     85        "renderPreferenceSection"
     86      );
     87      toggleRestoreDefaults = sandbox.stub(instance, "toggleRestoreDefaults");
     88    });
     89 
     90    it("should watch for about:preferences loading", () => {
     91      sandbox.stub(Services.obs, "addObserver");
     92 
     93      instance.init();
     94 
     95      assert.calledOnce(Services.obs.addObserver);
     96      assert.calledWith(
     97        Services.obs.addObserver,
     98        instance,
     99        PREFERENCES_LOADED_EVENT
    100      );
    101    });
    102    it("should stop watching on uninit", () => {
    103      sandbox.stub(Services.obs, "removeObserver");
    104 
    105      instance.uninit();
    106 
    107      assert.calledOnce(Services.obs.removeObserver);
    108      assert.calledWith(
    109        Services.obs.removeObserver,
    110        instance,
    111        PREFERENCES_LOADED_EVENT
    112      );
    113    });
    114    it("should try to render on event", async () => {
    115      Sections.push({
    116        rowsPref: "row_pref",
    117        maxRows: 3,
    118        pref: { descString: "foo" },
    119        learnMore: { link: "https://foo.com" },
    120        id: "topstories",
    121      });
    122 
    123      Sections.push({
    124        rowsPref: "row_pref",
    125        maxRows: 3,
    126        pref: { descString: "foo" },
    127        learnMore: { link: "https://foo.com" },
    128        id: "highlights",
    129      });
    130 
    131      await instance.observe(window, PREFERENCES_LOADED_EVENT);
    132 
    133      // Render all the prefs
    134      assert.callCount(renderPreferenceSection, 6);
    135 
    136      // Show or hide the "Restore defaults" button depending on prefs
    137      assert.calledOnce(toggleRestoreDefaults);
    138    });
    139  });
    140 
    141  describe("#renderPreferenceSection", () => {
    142    let node;
    143    let Preferences;
    144    let document;
    145 
    146    beforeEach(() => {
    147      node = {
    148        appendChild: sandbox.stub().returnsArg(0),
    149        addEventListener: sandbox.stub(),
    150        classList: { add: sandbox.stub(), remove: sandbox.stub() },
    151        cloneNode: sandbox.stub().returnsThis(),
    152        insertAdjacentElement: sandbox.stub().returnsArg(1),
    153        setAttribute: sandbox.stub(),
    154        remove: sandbox.stub(),
    155        style: {},
    156      };
    157      document = {
    158        createXULElement: sandbox.stub().returns(node),
    159        l10n: {
    160          setAttributes(el, id, args) {
    161            el.setAttribute("data-l10n-id", id);
    162            el.setAttribute("data-l10n-args", JSON.stringify(args));
    163          },
    164        },
    165        createProcessingInstruction: sandbox.stub(),
    166        createElementNS: sandbox.stub().callsFake(() => node),
    167        getElementById: sandbox.stub().returns(node),
    168        insertBefore: sandbox.stub().returnsArg(0),
    169        querySelector: sandbox.stub().returns({ appendChild: sandbox.stub() }),
    170      };
    171      Preferences = {
    172        add: sandbox.stub(),
    173        get: sandbox.stub().returns({
    174          on: sandbox.stub(),
    175        }),
    176      };
    177    });
    178 
    179    describe("#linkPref", () => {
    180      it("should add a pref to the global", () => {
    181        const sectionData = { pref: { feed: "feed" } };
    182        instance.renderPreferenceSection(sectionData, document, Preferences);
    183 
    184        assert.calledOnce(Preferences.add);
    185      });
    186 
    187      it("should skip adding if not shown", () => {
    188        const sectionData = { shouldHidePref: true };
    189        instance.renderPreferenceSection(sectionData, document, Preferences);
    190 
    191        assert.notCalled(Preferences.add);
    192      });
    193    });
    194 
    195    describe("title line", () => {
    196      it("should render a title", () => {
    197        const titleString = "the_title";
    198        const sectionData = { pref: { titleString } };
    199        instance.renderPreferenceSection(sectionData, document, Preferences);
    200 
    201        assert.calledWith(node.setAttribute, "data-l10n-id", titleString);
    202      });
    203    });
    204 
    205    describe("top stories", () => {
    206      const href = "https://disclaimer/";
    207      const eventSource = "https://disclaimer/";
    208      let sectionData;
    209 
    210      beforeEach(() => {
    211        sectionData = {
    212          id: "topstories",
    213          pref: { feed: "feed", learnMore: { link: { href } } },
    214          eventSource,
    215        };
    216      });
    217 
    218      it("should setup a user event for top stories eventSource", () => {
    219        sinon.spy(instance, "setupUserEvent");
    220        instance.renderPreferenceSection(sectionData, document, Preferences);
    221 
    222        assert.calledWith(node.addEventListener, "command");
    223        assert.calledWith(instance.setupUserEvent, node, eventSource);
    224      });
    225 
    226      it("should setup a user event for top stories nested pref eventSource", () => {
    227        sinon.spy(instance, "setupUserEvent");
    228        const section = {
    229          id: "topstories",
    230          pref: {
    231            feed: "feed",
    232            learnMore: { link: { href } },
    233            nestedPrefs: [
    234              {
    235                name: "showSponsored",
    236                titleString:
    237                  "home-prefs-recommended-by-option-sponsored-stories",
    238                icon: "icon-info",
    239                eventSource: "POCKET_SPOCS",
    240              },
    241            ],
    242          },
    243        };
    244        instance.renderPreferenceSection(section, document, Preferences);
    245 
    246        assert.calledWith(node.addEventListener, "command");
    247        assert.calledWith(instance.setupUserEvent, node, "POCKET_SPOCS");
    248      });
    249 
    250      it("should fire store dispatch with onCommand", () => {
    251        const element = {
    252          addEventListener: (command, action) => {
    253            // Trigger the action right away because we only care about testing the action here.
    254            action({ target: { checked: true } });
    255          },
    256        };
    257        instance.setupUserEvent(element, eventSource);
    258        assert.calledWith(
    259          instance.store.dispatch,
    260          ac.UserEvent({
    261            event: "PREF_CHANGED",
    262            source: eventSource,
    263            value: { menu_source: "ABOUT_PREFERENCES", status: true },
    264          })
    265        );
    266      });
    267 
    268      // The Weather pref now has a link to learn more, other prefs such as Top Stories don't any more
    269      it("should add a link for weather", () => {
    270        const section = {
    271          id: "weather",
    272          pref: { feed: "feed", learnMore: { link: { href } } },
    273          eventSource,
    274        };
    275 
    276        instance.renderPreferenceSection(section, document, Preferences);
    277 
    278        assert.calledWith(node.setAttribute, "href", href);
    279      });
    280    });
    281 
    282    describe("description line", () => {
    283      it("should render a description", () => {
    284        const descString = "the_desc";
    285        const sectionData = { pref: { descString } };
    286 
    287        instance.renderPreferenceSection(sectionData, document, Preferences);
    288 
    289        assert.calledWith(node.setAttribute, "data-l10n-id", descString);
    290      });
    291 
    292      it("should render rows dropdown with appropriate number", () => {
    293        const sectionData = {
    294          rowsPref: "row_pref",
    295          maxRows: 3,
    296          pref: { descString: "foo" },
    297        };
    298 
    299        instance.renderPreferenceSection(sectionData, document, Preferences);
    300 
    301        assert.calledWith(node.setAttribute, "value", 1);
    302        assert.calledWith(node.setAttribute, "value", 2);
    303        assert.calledWith(node.setAttribute, "value", 3);
    304      });
    305    });
    306    describe("nested prefs", () => {
    307      const titleString = "im_nested";
    308      let sectionData;
    309 
    310      beforeEach(() => {
    311        sectionData = { pref: { nestedPrefs: [{ titleString }] } };
    312      });
    313 
    314      it("should render a nested pref", () => {
    315        instance.renderPreferenceSection(sectionData, document, Preferences);
    316 
    317        assert.calledWith(node.setAttribute, "data-l10n-id", titleString);
    318      });
    319 
    320      it("should set node hidden to true", () => {
    321        sectionData.pref.nestedPrefs[0].hidden = true;
    322 
    323        instance.renderPreferenceSection(sectionData, document, Preferences);
    324 
    325        assert.isTrue(node.hidden);
    326      });
    327      it("should add a change event", () => {
    328        instance.renderPreferenceSection(sectionData, document, Preferences);
    329 
    330        assert.calledOnce(Preferences.get().on);
    331        assert.calledWith(Preferences.get().on, "change");
    332      });
    333 
    334      it("should default node disabled to false", async () => {
    335        Preferences.get = sandbox.stub().returns({
    336          on: sandbox.stub(),
    337          _value: true,
    338        });
    339 
    340        instance.renderPreferenceSection(sectionData, document, Preferences);
    341 
    342        assert.isFalse(node.disabled);
    343      });
    344      it("should default node disabled to true", async () => {
    345        instance.renderPreferenceSection(sectionData, document, Preferences);
    346 
    347        assert.isTrue(node.disabled);
    348      });
    349      it("should set node disabled to true", async () => {
    350        const pref = {
    351          on: sandbox.stub(),
    352          _value: true,
    353        };
    354        Preferences.get = sandbox.stub().returns(pref);
    355 
    356        instance.renderPreferenceSection(sectionData, document, Preferences);
    357        pref._value = !pref._value;
    358        await Preferences.get().on.firstCall.args[1]();
    359 
    360        assert.isTrue(node.disabled);
    361      });
    362      it("should set node disabled to false", async () => {
    363        const pref = {
    364          on: sandbox.stub(),
    365          _value: false,
    366        };
    367        Preferences.get = sandbox.stub().returns(pref);
    368 
    369        instance.renderPreferenceSection(sectionData, document, Preferences);
    370        pref._value = !pref._value;
    371        await Preferences.get().on.firstCall.args[1]();
    372 
    373        assert.isFalse(node.disabled);
    374      });
    375    });
    376  });
    377 
    378  describe("#toggleRestoreDefaults", () => {
    379    it("should call toggleRestoreDefaultsBtn", async () => {
    380      let gHomePane;
    381      gHomePane = { toggleRestoreDefaultsBtn: sandbox.stub() };
    382 
    383      await instance.toggleRestoreDefaults(gHomePane);
    384 
    385      assert.calledOnce(gHomePane.toggleRestoreDefaultsBtn);
    386    });
    387  });
    388 
    389  describe("#getString", () => {
    390    it("should not fail if titleString is not provided", () => {
    391      const emptyPref = {};
    392 
    393      const returnString = instance.getString(emptyPref);
    394      assert.equal(returnString, undefined);
    395    });
    396 
    397    it("should return the string id if titleString is just a string", () => {
    398      const titleString = "foo";
    399 
    400      const returnString = instance.getString(titleString);
    401      assert.equal(returnString, titleString);
    402    });
    403 
    404    it("should set id and args if titleString is an object with id and values", () => {
    405      const titleString = { id: "foo", values: { provider: "bar" } };
    406 
    407      const returnString = instance.getString(titleString);
    408      assert.equal(returnString, titleString.id);
    409    });
    410  });
    411 });