tor-browser

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

test_UrlbarSearchUtils.js (13501B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 const { UrlbarSearchUtils } = ChromeUtils.importESModule(
      6  "moz-src:///browser/components/urlbar/UrlbarSearchUtils.sys.mjs"
      7 );
      8 const { updateAppInfo } = ChromeUtils.importESModule(
      9  "resource://testing-common/AppInfo.sys.mjs"
     10 );
     11 
     12 const SEARCH_CONFIG = [
     13  {
     14    recordType: "engine",
     15    identifier: "testdefault",
     16    base: {
     17      name: "Default Engine",
     18      urls: {
     19        search: {
     20          base: "https://www.example.com/search",
     21          searchTermParamName: "q",
     22        },
     23      },
     24    },
     25  },
     26  {
     27    // For testing add/remove app provided engine.
     28    recordType: "engine",
     29    identifier: "aliased",
     30    base: {
     31      name: "Aliased Engine",
     32      urls: {
     33        search: {
     34          base: "https://aliased.example.com/search",
     35          searchTermParamName: "q",
     36        },
     37      },
     38      aliases: ["aliased"],
     39    },
     40  },
     41  {
     42    recordType: "defaultEngines",
     43    globalDefault: "testdefault",
     44    specificDefaults: [],
     45  },
     46 ];
     47 
     48 let baconEngineExtension;
     49 
     50 add_setup(async function () {
     51  updateAppInfo({
     52    name: "firefox",
     53  });
     54 
     55  // Tell the search service we are running in the US.  This also has the
     56  // desired side-effect of preventing our geoip lookup.
     57  Services.prefs.setCharPref("browser.search.region", "US");
     58 
     59  SearchTestUtils.setRemoteSettingsConfig(SEARCH_CONFIG);
     60  await Services.search.init();
     61 
     62  await UrlbarSearchUtils.init();
     63 });
     64 
     65 add_task(async function search_engine_match() {
     66  let engine = await Services.search.getDefault();
     67  Assert.equal(engine.name, "Default Engine", "Default engine is correct.");
     68  let domain = engine.searchUrlDomain;
     69  let token = domain.substr(0, 1);
     70  let matchedEngine = (
     71    await UrlbarSearchUtils.enginesForDomainPrefix(token)
     72  )[0];
     73  Assert.equal(matchedEngine, engine);
     74 });
     75 
     76 add_task(async function no_match() {
     77  Assert.equal(
     78    0,
     79    (await UrlbarSearchUtils.enginesForDomainPrefix("nomatchprefix")).length
     80  );
     81 });
     82 
     83 add_task(async function hide_search_engine_nomatch() {
     84  let engine = await Services.search.getDefault();
     85  let domain = engine.searchUrlDomain;
     86  let token = domain.substr(0, 1);
     87  let promiseTopic = promiseSearchTopic("engine-changed");
     88  await Promise.all([Services.search.removeEngine(engine), promiseTopic]);
     89  Assert.ok(engine.hidden);
     90  let matchedEngines = await UrlbarSearchUtils.enginesForDomainPrefix(token);
     91  Assert.ok(
     92    !matchedEngines.length || matchedEngines[0].searchUrlDomain != domain
     93  );
     94  engine.hidden = false;
     95  await TestUtils.waitForCondition(
     96    async () => (await UrlbarSearchUtils.enginesForDomainPrefix(token)).length
     97  );
     98  let matchedEngine2 = (
     99    await UrlbarSearchUtils.enginesForDomainPrefix(token)
    100  )[0];
    101  Assert.ok(matchedEngine2);
    102  await Services.search.setDefault(
    103    engine,
    104    Ci.nsISearchService.CHANGE_REASON_UNKNOWN
    105  );
    106 });
    107 
    108 add_task(async function onlyEnabled_option_nomatch() {
    109  let defaultEngine = await Services.search.getDefault();
    110  let domain = defaultEngine.searchUrlDomain;
    111  let token = domain.substr(0, 1);
    112  defaultEngine.hideOneOffButton = true;
    113 
    114  let matchedEngines = await UrlbarSearchUtils.enginesForDomainPrefix(token);
    115  Assert.notEqual(matchedEngines[0], defaultEngine);
    116 
    117  defaultEngine.hideOneOffButton = false;
    118  matchedEngines = await UrlbarSearchUtils.enginesForDomainPrefix(token);
    119  Assert.equal(matchedEngines[0].searchUrlDomain, domain);
    120  Assert.equal(matchedEngines[0], defaultEngine);
    121 });
    122 
    123 add_task(async function add_search_engine_match() {
    124  Assert.equal(
    125    0,
    126    (await UrlbarSearchUtils.enginesForDomainPrefix("bacon")).length
    127  );
    128  baconEngineExtension = await SearchTestUtils.installSearchExtension(
    129    {
    130      name: "bacon",
    131      keyword: "pork",
    132      search_url: "https://www.bacon.moz/",
    133    },
    134    { skipUnload: true }
    135  );
    136  let matchedEngine = (
    137    await UrlbarSearchUtils.enginesForDomainPrefix("bacon")
    138  )[0];
    139  Assert.ok(matchedEngine);
    140  Assert.equal(matchedEngine.name, "bacon");
    141  Assert.equal(await matchedEngine.getIconURL(), null);
    142  info("also type part of the public suffix");
    143  matchedEngine = (
    144    await UrlbarSearchUtils.enginesForDomainPrefix("bacon.m")
    145  )[0];
    146  Assert.ok(matchedEngine);
    147  Assert.equal(matchedEngine.name, "bacon");
    148  Assert.equal(await matchedEngine.getIconURL(), null);
    149 });
    150 
    151 add_task(async function match_multiple_search_engines() {
    152  Assert.equal(
    153    0,
    154    (await UrlbarSearchUtils.enginesForDomainPrefix("baseball")).length
    155  );
    156  await SearchTestUtils.installSearchExtension({
    157    name: "baseball",
    158    search_url: "https://www.baseball.moz/",
    159  });
    160  let matchedEngines = await UrlbarSearchUtils.enginesForDomainPrefix("ba");
    161  Assert.equal(
    162    matchedEngines.length,
    163    2,
    164    "enginesForDomainPrefix returned two engines."
    165  );
    166  Assert.equal(matchedEngines[0].name, "bacon");
    167  Assert.equal(matchedEngines[1].name, "baseball");
    168 });
    169 
    170 add_task(async function test_aliased_search_engine_match() {
    171  Assert.equal(null, await UrlbarSearchUtils.engineForAlias("sober"));
    172  // Lower case
    173  let matchedEngine = await UrlbarSearchUtils.engineForAlias("pork");
    174  Assert.ok(matchedEngine);
    175  Assert.equal(matchedEngine.name, "bacon");
    176  Assert.ok(matchedEngine.aliases.includes("pork"));
    177  Assert.equal(await matchedEngine.getIconURL(), null);
    178  // Upper case
    179  matchedEngine = await UrlbarSearchUtils.engineForAlias("PORK");
    180  Assert.ok(matchedEngine);
    181  Assert.equal(matchedEngine.name, "bacon");
    182  Assert.ok(matchedEngine.aliases.includes("pork"));
    183  Assert.equal(await matchedEngine.getIconURL(), null);
    184  // Cap case
    185  matchedEngine = await UrlbarSearchUtils.engineForAlias("Pork");
    186  Assert.ok(matchedEngine);
    187  Assert.equal(matchedEngine.name, "bacon");
    188  Assert.ok(matchedEngine.aliases.includes("pork"));
    189  Assert.equal(await matchedEngine.getIconURL(), null);
    190 });
    191 
    192 add_task(async function test_aliased_search_engine_match_upper_case_alias() {
    193  Assert.equal(
    194    0,
    195    (await UrlbarSearchUtils.enginesForDomainPrefix("patch")).length
    196  );
    197  await SearchTestUtils.installSearchExtension({
    198    name: "patch",
    199    keyword: "PR",
    200    search_url: "https://www.patch.moz/",
    201  });
    202  // lower case
    203  let matchedEngine = await UrlbarSearchUtils.engineForAlias("pr");
    204  Assert.ok(matchedEngine);
    205  Assert.equal(matchedEngine.name, "patch");
    206  Assert.ok(matchedEngine.aliases.includes("PR"));
    207  Assert.equal(await matchedEngine.getIconURL(), null);
    208  // Upper case
    209  matchedEngine = await UrlbarSearchUtils.engineForAlias("PR");
    210  Assert.ok(matchedEngine);
    211  Assert.equal(matchedEngine.name, "patch");
    212  Assert.ok(matchedEngine.aliases.includes("PR"));
    213  Assert.equal(await matchedEngine.getIconURL(), null);
    214  // Cap case
    215  matchedEngine = await UrlbarSearchUtils.engineForAlias("Pr");
    216  Assert.ok(matchedEngine);
    217  Assert.equal(matchedEngine.name, "patch");
    218  Assert.ok(matchedEngine.aliases.includes("PR"));
    219  Assert.equal(await matchedEngine.getIconURL(), null);
    220 });
    221 
    222 add_task(async function remove_search_engine_nomatch() {
    223  let promiseTopic = promiseSearchTopic("engine-removed");
    224  await Promise.all([baconEngineExtension.unload(), promiseTopic]);
    225  Assert.equal(
    226    0,
    227    (await UrlbarSearchUtils.enginesForDomainPrefix("bacon")).length
    228  );
    229 });
    230 
    231 add_task(async function test_app_provided_aliased_search_engine_match() {
    232  let engine = await UrlbarSearchUtils.engineForAlias("@aliased");
    233  Assert.ok(engine);
    234  Assert.equal(engine.name, "Aliased Engine");
    235  let promiseTopic = promiseSearchTopic("engine-changed");
    236  await Promise.all([Services.search.removeEngine(engine), promiseTopic]);
    237  let matchedEngine = await UrlbarSearchUtils.engineForAlias("@aliased");
    238  Assert.ok(!matchedEngine);
    239  engine.hidden = false;
    240  await TestUtils.waitForCondition(() =>
    241    UrlbarSearchUtils.engineForAlias("@aliased")
    242  );
    243  engine = await UrlbarSearchUtils.engineForAlias("@aliased");
    244  Assert.ok(engine);
    245 });
    246 
    247 add_task(async function test_serps_are_equivalent() {
    248  info("Subset URL has extraneous parameters.");
    249  let url1 = "https://example.com/search?q=test&type=images";
    250  let url2 = "https://example.com/search?q=test";
    251  Assert.ok(!UrlbarSearchUtils.serpsAreEquivalent(url1, url2));
    252  info("Superset URL has extraneous parameters.");
    253  Assert.ok(UrlbarSearchUtils.serpsAreEquivalent(url2, url1));
    254 
    255  info("Same keys, different values.");
    256  url1 = "https://example.com/search?q=test&type=images";
    257  url2 = "https://example.com/search?q=test123&type=maps";
    258  Assert.ok(!UrlbarSearchUtils.serpsAreEquivalent(url1, url2));
    259  Assert.ok(!UrlbarSearchUtils.serpsAreEquivalent(url2, url1));
    260 
    261  info("Subset matching isn't strict (URL is subset of itself).");
    262  Assert.ok(UrlbarSearchUtils.serpsAreEquivalent(url1, url1));
    263 
    264  info("Origin and pathname are ignored.");
    265  url1 = "https://example.com/search?q=test";
    266  url2 = "https://example-1.com/maps?q=test";
    267  Assert.ok(UrlbarSearchUtils.serpsAreEquivalent(url1, url2));
    268  Assert.ok(UrlbarSearchUtils.serpsAreEquivalent(url2, url1));
    269 
    270  info("Params can be optionally ignored");
    271  url1 = "https://example.com/search?q=test&abc=123&foo=bar";
    272  url2 = "https://example.com/search?q=test";
    273  Assert.ok(!UrlbarSearchUtils.serpsAreEquivalent(url1, url2));
    274  Assert.ok(UrlbarSearchUtils.serpsAreEquivalent(url1, url2, ["abc", "foo"]));
    275 });
    276 
    277 add_task(async function test_get_root_domain_from_engine() {
    278  let extension = await SearchTestUtils.installSearchExtension(
    279    {
    280      name: "TestEngine2",
    281      search_url: "https://example.com/",
    282    },
    283    { skipUnload: true }
    284  );
    285  let engine = Services.search.getEngineByName("TestEngine2");
    286  Assert.equal(UrlbarSearchUtils.getRootDomainFromEngine(engine), "example");
    287  await extension.unload();
    288 
    289  extension = await SearchTestUtils.installSearchExtension(
    290    {
    291      name: "TestEngine",
    292      search_url: "https://www.subdomain.othersubdomain.example.com",
    293    },
    294    { skipUnload: true }
    295  );
    296  engine = Services.search.getEngineByName("TestEngine");
    297  Assert.equal(UrlbarSearchUtils.getRootDomainFromEngine(engine), "example");
    298  await extension.unload();
    299 
    300  // We let engines with URL ending in .test through even though its not a valid
    301  // TLD.
    302  extension = await SearchTestUtils.installSearchExtension(
    303    {
    304      name: "TestMalformed",
    305      search_url: "https://mochi.test/",
    306      search_url_get_params: "search={searchTerms}",
    307    },
    308    { skipUnload: true }
    309  );
    310  engine = Services.search.getEngineByName("TestMalformed");
    311  Assert.equal(UrlbarSearchUtils.getRootDomainFromEngine(engine), "mochi");
    312  await extension.unload();
    313 
    314  // We return the domain for engines with a malformed URL.
    315  extension = await SearchTestUtils.installSearchExtension(
    316    {
    317      name: "TestMalformed",
    318      search_url: "https://subdomain.foobar/",
    319      search_url_get_params: "search={searchTerms}",
    320    },
    321    { skipUnload: true }
    322  );
    323  engine = Services.search.getEngineByName("TestMalformed");
    324  Assert.equal(
    325    UrlbarSearchUtils.getRootDomainFromEngine(engine),
    326    "subdomain.foobar"
    327  );
    328  await extension.unload();
    329 });
    330 
    331 add_task(async function matchAllDomainLevels() {
    332  let baseHostname = "matchalldomainlevels";
    333  Assert.equal(
    334    (await UrlbarSearchUtils.enginesForDomainPrefix(baseHostname)).length,
    335    0,
    336    `Sanity check: No engines initially match ${baseHostname}`
    337  );
    338 
    339  // Install engines with the following domains. When we match engines below,
    340  // perfectly matching domains should come before partially matching domains.
    341  let baseDomain = `${baseHostname}.com`;
    342  let perfectDomains = [baseDomain, `www.${baseDomain}`];
    343  let partialDomains = [`foo.${baseDomain}`, `foo.bar.${baseDomain}`];
    344 
    345  // Install engines with partially matching domains first so that the test
    346  // isn't incidentally passing because engines are installed in the order it
    347  // ultimately expects them in. Wait for each engine to finish installing
    348  // before starting the next one to avoid intermittent out-of-order failures.
    349  let extensions = [];
    350  for (let list of [partialDomains, perfectDomains]) {
    351    for (let domain of list) {
    352      let ext = await SearchTestUtils.installSearchExtension(
    353        {
    354          name: domain,
    355          search_url: `https://${domain}/`,
    356        },
    357        { skipUnload: true }
    358      );
    359      extensions.push(ext);
    360    }
    361  }
    362 
    363  // Perfect matches come before partial matches.
    364  let expectedDomains = [...perfectDomains, ...partialDomains];
    365 
    366  // Do searches for the following strings. Each should match all the engines
    367  // installed above.
    368  let searchStrings = [baseHostname, baseHostname + "."];
    369  for (let searchString of searchStrings) {
    370    info(`Searching for "${searchString}"`);
    371    let engines = await UrlbarSearchUtils.enginesForDomainPrefix(searchString, {
    372      matchAllDomainLevels: true,
    373    });
    374    // Domain names are saved in engine names.
    375    let actualDomains = engines.map(e => e.name);
    376    Assert.deepEqual(
    377      actualDomains,
    378      expectedDomains,
    379      "Expected matching engine names/domains in the expected order"
    380    );
    381  }
    382 
    383  await Promise.all(extensions.map(e => e.unload()));
    384 });
    385 
    386 function promiseSearchTopic(expectedVerb) {
    387  return new Promise(resolve => {
    388    Services.obs.addObserver(function observe(subject, topic, verb) {
    389      info("browser-search-engine-modified: " + verb);
    390      if (verb == expectedVerb) {
    391        Services.obs.removeObserver(observe, "browser-search-engine-modified");
    392        resolve();
    393      }
    394    }, "browser-search-engine-modified");
    395  });
    396 }