tor-browser

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

test_UrlbarController_unit.js (9253B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 /**
      5 * These tests unit test the functionality of UrlbarController by stubbing out the
      6 * model and providing stubs to be called.
      7 */
      8 
      9 "use strict";
     10 
     11 // A fake ProvidersManager.
     12 let fPM;
     13 let sandbox;
     14 let generalListener;
     15 let controller;
     16 
     17 /**
     18 * Asserts that the query context has the expected values.
     19 *
     20 * @param {UrlbarQueryContext} context The query context.
     21 * @param {object} expectedValues The expected values for the UrlbarQueryContext.
     22 */
     23 function assertContextMatches(context, expectedValues) {
     24  Assert.ok(
     25    context instanceof UrlbarQueryContext,
     26    "Should be a UrlbarQueryContext"
     27  );
     28 
     29  for (let [key, value] of Object.entries(expectedValues)) {
     30    Assert.equal(
     31      context[key],
     32      value,
     33      `Should have the expected value for ${key} in the UrlbarQueryContext`
     34    );
     35  }
     36 }
     37 
     38 add_setup(function () {
     39  sandbox = sinon.createSandbox();
     40 
     41  fPM = {
     42    startQuery: sandbox.stub(),
     43    cancelQuery: sandbox.stub(),
     44  };
     45 
     46  generalListener = {
     47    onQueryStarted: sandbox.stub(),
     48    onQueryResults: sandbox.stub(),
     49    onQueryCancelled: sandbox.stub(),
     50  };
     51 
     52  controller = UrlbarTestUtils.newMockController({
     53    manager: fPM,
     54  });
     55  controller.addListener(generalListener);
     56 });
     57 
     58 add_task(function test_constructor_throws() {
     59  Assert.throws(
     60    () => new UrlbarController(),
     61    /options is undefined/,
     62    "Should throw if the input was not supplied"
     63  );
     64  Assert.throws(
     65    () => new UrlbarController({ input: {} }),
     66    /input is missing 'window' property/,
     67    "Should throw if the input is not a UrlbarInput"
     68  );
     69  Assert.throws(
     70    () => new UrlbarController({ input: { window: {} } }),
     71    /input.window should be an actual browser window/,
     72    "Should throw if the input.window is not a window"
     73  );
     74  Assert.throws(
     75    () =>
     76      new UrlbarController({
     77        input: {
     78          window: {
     79            location: "about:fake",
     80          },
     81        },
     82      }),
     83    /input.window should be an actual browser window/,
     84    "Should throw if the input.window is not an object"
     85  );
     86  Assert.throws(
     87    () =>
     88      new UrlbarController({
     89        input: {
     90          window: {
     91            location: {
     92              href: "about:fake",
     93            },
     94          },
     95        },
     96      }),
     97    /input.window should be an actual browser window/,
     98    "Should throw if the input.window does not have the correct location"
     99  );
    100  Assert.throws(
    101    () =>
    102      new UrlbarController({
    103        input: {
    104          window: {
    105            location: {
    106              href: AppConstants.BROWSER_CHROME_URL,
    107            },
    108          },
    109        },
    110      }),
    111    /input.isPrivate must be set/,
    112    "Should throw if input.isPrivate is not set"
    113  );
    114 
    115  new UrlbarController({
    116    input: {
    117      isPrivate: false,
    118      window: {
    119        location: {
    120          href: AppConstants.BROWSER_CHROME_URL,
    121        },
    122      },
    123    },
    124  });
    125  Assert.ok(true, "Correct call should not throw");
    126 });
    127 
    128 add_task(function test_add_and_remove_listeners() {
    129  Assert.throws(
    130    () => controller.addListener(null),
    131    /Expected listener to be an object/,
    132    "Should throw for a null listener"
    133  );
    134  Assert.throws(
    135    () => controller.addListener(123),
    136    /Expected listener to be an object/,
    137    "Should throw for a non-object listener"
    138  );
    139 
    140  const listener = {};
    141 
    142  controller.addListener(listener);
    143 
    144  Assert.ok(
    145    controller._listeners.has(listener),
    146    "Should have added the listener to the list."
    147  );
    148 
    149  // Adding a non-existent listener shouldn't throw.
    150  controller.removeListener(123);
    151 
    152  controller.removeListener(listener);
    153 
    154  Assert.ok(
    155    !controller._listeners.has(listener),
    156    "Should have removed the listener from the list"
    157  );
    158 
    159  sandbox.resetHistory();
    160 });
    161 
    162 add_task(function test__notify() {
    163  const listener1 = {
    164    onFake: sandbox.stub().callsFake(() => {
    165      throw new Error("fake error");
    166    }),
    167  };
    168  const listener2 = {
    169    onFake: sandbox.stub(),
    170  };
    171 
    172  controller.addListener(listener1);
    173  controller.addListener(listener2);
    174 
    175  const param = "1234";
    176 
    177  controller.notify("onFake", param);
    178 
    179  Assert.equal(
    180    listener1.onFake.callCount,
    181    1,
    182    "Should have called the first listener method."
    183  );
    184  Assert.deepEqual(
    185    listener1.onFake.args[0],
    186    [param],
    187    "Should have called the first listener with the correct argument"
    188  );
    189  Assert.equal(
    190    listener2.onFake.callCount,
    191    1,
    192    "Should have called the second listener method."
    193  );
    194  Assert.deepEqual(
    195    listener2.onFake.args[0],
    196    [param],
    197    "Should have called the first listener with the correct argument"
    198  );
    199 
    200  controller.removeListener(listener2);
    201  controller.removeListener(listener1);
    202 
    203  // This should succeed without errors.
    204  controller.notify("onNewFake");
    205 
    206  sandbox.resetHistory();
    207 });
    208 
    209 add_task(function test_handle_query_starts_search() {
    210  const context = createContext();
    211  controller.startQuery(context);
    212 
    213  Assert.equal(
    214    fPM.startQuery.callCount,
    215    1,
    216    "Should have called startQuery once"
    217  );
    218  Assert.equal(
    219    fPM.startQuery.args[0].length,
    220    2,
    221    "Should have called startQuery with two arguments"
    222  );
    223 
    224  assertContextMatches(fPM.startQuery.args[0][0], {});
    225  Assert.equal(
    226    fPM.startQuery.args[0][1],
    227    controller,
    228    "Should have passed the controller as the second argument"
    229  );
    230 
    231  Assert.equal(
    232    generalListener.onQueryStarted.callCount,
    233    1,
    234    "Should have called onQueryStarted for the listener"
    235  );
    236  Assert.deepEqual(
    237    generalListener.onQueryStarted.args[0],
    238    [context],
    239    "Should have called onQueryStarted with the context"
    240  );
    241 
    242  sandbox.resetHistory();
    243 });
    244 
    245 add_task(async function test_handle_query_starts_search_sets_allowAutofill() {
    246  let originalValue = Services.prefs.getBoolPref("browser.urlbar.autoFill");
    247  Services.prefs.setBoolPref("browser.urlbar.autoFill", !originalValue);
    248 
    249  await controller.startQuery(createContext());
    250 
    251  Assert.equal(
    252    fPM.startQuery.callCount,
    253    1,
    254    "Should have called startQuery once"
    255  );
    256  Assert.equal(
    257    fPM.startQuery.args[0].length,
    258    2,
    259    "Should have called startQuery with two arguments"
    260  );
    261 
    262  assertContextMatches(fPM.startQuery.args[0][0], {
    263    allowAutofill: !originalValue,
    264  });
    265  Assert.equal(
    266    fPM.startQuery.args[0][1],
    267    controller,
    268    "Should have passed the controller as the second argument"
    269  );
    270 
    271  sandbox.resetHistory();
    272 
    273  Services.prefs.clearUserPref("browser.urlbar.autoFill");
    274 });
    275 
    276 add_task(function test_cancel_query() {
    277  const context = createContext();
    278  controller.startQuery(context);
    279 
    280  controller.cancelQuery();
    281 
    282  Assert.equal(
    283    fPM.cancelQuery.callCount,
    284    1,
    285    "Should have called cancelQuery once"
    286  );
    287  Assert.equal(
    288    fPM.cancelQuery.args[0].length,
    289    1,
    290    "Should have called cancelQuery with one argument"
    291  );
    292 
    293  Assert.equal(
    294    generalListener.onQueryCancelled.callCount,
    295    1,
    296    "Should have called onQueryCancelled for the listener"
    297  );
    298  Assert.deepEqual(
    299    generalListener.onQueryCancelled.args[0],
    300    [context],
    301    "Should have called onQueryCancelled with the context"
    302  );
    303 
    304  sandbox.resetHistory();
    305 });
    306 
    307 add_task(function test_receiveResults() {
    308  const context = createContext();
    309  context.results = [];
    310  controller.receiveResults(context);
    311 
    312  Assert.equal(
    313    generalListener.onQueryResults.callCount,
    314    1,
    315    "Should have called onQueryResults for the listener"
    316  );
    317  Assert.deepEqual(
    318    generalListener.onQueryResults.args[0],
    319    [context],
    320    "Should have called onQueryResults with the context"
    321  );
    322 
    323  sandbox.resetHistory();
    324 });
    325 
    326 add_task(async function test_notifications_order() {
    327  // Clear any pending notifications.
    328  const context = createContext();
    329  await controller.startQuery(context);
    330 
    331  // Check that when multiple queries are executed, the notifications arrive
    332  // in the proper order.
    333  let collectingListener = new Proxy(
    334    {},
    335    {
    336      _notifications: [],
    337      get(target, name) {
    338        if (name == "notifications") {
    339          return this._notifications;
    340        }
    341        return () => {
    342          this._notifications.push(name);
    343        };
    344      },
    345    }
    346  );
    347  controller.addListener(collectingListener);
    348  controller.startQuery(context);
    349  Assert.deepEqual(
    350    ["onQueryStarted"],
    351    collectingListener.notifications,
    352    "Check onQueryStarted is fired synchronously"
    353  );
    354  controller.startQuery(context);
    355  Assert.deepEqual(
    356    ["onQueryStarted", "onQueryCancelled", "onQueryFinished", "onQueryStarted"],
    357    collectingListener.notifications,
    358    "Check order of notifications"
    359  );
    360  controller.cancelQuery();
    361  Assert.deepEqual(
    362    [
    363      "onQueryStarted",
    364      "onQueryCancelled",
    365      "onQueryFinished",
    366      "onQueryStarted",
    367      "onQueryCancelled",
    368      "onQueryFinished",
    369    ],
    370    collectingListener.notifications,
    371    "Check order of notifications"
    372  );
    373  await controller.startQuery(context);
    374  controller.cancelQuery();
    375  Assert.deepEqual(
    376    [
    377      "onQueryStarted",
    378      "onQueryCancelled",
    379      "onQueryFinished",
    380      "onQueryStarted",
    381      "onQueryCancelled",
    382      "onQueryFinished",
    383      "onQueryStarted",
    384      "onQueryFinished",
    385    ],
    386    collectingListener.notifications,
    387    "Check order of notifications"
    388  );
    389 });