tor-browser

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

test_providerOmnibox.js (25504B)


      1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
      2 * vim:set ts=2 sw=2 sts=2 et:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 const { ExtensionSearchHandler } = ChromeUtils.importESModule(
      8  "resource://gre/modules/ExtensionSearchHandler.sys.mjs"
      9 );
     10 
     11 let controller = Cc["@mozilla.org/autocomplete/controller;1"].getService(
     12  Ci.nsIAutoCompleteController
     13 );
     14 
     15 const SUGGEST_PREF = "browser.urlbar.suggest.searches";
     16 const SUGGEST_ENABLED_PREF = "browser.search.suggest.enabled";
     17 
     18 async function cleanup() {
     19  await PlacesUtils.bookmarks.eraseEverything();
     20  await PlacesUtils.history.clear();
     21 }
     22 
     23 add_setup(function () {
     24  Services.prefs.setBoolPref(SUGGEST_PREF, false);
     25  Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, false);
     26 
     27  registerCleanupFunction(async () => {
     28    Services.prefs.clearUserPref(SUGGEST_PREF);
     29    Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF);
     30  });
     31 });
     32 
     33 add_task(async function test_correct_errors_are_thrown() {
     34  let keyword = "foo";
     35  let anotherKeyword = "bar";
     36  let unregisteredKeyword = "baz";
     37 
     38  // Register a keyword.
     39  ExtensionSearchHandler.registerKeyword(keyword, { emit: () => {} });
     40 
     41  // Try registering the keyword again.
     42  Assert.throws(
     43    () => ExtensionSearchHandler.registerKeyword(keyword, { emit: () => {} }),
     44    /The keyword provided is already registered/
     45  );
     46 
     47  // Register a different keyword.
     48  ExtensionSearchHandler.registerKeyword(anotherKeyword, { emit: () => {} });
     49 
     50  // Try calling handleSearch for an unregistered keyword.
     51  let searchData = {
     52    keyword: unregisteredKeyword,
     53    text: `${unregisteredKeyword} `,
     54  };
     55  Assert.throws(
     56    () => ExtensionSearchHandler.handleSearch(searchData, () => {}),
     57    /The keyword provided is not registered/
     58  );
     59 
     60  // Try calling handleSearch without a callback.
     61  Assert.throws(
     62    () => ExtensionSearchHandler.handleSearch(searchData),
     63    /The keyword provided is not registered/
     64  );
     65 
     66  // Try getting the description for a keyword which isn't registered.
     67  Assert.throws(
     68    () => ExtensionSearchHandler.getDescription(unregisteredKeyword),
     69    /The keyword provided is not registered/
     70  );
     71 
     72  // Try setting the default suggestion for a keyword which isn't registered.
     73  Assert.throws(
     74    () =>
     75      ExtensionSearchHandler.setDefaultSuggestion(
     76        unregisteredKeyword,
     77        "suggestion"
     78      ),
     79    /The keyword provided is not registered/
     80  );
     81 
     82  // Try calling handleInputCancelled when there is no active input session.
     83  Assert.throws(
     84    () => ExtensionSearchHandler.handleInputCancelled(),
     85    /There is no active input session/
     86  );
     87 
     88  // Try calling handleInputEntered when there is no active input session.
     89  Assert.throws(
     90    () =>
     91      ExtensionSearchHandler.handleInputEntered(
     92        anotherKeyword,
     93        `${anotherKeyword} test`,
     94        "tab"
     95      ),
     96    /There is no active input session/
     97  );
     98 
     99  // Start a session by calling handleSearch with the registered keyword.
    100  searchData = {
    101    keyword,
    102    text: `${keyword} test`,
    103  };
    104  ExtensionSearchHandler.handleSearch(searchData, () => {});
    105 
    106  // Try providing suggestions for an unregistered keyword.
    107  Assert.throws(
    108    () => ExtensionSearchHandler.addSuggestions(unregisteredKeyword, 0, []),
    109    /The keyword provided is not registered/
    110  );
    111 
    112  // Try providing suggestions for an inactive keyword.
    113  Assert.throws(
    114    () => ExtensionSearchHandler.addSuggestions(anotherKeyword, 0, []),
    115    /The keyword provided is not apart of an active input session/
    116  );
    117 
    118  // Try calling handleSearch for an inactive keyword.
    119  searchData = {
    120    keyword: anotherKeyword,
    121    text: `${anotherKeyword} `,
    122  };
    123  Assert.throws(
    124    () => ExtensionSearchHandler.handleSearch(searchData, () => {}),
    125    /A different input session is already ongoing/
    126  );
    127 
    128  // Try calling addSuggestions with an old callback ID.
    129  Assert.throws(
    130    () => ExtensionSearchHandler.addSuggestions(keyword, 0, []),
    131    /The callback is no longer active for the keyword provided/
    132  );
    133 
    134  // Add suggestions with a valid callback ID.
    135  ExtensionSearchHandler.addSuggestions(keyword, 1, []);
    136 
    137  // Add suggestions again with a valid callback ID.
    138  ExtensionSearchHandler.addSuggestions(keyword, 1, []);
    139 
    140  // Try calling addSuggestions with a future callback ID.
    141  Assert.throws(
    142    () => ExtensionSearchHandler.addSuggestions(keyword, 2, []),
    143    /The callback is no longer active for the keyword provided/
    144  );
    145 
    146  // End the input session by calling handleInputCancelled.
    147  ExtensionSearchHandler.handleInputCancelled();
    148 
    149  // Try calling handleInputCancelled after the session has ended.
    150  Assert.throws(
    151    () => ExtensionSearchHandler.handleInputCancelled(),
    152    /There is no active input sessio/
    153  );
    154 
    155  // Try calling handleSearch that doesn't have a space after the keyword.
    156  searchData = {
    157    keyword: anotherKeyword,
    158    text: `${anotherKeyword}`,
    159  };
    160  Assert.throws(
    161    () => ExtensionSearchHandler.handleSearch(searchData, () => {}),
    162    /The text provided must start with/
    163  );
    164 
    165  // Try calling handleSearch with text starting with the wrong keyword.
    166  searchData = {
    167    keyword: anotherKeyword,
    168    text: `${keyword} test`,
    169  };
    170  Assert.throws(
    171    () => ExtensionSearchHandler.handleSearch(searchData, () => {}),
    172    /The text provided must start with/
    173  );
    174 
    175  // Start a new session by calling handleSearch with a different keyword
    176  searchData = {
    177    keyword: anotherKeyword,
    178    text: `${anotherKeyword} test`,
    179  };
    180  ExtensionSearchHandler.handleSearch(searchData, () => {});
    181 
    182  // Try adding suggestions again with the same callback ID now that the input session has ended.
    183  Assert.throws(
    184    () => ExtensionSearchHandler.addSuggestions(keyword, 1, []),
    185    /The keyword provided is not apart of an active input session/
    186  );
    187 
    188  // Add suggestions with a valid callback ID.
    189  ExtensionSearchHandler.addSuggestions(anotherKeyword, 2, []);
    190 
    191  // Try adding suggestions with a valid callback ID but a different keyword.
    192  Assert.throws(
    193    () => ExtensionSearchHandler.addSuggestions(keyword, 2, []),
    194    /The keyword provided is not apart of an active input session/
    195  );
    196 
    197  // Try adding suggestions with a valid callback ID but an unregistered keyword.
    198  Assert.throws(
    199    () => ExtensionSearchHandler.addSuggestions(unregisteredKeyword, 2, []),
    200    /The keyword provided is not registered/
    201  );
    202 
    203  // Set the default suggestion.
    204  ExtensionSearchHandler.setDefaultSuggestion(anotherKeyword, {
    205    description: "test result",
    206  });
    207 
    208  // Try ending the session using handleInputEntered with a different keyword.
    209  Assert.throws(
    210    () =>
    211      ExtensionSearchHandler.handleInputEntered(
    212        keyword,
    213        `${keyword} test`,
    214        "tab"
    215      ),
    216    /A different input session is already ongoing/
    217  );
    218 
    219  // Try calling handleInputEntered with invalid text.
    220  Assert.throws(
    221    () =>
    222      ExtensionSearchHandler.handleInputEntered(anotherKeyword, ` test`, "tab"),
    223    /The text provided must start with/
    224  );
    225 
    226  // Try calling handleInputEntered with an invalid disposition.
    227  Assert.throws(
    228    () =>
    229      ExtensionSearchHandler.handleInputEntered(
    230        anotherKeyword,
    231        `${anotherKeyword} test`,
    232        "invalid"
    233      ),
    234    /Invalid "where" argument/
    235  );
    236 
    237  // End the session by calling handleInputEntered.
    238  ExtensionSearchHandler.handleInputEntered(
    239    anotherKeyword,
    240    `${anotherKeyword} test`,
    241    "tab"
    242  );
    243 
    244  // Try calling handleInputEntered after the session has ended.
    245  Assert.throws(
    246    () =>
    247      ExtensionSearchHandler.handleInputEntered(
    248        anotherKeyword,
    249        `${anotherKeyword} test`,
    250        "tab"
    251      ),
    252    /There is no active input session/
    253  );
    254 
    255  // Unregister the keyword.
    256  ExtensionSearchHandler.unregisterKeyword(keyword);
    257 
    258  // Try setting the default suggestion for the unregistered keyword.
    259  Assert.throws(
    260    () =>
    261      ExtensionSearchHandler.setDefaultSuggestion(keyword, {
    262        description: "test",
    263      }),
    264    /The keyword provided is not registered/
    265  );
    266 
    267  // Try handling a search with the unregistered keyword.
    268  searchData = {
    269    keyword,
    270    text: `${keyword} test`,
    271  };
    272  Assert.throws(
    273    () => ExtensionSearchHandler.handleSearch(searchData, () => {}),
    274    /The keyword provided is not registered/
    275  );
    276 
    277  // Try unregistering the keyword again.
    278  Assert.throws(
    279    () => ExtensionSearchHandler.unregisterKeyword(keyword),
    280    /The keyword provided is not registered/
    281  );
    282 
    283  // Unregister the other keyword.
    284  ExtensionSearchHandler.unregisterKeyword(anotherKeyword);
    285 
    286  // Try unregistering the word which was never registered.
    287  Assert.throws(
    288    () => ExtensionSearchHandler.unregisterKeyword(unregisteredKeyword),
    289    /The keyword provided is not registered/
    290  );
    291 
    292  // Try setting the default suggestion for a word that was never registered.
    293  Assert.throws(
    294    () =>
    295      ExtensionSearchHandler.setDefaultSuggestion(unregisteredKeyword, {
    296        description: "test",
    297      }),
    298    /The keyword provided is not registered/
    299  );
    300 
    301  await cleanup();
    302 });
    303 
    304 add_task(async function test_extension_private_browsing() {
    305  let events = [];
    306  let mockExtension = {
    307    emit: message => events.push(message),
    308    privateBrowsingAllowed: false,
    309  };
    310 
    311  let keyword = "foo";
    312 
    313  ExtensionSearchHandler.registerKeyword(keyword, mockExtension);
    314 
    315  let searchData = {
    316    keyword,
    317    text: `${keyword} test`,
    318    inPrivateWindow: true,
    319  };
    320  let result = await ExtensionSearchHandler.handleSearch(searchData);
    321  Assert.equal(result, false, "unable to handle search for private window");
    322 
    323  // Try calling handleInputEntered after the session has ended.
    324  Assert.throws(
    325    () =>
    326      ExtensionSearchHandler.handleInputEntered(
    327        keyword,
    328        `${keyword} test`,
    329        "tab"
    330      ),
    331    /There is no active input session/
    332  );
    333 
    334  ExtensionSearchHandler.unregisterKeyword(keyword);
    335  await cleanup();
    336 });
    337 
    338 add_task(async function test_extension_private_browsing_allowed() {
    339  let extensionName = "Foo Bar";
    340  let mockExtension = {
    341    name: extensionName,
    342    emit: (message, text, id) => {
    343      if (message === ExtensionSearchHandler.MSG_INPUT_CHANGED) {
    344        ExtensionSearchHandler.addSuggestions(keyword, id, [
    345          { content: "foo", description: "first suggestion" },
    346          { content: "foobar", description: "second suggestion" },
    347        ]);
    348        // The API doesn't have a way to notify when addition is complete.
    349        do_timeout(1000, () => {
    350          controller.stopSearch();
    351        });
    352      }
    353    },
    354    privateBrowsingAllowed: true,
    355  };
    356 
    357  let keyword = "foo";
    358  ExtensionSearchHandler.registerKeyword(keyword, mockExtension);
    359 
    360  let query = `${keyword} foo`;
    361  let context = createContext(query, { isPrivate: true });
    362  await check_results({
    363    context,
    364    matches: [
    365      makeOmniboxResult(context, {
    366        heuristic: true,
    367        keyword,
    368        description: extensionName,
    369        content: query,
    370      }),
    371      makeOmniboxResult(context, {
    372        keyword,
    373        content: `${keyword} foobar`,
    374        description: "second suggestion",
    375      }),
    376    ],
    377  });
    378 
    379  ExtensionSearchHandler.unregisterKeyword(keyword);
    380  await cleanup();
    381 });
    382 
    383 add_task(async function test_correct_events_are_emitted() {
    384  let events = [];
    385  function checkEvents(expectedEvents) {
    386    Assert.equal(
    387      events.length,
    388      expectedEvents.length,
    389      "The correct number of events fired"
    390    );
    391    expectedEvents.forEach((e, i) =>
    392      Assert.equal(e, events[i], `Expected "${e}" event to fire`)
    393    );
    394    events = [];
    395  }
    396 
    397  let mockExtension = { emit: message => events.push(message) };
    398 
    399  let keyword = "foo";
    400  let anotherKeyword = "bar";
    401 
    402  ExtensionSearchHandler.registerKeyword(keyword, mockExtension);
    403  ExtensionSearchHandler.registerKeyword(anotherKeyword, mockExtension);
    404 
    405  let searchData = {
    406    keyword,
    407    text: `${keyword} `,
    408  };
    409  ExtensionSearchHandler.handleSearch(searchData, () => {});
    410  checkEvents([ExtensionSearchHandler.MSG_INPUT_STARTED]);
    411 
    412  searchData.text = `${keyword} f`;
    413  ExtensionSearchHandler.handleSearch(searchData, () => {});
    414  checkEvents([ExtensionSearchHandler.MSG_INPUT_CHANGED]);
    415 
    416  ExtensionSearchHandler.handleInputEntered(keyword, searchData.text, "tab");
    417  checkEvents([ExtensionSearchHandler.MSG_INPUT_ENTERED]);
    418 
    419  ExtensionSearchHandler.handleSearch(searchData, () => {});
    420  checkEvents([
    421    ExtensionSearchHandler.MSG_INPUT_STARTED,
    422    ExtensionSearchHandler.MSG_INPUT_CHANGED,
    423  ]);
    424 
    425  ExtensionSearchHandler.handleInputCancelled();
    426  checkEvents([ExtensionSearchHandler.MSG_INPUT_CANCELLED]);
    427 
    428  ExtensionSearchHandler.handleSearch(
    429    {
    430      keyword: anotherKeyword,
    431      text: `${anotherKeyword} baz`,
    432    },
    433    () => {}
    434  );
    435  checkEvents([
    436    ExtensionSearchHandler.MSG_INPUT_STARTED,
    437    ExtensionSearchHandler.MSG_INPUT_CHANGED,
    438  ]);
    439 
    440  ExtensionSearchHandler.handleInputEntered(
    441    anotherKeyword,
    442    `${anotherKeyword} baz`,
    443    "tab"
    444  );
    445  checkEvents([ExtensionSearchHandler.MSG_INPUT_ENTERED]);
    446 
    447  ExtensionSearchHandler.unregisterKeyword(keyword);
    448 });
    449 
    450 add_task(async function test_removes_suggestion_if_its_content_is_typed_in() {
    451  let keyword = "test";
    452  let extensionName = "Foo Bar";
    453 
    454  let mockExtension = {
    455    name: extensionName,
    456    emit(message, text, id) {
    457      if (message === ExtensionSearchHandler.MSG_INPUT_CHANGED) {
    458        ExtensionSearchHandler.addSuggestions(keyword, id, [
    459          { content: "foo", description: "first suggestion" },
    460          { content: "bar", description: "second suggestion" },
    461          { content: "baz", description: "third suggestion" },
    462        ]);
    463        // The API doesn't have a way to notify when addition is complete.
    464        do_timeout(1000, () => {
    465          controller.stopSearch();
    466        });
    467      }
    468    },
    469  };
    470 
    471  ExtensionSearchHandler.registerKeyword(keyword, mockExtension);
    472 
    473  let query = `${keyword} unmatched`;
    474  let context = createContext(query, { isPrivate: false });
    475  await check_results({
    476    context,
    477    matches: [
    478      makeOmniboxResult(context, {
    479        heuristic: true,
    480        keyword,
    481        description: extensionName,
    482        content: `${keyword} unmatched`,
    483      }),
    484      makeOmniboxResult(context, {
    485        keyword,
    486        content: `${keyword} foo`,
    487        description: "first suggestion",
    488      }),
    489      makeOmniboxResult(context, {
    490        keyword,
    491        content: `${keyword} bar`,
    492        description: "second suggestion",
    493      }),
    494      makeOmniboxResult(context, {
    495        keyword,
    496        content: `${keyword} baz`,
    497        description: "third suggestion",
    498      }),
    499    ],
    500  });
    501 
    502  query = `${keyword} foo`;
    503  context = createContext(query, { isPrivate: false });
    504  await check_results({
    505    context,
    506    matches: [
    507      makeOmniboxResult(context, {
    508        heuristic: true,
    509        keyword,
    510        description: extensionName,
    511        content: `${keyword} foo`,
    512      }),
    513      makeOmniboxResult(context, {
    514        keyword,
    515        content: `${keyword} bar`,
    516        description: "second suggestion",
    517      }),
    518      makeOmniboxResult(context, {
    519        keyword,
    520        content: `${keyword} baz`,
    521        description: "third suggestion",
    522      }),
    523    ],
    524  });
    525 
    526  query = `${keyword} bar`;
    527  context = createContext(query, { isPrivate: false });
    528  await check_results({
    529    context,
    530    matches: [
    531      makeOmniboxResult(context, {
    532        heuristic: true,
    533        keyword,
    534        description: extensionName,
    535        content: `${keyword} bar`,
    536      }),
    537      makeOmniboxResult(context, {
    538        keyword,
    539        content: `${keyword} foo`,
    540        description: "first suggestion",
    541      }),
    542      makeOmniboxResult(context, {
    543        keyword,
    544        content: `${keyword} baz`,
    545        description: "third suggestion",
    546      }),
    547    ],
    548  });
    549 
    550  query = `${keyword} baz`;
    551  context = createContext(query, { isPrivate: false });
    552  await check_results({
    553    context,
    554    matches: [
    555      makeOmniboxResult(context, {
    556        heuristic: true,
    557        keyword,
    558        description: extensionName,
    559        content: `${keyword} baz`,
    560      }),
    561      makeOmniboxResult(context, {
    562        keyword,
    563        content: `${keyword} foo`,
    564        description: "first suggestion",
    565      }),
    566      makeOmniboxResult(context, {
    567        keyword,
    568        content: `${keyword} bar`,
    569        description: "second suggestion",
    570      }),
    571    ],
    572  });
    573 
    574  ExtensionSearchHandler.unregisterKeyword(keyword);
    575  await cleanup();
    576 });
    577 
    578 add_task(async function test_extension_results_should_come_first() {
    579  let keyword = "test";
    580  let extensionName = "Omnibox Example";
    581 
    582  let uri = Services.io.newURI(`http://a.com/b`);
    583  await PlacesTestUtils.addVisits([{ uri, title: `${keyword} -` }]);
    584 
    585  let mockExtension = {
    586    name: extensionName,
    587    emit(message, text, id) {
    588      if (message === ExtensionSearchHandler.MSG_INPUT_CHANGED) {
    589        ExtensionSearchHandler.addSuggestions(keyword, id, [
    590          { content: "foo", description: "first suggestion" },
    591          { content: "bar", description: "second suggestion" },
    592          { content: "baz", description: "third suggestion" },
    593        ]);
    594      }
    595    },
    596  };
    597 
    598  ExtensionSearchHandler.registerKeyword(keyword, mockExtension);
    599 
    600  // Start an input session before testing MSG_INPUT_CHANGED.
    601  ExtensionSearchHandler.handleSearch(
    602    { keyword, text: `${keyword} ` },
    603    () => {}
    604  );
    605 
    606  let query = `${keyword} -`;
    607  let context = createContext(query, { isPrivate: false });
    608  await check_results({
    609    context,
    610    matches: [
    611      makeOmniboxResult(context, {
    612        heuristic: true,
    613        keyword,
    614        description: extensionName,
    615        content: `${keyword} -`,
    616      }),
    617      makeOmniboxResult(context, {
    618        keyword,
    619        content: `${keyword} foo`,
    620        description: "first suggestion",
    621      }),
    622      makeOmniboxResult(context, {
    623        keyword,
    624        content: `${keyword} bar`,
    625        description: "second suggestion",
    626      }),
    627      makeOmniboxResult(context, {
    628        keyword,
    629        content: `${keyword} baz`,
    630        description: "third suggestion",
    631      }),
    632      makeVisitResult(context, {
    633        uri: `http://a.com/b`,
    634        title: `${keyword} -`,
    635      }),
    636    ],
    637  });
    638 
    639  ExtensionSearchHandler.unregisterKeyword(keyword);
    640  await cleanup();
    641 });
    642 
    643 add_task(async function test_setting_the_default_suggestion() {
    644  let keyword = "test";
    645  let extensionName = "Omnibox Example";
    646 
    647  let mockExtension = {
    648    name: extensionName,
    649    emit(message, text, id) {
    650      if (message === ExtensionSearchHandler.MSG_INPUT_CHANGED) {
    651        ExtensionSearchHandler.addSuggestions(keyword, id, []);
    652        // The API doesn't have a way to notify when addition is complete.
    653        do_timeout(1000, () => {
    654          controller.stopSearch();
    655        });
    656      }
    657    },
    658  };
    659 
    660  ExtensionSearchHandler.registerKeyword(keyword, mockExtension);
    661 
    662  ExtensionSearchHandler.setDefaultSuggestion(keyword, {
    663    description: "hello world",
    664  });
    665 
    666  let query = `${keyword} search query`;
    667  let context = createContext(query, { isPrivate: false });
    668  await check_results({
    669    context,
    670    matches: [
    671      makeOmniboxResult(context, {
    672        heuristic: true,
    673        keyword,
    674        description: "hello world",
    675        content: query,
    676      }),
    677    ],
    678  });
    679 
    680  ExtensionSearchHandler.setDefaultSuggestion(keyword, {
    681    description: "foo bar",
    682  });
    683 
    684  context = createContext(query, { isPrivate: false });
    685  await check_results({
    686    context,
    687    searchParam: "enable-actions",
    688    matches: [
    689      makeOmniboxResult(context, {
    690        heuristic: true,
    691        keyword,
    692        description: "foo bar",
    693        content: query,
    694      }),
    695    ],
    696  });
    697 
    698  ExtensionSearchHandler.unregisterKeyword(keyword);
    699  await cleanup();
    700 });
    701 
    702 add_task(async function test_maximum_number_of_suggestions_is_enforced() {
    703  let keyword = "test";
    704  let extensionName = "Omnibox Example";
    705 
    706  let mockExtension = {
    707    name: extensionName,
    708    emit(message, text, id) {
    709      if (message === ExtensionSearchHandler.MSG_INPUT_CHANGED) {
    710        ExtensionSearchHandler.addSuggestions(keyword, id, [
    711          { content: "a", description: "first suggestion" },
    712          { content: "b", description: "second suggestion" },
    713          { content: "c", description: "third suggestion" },
    714          { content: "d", description: "fourth suggestion" },
    715          { content: "e", description: "fifth suggestion" },
    716          { content: "f", description: "sixth suggestion" },
    717          { content: "g", description: "seventh suggestion" },
    718          { content: "h", description: "eigth suggestion" },
    719          { content: "i", description: "ninth suggestion" },
    720          { content: "j", description: "tenth suggestion" },
    721          { content: "k", description: "eleventh suggestion" },
    722          { content: "l", description: "twelfth suggestion" },
    723        ]);
    724        // The API doesn't have a way to notify when addition is complete.
    725        do_timeout(1000, () => {
    726          controller.stopSearch();
    727        });
    728      }
    729    },
    730  };
    731 
    732  ExtensionSearchHandler.registerKeyword(keyword, mockExtension);
    733 
    734  // Start an input session before testing MSG_INPUT_CHANGED.
    735  ExtensionSearchHandler.handleSearch(
    736    { keyword, text: `${keyword} ` },
    737    () => {}
    738  );
    739 
    740  let query = `${keyword} #`;
    741  let context = createContext(query, { isPrivate: false });
    742  await check_results({
    743    context,
    744    matches: [
    745      makeOmniboxResult(context, {
    746        heuristic: true,
    747        keyword,
    748        description: extensionName,
    749        content: `${keyword} #`,
    750      }),
    751      makeOmniboxResult(context, {
    752        keyword,
    753        content: `${keyword} a`,
    754        description: "first suggestion",
    755      }),
    756      makeOmniboxResult(context, {
    757        keyword,
    758        content: `${keyword} b`,
    759        description: "second suggestion",
    760      }),
    761      makeOmniboxResult(context, {
    762        keyword,
    763        content: `${keyword} c`,
    764        description: "third suggestion",
    765      }),
    766      makeOmniboxResult(context, {
    767        keyword,
    768        content: `${keyword} d`,
    769        description: "fourth suggestion",
    770      }),
    771      makeOmniboxResult(context, {
    772        keyword,
    773        content: `${keyword} e`,
    774        description: "fifth suggestion",
    775      }),
    776      makeOmniboxResult(context, {
    777        keyword,
    778        content: `${keyword} f`,
    779        description: "sixth suggestion",
    780      }),
    781      makeOmniboxResult(context, {
    782        keyword,
    783        content: `${keyword} g`,
    784        description: "seventh suggestion",
    785      }),
    786      makeOmniboxResult(context, {
    787        keyword,
    788        content: `${keyword} h`,
    789        description: "eigth suggestion",
    790      }),
    791      makeOmniboxResult(context, {
    792        keyword,
    793        content: `${keyword} i`,
    794        description: "ninth suggestion",
    795      }),
    796    ],
    797  });
    798 
    799  ExtensionSearchHandler.unregisterKeyword(keyword);
    800  await cleanup();
    801 });
    802 
    803 add_task(async function conflicting_alias() {
    804  Services.prefs.setBoolPref(SUGGEST_PREF, true);
    805  Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true);
    806 
    807  let engine = await addTestSuggestionsEngine();
    808  let keyword = "test";
    809  engine.alias = keyword;
    810  let oldDefaultEngine = await Services.search.getDefault();
    811  Services.search.setDefault(engine, Ci.nsISearchService.CHANGE_REASON_UNKNOWN);
    812 
    813  let extensionName = "Omnibox Example";
    814 
    815  let mockExtension = {
    816    name: extensionName,
    817    emit(message, text, id) {
    818      if (message === ExtensionSearchHandler.MSG_INPUT_CHANGED) {
    819        ExtensionSearchHandler.addSuggestions(keyword, id, [
    820          { content: "foo", description: "first suggestion" },
    821          { content: "bar", description: "second suggestion" },
    822          { content: "baz", description: "third suggestion" },
    823        ]);
    824        // The API doesn't have a way to notify when addition is complete.
    825        do_timeout(1000, () => {
    826          controller.stopSearch();
    827        });
    828      }
    829    },
    830  };
    831 
    832  ExtensionSearchHandler.registerKeyword(keyword, mockExtension);
    833  let query = `${keyword} unmatched`;
    834  let context = createContext(query, { isPrivate: false });
    835  await check_results({
    836    context,
    837    matches: [
    838      makeOmniboxResult(context, {
    839        heuristic: true,
    840        keyword,
    841        description: extensionName,
    842        content: `${keyword} unmatched`,
    843      }),
    844      makeOmniboxResult(context, {
    845        keyword,
    846        content: `${keyword} foo`,
    847        description: "first suggestion",
    848      }),
    849      makeOmniboxResult(context, {
    850        keyword,
    851        content: `${keyword} bar`,
    852        description: "second suggestion",
    853      }),
    854      makeOmniboxResult(context, {
    855        keyword,
    856        content: `${keyword} baz`,
    857        description: "third suggestion",
    858      }),
    859      makeSearchResult(context, {
    860        query: "unmatched",
    861        engineName: SUGGESTIONS_ENGINE_NAME,
    862        alias: keyword,
    863        suggestion: "unmatched",
    864      }),
    865      makeSearchResult(context, {
    866        query: "unmatched",
    867        engineName: SUGGESTIONS_ENGINE_NAME,
    868        alias: keyword,
    869        suggestion: "unmatched foo",
    870      }),
    871      makeSearchResult(context, {
    872        query: "unmatched",
    873        engineName: SUGGESTIONS_ENGINE_NAME,
    874        alias: keyword,
    875        suggestion: "unmatched bar",
    876      }),
    877    ],
    878  });
    879 
    880  Services.search.setDefault(
    881    oldDefaultEngine,
    882    Ci.nsISearchService.CHANGE_REASON_UNKNOWN
    883  );
    884  Services.prefs.setBoolPref(SUGGEST_PREF, false);
    885  Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, false);
    886  await cleanup();
    887 });