Bug 1856736: Revert group labels and result labels to their previous appearance r=adw
[gecko.git] / browser / components / urlbar / tests / quicksuggest / unit / test_quicksuggest.js
blob988c9f3ad272b9a318678e1974519495d4021364
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/. */
5 // Basic tests for the quick suggest provider using the remote settings source.
6 // See also test_quicksuggest_merino.js.
8 "use strict";
10 const TELEMETRY_REMOTE_SETTINGS_LATENCY =
11   "FX_URLBAR_QUICK_SUGGEST_REMOTE_SETTINGS_LATENCY_MS";
13 const SPONSORED_SEARCH_STRING = "amp";
14 const NONSPONSORED_SEARCH_STRING = "wikipedia";
16 const HTTP_SEARCH_STRING = "http prefix";
17 const HTTPS_SEARCH_STRING = "https prefix";
18 const PREFIX_SUGGESTIONS_STRIPPED_URL = "example.com/prefix-test";
20 const { TIMESTAMP_TEMPLATE, TIMESTAMP_LENGTH } = QuickSuggest;
21 const TIMESTAMP_SEARCH_STRING = "timestamp";
22 const TIMESTAMP_SUGGESTION_URL = `http://example.com/timestamp-${TIMESTAMP_TEMPLATE}`;
23 const TIMESTAMP_SUGGESTION_CLICK_URL = `http://click.reporting.test.com/timestamp-${TIMESTAMP_TEMPLATE}-foo`;
25 const REMOTE_SETTINGS_RESULTS = [
26   {
27     id: 1,
28     url: "http://example.com/amp",
29     title: "AMP Suggestion",
30     keywords: [SPONSORED_SEARCH_STRING],
31     click_url: "http://example.com/amp-click",
32     impression_url: "http://example.com/amp-impression",
33     advertiser: "Amp",
34     iab_category: "22 - Shopping",
35   },
36   {
37     id: 2,
38     url: "http://example.com/wikipedia",
39     title: "Wikipedia Suggestion",
40     keywords: [NONSPONSORED_SEARCH_STRING],
41     click_url: "http://example.com/wikipedia-click",
42     impression_url: "http://example.com/wikipedia-impression",
43     advertiser: "Wikipedia",
44     iab_category: "5 - Education",
45   },
46   {
47     id: 3,
48     url: "http://" + PREFIX_SUGGESTIONS_STRIPPED_URL,
49     title: "HTTP Suggestion",
50     keywords: [HTTP_SEARCH_STRING],
51     click_url: "http://example.com/http-click",
52     impression_url: "http://example.com/http-impression",
53     advertiser: "HttpAdvertiser",
54     iab_category: "22 - Shopping",
55   },
56   {
57     id: 4,
58     url: "https://" + PREFIX_SUGGESTIONS_STRIPPED_URL,
59     title: "https suggestion",
60     keywords: [HTTPS_SEARCH_STRING],
61     click_url: "http://click.reporting.test.com/prefix",
62     impression_url: "http://impression.reporting.test.com/prefix",
63     advertiser: "TestAdvertiserPrefix",
64     iab_category: "22 - Shopping",
65   },
66   {
67     id: 5,
68     url: TIMESTAMP_SUGGESTION_URL,
69     title: "Timestamp suggestion",
70     keywords: [TIMESTAMP_SEARCH_STRING],
71     click_url: TIMESTAMP_SUGGESTION_CLICK_URL,
72     impression_url: "http://impression.reporting.test.com/timestamp",
73     advertiser: "TestAdvertiserTimestamp",
74     iab_category: "22 - Shopping",
75   },
78 function expectedNonSponsoredResult() {
79   return makeWikipediaResult({
80     blockId: 2,
81   });
84 function expectedSponsoredResult() {
85   return makeAmpResult();
88 function expectedHttpResult() {
89   let suggestion = REMOTE_SETTINGS_RESULTS[2];
90   return makeAmpResult({
91     keyword: HTTP_SEARCH_STRING,
92     title: suggestion.title,
93     url: suggestion.url,
94     originalUrl: suggestion.url,
95     impressionUrl: suggestion.impression_url,
96     clickUrl: suggestion.click_url,
97     blockId: suggestion.id,
98     advertiser: suggestion.advertiser,
99   });
102 function expectedHttpsResult() {
103   let suggestion = REMOTE_SETTINGS_RESULTS[3];
104   return makeAmpResult({
105     keyword: HTTPS_SEARCH_STRING,
106     title: suggestion.title,
107     url: suggestion.url,
108     originalUrl: suggestion.url,
109     impressionUrl: suggestion.impression_url,
110     clickUrl: suggestion.click_url,
111     blockId: suggestion.id,
112     advertiser: suggestion.advertiser,
113   });
116 add_setup(async function init() {
117   UrlbarPrefs.set("quicksuggest.enabled", true);
118   UrlbarPrefs.set("quicksuggest.shouldShowOnboardingDialog", false);
119   UrlbarPrefs.set("quicksuggest.remoteSettings.enabled", true);
120   UrlbarPrefs.set("merino.enabled", false);
122   // Install a default test engine.
123   let engine = await addTestSuggestionsEngine();
124   await Services.search.setDefault(
125     engine,
126     Ci.nsISearchService.CHANGE_REASON_UNKNOWN
127   );
129   const testDataTypeResults = [
130     Object.assign({}, REMOTE_SETTINGS_RESULTS[0], { title: "test-data-type" }),
131   ];
133   await QuickSuggestTestUtils.ensureQuickSuggestInit({
134     remoteSettingsResults: [
135       {
136         type: "data",
137         attachment: REMOTE_SETTINGS_RESULTS,
138       },
139       {
140         type: "test-data-type",
141         attachment: testDataTypeResults,
142       },
143     ],
144   });
147 add_task(async function telemetryType_sponsored() {
148   Assert.equal(
149     QuickSuggest.getFeature("AdmWikipedia").getSuggestionTelemetryType({
150       is_sponsored: true,
151     }),
152     "adm_sponsored",
153     "Telemetry type should be 'adm_sponsored'"
154   );
157 add_task(async function telemetryType_nonsponsored() {
158   Assert.equal(
159     QuickSuggest.getFeature("AdmWikipedia").getSuggestionTelemetryType({
160       is_sponsored: false,
161     }),
162     "adm_nonsponsored",
163     "Telemetry type should be 'adm_nonsponsored'"
164   );
165   Assert.equal(
166     QuickSuggest.getFeature("AdmWikipedia").getSuggestionTelemetryType({}),
167     "adm_nonsponsored",
168     "Telemetry type should be 'adm_nonsponsored' if `is_sponsored` not defined"
169   );
172 // Tests with only non-sponsored suggestions enabled with a matching search
173 // string.
174 add_tasks_with_rust(async function nonsponsoredOnly_match() {
175   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
176   UrlbarPrefs.set("suggest.quicksuggest.sponsored", false);
178   let context = createContext(NONSPONSORED_SEARCH_STRING, {
179     providers: [UrlbarProviderQuickSuggest.name],
180     isPrivate: false,
181   });
182   await check_results({
183     context,
184     matches: [expectedNonSponsoredResult()],
185   });
188 // Tests with only non-sponsored suggestions enabled with a non-matching search
189 // string.
190 add_tasks_with_rust(async function nonsponsoredOnly_noMatch() {
191   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
192   UrlbarPrefs.set("suggest.quicksuggest.sponsored", false);
194   let context = createContext(SPONSORED_SEARCH_STRING, {
195     providers: [UrlbarProviderQuickSuggest.name],
196     isPrivate: false,
197   });
198   await check_results({ context, matches: [] });
201 // Tests with only sponsored suggestions enabled with a matching search string.
202 add_tasks_with_rust(async function sponsoredOnly_sponsored() {
203   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", false);
204   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
206   let context = createContext(SPONSORED_SEARCH_STRING, {
207     providers: [UrlbarProviderQuickSuggest.name],
208     isPrivate: false,
209   });
210   await check_results({
211     context,
212     matches: [expectedSponsoredResult()],
213   });
216 // Tests with only sponsored suggestions enabled with a non-matching search
217 // string.
218 add_tasks_with_rust(async function sponsoredOnly_nonsponsored() {
219   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", false);
220   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
222   let context = createContext(NONSPONSORED_SEARCH_STRING, {
223     providers: [UrlbarProviderQuickSuggest.name],
224     isPrivate: false,
225   });
226   await check_results({ context, matches: [] });
229 // Tests with both sponsored and non-sponsored suggestions enabled with a
230 // search string that matches the sponsored suggestion.
231 add_tasks_with_rust(async function both_sponsored() {
232   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
233   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
235   let context = createContext(SPONSORED_SEARCH_STRING, {
236     providers: [UrlbarProviderQuickSuggest.name],
237     isPrivate: false,
238   });
239   await check_results({
240     context,
241     matches: [expectedSponsoredResult()],
242   });
245 // Tests with both sponsored and non-sponsored suggestions enabled with a
246 // search string that matches the non-sponsored suggestion.
247 add_tasks_with_rust(async function both_nonsponsored() {
248   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
249   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
251   let context = createContext(NONSPONSORED_SEARCH_STRING, {
252     providers: [UrlbarProviderQuickSuggest.name],
253     isPrivate: false,
254   });
255   await check_results({
256     context,
257     matches: [expectedNonSponsoredResult()],
258   });
261 // Tests with both sponsored and non-sponsored suggestions enabled with a
262 // search string that doesn't match either suggestion.
263 add_tasks_with_rust(async function both_noMatch() {
264   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
265   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
267   let context = createContext("this doesn't match anything", {
268     providers: [UrlbarProviderQuickSuggest.name],
269     isPrivate: false,
270   });
271   await check_results({ context, matches: [] });
274 // Tests with both the main and sponsored prefs disabled with a search string
275 // that matches the sponsored suggestion.
276 add_tasks_with_rust(async function neither_sponsored() {
277   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", false);
278   UrlbarPrefs.set("suggest.quicksuggest.sponsored", false);
280   let context = createContext(SPONSORED_SEARCH_STRING, {
281     providers: [UrlbarProviderQuickSuggest.name],
282     isPrivate: false,
283   });
284   await check_results({ context, matches: [] });
287 // Tests with both the main and sponsored prefs disabled with a search string
288 // that matches the non-sponsored suggestion.
289 add_tasks_with_rust(async function neither_nonsponsored() {
290   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", false);
291   UrlbarPrefs.set("suggest.quicksuggest.sponsored", false);
293   let context = createContext(NONSPONSORED_SEARCH_STRING, {
294     providers: [UrlbarProviderQuickSuggest.name],
295     isPrivate: false,
296   });
297   await check_results({ context, matches: [] });
300 // Search string matching should be case insensitive and ignore leading spaces.
301 add_tasks_with_rust(async function caseInsensitiveAndLeadingSpaces() {
302   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
303   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
305   let context = createContext("  " + SPONSORED_SEARCH_STRING.toUpperCase(), {
306     providers: [UrlbarProviderQuickSuggest.name],
307     isPrivate: false,
308   });
309   await check_results({
310     context,
311     matches: [expectedSponsoredResult()],
312   });
315 // The provider should not be active for search strings that are empty or
316 // contain only spaces.
317 add_tasks_with_rust(async function emptySearchStringsAndSpaces() {
318   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
319   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
321   let searchStrings = ["", " ", "  ", "              "];
322   for (let str of searchStrings) {
323     let msg = JSON.stringify(str) + ` (length = ${str.length})`;
324     info("Testing search string: " + msg);
326     let context = createContext(str, {
327       providers: [UrlbarProviderQuickSuggest.name],
328       isPrivate: false,
329     });
330     await check_results({
331       context,
332       matches: [],
333     });
334     Assert.ok(
335       !UrlbarProviderQuickSuggest.isActive(context),
336       "Provider should not be active for search string: " + msg
337     );
338   }
341 // Results should be returned even when `browser.search.suggest.enabled` is
342 // false.
343 add_tasks_with_rust(async function browser_search_suggest_enabled() {
344   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
345   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
346   UrlbarPrefs.set("browser.search.suggest.enabled", false);
348   let context = createContext(SPONSORED_SEARCH_STRING, {
349     providers: [UrlbarProviderQuickSuggest.name],
350     isPrivate: false,
351   });
352   await check_results({
353     context,
354     matches: [expectedSponsoredResult()],
355   });
357   UrlbarPrefs.clear("browser.search.suggest.enabled");
360 // Results should be returned even when `browser.urlbar.suggest.searches` is
361 // false.
362 add_tasks_with_rust(async function browser_search_suggest_enabled() {
363   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
364   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
365   UrlbarPrefs.set("suggest.searches", false);
367   let context = createContext(SPONSORED_SEARCH_STRING, {
368     providers: [UrlbarProviderQuickSuggest.name],
369     isPrivate: false,
370   });
371   await check_results({
372     context,
373     matches: [expectedSponsoredResult()],
374   });
376   UrlbarPrefs.clear("suggest.searches");
379 // Neither sponsored nor non-sponsored results should appear in private contexts
380 // even when suggestions in private windows are enabled.
381 add_tasks_with_rust(async function privateContext() {
382   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
383   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
385   for (let privateSuggestionsEnabled of [true, false]) {
386     UrlbarPrefs.set(
387       "browser.search.suggest.enabled.private",
388       privateSuggestionsEnabled
389     );
390     let context = createContext(SPONSORED_SEARCH_STRING, {
391       providers: [UrlbarProviderQuickSuggest.name],
392       isPrivate: true,
393     });
394     await check_results({
395       context,
396       matches: [],
397     });
398   }
400   UrlbarPrefs.clear("browser.search.suggest.enabled.private");
403 // When search suggestions come before general results and the only general
404 // result is a quick suggest result, it should come last.
405 add_tasks_with_rust(async function suggestionsBeforeGeneral_only() {
406   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
407   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
408   UrlbarPrefs.set("browser.search.suggest.enabled", true);
409   UrlbarPrefs.set("suggest.searches", true);
410   UrlbarPrefs.set("showSearchSuggestionsFirst", true);
412   let context = createContext(SPONSORED_SEARCH_STRING, { isPrivate: false });
413   await check_results({
414     context,
415     matches: [
416       makeSearchResult(context, {
417         heuristic: true,
418         query: SPONSORED_SEARCH_STRING,
419         engineName: Services.search.defaultEngine.name,
420       }),
421       makeSearchResult(context, {
422         query: SPONSORED_SEARCH_STRING,
423         suggestion: SPONSORED_SEARCH_STRING + " foo",
424         engineName: Services.search.defaultEngine.name,
425       }),
426       makeSearchResult(context, {
427         query: SPONSORED_SEARCH_STRING,
428         suggestion: SPONSORED_SEARCH_STRING + " bar",
429         engineName: Services.search.defaultEngine.name,
430       }),
431       expectedSponsoredResult(),
432     ],
433   });
435   UrlbarPrefs.clear("browser.search.suggest.enabled");
436   UrlbarPrefs.clear("suggest.searches");
437   UrlbarPrefs.clear("showSearchSuggestionsFirst");
440 // When search suggestions come before general results and there are other
441 // general results besides quick suggest, the quick suggest result should come
442 // last.
443 add_tasks_with_rust(async function suggestionsBeforeGeneral_others() {
444   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
445   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
446   UrlbarPrefs.set("browser.search.suggest.enabled", true);
447   UrlbarPrefs.set("suggest.searches", true);
448   UrlbarPrefs.set("showSearchSuggestionsFirst", true);
450   let context = createContext(SPONSORED_SEARCH_STRING, { isPrivate: false });
452   // Add some history that will match our query below.
453   let maxResults = UrlbarPrefs.get("maxRichResults");
454   let historyResults = [];
455   for (let i = 0; i < maxResults; i++) {
456     let url = "http://example.com/" + SPONSORED_SEARCH_STRING + i;
457     historyResults.push(
458       makeVisitResult(context, {
459         uri: url,
460         title: "test visit for " + url,
461       })
462     );
463     await PlacesTestUtils.addVisits(url);
464   }
465   historyResults = historyResults.reverse().slice(0, historyResults.length - 4);
467   await check_results({
468     context,
469     matches: [
470       makeSearchResult(context, {
471         heuristic: true,
472         query: SPONSORED_SEARCH_STRING,
473         engineName: Services.search.defaultEngine.name,
474       }),
475       makeSearchResult(context, {
476         query: SPONSORED_SEARCH_STRING,
477         suggestion: SPONSORED_SEARCH_STRING + " foo",
478         engineName: Services.search.defaultEngine.name,
479       }),
480       makeSearchResult(context, {
481         query: SPONSORED_SEARCH_STRING,
482         suggestion: SPONSORED_SEARCH_STRING + " bar",
483         engineName: Services.search.defaultEngine.name,
484       }),
485       ...historyResults,
486       expectedSponsoredResult(),
487     ],
488   });
490   UrlbarPrefs.clear("browser.search.suggest.enabled");
491   UrlbarPrefs.clear("suggest.searches");
492   UrlbarPrefs.clear("showSearchSuggestionsFirst");
493   await PlacesUtils.history.clear();
496 // When general results come before search suggestions and the only general
497 // result is a quick suggest result, it should come before suggestions.
498 add_tasks_with_rust(async function generalBeforeSuggestions_only() {
499   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
500   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
501   UrlbarPrefs.set("browser.search.suggest.enabled", true);
502   UrlbarPrefs.set("suggest.searches", true);
503   UrlbarPrefs.set("showSearchSuggestionsFirst", false);
505   let context = createContext(SPONSORED_SEARCH_STRING, { isPrivate: false });
506   await check_results({
507     context,
508     matches: [
509       makeSearchResult(context, {
510         heuristic: true,
511         query: SPONSORED_SEARCH_STRING,
512         engineName: Services.search.defaultEngine.name,
513       }),
514       expectedSponsoredResult(),
515       makeSearchResult(context, {
516         query: SPONSORED_SEARCH_STRING,
517         suggestion: SPONSORED_SEARCH_STRING + " foo",
518         engineName: Services.search.defaultEngine.name,
519       }),
520       makeSearchResult(context, {
521         query: SPONSORED_SEARCH_STRING,
522         suggestion: SPONSORED_SEARCH_STRING + " bar",
523         engineName: Services.search.defaultEngine.name,
524       }),
525     ],
526   });
528   UrlbarPrefs.clear("browser.search.suggest.enabled");
529   UrlbarPrefs.clear("suggest.searches");
530   UrlbarPrefs.clear("showSearchSuggestionsFirst");
533 // When general results come before search suggestions and there are other
534 // general results besides quick suggest, the quick suggest result should be the
535 // last general result.
536 add_tasks_with_rust(async function generalBeforeSuggestions_others() {
537   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
538   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
539   UrlbarPrefs.set("browser.search.suggest.enabled", true);
540   UrlbarPrefs.set("suggest.searches", true);
541   UrlbarPrefs.set("showSearchSuggestionsFirst", false);
543   let context = createContext(SPONSORED_SEARCH_STRING, { isPrivate: false });
545   // Add some history that will match our query below.
546   let maxResults = UrlbarPrefs.get("maxRichResults");
547   let historyResults = [];
548   for (let i = 0; i < maxResults; i++) {
549     let url = "http://example.com/" + SPONSORED_SEARCH_STRING + i;
550     historyResults.push(
551       makeVisitResult(context, {
552         uri: url,
553         title: "test visit for " + url,
554       })
555     );
556     await PlacesTestUtils.addVisits(url);
557   }
558   historyResults = historyResults.reverse().slice(0, historyResults.length - 4);
560   await check_results({
561     context,
562     matches: [
563       makeSearchResult(context, {
564         heuristic: true,
565         query: SPONSORED_SEARCH_STRING,
566         engineName: Services.search.defaultEngine.name,
567       }),
568       ...historyResults,
569       expectedSponsoredResult(),
570       makeSearchResult(context, {
571         query: SPONSORED_SEARCH_STRING,
572         suggestion: SPONSORED_SEARCH_STRING + " foo",
573         engineName: Services.search.defaultEngine.name,
574       }),
575       makeSearchResult(context, {
576         query: SPONSORED_SEARCH_STRING,
577         suggestion: SPONSORED_SEARCH_STRING + " bar",
578         engineName: Services.search.defaultEngine.name,
579       }),
580     ],
581   });
583   UrlbarPrefs.clear("browser.search.suggest.enabled");
584   UrlbarPrefs.clear("suggest.searches");
585   UrlbarPrefs.clear("showSearchSuggestionsFirst");
586   await PlacesUtils.history.clear();
589 add_tasks_with_rust(async function dedupeAgainstURL_samePrefix() {
590   await doDedupeAgainstURLTest({
591     searchString: HTTP_SEARCH_STRING,
592     expectedQuickSuggestResult: expectedHttpResult(),
593     otherPrefix: "http://",
594     expectOther: false,
595   });
598 add_tasks_with_rust(async function dedupeAgainstURL_higherPrefix() {
599   await doDedupeAgainstURLTest({
600     searchString: HTTPS_SEARCH_STRING,
601     expectedQuickSuggestResult: expectedHttpsResult(),
602     otherPrefix: "http://",
603     expectOther: false,
604   });
607 add_tasks_with_rust(async function dedupeAgainstURL_lowerPrefix() {
608   await doDedupeAgainstURLTest({
609     searchString: HTTP_SEARCH_STRING,
610     expectedQuickSuggestResult: expectedHttpResult(),
611     otherPrefix: "https://",
612     expectOther: true,
613   });
617  * Tests how the muxer dedupes URL results against quick suggest results.
618  * Depending on prefix rank, quick suggest results should be preferred over
619  * other URL results with the same stripped URL: Other results should be
620  * discarded when their prefix rank is lower than the prefix rank of the quick
621  * suggest. They should not be discarded when their prefix rank is higher, and
622  * in that case both results should be included.
624  * This function adds a visit to the URL formed by the given `otherPrefix` and
625  * `PREFIX_SUGGESTIONS_STRIPPED_URL`. The visit's title will be set to the given
626  * `searchString` so that both the visit and the quick suggest will match it.
628  * @param {object} options
629  *   Options object.
630  * @param {string} options.searchString
631  *   The search string that should trigger one of the mock prefix-test quick
632  *   suggest results.
633  * @param {object} options.expectedQuickSuggestResult
634  *   The expected quick suggest result.
635  * @param {string} options.otherPrefix
636  *   The visit will be created with a URL with this prefix, e.g., "http://".
637  * @param {boolean} options.expectOther
638  *   Whether the visit result should appear in the final results.
639  */
640 async function doDedupeAgainstURLTest({
641   searchString,
642   expectedQuickSuggestResult,
643   otherPrefix,
644   expectOther,
645 }) {
646   // Disable search suggestions.
647   UrlbarPrefs.set("suggest.searches", false);
649   // Add a visit that will match our query below.
650   let otherURL = otherPrefix + PREFIX_SUGGESTIONS_STRIPPED_URL;
651   await PlacesTestUtils.addVisits({ uri: otherURL, title: searchString });
653   // First, do a search with quick suggest disabled to make sure the search
654   // string matches the visit.
655   info("Doing first query");
656   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", false);
657   UrlbarPrefs.set("suggest.quicksuggest.sponsored", false);
658   let context = createContext(searchString, { isPrivate: false });
659   await check_results({
660     context,
661     matches: [
662       makeSearchResult(context, {
663         heuristic: true,
664         query: searchString,
665         engineName: Services.search.defaultEngine.name,
666       }),
667       makeVisitResult(context, {
668         uri: otherURL,
669         title: searchString,
670       }),
671     ],
672   });
674   // Now do another search with quick suggest enabled.
675   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
676   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
678   context = createContext(searchString, { isPrivate: false });
680   let expectedResults = [
681     makeSearchResult(context, {
682       heuristic: true,
683       query: searchString,
684       engineName: Services.search.defaultEngine.name,
685     }),
686   ];
687   if (expectOther) {
688     expectedResults.push(
689       makeVisitResult(context, {
690         uri: otherURL,
691         title: searchString,
692       })
693     );
694   }
695   expectedResults.push(expectedQuickSuggestResult);
697   info("Doing second query");
698   await check_results({ context, matches: expectedResults });
700   UrlbarPrefs.clear("suggest.quicksuggest.nonsponsored");
701   UrlbarPrefs.clear("suggest.quicksuggest.sponsored");
702   UrlbarPrefs.clear("suggest.searches");
703   await PlacesUtils.history.clear();
706 // Tests the remote settings latency histogram.
707 add_task(async function latencyTelemetry() {
708   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
709   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
711   let histogram = Services.telemetry.getHistogramById(
712     TELEMETRY_REMOTE_SETTINGS_LATENCY
713   );
714   histogram.clear();
716   let context = createContext(SPONSORED_SEARCH_STRING, {
717     providers: [UrlbarProviderQuickSuggest.name],
718     isPrivate: false,
719   });
720   await check_results({
721     context,
722     matches: [expectedSponsoredResult()],
723   });
725   // In the latency histogram, there should be a single value across all
726   // buckets.
727   Assert.deepEqual(
728     Object.values(histogram.snapshot().values).filter(v => v > 0),
729     [1],
730     "Latency histogram updated after search"
731   );
732   Assert.ok(
733     !TelemetryStopwatch.running(TELEMETRY_REMOTE_SETTINGS_LATENCY, context),
734     "Stopwatch not running after search"
735   );
738 // Tests setup and teardown of the remote settings client depending on whether
739 // quick suggest is enabled.
740 add_task(async function setupAndTeardown() {
741   Assert.ok(
742     QuickSuggest.jsBackend.isEnabled,
743     "Remote settings backend is enabled initially"
744   );
746   // Disable the suggest prefs so the settings client starts out torn down.
747   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", false);
748   UrlbarPrefs.set("suggest.quicksuggest.sponsored", false);
749   Assert.ok(
750     !QuickSuggest.jsBackend.rs,
751     "Settings client is null after disabling suggest prefs"
752   );
753   Assert.ok(
754     QuickSuggest.jsBackend.isEnabled,
755     "Remote settings backend remains enabled"
756   );
758   // Setting one of the suggest prefs should cause the client to be set up. We
759   // assume all previous tasks left `quicksuggest.enabled` true (from the init
760   // task).
761   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
762   Assert.ok(
763     QuickSuggest.jsBackend.rs,
764     "Settings client is non-null after enabling suggest.quicksuggest.nonsponsored"
765   );
767   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", false);
768   Assert.ok(
769     !QuickSuggest.jsBackend.rs,
770     "Settings client is null after disabling suggest.quicksuggest.nonsponsored"
771   );
773   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
774   Assert.ok(
775     QuickSuggest.jsBackend.rs,
776     "Settings client is non-null after enabling suggest.quicksuggest.sponsored"
777   );
779   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
780   Assert.ok(
781     QuickSuggest.jsBackend.rs,
782     "Settings client remains non-null after enabling suggest.quicksuggest.nonsponsored"
783   );
785   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", false);
786   Assert.ok(
787     QuickSuggest.jsBackend.rs,
788     "Settings client remains non-null after disabling suggest.quicksuggest.nonsponsored"
789   );
791   UrlbarPrefs.set("suggest.quicksuggest.sponsored", false);
792   Assert.ok(
793     !QuickSuggest.jsBackend.rs,
794     "Settings client is null after disabling suggest.quicksuggest.sponsored"
795   );
797   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
798   Assert.ok(
799     QuickSuggest.jsBackend.rs,
800     "Settings client is non-null after enabling suggest.quicksuggest.nonsponsored"
801   );
803   UrlbarPrefs.set("quicksuggest.enabled", false);
804   Assert.ok(
805     !QuickSuggest.jsBackend.rs,
806     "Settings client is null after disabling quicksuggest.enabled"
807   );
809   UrlbarPrefs.set("quicksuggest.enabled", true);
810   Assert.ok(
811     QuickSuggest.jsBackend.rs,
812     "Settings client is non-null after re-enabling quicksuggest.enabled"
813   );
814   Assert.ok(
815     QuickSuggest.jsBackend.isEnabled,
816     "Remote settings backend is enabled after re-enabling quicksuggest.enabled"
817   );
819   UrlbarPrefs.set("quicksuggest.rustEnabled", true);
820   Assert.ok(
821     !QuickSuggest.jsBackend.rs,
822     "Settings client is null after enabling the Rust backend"
823   );
824   Assert.ok(
825     !QuickSuggest.jsBackend.isEnabled,
826     "Remote settings backend is disabled after enabling the Rust backend"
827   );
829   UrlbarPrefs.clear("quicksuggest.rustEnabled");
830   Assert.ok(
831     QuickSuggest.jsBackend.rs,
832     "Settings client is non-null after disabling the Rust backend"
833   );
834   Assert.ok(
835     QuickSuggest.jsBackend.isEnabled,
836     "Remote settings backend is enabled after disabling the Rust backend"
837   );
839   // Leave the prefs in the same state as when the task started.
840   UrlbarPrefs.clear("suggest.quicksuggest.nonsponsored");
841   UrlbarPrefs.clear("suggest.quicksuggest.sponsored");
842   UrlbarPrefs.set("quicksuggest.enabled", true);
843   Assert.ok(
844     !QuickSuggest.jsBackend.rs,
845     "Settings client remains null at end of task"
846   );
849 // Timestamp templates in URLs should be replaced with real timestamps.
850 add_tasks_with_rust(async function timestamps() {
851   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
852   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
854   // Do a search.
855   let context = createContext(TIMESTAMP_SEARCH_STRING, {
856     providers: [UrlbarProviderQuickSuggest.name],
857     isPrivate: false,
858   });
859   let controller = UrlbarTestUtils.newMockController({
860     input: {
861       isPrivate: context.isPrivate,
862       onFirstResult() {
863         return false;
864       },
865       getSearchSource() {
866         return "dummy-search-source";
867       },
868       window: {
869         location: {
870           href: AppConstants.BROWSER_CHROME_URL,
871         },
872       },
873     },
874   });
875   await controller.startQuery(context);
877   // Should be one quick suggest result.
878   Assert.equal(context.results.length, 1, "One result returned");
879   let result = context.results[0];
881   QuickSuggestTestUtils.assertTimestampsReplaced(result, {
882     url: TIMESTAMP_SUGGESTION_URL,
883     sponsoredClickUrl: TIMESTAMP_SUGGESTION_CLICK_URL,
884   });
887 // Real quick suggest URLs include a timestamp template that
888 // UrlbarProviderQuickSuggest fills in when it fetches suggestions. When the
889 // user picks a quick suggest, its URL with its particular timestamp is added to
890 // history. If the user triggers the quick suggest again later, its new
891 // timestamp may be different from the one in the user's history. In that case,
892 // the two URLs should be treated as dupes and only the quick suggest should be
893 // shown, not the URL from history.
894 add_tasks_with_rust(async function dedupeAgainstURL_timestamps() {
895   // Disable search suggestions.
896   UrlbarPrefs.set("suggest.searches", false);
898   // Add a visit that will match the query below and dupe the quick suggest.
899   let dupeURL = TIMESTAMP_SUGGESTION_URL.replace(
900     TIMESTAMP_TEMPLATE,
901     "2013051113"
902   );
904   // Add other visits that will match the query and almost dupe the quick
905   // suggest but not quite because they have invalid timestamps.
906   let badTimestamps = [
907     // not numeric digits
908     "x".repeat(TIMESTAMP_LENGTH),
909     // too few digits
910     "5".repeat(TIMESTAMP_LENGTH - 1),
911     // empty string, too few digits
912     "",
913   ];
914   let badTimestampURLs = badTimestamps.map(str =>
915     TIMESTAMP_SUGGESTION_URL.replace(TIMESTAMP_TEMPLATE, str)
916   );
918   await PlacesTestUtils.addVisits(
919     [dupeURL, ...badTimestampURLs].map(uri => ({
920       uri,
921       title: TIMESTAMP_SEARCH_STRING,
922     }))
923   );
925   // First, do a search with quick suggest disabled to make sure the search
926   // string matches all the other URLs.
927   info("Doing first query");
928   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", false);
929   UrlbarPrefs.set("suggest.quicksuggest.sponsored", false);
930   let context = createContext(TIMESTAMP_SEARCH_STRING, { isPrivate: false });
932   let expectedHeuristic = makeSearchResult(context, {
933     heuristic: true,
934     query: TIMESTAMP_SEARCH_STRING,
935     engineName: Services.search.defaultEngine.name,
936   });
937   let expectedDupeResult = makeVisitResult(context, {
938     uri: dupeURL,
939     title: TIMESTAMP_SEARCH_STRING,
940   });
941   let expectedBadTimestampResults = [...badTimestampURLs].reverse().map(uri =>
942     makeVisitResult(context, {
943       uri,
944       title: TIMESTAMP_SEARCH_STRING,
945     })
946   );
948   await check_results({
949     context,
950     matches: [
951       expectedHeuristic,
952       ...expectedBadTimestampResults,
953       expectedDupeResult,
954     ],
955   });
957   // Now do another search with quick suggest enabled.
958   info("Doing second query");
959   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
960   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
961   context = createContext(TIMESTAMP_SEARCH_STRING, { isPrivate: false });
963   let expectedQuickSuggest = makeAmpResult({
964     originalUrl: TIMESTAMP_SUGGESTION_URL,
965     keyword: TIMESTAMP_SEARCH_STRING,
966     title: "Timestamp suggestion",
967     impressionUrl: "http://impression.reporting.test.com/timestamp",
968     blockId: 5,
969     advertiser: "TestAdvertiserTimestamp",
970     iabCategory: "22 - Shopping",
971   });
973   let expectedResults = [
974     expectedHeuristic,
975     ...expectedBadTimestampResults,
976     expectedQuickSuggest,
977   ];
979   let controller = UrlbarTestUtils.newMockController({
980     input: {
981       isPrivate: false,
982       onFirstResult() {
983         return false;
984       },
985       getSearchSource() {
986         return "dummy-search-source";
987       },
988       window: {
989         location: {
990           href: AppConstants.BROWSER_CHROME_URL,
991         },
992       },
993     },
994   });
995   await controller.startQuery(context);
996   info("Actual results: " + JSON.stringify(context.results));
998   Assert.equal(
999     context.results.length,
1000     expectedResults.length,
1001     "Found the expected number of results"
1002   );
1004   function getPayload(result, keysToIgnore = []) {
1005     let payload = {};
1006     for (let [key, value] of Object.entries(result.payload)) {
1007       if (value !== undefined && !keysToIgnore.includes(key)) {
1008         payload[key] = value;
1009       }
1010     }
1011     return payload;
1012   }
1014   // Check actual vs. expected result properties.
1015   for (let i = 0; i < expectedResults.length; i++) {
1016     let actual = context.results[i];
1017     let expected = expectedResults[i];
1018     info(
1019       `Comparing results at index ${i}:` +
1020         " actual=" +
1021         JSON.stringify(actual) +
1022         " expected=" +
1023         JSON.stringify(expected)
1024     );
1025     Assert.equal(
1026       actual.type,
1027       expected.type,
1028       `result.type at result index ${i}`
1029     );
1030     Assert.equal(
1031       actual.source,
1032       expected.source,
1033       `result.source at result index ${i}`
1034     );
1035     Assert.equal(
1036       actual.heuristic,
1037       expected.heuristic,
1038       `result.heuristic at result index ${i}`
1039     );
1041     // Check payloads except for the last result, which should be the quick
1042     // suggest.
1043     if (i != expectedResults.length - 1) {
1044       Assert.deepEqual(
1045         getPayload(context.results[i]),
1046         getPayload(expectedResults[i]),
1047         "Payload at index " + i
1048       );
1049     }
1050   }
1052   // Check the quick suggest's payload excluding the timestamp-related
1053   // properties.
1054   let actualQuickSuggest = context.results[context.results.length - 1];
1055   let timestampKeys = [
1056     "displayUrl",
1057     "sponsoredClickUrl",
1058     "url",
1059     "urlTimestampIndex",
1060   ];
1061   Assert.deepEqual(
1062     getPayload(actualQuickSuggest, timestampKeys),
1063     getPayload(expectedQuickSuggest, timestampKeys),
1064     "Quick suggest payload excluding timestamp-related keys"
1065   );
1067   // Now check the timestamps in the payload.
1068   QuickSuggestTestUtils.assertTimestampsReplaced(actualQuickSuggest, {
1069     url: TIMESTAMP_SUGGESTION_URL,
1070     sponsoredClickUrl: TIMESTAMP_SUGGESTION_CLICK_URL,
1071   });
1073   // Clean up.
1074   UrlbarPrefs.clear("suggest.quicksuggest.nonsponsored");
1075   UrlbarPrefs.clear("suggest.quicksuggest.sponsored");
1076   UrlbarPrefs.clear("suggest.searches");
1077   await PlacesUtils.history.clear();
1080 // Tests the API for blocking suggestions and the backing pref.
1081 add_task(async function blockedSuggestionsAPI() {
1082   // Start with no blocked suggestions.
1083   await QuickSuggest.blockedSuggestions.clear();
1084   Assert.equal(
1085     QuickSuggest.blockedSuggestions._test_digests.size,
1086     0,
1087     "blockedSuggestions._test_digests is empty"
1088   );
1089   Assert.equal(
1090     UrlbarPrefs.get("quicksuggest.blockedDigests"),
1091     "",
1092     "quicksuggest.blockedDigests is an empty string"
1093   );
1095   // Make some URLs.
1096   let urls = [];
1097   for (let i = 0; i < 3; i++) {
1098     urls.push("http://example.com/" + i);
1099   }
1101   // Block each URL in turn and make sure previously blocked URLs are still
1102   // blocked and the remaining URLs are not blocked.
1103   for (let i = 0; i < urls.length; i++) {
1104     await QuickSuggest.blockedSuggestions.add(urls[i]);
1105     for (let j = 0; j < urls.length; j++) {
1106       Assert.equal(
1107         await QuickSuggest.blockedSuggestions.has(urls[j]),
1108         j <= i,
1109         `Suggestion at index ${j} is blocked or not as expected`
1110       );
1111     }
1112   }
1114   // Make sure all URLs are blocked for good measure.
1115   for (let url of urls) {
1116     Assert.ok(
1117       await QuickSuggest.blockedSuggestions.has(url),
1118       `Suggestion is blocked: ${url}`
1119     );
1120   }
1122   // Check `blockedSuggestions._test_digests` and `quicksuggest.blockedDigests`.
1123   Assert.equal(
1124     QuickSuggest.blockedSuggestions._test_digests.size,
1125     urls.length,
1126     "blockedSuggestions._test_digests has correct size"
1127   );
1128   let array = JSON.parse(UrlbarPrefs.get("quicksuggest.blockedDigests"));
1129   Assert.ok(Array.isArray(array), "Parsed value of pref is an array");
1130   Assert.equal(array.length, urls.length, "Array has correct length");
1132   // Write some junk to `quicksuggest.blockedDigests`.
1133   // `blockedSuggestions._test_digests` should not be changed and all previously
1134   // blocked URLs should remain blocked.
1135   UrlbarPrefs.set("quicksuggest.blockedDigests", "not a json array");
1136   await QuickSuggest.blockedSuggestions._test_readyPromise;
1137   for (let url of urls) {
1138     Assert.ok(
1139       await QuickSuggest.blockedSuggestions.has(url),
1140       `Suggestion remains blocked: ${url}`
1141     );
1142   }
1143   Assert.equal(
1144     QuickSuggest.blockedSuggestions._test_digests.size,
1145     urls.length,
1146     "blockedSuggestions._test_digests still has correct size"
1147   );
1149   // Block a new URL. All URLs should remain blocked and the pref should be
1150   // updated.
1151   let newURL = "http://example.com/new-block";
1152   await QuickSuggest.blockedSuggestions.add(newURL);
1153   urls.push(newURL);
1154   for (let url of urls) {
1155     Assert.ok(
1156       await QuickSuggest.blockedSuggestions.has(url),
1157       `Suggestion is blocked: ${url}`
1158     );
1159   }
1160   Assert.equal(
1161     QuickSuggest.blockedSuggestions._test_digests.size,
1162     urls.length,
1163     "blockedSuggestions._test_digests has correct size"
1164   );
1165   array = JSON.parse(UrlbarPrefs.get("quicksuggest.blockedDigests"));
1166   Assert.ok(Array.isArray(array), "Parsed value of pref is an array");
1167   Assert.equal(array.length, urls.length, "Array has correct length");
1169   // Add a new URL digest directly to the JSON'ed array in the pref.
1170   newURL = "http://example.com/direct-to-pref";
1171   urls.push(newURL);
1172   array = JSON.parse(UrlbarPrefs.get("quicksuggest.blockedDigests"));
1173   array.push(await QuickSuggest.blockedSuggestions._test_getDigest(newURL));
1174   UrlbarPrefs.set("quicksuggest.blockedDigests", JSON.stringify(array));
1175   await QuickSuggest.blockedSuggestions._test_readyPromise;
1177   // All URLs should remain blocked and the new URL should be blocked.
1178   for (let url of urls) {
1179     Assert.ok(
1180       await QuickSuggest.blockedSuggestions.has(url),
1181       `Suggestion is blocked: ${url}`
1182     );
1183   }
1184   Assert.equal(
1185     QuickSuggest.blockedSuggestions._test_digests.size,
1186     urls.length,
1187     "blockedSuggestions._test_digests has correct size"
1188   );
1190   // Clear the pref. All URLs should be unblocked.
1191   UrlbarPrefs.clear("quicksuggest.blockedDigests");
1192   await QuickSuggest.blockedSuggestions._test_readyPromise;
1193   for (let url of urls) {
1194     Assert.ok(
1195       !(await QuickSuggest.blockedSuggestions.has(url)),
1196       `Suggestion is no longer blocked: ${url}`
1197     );
1198   }
1199   Assert.equal(
1200     QuickSuggest.blockedSuggestions._test_digests.size,
1201     0,
1202     "blockedSuggestions._test_digests is now empty"
1203   );
1205   // Block all the URLs again and test `blockedSuggestions.clear()`.
1206   for (let url of urls) {
1207     await QuickSuggest.blockedSuggestions.add(url);
1208   }
1209   for (let url of urls) {
1210     Assert.ok(
1211       await QuickSuggest.blockedSuggestions.has(url),
1212       `Suggestion is blocked: ${url}`
1213     );
1214   }
1215   await QuickSuggest.blockedSuggestions.clear();
1216   for (let url of urls) {
1217     Assert.ok(
1218       !(await QuickSuggest.blockedSuggestions.has(url)),
1219       `Suggestion is no longer blocked: ${url}`
1220     );
1221   }
1222   Assert.equal(
1223     QuickSuggest.blockedSuggestions._test_digests.size,
1224     0,
1225     "blockedSuggestions._test_digests is now empty"
1226   );
1229 // Test whether the blocking for remote settings results works.
1230 add_tasks_with_rust(async function block() {
1231   for (const result of REMOTE_SETTINGS_RESULTS) {
1232     await QuickSuggest.blockedSuggestions.add(result.url);
1233   }
1235   for (const result of REMOTE_SETTINGS_RESULTS) {
1236     const context = createContext(result.keywords[0], {
1237       providers: [UrlbarProviderQuickSuggest.name],
1238       isPrivate: false,
1239     });
1240     await check_results({
1241       context,
1242       matches: [],
1243     });
1244   }
1246   await QuickSuggest.blockedSuggestions.clear();
1249 // Makes sure remote settings data is fetched using the correct `type` based on
1250 // the value of the `quickSuggestRemoteSettingsDataType` Nimbus variable.
1251 add_task(async function remoteSettingsDataType() {
1252   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
1254   for (let dataType of [undefined, "test-data-type"]) {
1255     // Set up a mock Nimbus rollout with the data type.
1256     let value = {};
1257     if (dataType) {
1258       value.quickSuggestRemoteSettingsDataType = dataType;
1259     }
1260     let cleanUpNimbus = await UrlbarTestUtils.initNimbusFeature(value);
1262     // Make the result for test data type.
1263     let expected = expectedSponsoredResult();
1264     if (dataType) {
1265       expected = JSON.parse(JSON.stringify(expected));
1266       expected.payload.title = dataType;
1267     }
1269     // Re-enable to trigger sync from remote settings.
1270     UrlbarPrefs.set("quicksuggest.remoteSettings.enabled", false);
1271     UrlbarPrefs.set("quicksuggest.remoteSettings.enabled", true);
1273     let context = createContext(SPONSORED_SEARCH_STRING, {
1274       providers: [UrlbarProviderQuickSuggest.name],
1275       isPrivate: false,
1276     });
1277     await check_results({
1278       context,
1279       matches: [expected],
1280     });
1282     await cleanUpNimbus();
1283   }
1286 // For priority sponsored suggestion,
1287 // always isBestMatch will be true and suggestIndex will be 1.
1288 const EXPECTED_SPONSORED_PRIORITY_RESULT = {
1289   ...expectedSponsoredResult(),
1290   isBestMatch: true,
1293 add_task(async function sponsoredPriority_normal() {
1294   await doSponsoredPriorityTest({
1295     searchWord: SPONSORED_SEARCH_STRING,
1296     remoteSettingsData: [REMOTE_SETTINGS_RESULTS[0]],
1297     expectedMatches: [EXPECTED_SPONSORED_PRIORITY_RESULT],
1298   });
1301 add_task(async function sponsoredPriority_nonsponsoredSuggestion() {
1302   // Not affect to except sponsored suggestion.
1303   await doSponsoredPriorityTest({
1304     searchWord: NONSPONSORED_SEARCH_STRING,
1305     remoteSettingsData: [REMOTE_SETTINGS_RESULTS[1]],
1306     expectedMatches: [expectedNonSponsoredResult()],
1307   });
1310 add_task(async function sponsoredPriority_sponsoredIndex() {
1311   await doSponsoredPriorityTest({
1312     nimbusSettings: { quickSuggestSponsoredIndex: 2 },
1313     searchWord: SPONSORED_SEARCH_STRING,
1314     remoteSettingsData: [REMOTE_SETTINGS_RESULTS[0]],
1315     expectedMatches: [EXPECTED_SPONSORED_PRIORITY_RESULT],
1316   });
1319 add_task(async function sponsoredPriority_position() {
1320   await doSponsoredPriorityTest({
1321     nimbusSettings: { quickSuggestAllowPositionInSuggestions: true },
1322     searchWord: SPONSORED_SEARCH_STRING,
1323     remoteSettingsData: [
1324       Object.assign({}, REMOTE_SETTINGS_RESULTS[0], { position: 2 }),
1325     ],
1326     expectedMatches: [EXPECTED_SPONSORED_PRIORITY_RESULT],
1327   });
1330 async function doSponsoredPriorityTest({
1331   remoteSettingsConfig = {},
1332   nimbusSettings = {},
1333   searchWord,
1334   remoteSettingsData,
1335   expectedMatches,
1336 }) {
1337   UrlbarPrefs.set("suggest.quicksuggest.nonsponsored", true);
1338   UrlbarPrefs.set("suggest.quicksuggest.sponsored", true);
1340   const cleanUpNimbusEnable = await UrlbarTestUtils.initNimbusFeature({
1341     ...nimbusSettings,
1342     quickSuggestSponsoredPriority: true,
1343   });
1345   await QuickSuggestTestUtils.setRemoteSettingsResults([
1346     {
1347       type: "data",
1348       attachment: remoteSettingsData,
1349     },
1350   ]);
1351   await QuickSuggestTestUtils.setConfig(remoteSettingsConfig);
1353   await check_results({
1354     context: createContext(searchWord, {
1355       providers: [UrlbarProviderQuickSuggest.name],
1356       isPrivate: false,
1357     }),
1358     matches: expectedMatches,
1359   });
1361   await cleanUpNimbusEnable();