tor-browser

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

test_quicksuggest_addons.js (14522B)


      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 addon quick suggest results.
      6 
      7 "use strict";
      8 
      9 ChromeUtils.defineESModuleGetters(this, {
     10  AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
     11  AddonTestUtils: "resource://testing-common/AddonTestUtils.sys.mjs",
     12  ExtensionTestCommon: "resource://testing-common/ExtensionTestCommon.sys.mjs",
     13 });
     14 
     15 AddonTestUtils.init(this, false);
     16 AddonTestUtils.createAppInfo(
     17  "xpcshell@tests.mozilla.org",
     18  "XPCShell",
     19  "42",
     20  "42"
     21 );
     22 
     23 // TODO: Firefox no longer uses `rating` and `number_of_ratings` but they are
     24 // still present in Merino and RS suggestions, so they are included here for
     25 // greater accuracy. We should remove them from Merino, RS, and tests.
     26 const MERINO_SUGGESTIONS = [
     27  {
     28    provider: "amo",
     29    icon: "icon",
     30    url: "https://example.com/merino-addon",
     31    title: "title",
     32    description: "description",
     33    custom_details: {
     34      amo: {
     35        rating: "5",
     36        number_of_ratings: "1234567",
     37        guid: "test@addon",
     38      },
     39    },
     40  },
     41 ];
     42 
     43 const REMOTE_SETTINGS_RESULTS = [
     44  {
     45    type: "amo-suggestions",
     46    attachment: [
     47      {
     48        url: "https://example.com/first-addon",
     49        guid: "first@addon",
     50        icon: "https://example.com/first-addon.svg",
     51        title: "First Addon",
     52        rating: "4.7",
     53        keywords: ["first", "1st", "two words", "aa b c"],
     54        description: "Description for the First Addon",
     55        number_of_ratings: 1256,
     56        score: 0.25,
     57      },
     58      {
     59        url: "https://example.com/second-addon",
     60        guid: "second@addon",
     61        icon: "https://example.com/second-addon.svg",
     62        title: "Second Addon",
     63        rating: "1.7",
     64        keywords: ["second", "2nd"],
     65        description: "Description for the Second Addon",
     66        number_of_ratings: 256,
     67        score: 0.25,
     68      },
     69      {
     70        url: "https://example.com/third-addon",
     71        guid: "third@addon",
     72        icon: "https://example.com/third-addon.svg",
     73        title: "Third Addon",
     74        rating: "3.7",
     75        keywords: ["third", "3rd"],
     76        description: "Description for the Third Addon",
     77        number_of_ratings: 3,
     78        score: 0.25,
     79      },
     80      {
     81        url: "https://example.com/fourth-addon?utm_medium=aaa&utm_source=bbb",
     82        guid: "fourth@addon",
     83        icon: "https://example.com/fourth-addon.svg",
     84        title: "Fourth Addon",
     85        rating: "4.7",
     86        keywords: ["fourth", "4th"],
     87        description: "Description for the Fourth Addon",
     88        number_of_ratings: 4,
     89        score: 0.25,
     90      },
     91    ],
     92  },
     93 ];
     94 
     95 add_setup(async function init() {
     96  await AddonTestUtils.promiseStartupManager();
     97 
     98  // Disable search suggestions so we don't hit the network.
     99  Services.prefs.setBoolPref("browser.search.suggest.enabled", false);
    100 
    101  await QuickSuggestTestUtils.ensureQuickSuggestInit({
    102    remoteSettingsRecords: REMOTE_SETTINGS_RESULTS,
    103    merinoSuggestions: MERINO_SUGGESTIONS,
    104    prefs: [["suggest.quicksuggest.all", true]],
    105  });
    106 });
    107 
    108 add_task(async function telemetryType() {
    109  Assert.equal(
    110    QuickSuggest.getFeature("AddonSuggestions").getSuggestionTelemetryType({}),
    111    "amo",
    112    "Telemetry type should be 'amo'"
    113  );
    114 });
    115 
    116 // When quick suggest prefs are disabled, addon suggestions should be disabled.
    117 add_task(async function prefsDisabled() {
    118  let prefs = [
    119    "quicksuggest.enabled",
    120    "addons.featureGate",
    121    "suggest.quicksuggest.all",
    122    "suggest.addons",
    123  ];
    124  for (let pref of prefs) {
    125    info("Testing pref: " + pref);
    126 
    127    // Before disabling the pref, first make sure the suggestion is added.
    128    await check_results({
    129      context: createContext("test", {
    130        providers: [UrlbarProviderQuickSuggest.name],
    131        isPrivate: false,
    132      }),
    133      matches: [
    134        makeExpectedResult({
    135          suggestion: MERINO_SUGGESTIONS[0],
    136          source: "merino",
    137          provider: "amo",
    138        }),
    139      ],
    140    });
    141 
    142    // Now disable the pref.
    143    UrlbarPrefs.set(pref, false);
    144    await check_results({
    145      context: createContext("test", {
    146        providers: [UrlbarProviderQuickSuggest.name],
    147        isPrivate: false,
    148      }),
    149      matches: [],
    150    });
    151 
    152    UrlbarPrefs.set(pref, true);
    153    await QuickSuggestTestUtils.forceSync();
    154  }
    155 });
    156 
    157 // Check wheather the addon suggestions will be shown by the setup of Nimbus
    158 // variable.
    159 add_task(async function nimbus() {
    160  // Disable the fature gate.
    161  UrlbarPrefs.set("addons.featureGate", false);
    162  await check_results({
    163    context: createContext("test", {
    164      providers: [UrlbarProviderQuickSuggest.name],
    165      isPrivate: false,
    166    }),
    167    matches: [],
    168  });
    169 
    170  // Enable by Nimbus.
    171  const cleanUpNimbusEnable = await UrlbarTestUtils.initNimbusFeature({
    172    addonsFeatureGate: true,
    173  });
    174  await QuickSuggestTestUtils.forceSync();
    175  await check_results({
    176    context: createContext("test", {
    177      providers: [UrlbarProviderQuickSuggest.name],
    178      isPrivate: false,
    179    }),
    180    matches: [
    181      makeExpectedResult({
    182        suggestion: MERINO_SUGGESTIONS[0],
    183        source: "merino",
    184        provider: "amo",
    185      }),
    186    ],
    187  });
    188  await cleanUpNimbusEnable();
    189 
    190  // Enable locally.
    191  UrlbarPrefs.set("addons.featureGate", true);
    192  await QuickSuggestTestUtils.forceSync();
    193 
    194  // Disable by Nimbus.
    195  const cleanUpNimbusDisable = await UrlbarTestUtils.initNimbusFeature({
    196    addonsFeatureGate: false,
    197  });
    198  await check_results({
    199    context: createContext("test", {
    200      providers: [UrlbarProviderQuickSuggest.name],
    201      isPrivate: false,
    202    }),
    203    matches: [],
    204  });
    205  await cleanUpNimbusDisable();
    206 
    207  // Revert.
    208  UrlbarPrefs.clear("addons.featureGate");
    209  await QuickSuggestTestUtils.forceSync();
    210 });
    211 
    212 add_task(async function hideIfAlreadyInstalled() {
    213  // Show suggestion.
    214  await check_results({
    215    context: createContext("test", {
    216      providers: [UrlbarProviderQuickSuggest.name],
    217      isPrivate: false,
    218    }),
    219    matches: [
    220      makeExpectedResult({
    221        suggestion: MERINO_SUGGESTIONS[0],
    222        source: "merino",
    223        provider: "amo",
    224      }),
    225    ],
    226  });
    227 
    228  // Install an addon for the suggestion.
    229  const xpi = ExtensionTestCommon.generateXPI({
    230    manifest: {
    231      browser_specific_settings: {
    232        gecko: { id: "test@addon" },
    233      },
    234    },
    235  });
    236  const addon = await AddonManager.installTemporaryAddon(xpi);
    237 
    238  // Show suggestion for the addon installed.
    239  await check_results({
    240    context: createContext("test", {
    241      providers: [UrlbarProviderQuickSuggest.name],
    242      isPrivate: false,
    243    }),
    244    matches: [],
    245  });
    246 
    247  await addon.uninstall();
    248  xpi.remove(false);
    249 });
    250 
    251 add_task(async function remoteSettings() {
    252  const testCases = [
    253    {
    254      input: "f",
    255      expected: null,
    256    },
    257    {
    258      input: "fi",
    259      expected: null,
    260    },
    261    {
    262      input: "fir",
    263      expected: null,
    264    },
    265    {
    266      input: "firs",
    267      expected: null,
    268    },
    269    {
    270      input: "first",
    271      expected: makeExpectedResult({
    272        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    273      }),
    274    },
    275    {
    276      input: "1st",
    277      expected: makeExpectedResult({
    278        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    279      }),
    280    },
    281    {
    282      input: "t",
    283      expected: null,
    284    },
    285    {
    286      input: "tw",
    287      expected: null,
    288    },
    289    {
    290      input: "two",
    291      expected: makeExpectedResult({
    292        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    293      }),
    294    },
    295    {
    296      input: "two ",
    297      expected: makeExpectedResult({
    298        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    299      }),
    300    },
    301    {
    302      input: "two w",
    303      expected: makeExpectedResult({
    304        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    305      }),
    306    },
    307    {
    308      input: "two wo",
    309      expected: makeExpectedResult({
    310        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    311      }),
    312    },
    313    {
    314      input: "two wor",
    315      expected: makeExpectedResult({
    316        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    317      }),
    318    },
    319    {
    320      input: "two word",
    321      expected: makeExpectedResult({
    322        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    323      }),
    324    },
    325    {
    326      input: "two words",
    327      expected: makeExpectedResult({
    328        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    329      }),
    330    },
    331    {
    332      input: "aa",
    333      expected: makeExpectedResult({
    334        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    335      }),
    336    },
    337    {
    338      input: "aa ",
    339      expected: makeExpectedResult({
    340        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    341      }),
    342    },
    343    {
    344      input: "aa b",
    345      expected: makeExpectedResult({
    346        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    347      }),
    348    },
    349    {
    350      input: "aa b ",
    351      expected: makeExpectedResult({
    352        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    353      }),
    354    },
    355    {
    356      input: "aa b c",
    357      expected: makeExpectedResult({
    358        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    359      }),
    360    },
    361    {
    362      input: "second",
    363      expected: makeExpectedResult({
    364        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[1],
    365      }),
    366    },
    367    {
    368      input: "2nd",
    369      expected: makeExpectedResult({
    370        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[1],
    371      }),
    372    },
    373    {
    374      input: "third",
    375      expected: makeExpectedResult({
    376        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[2],
    377      }),
    378    },
    379    {
    380      input: "3rd",
    381      expected: makeExpectedResult({
    382        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[2],
    383      }),
    384    },
    385    {
    386      input: "fourth",
    387      expected: makeExpectedResult({
    388        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[3],
    389        setUtmParams: false,
    390      }),
    391    },
    392    {
    393      input: "FoUrTh",
    394      expected: makeExpectedResult({
    395        suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[3],
    396        setUtmParams: false,
    397      }),
    398    },
    399  ];
    400 
    401  // Disable Merino so we trigger only remote settings suggestions.
    402  UrlbarPrefs.set("quicksuggest.online.enabled", false);
    403 
    404  for (let { input, expected } of testCases) {
    405    await check_results({
    406      context: createContext(input, {
    407        providers: [UrlbarProviderQuickSuggest.name],
    408        isPrivate: false,
    409      }),
    410      matches: expected ? [expected] : [],
    411    });
    412  }
    413 
    414  UrlbarPrefs.clear("quicksuggest.online.enabled");
    415 });
    416 
    417 add_task(async function merinoIsTopPick() {
    418  const suggestion = JSON.parse(JSON.stringify(MERINO_SUGGESTIONS[0]));
    419 
    420  // is_top_pick is specified as false.
    421  suggestion.is_top_pick = false;
    422  MerinoTestUtils.server.response.body.suggestions = [suggestion];
    423  await check_results({
    424    context: createContext("test", {
    425      providers: [UrlbarProviderQuickSuggest.name],
    426      isPrivate: false,
    427    }),
    428    matches: [
    429      makeExpectedResult({
    430        suggestion,
    431        source: "merino",
    432        provider: "amo",
    433      }),
    434    ],
    435  });
    436 
    437  // is_top_pick is undefined.
    438  delete suggestion.is_top_pick;
    439  MerinoTestUtils.server.response.body.suggestions = [suggestion];
    440  await check_results({
    441    context: createContext("test", {
    442      providers: [UrlbarProviderQuickSuggest.name],
    443      isPrivate: false,
    444    }),
    445    matches: [
    446      makeExpectedResult({
    447        suggestion,
    448        source: "merino",
    449        provider: "amo",
    450      }),
    451    ],
    452  });
    453 });
    454 
    455 // Tests the "Not relevant" command: a dismissed suggestion shouldn't be added.
    456 add_task(async function notRelevant() {
    457  // Disable Merino suggestions to make this task simpler.
    458  UrlbarPrefs.set("quicksuggest.online.enabled", false);
    459 
    460  await doDismissOneTest({
    461    result: makeExpectedResult({
    462      suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    463    }),
    464    command: "not_relevant",
    465    feature: QuickSuggest.getFeature("AddonSuggestions"),
    466    queriesForDismissals: [
    467      {
    468        query: REMOTE_SETTINGS_RESULTS[0].attachment[0].keywords[0],
    469      },
    470    ],
    471    queriesForOthers: [
    472      {
    473        query: REMOTE_SETTINGS_RESULTS[0].attachment[1].keywords[0],
    474        expectedResults: [
    475          makeExpectedResult({
    476            suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[1],
    477          }),
    478        ],
    479      },
    480    ],
    481  });
    482 
    483  UrlbarPrefs.clear("quicksuggest.online.enabled");
    484 });
    485 
    486 // Tests the "Not interested" command: all addon suggestions should be disabled
    487 // and not added anymore.
    488 add_task(async function notInterested() {
    489  await doDismissAllTest({
    490    result: makeExpectedResult({
    491      suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    492    }),
    493    command: "not_interested",
    494    feature: QuickSuggest.getFeature("AddonSuggestions"),
    495    pref: "suggest.addons",
    496    queries: [
    497      {
    498        query: REMOTE_SETTINGS_RESULTS[0].attachment[0].keywords[0],
    499      },
    500      {
    501        query: REMOTE_SETTINGS_RESULTS[0].attachment[1].keywords[0],
    502        expectedResults: [
    503          makeExpectedResult({
    504            suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[1],
    505          }),
    506        ],
    507      },
    508    ],
    509  });
    510 });
    511 
    512 // Tests the "show less frequently" behavior.
    513 add_task(async function showLessFrequently() {
    514  await doShowLessFrequentlyTests({
    515    feature: QuickSuggest.getFeature("AddonSuggestions"),
    516    showLessFrequentlyCountPref: "addons.showLessFrequentlyCount",
    517    nimbusCapVariable: "addonsShowLessFrequentlyCap",
    518    expectedResult: makeExpectedResult({
    519      suggestion: REMOTE_SETTINGS_RESULTS[0].attachment[0],
    520    }),
    521    keyword: "two words",
    522  });
    523 });
    524 
    525 // The `Amo` Rust provider should be passed to the Rust component when querying
    526 // depending on whether addon suggestions are enabled.
    527 add_task(async function rustProviders() {
    528  await doRustProvidersTests({
    529    searchString: "first",
    530    tests: [
    531      {
    532        prefs: {
    533          "suggest.addons": true,
    534        },
    535        expectedUrls: ["https://example.com/first-addon"],
    536      },
    537      {
    538        prefs: {
    539          "suggest.addons": false,
    540        },
    541        expectedUrls: [],
    542      },
    543    ],
    544  });
    545 
    546  UrlbarPrefs.clear("suggest.addons");
    547  await QuickSuggestTestUtils.forceSync();
    548 });
    549 
    550 function makeExpectedResult({
    551  suggestion,
    552  source,
    553  provider,
    554  setUtmParams = true,
    555 }) {
    556  return QuickSuggestTestUtils.amoResult({
    557    source,
    558    provider,
    559    setUtmParams,
    560    title: suggestion.title,
    561    description: suggestion.description,
    562    url: suggestion.url,
    563    originalUrl: suggestion.url,
    564    icon: suggestion.icon,
    565  });
    566 }