tor-browser

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

test_quicksuggest_yelp.js (32253B)


      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 // Tests Yelp suggestions.
      6 
      7 "use strict";
      8 
      9 ChromeUtils.defineESModuleGetters(this, {
     10  UrlbarProviderSearchSuggestions:
     11    "moz-src:///browser/components/urlbar/UrlbarProviderSearchSuggestions.sys.mjs",
     12 });
     13 
     14 const { GEOLOCATION } = MerinoTestUtils;
     15 
     16 const CONFIG_V2 = [
     17  {
     18    identifier: "engine_with_suggestions",
     19    base: {
     20      urls: {
     21        suggestions: {
     22          // This url will never respond with search suggestions.
     23          base: "https://mochi.test/",
     24          searchTermParamName: "q",
     25        },
     26      },
     27    },
     28  },
     29 ];
     30 
     31 const REMOTE_SETTINGS_RECORDS = [
     32  {
     33    type: "yelp-suggestions",
     34    attachment: {
     35      subjects: ["a service"],
     36      businessSubjects: ["the shop", "ab", "alongerkeyword", "1234"],
     37      preModifiers: ["best", "local"],
     38      postModifiers: ["delivery"],
     39      locationSigns: ["in", "nearby"],
     40      yelpModifiers: [],
     41      icon: "1234",
     42      score: 0.5,
     43    },
     44  },
     45  ...QuickSuggestTestUtils.geonamesRecords(),
     46  ...QuickSuggestTestUtils.geonamesAlternatesRecords(),
     47 ];
     48 
     49 const TOKYO_RESULT = {
     50  url: "https://www.yelp.com/search?find_desc=the+shop&find_loc=Tokyo%2C+Tokyo-to",
     51  title: "the shop in Tokyo, Tokyo-to",
     52 };
     53 
     54 const AB_RESULT = {
     55  url: "https://www.yelp.com/search?find_desc=ab&find_loc=Yokohama%2C+Kanagawa",
     56  title: "ab in Yokohama, Kanagawa",
     57 };
     58 
     59 const ALONGERKEYWORD_RESULT = {
     60  url: "https://www.yelp.com/search?find_desc=alongerkeyword&find_loc=Yokohama%2C+Kanagawa",
     61  title: "alongerkeyword in Yokohama, Kanagawa",
     62 };
     63 
     64 add_setup(async function () {
     65  // Add a search engine with search suggestions so sponsored suggestions can
     66  // be shown first. See the `quickSuggestSponsoredIndex` pref for more info.
     67  SearchTestUtils.setRemoteSettingsConfig(CONFIG_V2);
     68  await Services.search.init();
     69  await QuickSuggestTestUtils.ensureQuickSuggestInit({
     70    remoteSettingsRecords: REMOTE_SETTINGS_RECORDS,
     71    prefs: [
     72      ["suggest.quicksuggest.sponsored", true],
     73      ["yelp.serviceResultDistinction", true],
     74    ],
     75  });
     76 
     77  await MerinoTestUtils.initGeolocation();
     78 
     79  // Many parts of this test assume the default minKeywordLength is 4. Please
     80  // update it if the default changes.
     81  Assert.equal(
     82    UrlbarPrefs.get("yelp.minKeywordLength"),
     83    4,
     84    "Sanity check: This test assumes the default minKeywordLength is 4"
     85  );
     86 });
     87 
     88 add_task(async function basic() {
     89  const TEST_DATA = [
     90    {
     91      description: "Basic service subject",
     92      query: "best a service delivery in tokyo",
     93      expected: {
     94        url: "https://www.yelp.com/search?find_desc=best+a+service+delivery&find_loc=Tokyo%2C+Tokyo-to",
     95        titleL10n: {
     96          id: "firefox-suggest-yelp-service-title",
     97          args: {
     98            service: "best a service delivery in Tokyo, Tokyo-to",
     99          },
    100          argsHighlights: {
    101            service: [
    102              [0, 4],
    103              [5, 1],
    104              [7, 7],
    105              [15, 8],
    106              [24, 2],
    107              [27, 5],
    108              [34, 5],
    109            ],
    110          },
    111        },
    112        title: "best a service delivery in Tokyo, Tokyo-to",
    113      },
    114    },
    115    {
    116      description: "Basic business subject",
    117      query: "local the shop delivery in tokyo",
    118      expected: {
    119        url: "https://www.yelp.com/search?find_desc=local+the+shop+delivery&find_loc=Tokyo%2C+Tokyo-to",
    120        title: "local the shop delivery in Tokyo, Tokyo-to",
    121      },
    122    },
    123    {
    124      description: "With upper case",
    125      query: "LoCaL tHe ShOp dElIvErY iN tOkYo",
    126      expected: {
    127        url: "https://www.yelp.com/search?find_desc=LoCaL+tHe+ShOp+dElIvErY&find_loc=Tokyo%2C+Tokyo-to",
    128        title: "LoCaL tHe ShOp dElIvErY iN Tokyo, Tokyo-to",
    129      },
    130    },
    131    {
    132      description: "No specific location with location-sign",
    133      query: "the shop in",
    134      expected: {
    135        url: "https://www.yelp.com/search?find_desc=the+shop&find_loc=Yokohama%2C+Kanagawa",
    136        title: "the shop in Yokohama, Kanagawa",
    137      },
    138    },
    139    {
    140      description: "No specific location with location-modifier",
    141      query: "the shop nearby",
    142      expected: {
    143        url: "https://www.yelp.com/search?find_desc=the+shop&find_loc=Yokohama%2C+Kanagawa",
    144        title: "the shop nearby Yokohama, Kanagawa",
    145      },
    146    },
    147    {
    148      description: "Query too short, no subject exact match: th",
    149      query: "th",
    150      expected: null,
    151    },
    152    {
    153      description: "Query too short, no subject not exact match: the",
    154      query: "the",
    155      expected: null,
    156    },
    157    {
    158      description: "Query too short, no subject not exact match: the ",
    159      query: "the ",
    160      expected: {
    161        url: "https://www.yelp.com/search?find_desc=the+shop&find_loc=Yokohama%2C+Kanagawa",
    162        title: "the shop in Yokohama, Kanagawa",
    163      },
    164    },
    165    {
    166      description: "Query length == minKeywordLength, no subject exact the s",
    167      query: "the s",
    168      expected: {
    169        url: "https://www.yelp.com/search?find_desc=the+shop&find_loc=Yokohama%2C+Kanagawa",
    170        title: "the shop in Yokohama, Kanagawa",
    171      },
    172    },
    173    {
    174      description:
    175        "Query length == minKeywordLength, subject exact match: 1234",
    176      query: "1234",
    177      expected: {
    178        url: "https://www.yelp.com/search?find_desc=1234&find_loc=Yokohama%2C+Kanagawa",
    179        title: "1234 in Yokohama, Kanagawa",
    180      },
    181    },
    182    {
    183      description:
    184        "Query length > minKeywordLength, subject exact match: the shop",
    185      query: "the shop",
    186      expected: {
    187        url: "https://www.yelp.com/search?find_desc=the+shop&find_loc=Yokohama%2C+Kanagawa",
    188        title: "the shop in Yokohama, Kanagawa",
    189      },
    190    },
    191    {
    192      description: "Pre-modifier only",
    193      query: "best",
    194      expected: null,
    195    },
    196    {
    197      description: "Pre-modifier only with trailing space",
    198      query: "best ",
    199      expected: null,
    200    },
    201    {
    202      description: "Pre-modifier, subject too short",
    203      query: "best r",
    204      expected: null,
    205    },
    206    {
    207      description: "Pre-modifier, query long enough, subject long enough",
    208      query: "local th",
    209      expected: {
    210        url: "https://www.yelp.com/search?find_desc=local+the+shop&find_loc=Yokohama%2C+Kanagawa",
    211        title: "local the shop in Yokohama, Kanagawa",
    212      },
    213    },
    214    {
    215      description: "Subject exact match with length < minKeywordLength",
    216      query: "ab",
    217      expected: AB_RESULT,
    218    },
    219    {
    220      description:
    221        "Subject exact match with length < minKeywordLength, showLessFrequentlyCount non-zero",
    222      query: "ab",
    223      showLessFrequentlyCount: 1,
    224      expected: null,
    225    },
    226    {
    227      description:
    228        "Subject exact match with length == minKeywordLength, showLessFrequentlyCount non-zero",
    229      query: "1234",
    230      showLessFrequentlyCount: 1,
    231      expected: {
    232        url: "https://www.yelp.com/search?find_desc=1234&find_loc=Yokohama%2C+Kanagawa",
    233        title: "1234 in Yokohama, Kanagawa",
    234      },
    235    },
    236    {
    237      description:
    238        "Subject exact match with length > minKeywordLength, showLessFrequentlyCount non-zero",
    239      query: "the shop",
    240      showLessFrequentlyCount: 1,
    241      expected: {
    242        url: "https://www.yelp.com/search?find_desc=the+shop&find_loc=Yokohama%2C+Kanagawa",
    243        title: "the shop in Yokohama, Kanagawa",
    244      },
    245    },
    246    {
    247      description: "Query too short: alo",
    248      query: "alo",
    249      expected: null,
    250    },
    251    {
    252      description: "Query length == minKeywordLength, subject not exact match",
    253      query: "alon",
    254      expected: ALONGERKEYWORD_RESULT,
    255    },
    256    {
    257      description: "Query length > minKeywordLength, subject not exact match",
    258      query: "along",
    259      expected: ALONGERKEYWORD_RESULT,
    260    },
    261    {
    262      description:
    263        "Query length == minKeywordLength, subject not exact match, showLessFrequentlyCount non-zero",
    264      query: "alon",
    265      showLessFrequentlyCount: 1,
    266      expected: ALONGERKEYWORD_RESULT,
    267    },
    268    {
    269      description:
    270        "Query length == minKeywordLength + showLessFrequentlyCount, subject not exact match",
    271      query: "along",
    272      showLessFrequentlyCount: 1,
    273      expected: ALONGERKEYWORD_RESULT,
    274    },
    275    {
    276      description:
    277        "Query length < minKeywordLength + showLessFrequentlyCount, subject not exact match",
    278      query: "along",
    279      showLessFrequentlyCount: 2,
    280      expected: ALONGERKEYWORD_RESULT,
    281    },
    282    {
    283      description:
    284        "Query length == minKeywordLength + showLessFrequentlyCount, subject not exact match",
    285      query: "alonge",
    286      showLessFrequentlyCount: 2,
    287      expected: ALONGERKEYWORD_RESULT,
    288    },
    289  ];
    290 
    291  for (let {
    292    description,
    293    query,
    294    showLessFrequentlyCount,
    295    expected,
    296  } of TEST_DATA) {
    297    info(
    298      "Doing basic subtest: " +
    299        JSON.stringify({
    300          description,
    301          query,
    302          showLessFrequentlyCount,
    303          expected,
    304        })
    305    );
    306 
    307    if (typeof showLessFrequentlyCount == "number") {
    308      UrlbarPrefs.set("yelp.showLessFrequentlyCount", showLessFrequentlyCount);
    309    }
    310 
    311    await check_results({
    312      context: createContext(query, {
    313        providers: [
    314          UrlbarProviderQuickSuggest.name,
    315          UrlbarProviderSearchSuggestions.name,
    316        ],
    317        isPrivate: false,
    318      }),
    319      matches: expected ? [QuickSuggestTestUtils.yelpResult(expected)] : [],
    320    });
    321 
    322    UrlbarPrefs.clear("yelp.showLessFrequentlyCount");
    323  }
    324 });
    325 
    326 add_task(async function telemetryType() {
    327  Assert.equal(
    328    QuickSuggest.getFeature("YelpSuggestions").getSuggestionTelemetryType({}),
    329    "yelp",
    330    "Telemetry type should be 'yelp'"
    331  );
    332 });
    333 
    334 // When relevant Yelp and Suggest prefs are disabled, suggestions should not be
    335 // added.
    336 add_task(async function prefsDisabled() {
    337  const prefs = [
    338    "suggest.yelp",
    339    "yelp.featureGate",
    340    "suggest.quicksuggest.all",
    341    "suggest.quicksuggest.sponsored",
    342    "quicksuggest.enabled",
    343  ];
    344  for (const pref of prefs) {
    345    info("Doing test with pref: " + pref);
    346 
    347    // First make sure the suggestion is added, if the rust is enabled.
    348    await check_results({
    349      context: createContext("the shop in tokyo", {
    350        providers: [
    351          UrlbarProviderQuickSuggest.name,
    352          UrlbarProviderSearchSuggestions.name,
    353        ],
    354        isPrivate: false,
    355      }),
    356      matches: [QuickSuggestTestUtils.yelpResult(TOKYO_RESULT)],
    357    });
    358 
    359    // Now disable the pref.
    360    UrlbarPrefs.set(pref, false);
    361    Assert.ok(
    362      !QuickSuggest.getFeature("YelpSuggestions").isEnabled,
    363      "Yelp should be disabled"
    364    );
    365    await check_results({
    366      context: createContext("the shop in tokyo", {
    367        providers: [
    368          UrlbarProviderQuickSuggest.name,
    369          UrlbarProviderSearchSuggestions.name,
    370        ],
    371        isPrivate: false,
    372      }),
    373      matches: [],
    374    });
    375 
    376    // Revert.
    377    UrlbarPrefs.set(pref, true);
    378    await QuickSuggestTestUtils.forceSync();
    379 
    380    // Make sure Yelp is enabled again.
    381    Assert.ok(
    382      QuickSuggest.getFeature("YelpSuggestions").isEnabled,
    383      "Yelp should be re-enabled"
    384    );
    385    await check_results({
    386      context: createContext("the shop in tokyo", {
    387        providers: [
    388          UrlbarProviderQuickSuggest.name,
    389          UrlbarProviderSearchSuggestions.name,
    390        ],
    391        isPrivate: false,
    392      }),
    393      matches: [QuickSuggestTestUtils.yelpResult(TOKYO_RESULT)],
    394    });
    395  }
    396 });
    397 
    398 // Check wheather the Yelp suggestions will be shown by the setup of Nimbus
    399 // variable.
    400 add_task(async function featureGate() {
    401  // Disable the fature gate.
    402  UrlbarPrefs.set("yelp.featureGate", false);
    403  await check_results({
    404    context: createContext("the shop in tokyo", {
    405      providers: [
    406        UrlbarProviderQuickSuggest.name,
    407        UrlbarProviderSearchSuggestions.name,
    408      ],
    409      isPrivate: false,
    410    }),
    411    matches: [],
    412  });
    413 
    414  // Enable by Nimbus.
    415  const cleanUpNimbusEnable = await UrlbarTestUtils.initNimbusFeature({
    416    yelpFeatureGate: true,
    417  });
    418  await QuickSuggestTestUtils.forceSync();
    419  await check_results({
    420    context: createContext("the shop in tokyo", {
    421      providers: [
    422        UrlbarProviderQuickSuggest.name,
    423        UrlbarProviderSearchSuggestions.name,
    424      ],
    425      isPrivate: false,
    426    }),
    427    matches: [QuickSuggestTestUtils.yelpResult(TOKYO_RESULT)],
    428  });
    429  await cleanUpNimbusEnable();
    430 
    431  // Enable locally.
    432  UrlbarPrefs.set("yelp.featureGate", true);
    433  await QuickSuggestTestUtils.forceSync();
    434 
    435  // Disable by Nimbus.
    436  const cleanUpNimbusDisable = await UrlbarTestUtils.initNimbusFeature({
    437    yelpFeatureGate: false,
    438  });
    439  await check_results({
    440    context: createContext("the shop in tokyo", {
    441      providers: [
    442        UrlbarProviderQuickSuggest.name,
    443        UrlbarProviderSearchSuggestions.name,
    444      ],
    445      isPrivate: false,
    446    }),
    447    matches: [],
    448  });
    449  await cleanUpNimbusDisable();
    450 
    451  // Revert.
    452  UrlbarPrefs.set("yelp.featureGate", true);
    453  await QuickSuggestTestUtils.forceSync();
    454 });
    455 
    456 // Check wheather the Yelp suggestions will be shown as top_pick by the Nimbus
    457 // variable.
    458 add_task(async function yelpSuggestPriority() {
    459  // Enable by Nimbus.
    460  const cleanUpNimbusEnable = await UrlbarTestUtils.initNimbusFeature({
    461    yelpSuggestPriority: true,
    462  });
    463  await QuickSuggestTestUtils.forceSync();
    464 
    465  await check_results({
    466    context: createContext("the shop in tokyo", {
    467      providers: [
    468        UrlbarProviderQuickSuggest.name,
    469        UrlbarProviderSearchSuggestions.name,
    470      ],
    471      isPrivate: false,
    472    }),
    473    matches: [
    474      QuickSuggestTestUtils.yelpResult({
    475        ...TOKYO_RESULT,
    476        isTopPick: true,
    477      }),
    478    ],
    479  });
    480 
    481  await cleanUpNimbusEnable();
    482  await QuickSuggestTestUtils.forceSync();
    483 
    484  await check_results({
    485    context: createContext("the shop in tokyo", {
    486      providers: [
    487        UrlbarProviderQuickSuggest.name,
    488        UrlbarProviderSearchSuggestions.name,
    489      ],
    490      isPrivate: false,
    491    }),
    492    matches: [
    493      QuickSuggestTestUtils.yelpResult({
    494        ...TOKYO_RESULT,
    495        isTopPick: false,
    496      }),
    497    ],
    498  });
    499 });
    500 
    501 // Tests the `yelpSuggestNonPriorityIndex` Nimbus variable, which controls the
    502 // group-relative suggestedIndex.
    503 add_task(async function nimbusSuggestedIndex() {
    504  // When the Nimbus variable is defined, it should override the default
    505  // suggested index used for Yelp. We use -2 here since that's unlikely to ever
    506  // be the default Yelp index.
    507  const cleanUpNimbusEnable = await UrlbarTestUtils.initNimbusFeature({
    508    yelpSuggestNonPriorityIndex: -2,
    509  });
    510  await QuickSuggestTestUtils.forceSync();
    511 
    512  await check_results({
    513    context: createContext("the shop in tokyo", {
    514      providers: [
    515        UrlbarProviderQuickSuggest.name,
    516        UrlbarProviderSearchSuggestions.name,
    517      ],
    518      isPrivate: false,
    519    }),
    520    matches: [
    521      QuickSuggestTestUtils.yelpResult({
    522        ...TOKYO_RESULT,
    523        isTopPick: false,
    524        suggestedIndex: -2,
    525      }),
    526    ],
    527  });
    528 
    529  await cleanUpNimbusEnable();
    530  await QuickSuggestTestUtils.forceSync();
    531 
    532  // When the Nimbus variable isn't defined, the suggested index should be the
    533  // default index used for Yelp, which is the sponsored suggestions index, 0.
    534  await check_results({
    535    context: createContext("the shop in tokyo", {
    536      providers: [
    537        UrlbarProviderQuickSuggest.name,
    538        UrlbarProviderSearchSuggestions.name,
    539      ],
    540      isPrivate: false,
    541    }),
    542    matches: [
    543      QuickSuggestTestUtils.yelpResult({
    544        ...TOKYO_RESULT,
    545        isTopPick: false,
    546        suggestedIndex: 0,
    547      }),
    548    ],
    549  });
    550 });
    551 
    552 // Tests the suggestedIndex if the browser.urlbar.showSearchSuggestionsFirst pref
    553 // is false.
    554 add_task(async function showSearchSuggestionsFirstDisabledSuggestedIndex() {
    555  info("Disable browser.urlbar.showSearchSuggestionsFirst pref");
    556  UrlbarPrefs.set("showSearchSuggestionsFirst", false);
    557  await check_results({
    558    context: createContext("the shop in tokyo", {
    559      providers: [
    560        UrlbarProviderQuickSuggest.name,
    561        UrlbarProviderSearchSuggestions.name,
    562      ],
    563      isPrivate: false,
    564    }),
    565    matches: [
    566      QuickSuggestTestUtils.yelpResult({
    567        ...TOKYO_RESULT,
    568        isTopPick: false,
    569        suggestedIndex: -1,
    570      }),
    571    ],
    572  });
    573 
    574  info("Enable browser.urlbar.showSearchSuggestionsFirst pref");
    575  UrlbarPrefs.set("showSearchSuggestionsFirst", true);
    576  await check_results({
    577    context: createContext("the shop in tokyo", {
    578      providers: [
    579        UrlbarProviderQuickSuggest.name,
    580        UrlbarProviderSearchSuggestions.name,
    581      ],
    582      isPrivate: false,
    583    }),
    584    matches: [
    585      QuickSuggestTestUtils.yelpResult({
    586        ...TOKYO_RESULT,
    587        isTopPick: false,
    588        suggestedIndex: 0,
    589      }),
    590    ],
    591  });
    592 
    593  UrlbarPrefs.clear("showSearchSuggestionsFirst");
    594 });
    595 
    596 // Tests the "Not relevant" command: a dismissed suggestion shouldn't be added.
    597 add_task(async function notRelevant() {
    598  await doDismissOneTest({
    599    result: QuickSuggestTestUtils.yelpResult(TOKYO_RESULT),
    600    command: "not_relevant",
    601    feature: QuickSuggest.getFeature("YelpSuggestions"),
    602    queriesForDismissals: [
    603      // Yelp suggestions are dismissed by URL excluding location, so all
    604      // "ramen in <valid location>" results should be dismissed.
    605      {
    606        query: "the shop in tokyo",
    607      },
    608      {
    609        query: "the shop in waterloo",
    610        expectedResults: [
    611          QuickSuggestTestUtils.yelpResult({
    612            url: "https://www.yelp.com/search?find_desc=the+shop&find_loc=Waterloo%2C+IA",
    613            title: "the shop in Waterloo, IA",
    614          }),
    615        ],
    616      },
    617    ],
    618    queriesForOthers: [
    619      {
    620        query: "alongerkeyword in tokyo",
    621        expectedResults: [
    622          QuickSuggestTestUtils.yelpResult({
    623            url: "https://www.yelp.com/search?find_desc=alongerkeyword&find_loc=Tokyo%2C+Tokyo-to",
    624            title: "alongerkeyword in Tokyo, Tokyo-to",
    625          }),
    626        ],
    627      },
    628    ],
    629    providers: [
    630      UrlbarProviderQuickSuggest.name,
    631      UrlbarProviderSearchSuggestions.name,
    632    ],
    633  });
    634 });
    635 
    636 // Tests the "Not interested" command: all Yelp suggestions should be disabled
    637 // and not added anymore.
    638 add_task(async function notInterested() {
    639  await doDismissAllTest({
    640    result: QuickSuggestTestUtils.yelpResult(TOKYO_RESULT),
    641    command: "not_interested",
    642    feature: QuickSuggest.getFeature("YelpSuggestions"),
    643    pref: "suggest.yelp",
    644    queries: [
    645      {
    646        query: "the shop in tokyo",
    647      },
    648      {
    649        query: "alongerkeyword in tokyo",
    650        expectedResults: [
    651          QuickSuggestTestUtils.yelpResult({
    652            url: "https://www.yelp.com/search?find_desc=alongerkeyword&find_loc=Tokyo%2C+Tokyo-to",
    653            title: "alongerkeyword in Tokyo, Tokyo-to",
    654          }),
    655        ],
    656      },
    657    ],
    658    providers: [
    659      UrlbarProviderQuickSuggest.name,
    660      UrlbarProviderSearchSuggestions.name,
    661    ],
    662  });
    663 });
    664 
    665 // Tests the "show less frequently" behavior.
    666 add_task(async function showLessFrequently() {
    667  UrlbarPrefs.clear("yelp.showLessFrequentlyCount");
    668  UrlbarPrefs.clear("yelp.minKeywordLength");
    669 
    670  let cleanUpNimbus = await UrlbarTestUtils.initNimbusFeature({
    671    yelpShowLessFrequentlyCap: 3,
    672  });
    673 
    674  let location = `${GEOLOCATION.city}, ${GEOLOCATION.region}`;
    675  let url = new URL("https://www.yelp.com/search");
    676  url.searchParams.set("find_desc", "local the shop");
    677  url.searchParams.set("find_loc", location);
    678 
    679  let result = QuickSuggestTestUtils.yelpResult({
    680    url: url.toString(),
    681    title: `local the shop in ${location}`,
    682  });
    683 
    684  const testData = [
    685    {
    686      input: "local the ",
    687      before: {
    688        canShowLessFrequently: true,
    689        showLessFrequentlyCount: 0,
    690        minKeywordLength: 4,
    691      },
    692      after: {
    693        canShowLessFrequently: true,
    694        showLessFrequentlyCount: 1,
    695        minKeywordLength: 11,
    696      },
    697    },
    698    {
    699      input: "local the s",
    700      before: {
    701        canShowLessFrequently: true,
    702        showLessFrequentlyCount: 1,
    703        minKeywordLength: 11,
    704      },
    705      after: {
    706        canShowLessFrequently: true,
    707        showLessFrequentlyCount: 2,
    708        minKeywordLength: 12,
    709      },
    710    },
    711    {
    712      input: "local the sh",
    713      before: {
    714        canShowLessFrequently: true,
    715        showLessFrequentlyCount: 2,
    716        minKeywordLength: 12,
    717      },
    718      after: {
    719        canShowLessFrequently: false,
    720        showLessFrequentlyCount: 3,
    721        minKeywordLength: 13,
    722      },
    723    },
    724    {
    725      input: "local the sho",
    726      before: {
    727        canShowLessFrequently: false,
    728        showLessFrequentlyCount: 3,
    729        minKeywordLength: 13,
    730      },
    731      after: {
    732        canShowLessFrequently: false,
    733        showLessFrequentlyCount: 3,
    734        minKeywordLength: 14,
    735      },
    736    },
    737    {
    738      input: "local the shop",
    739      before: {
    740        canShowLessFrequently: false,
    741        showLessFrequentlyCount: 3,
    742        minKeywordLength: 14,
    743      },
    744      after: {
    745        canShowLessFrequently: false,
    746        showLessFrequentlyCount: 3,
    747        minKeywordLength: 15,
    748      },
    749    },
    750  ];
    751 
    752  for (let { input, before, after } of testData) {
    753    let feature = QuickSuggest.getFeature("YelpSuggestions");
    754 
    755    await check_results({
    756      context: createContext(input, {
    757        providers: [
    758          UrlbarProviderQuickSuggest.name,
    759          UrlbarProviderSearchSuggestions.name,
    760        ],
    761        isPrivate: false,
    762      }),
    763      matches: [result],
    764    });
    765 
    766    Assert.equal(
    767      UrlbarPrefs.get("yelp.minKeywordLength"),
    768      before.minKeywordLength
    769    );
    770    Assert.equal(feature.canShowLessFrequently, before.canShowLessFrequently);
    771    Assert.equal(
    772      feature.showLessFrequentlyCount,
    773      before.showLessFrequentlyCount
    774    );
    775 
    776    triggerCommand({
    777      result,
    778      feature,
    779      command: "show_less_frequently",
    780      searchString: input,
    781      expectedCountsByCall: {
    782        acknowledgeFeedback: 1,
    783        invalidateResultMenuCommands: after.canShowLessFrequently ? 0 : 1,
    784      },
    785    });
    786 
    787    Assert.equal(
    788      UrlbarPrefs.get("yelp.minKeywordLength"),
    789      after.minKeywordLength
    790    );
    791    Assert.equal(feature.canShowLessFrequently, after.canShowLessFrequently);
    792    Assert.equal(
    793      feature.showLessFrequentlyCount,
    794      after.showLessFrequentlyCount
    795    );
    796 
    797    await check_results({
    798      context: createContext(input, {
    799        providers: [
    800          UrlbarProviderQuickSuggest.name,
    801          UrlbarProviderSearchSuggestions.name,
    802        ],
    803        isPrivate: false,
    804      }),
    805      matches: [],
    806    });
    807  }
    808 
    809  await cleanUpNimbus();
    810  UrlbarPrefs.clear("yelp.showLessFrequentlyCount");
    811  UrlbarPrefs.clear("yelp.minKeywordLength");
    812 });
    813 
    814 // The `Yelp` Rust provider should be passed to the Rust component when
    815 // querying depending on whether Yelp suggestions are enabled.
    816 add_task(async function rustProviders() {
    817  await doRustProvidersTests({
    818    searchString: "the shop in tokyo",
    819    tests: [
    820      {
    821        prefs: {
    822          "suggest.yelp": true,
    823        },
    824        expectedUrls: [
    825          "https://www.yelp.com/search?find_desc=the+shop&find_loc=tokyo",
    826        ],
    827      },
    828      {
    829        prefs: {
    830          "suggest.yelp": false,
    831        },
    832        expectedUrls: [],
    833      },
    834    ],
    835  });
    836 
    837  UrlbarPrefs.clear("suggest.yelp");
    838  await QuickSuggestTestUtils.forceSync();
    839 });
    840 
    841 add_task(async function minKeywordLength_defaultPrefValue() {
    842  await doMinKeywordLengthTest({
    843    // expected min length: 5 (Nimbus value should override default pref value)
    844    prefUserValue: null,
    845    nimbusValue: 5,
    846    tests: [
    847      {
    848        query: "al",
    849        expected: null,
    850      },
    851      {
    852        query: "alo",
    853        expected: null,
    854      },
    855      {
    856        query: "alon",
    857        expected: null,
    858      },
    859      {
    860        query: "along",
    861        expected: ALONGERKEYWORD_RESULT,
    862      },
    863      {
    864        query: "alongerkeyword",
    865        expected: ALONGERKEYWORD_RESULT,
    866      },
    867      {
    868        query: "best a",
    869        expected: null,
    870      },
    871      {
    872        query: "best al",
    873        expected: {
    874          url: "https://www.yelp.com/search?find_desc=best+alongerkeyword&find_loc=Yokohama%2C+Kanagawa",
    875          title: "best alongerkeyword in Yokohama, Kanagawa",
    876        },
    877      },
    878      {
    879        query: "ab",
    880        expected: AB_RESULT,
    881      },
    882    ],
    883  });
    884 });
    885 
    886 add_task(async function minKeywordLength_smallerPrefUserValue() {
    887  await doMinKeywordLengthTest({
    888    // expected min length: 5 (pref user value)
    889    prefUserValue: 5,
    890    nimbusValue: 6,
    891    tests: [
    892      {
    893        query: "al",
    894        expected: null,
    895      },
    896      {
    897        query: "alo",
    898        expected: null,
    899      },
    900      {
    901        query: "alon",
    902        expected: null,
    903      },
    904      {
    905        query: "along",
    906        expected: ALONGERKEYWORD_RESULT,
    907      },
    908      {
    909        query: "alongerkeyword",
    910        expected: ALONGERKEYWORD_RESULT,
    911      },
    912      {
    913        query: "best a",
    914        expected: null,
    915      },
    916      {
    917        query: "best al",
    918        expected: {
    919          url: "https://www.yelp.com/search?find_desc=best+alongerkeyword&find_loc=Yokohama%2C+Kanagawa",
    920          title: "best alongerkeyword in Yokohama, Kanagawa",
    921        },
    922      },
    923      {
    924        query: "ab",
    925        expected: AB_RESULT,
    926      },
    927    ],
    928  });
    929 });
    930 
    931 add_task(async function minKeywordLength_largerPrefUserValue() {
    932  await doMinKeywordLengthTest({
    933    // expected min length: 6 (pref user value)
    934    prefUserValue: 6,
    935    nimbusValue: 5,
    936    tests: [
    937      {
    938        query: "al",
    939        expected: null,
    940      },
    941      {
    942        query: "alo",
    943        expected: null,
    944      },
    945      {
    946        query: "alon",
    947        expected: null,
    948      },
    949      {
    950        query: "along",
    951        expected: null,
    952      },
    953      {
    954        query: "alonge",
    955        expected: ALONGERKEYWORD_RESULT,
    956      },
    957      {
    958        query: "alongerkeyword",
    959        expected: ALONGERKEYWORD_RESULT,
    960      },
    961      {
    962        query: "best a",
    963        expected: null,
    964      },
    965      {
    966        query: "best al",
    967        expected: {
    968          url: "https://www.yelp.com/search?find_desc=best+alongerkeyword&find_loc=Yokohama%2C+Kanagawa",
    969          title: "best alongerkeyword in Yokohama, Kanagawa",
    970        },
    971      },
    972      {
    973        query: "ab",
    974        expected: AB_RESULT,
    975      },
    976    ],
    977  });
    978 });
    979 
    980 add_task(async function minKeywordLength_onlyPrefValue() {
    981  await doMinKeywordLengthTest({
    982    // expected min length: 5 (pref user value)
    983    prefUserValue: 5,
    984    nimbusValue: null,
    985    tests: [
    986      {
    987        query: "al",
    988        expected: null,
    989      },
    990      {
    991        query: "alo",
    992        expected: null,
    993      },
    994      {
    995        query: "alon",
    996        expected: null,
    997      },
    998      {
    999        query: "along",
   1000        expected: ALONGERKEYWORD_RESULT,
   1001      },
   1002      {
   1003        query: "alongerkeyword",
   1004        expected: ALONGERKEYWORD_RESULT,
   1005      },
   1006      {
   1007        query: "best a",
   1008        expected: null,
   1009      },
   1010      {
   1011        query: "best al",
   1012        expected: {
   1013          url: "https://www.yelp.com/search?find_desc=best+alongerkeyword&find_loc=Yokohama%2C+Kanagawa",
   1014          title: "best alongerkeyword in Yokohama, Kanagawa",
   1015        },
   1016      },
   1017      {
   1018        query: "ab",
   1019        expected: AB_RESULT,
   1020      },
   1021    ],
   1022  });
   1023 });
   1024 
   1025 add_task(async function minKeywordLength_noNimbusOrPrefUserValue() {
   1026  await doMinKeywordLengthTest({
   1027    // expected min length: 4 (pref default value)
   1028    prefUserValue: null,
   1029    nimbusValue: null,
   1030    tests: [
   1031      {
   1032        query: "al",
   1033        expected: null,
   1034      },
   1035      {
   1036        query: "alo",
   1037        expected: null,
   1038      },
   1039      {
   1040        query: "alon",
   1041        expected: ALONGERKEYWORD_RESULT,
   1042      },
   1043      {
   1044        query: "along",
   1045        expected: ALONGERKEYWORD_RESULT,
   1046      },
   1047      {
   1048        query: "alongerkeyword",
   1049        expected: ALONGERKEYWORD_RESULT,
   1050      },
   1051      {
   1052        query: "best a",
   1053        expected: null,
   1054      },
   1055      {
   1056        query: "best al",
   1057        expected: {
   1058          url: "https://www.yelp.com/search?find_desc=best+alongerkeyword&find_loc=Yokohama%2C+Kanagawa",
   1059          title: "best alongerkeyword in Yokohama, Kanagawa",
   1060        },
   1061      },
   1062      {
   1063        query: "ab",
   1064        expected: AB_RESULT,
   1065      },
   1066    ],
   1067  });
   1068 });
   1069 
   1070 // Check wheather the special title for service will be shown by the setup of
   1071 // Nimbus variable.
   1072 add_task(async function yelpServiceResultDistinction() {
   1073  // Disable the pref.
   1074  UrlbarPrefs.set("yelp.serviceResultDistinction", false);
   1075  await check_results({
   1076    context: createContext("a service", {
   1077      providers: [
   1078        UrlbarProviderQuickSuggest.name,
   1079        UrlbarProviderSearchSuggestions.name,
   1080      ],
   1081      isPrivate: false,
   1082    }),
   1083    matches: [
   1084      QuickSuggestTestUtils.yelpResult({
   1085        url: "https://www.yelp.com/search?find_desc=a+service&find_loc=Yokohama%2C+Kanagawa",
   1086        title: "a service in Yokohama, Kanagawa",
   1087      }),
   1088    ],
   1089  });
   1090 
   1091  // Enable by Nimbus.
   1092  const cleanUpNimbusEnable = await UrlbarTestUtils.initNimbusFeature({
   1093    yelpServiceResultDistinction: true,
   1094  });
   1095  await QuickSuggestTestUtils.forceSync();
   1096  await check_results({
   1097    context: createContext("a service", {
   1098      providers: [
   1099        UrlbarProviderQuickSuggest.name,
   1100        UrlbarProviderSearchSuggestions.name,
   1101      ],
   1102      isPrivate: false,
   1103    }),
   1104    matches: [
   1105      QuickSuggestTestUtils.yelpResult({
   1106        url: "https://www.yelp.com/search?find_desc=a+service&find_loc=Yokohama%2C+Kanagawa",
   1107        titleL10n: {
   1108          id: "firefox-suggest-yelp-service-title",
   1109          args: {
   1110            service: "a service in Yokohama, Kanagawa",
   1111          },
   1112          argsHighlights: {
   1113            service: [
   1114              [0, 1],
   1115              [2, 7],
   1116              [18, 1],
   1117              [20, 1],
   1118              [24, 1],
   1119              [26, 1],
   1120              [28, 1],
   1121              [30, 1],
   1122            ],
   1123          },
   1124        },
   1125        title: "a service in Yokohama, Kanagawa",
   1126      }),
   1127    ],
   1128  });
   1129  await cleanUpNimbusEnable();
   1130 
   1131  // Enable locally.
   1132  UrlbarPrefs.set("yelp.serviceResultDistinction", true);
   1133  await QuickSuggestTestUtils.forceSync();
   1134 
   1135  // Disable by Nimbus.
   1136  const cleanUpNimbusDisable = await UrlbarTestUtils.initNimbusFeature({
   1137    yelpServiceResultDistinction: false,
   1138  });
   1139  await check_results({
   1140    context: createContext("a service", {
   1141      providers: [
   1142        UrlbarProviderQuickSuggest.name,
   1143        UrlbarProviderSearchSuggestions.name,
   1144      ],
   1145      isPrivate: false,
   1146    }),
   1147    matches: [
   1148      QuickSuggestTestUtils.yelpResult({
   1149        url: "https://www.yelp.com/search?find_desc=a+service&find_loc=Yokohama%2C+Kanagawa",
   1150        title: "a service in Yokohama, Kanagawa",
   1151      }),
   1152    ],
   1153  });
   1154  await cleanUpNimbusDisable();
   1155 
   1156  // Revert.
   1157  UrlbarPrefs.set("yelp.serviceResultDistinction", true);
   1158  await QuickSuggestTestUtils.forceSync();
   1159 });
   1160 
   1161 async function doMinKeywordLengthTest({ prefUserValue, nimbusValue, tests }) {
   1162  // Set or clear the pref.
   1163  let originalPrefUserValue = Services.prefs.prefHasUserValue(
   1164    "browser.urlbar.yelp.minKeywordLength"
   1165  )
   1166    ? UrlbarPrefs.get("yelp.minKeywordLength")
   1167    : null;
   1168  if (typeof prefUserValue == "number") {
   1169    UrlbarPrefs.set("yelp.minKeywordLength", prefUserValue);
   1170  } else {
   1171    UrlbarPrefs.clear("yelp.minKeywordLength");
   1172  }
   1173 
   1174  // Set up Nimbus.
   1175  let cleanUpNimbus;
   1176  if (typeof nimbusValue == "number") {
   1177    cleanUpNimbus = await UrlbarTestUtils.initNimbusFeature({
   1178      yelpMinKeywordLength: nimbusValue,
   1179    });
   1180  }
   1181 
   1182  for (let { query, expected } of tests) {
   1183    info("Running min keyword length test with query: " + query);
   1184    await check_results({
   1185      context: createContext(query, {
   1186        providers: [
   1187          UrlbarProviderQuickSuggest.name,
   1188          UrlbarProviderSearchSuggestions.name,
   1189        ],
   1190        isPrivate: false,
   1191      }),
   1192      matches: expected ? [QuickSuggestTestUtils.yelpResult(expected)] : [],
   1193    });
   1194  }
   1195 
   1196  await cleanUpNimbus?.();
   1197 
   1198  if (originalPrefUserValue === null) {
   1199    UrlbarPrefs.clear("yelp.minKeywordLength");
   1200  } else {
   1201    UrlbarPrefs.set("yelp.minKeywordLength", originalPrefUserValue);
   1202  }
   1203 }