diff options
Diffstat (limited to 'browser/components/urlbar/tests/unit/test_search_suggestions.js')
-rw-r--r-- | browser/components/urlbar/tests/unit/test_search_suggestions.js | 1695 |
1 files changed, 1695 insertions, 0 deletions
diff --git a/browser/components/urlbar/tests/unit/test_search_suggestions.js b/browser/components/urlbar/tests/unit/test_search_suggestions.js new file mode 100644 index 0000000000..0b1180959a --- /dev/null +++ b/browser/components/urlbar/tests/unit/test_search_suggestions.js @@ -0,0 +1,1695 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that search engine suggestions are returned by + * UrlbarProviderSearchSuggestions. + */ + +const { FormHistory } = ChromeUtils.import( + "resource://gre/modules/FormHistory.jsm" +); + +const ENGINE_NAME = "engine-suggestions.xml"; +// This is fixed to match the port number in engine-suggestions.xml. +const SERVER_PORT = 9000; +const SUGGEST_PREF = "browser.urlbar.suggest.searches"; +const SUGGEST_ENABLED_PREF = "browser.search.suggest.enabled"; +const PRIVATE_ENABLED_PREF = "browser.search.suggest.enabled.private"; +const PRIVATE_SEARCH_PREF = "browser.search.separatePrivateDefault.ui.enabled"; +const MAX_RICH_RESULTS_PREF = "browser.urlbar.maxRichResults"; +const MAX_FORM_HISTORY_PREF = "browser.urlbar.maxHistoricalSearchSuggestions"; +const SEARCH_STRING = "hello"; +const MATCH_BUCKETS_VALUE = "general:5,suggestion:Infinity"; + +var suggestionsFn; +var previousSuggestionsFn; + +/** + * Set the current suggestion funciton. + * @param {function} fn + * A function that that a search string and returns an array of strings that + * will be used as search suggestions. + * Note: `fn` should return > 0 suggestions in most cases. Otherwise, you may + * encounter unexpected behaviour with UrlbarProviderSuggestion's + * _lastLowResultsSearchSuggestion safeguard. + */ +function setSuggestionsFn(fn) { + previousSuggestionsFn = suggestionsFn; + suggestionsFn = fn; +} + +async function cleanup() { + Services.prefs.clearUserPref("browser.urlbar.autoFill"); + Services.prefs.clearUserPref("browser.urlbar.autoFill.searchEngines"); + Services.prefs.clearUserPref(SUGGEST_PREF); + Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF); + await PlacesUtils.bookmarks.eraseEverything(); + await PlacesUtils.history.clear(); +} + +async function cleanUpSuggestions() { + await cleanup(); + if (previousSuggestionsFn) { + suggestionsFn = previousSuggestionsFn; + previousSuggestionsFn = null; + } +} + +function makeExpectedFormHistoryResults(context, minCount = 0) { + let count = Math.max( + minCount, + Services.prefs.getIntPref(MAX_FORM_HISTORY_PREF, 0) + ); + let results = []; + for (let i = 0; i < count; i++) { + results.push( + makeFormHistoryResult(context, { + suggestion: `${SEARCH_STRING} world Form History ${i}`, + engineName: ENGINE_NAME, + }) + ); + } + return results; +} + +function makeExpectedRemoteSuggestionResults( + context, + { suggestionPrefix = SEARCH_STRING, query = undefined } = {} +) { + return [ + makeSearchResult(context, { + query, + engineName: ENGINE_NAME, + suggestion: suggestionPrefix + " foo", + }), + makeSearchResult(context, { + query, + engineName: ENGINE_NAME, + suggestion: suggestionPrefix + " bar", + }), + ]; +} + +function makeExpectedSuggestionResults( + context, + { suggestionPrefix = SEARCH_STRING, query = undefined } = {} +) { + return [ + ...makeExpectedFormHistoryResults(context), + ...makeExpectedRemoteSuggestionResults(context, { + suggestionPrefix, + query, + }), + ]; +} + +add_task(async function setup() { + Services.prefs.setCharPref( + "browser.urlbar.matchBuckets", + MATCH_BUCKETS_VALUE + ); + + let engine = await addTestSuggestionsEngine(searchStr => { + return suggestionsFn(searchStr); + }); + setSuggestionsFn(searchStr => { + let suffixes = ["foo", "bar"]; + return [searchStr].concat(suffixes.map(s => searchStr + " " + s)); + }); + + // Install the test engine. + let oldDefaultEngine = await Services.search.getDefault(); + registerCleanupFunction(async () => { + Services.search.setDefault(oldDefaultEngine); + Services.prefs.clearUserPref(PRIVATE_SEARCH_PREF); + }); + Services.search.setDefault(engine); + Services.prefs.setBoolPref(PRIVATE_SEARCH_PREF, false); + + // Add some form history. + let context = createContext(SEARCH_STRING, { isPrivate: false }); + let entries = makeExpectedFormHistoryResults(context, 2).map(r => ({ + value: r.payload.suggestion, + source: ENGINE_NAME, + })); + await UrlbarTestUtils.formHistory.add(entries); +}); + +add_task(async function disabled_urlbarSuggestions() { + Services.prefs.setBoolPref(SUGGEST_PREF, false); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); + let context = createContext(SEARCH_STRING, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + await cleanUpSuggestions(); +}); + +add_task(async function disabled_allSuggestions() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, false); + let context = createContext(SEARCH_STRING, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + await cleanUpSuggestions(); +}); + +add_task(async function disabled_privateWindow() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); + Services.prefs.setBoolPref(PRIVATE_ENABLED_PREF, false); + let context = createContext(SEARCH_STRING, { isPrivate: true }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + await cleanUpSuggestions(); +}); + +add_task(async function disabled_urlbarSuggestions_withRestrictionToken() { + Services.prefs.setBoolPref(SUGGEST_PREF, false); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); + let context = createContext( + `${UrlbarTokenizer.RESTRICT.SEARCH} ${SEARCH_STRING}`, + { isPrivate: false } + ); + await check_results({ + context, + matches: [ + makeSearchResult(context, { + query: SEARCH_STRING, + alias: UrlbarTokenizer.RESTRICT.SEARCH, + engineName: ENGINE_NAME, + heuristic: true, + }), + ...makeExpectedSuggestionResults(context, { + query: SEARCH_STRING, + }), + ], + }); + await cleanUpSuggestions(); +}); + +add_task( + async function disabled_urlbarSuggestions_withRestrictionToken_private() { + Services.prefs.setBoolPref(SUGGEST_PREF, false); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); + Services.prefs.setBoolPref(PRIVATE_ENABLED_PREF, false); + let context = createContext( + `${UrlbarTokenizer.RESTRICT.SEARCH} ${SEARCH_STRING}`, + { isPrivate: true } + ); + await check_results({ + context, + matches: [ + makeSearchResult(context, { + query: SEARCH_STRING, + alias: UrlbarTokenizer.RESTRICT.SEARCH, + engineName: ENGINE_NAME, + heuristic: true, + }), + ], + }); + await cleanUpSuggestions(); + } +); + +add_task( + async function disabled_urlbarSuggestions_withRestrictionToken_private_enabled() { + Services.prefs.setBoolPref(SUGGEST_PREF, false); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); + Services.prefs.setBoolPref(PRIVATE_ENABLED_PREF, true); + let context = createContext( + `${UrlbarTokenizer.RESTRICT.SEARCH} ${SEARCH_STRING}`, + { isPrivate: true } + ); + await check_results({ + context, + matches: [ + makeSearchResult(context, { + query: SEARCH_STRING, + alias: UrlbarTokenizer.RESTRICT.SEARCH, + engineName: ENGINE_NAME, + heuristic: true, + }), + ...makeExpectedSuggestionResults(context, { + query: SEARCH_STRING, + }), + ], + }); + await cleanUpSuggestions(); + } +); + +add_task(async function enabled_by_pref_privateWindow() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); + Services.prefs.setBoolPref(PRIVATE_ENABLED_PREF, true); + let context = createContext(SEARCH_STRING, { isPrivate: true }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedSuggestionResults(context), + ], + }); + await cleanUpSuggestions(); + + Services.prefs.clearUserPref(PRIVATE_ENABLED_PREF); +}); + +add_task(async function singleWordQuery() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); + let context = createContext(SEARCH_STRING, { isPrivate: false }); + + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedSuggestionResults(context), + ], + }); + + await cleanUpSuggestions(); +}); + +add_task(async function multiWordQuery() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); + const query = `${SEARCH_STRING} world`; + let context = createContext(query, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedSuggestionResults(context, { suggestionPrefix: query }), + ], + }); + + await cleanUpSuggestions(); +}); + +add_task(async function suffixMatch() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); + + setSuggestionsFn(searchStr => { + let prefixes = ["baz", "quux"]; + return prefixes.map(p => p + " " + searchStr); + }); + + let context = createContext(SEARCH_STRING, { isPrivate: false }); + + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedFormHistoryResults(context), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "baz " + SEARCH_STRING, + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "quux " + SEARCH_STRING, + }), + ], + }); + + await cleanUpSuggestions(); +}); + +add_task(async function queryIsNotASubstring() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + + setSuggestionsFn(searchStr => { + return ["aaa", "bbb"]; + }); + + let context = createContext(SEARCH_STRING, { isPrivate: false }); + + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedFormHistoryResults(context), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "aaa", + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "bbb", + }), + ], + }); + + await cleanUpSuggestions(); +}); + +add_task(async function restrictToken() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); + + // Add a visit and a bookmark. Actually, make the bookmark visited too so + // that it's guaranteed, with its higher frecency, to appear above the search + // suggestions. + await PlacesTestUtils.addVisits([ + { + uri: Services.io.newURI(`http://example.com/${SEARCH_STRING}-visit`), + title: `${SEARCH_STRING} visit`, + }, + { + uri: Services.io.newURI(`http://example.com/${SEARCH_STRING}-bookmark`), + title: `${SEARCH_STRING} bookmark`, + }, + ]); + + await PlacesTestUtils.addBookmarkWithDetails({ + uri: Services.io.newURI(`http://example.com/${SEARCH_STRING}-bookmark`), + title: `${SEARCH_STRING} bookmark`, + }); + + let context = createContext(SEARCH_STRING, { isPrivate: false }); + + // Do an unrestricted search to make sure everything appears in it, including + // the visit and bookmark. + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + makeBookmarkResult(context, { + uri: `http://example.com/${SEARCH_STRING}-bookmark`, + title: `${SEARCH_STRING} bookmark`, + }), + makeVisitResult(context, { + uri: `http://example.com/${SEARCH_STRING}-visit`, + title: `${SEARCH_STRING} visit`, + }), + ...makeExpectedSuggestionResults(context), + ], + }); + + // Now do a restricted search to make sure only suggestions appear. + context = createContext( + `${UrlbarTokenizer.RESTRICT.SEARCH} ${SEARCH_STRING}`, + { + isPrivate: false, + } + ); + await check_results({ + context, + matches: [ + makeSearchResult(context, { + engineName: ENGINE_NAME, + alias: UrlbarTokenizer.RESTRICT.SEARCH, + query: SEARCH_STRING, + heuristic: true, + }), + ...makeExpectedSuggestionResults(context, { + suggestionPrefix: SEARCH_STRING, + query: SEARCH_STRING, + }), + ], + }); + + // Typing the search restriction char shows the Search Engine entry and local + // results. + context = createContext(UrlbarTokenizer.RESTRICT.SEARCH, { + isPrivate: false, + }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { + engineName: ENGINE_NAME, + query: "", + heuristic: true, + }), + ...makeExpectedFormHistoryResults(context), + ], + }); + + // Also if followed by multiple spaces. + context = createContext(`${UrlbarTokenizer.RESTRICT.SEARCH} `, { + isPrivate: false, + }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { + engineName: ENGINE_NAME, + alias: UrlbarTokenizer.RESTRICT.SEARCH, + query: "", + heuristic: true, + }), + ...makeExpectedFormHistoryResults(context), + ], + }); + + // If followed by any char we should fetch suggestions. + // Note this uses "h" to match form history. + context = createContext(`${UrlbarTokenizer.RESTRICT.SEARCH}h`, { + isPrivate: false, + }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { + engineName: ENGINE_NAME, + query: "h", + heuristic: true, + }), + ...makeExpectedSuggestionResults(context, { + suggestionPrefix: "h", + query: "h", + }), + ], + }); + + // Also if followed by a space and single char. + context = createContext(`${UrlbarTokenizer.RESTRICT.SEARCH} h`, { + isPrivate: false, + }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { + engineName: ENGINE_NAME, + alias: UrlbarTokenizer.RESTRICT.SEARCH, + query: "h", + heuristic: true, + }), + ...makeExpectedSuggestionResults(context, { + suggestionPrefix: "h", + query: "h", + }), + ], + }); + + // Leading search-mode restriction tokens are removed. + context = createContext( + `${UrlbarTokenizer.RESTRICT.BOOKMARK} ${SEARCH_STRING}`, + { isPrivate: false } + ); + await check_results({ + context, + matches: [ + makeSearchResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + heuristic: true, + query: SEARCH_STRING, + alias: UrlbarTokenizer.RESTRICT.BOOKMARK, + }), + makeBookmarkResult(context, { + uri: `http://example.com/${SEARCH_STRING}-bookmark`, + title: `${SEARCH_STRING} bookmark`, + }), + ], + }); + + // Non-search-mode restriction tokens remain in the query and heuristic search + // result. + let token; + for (let t of Object.values(UrlbarTokenizer.RESTRICT)) { + if (!UrlbarTokenizer.SEARCH_MODE_RESTRICT.has(t)) { + token = t; + break; + } + } + Assert.ok( + token, + "Non-search-mode restrict token exists -- if not, you can probably remove me!" + ); + context = createContext(token, { + isPrivate: false, + }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + await cleanUpSuggestions(); +}); + +add_task(async function mixup_frecency() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + // At most, we should have 14 results in this subtest. We set this to 20 to + // make we're not cutting off any results and we are actually getting 12. + Services.prefs.setIntPref(MAX_RICH_RESULTS_PREF, 20); + + // Add a visit and a bookmark. Actually, make the bookmark visited too so + // that it's guaranteed, with its higher frecency, to appear above the search + // suggestions. + await PlacesTestUtils.addVisits([ + { + uri: Services.io.newURI("http://example.com/lo0"), + title: `${SEARCH_STRING} low frecency 0`, + }, + { + uri: Services.io.newURI("http://example.com/lo1"), + title: `${SEARCH_STRING} low frecency 1`, + }, + { + uri: Services.io.newURI("http://example.com/lo2"), + title: `${SEARCH_STRING} low frecency 2`, + }, + { + uri: Services.io.newURI("http://example.com/lo3"), + title: `${SEARCH_STRING} low frecency 3`, + }, + { + uri: Services.io.newURI("http://example.com/lo4"), + title: `${SEARCH_STRING} low frecency 4`, + }, + ]); + + for (let i = 0; i < 5; i++) { + await PlacesTestUtils.addVisits([ + { + uri: Services.io.newURI("http://example.com/hi0"), + title: `${SEARCH_STRING} high frecency 0`, + transition: Ci.nsINavHistoryService.TRANSITION_TYPED, + }, + { + uri: Services.io.newURI("http://example.com/hi1"), + title: `${SEARCH_STRING} high frecency 1`, + transition: Ci.nsINavHistoryService.TRANSITION_TYPED, + }, + { + uri: Services.io.newURI("http://example.com/hi2"), + title: `${SEARCH_STRING} high frecency 2`, + transition: Ci.nsINavHistoryService.TRANSITION_TYPED, + }, + { + uri: Services.io.newURI("http://example.com/hi3"), + title: `${SEARCH_STRING} high frecency 3`, + transition: Ci.nsINavHistoryService.TRANSITION_TYPED, + }, + ]); + } + + for (let i = 0; i < 4; i++) { + let href = `http://example.com/hi${i}`; + await PlacesTestUtils.addBookmarkWithDetails({ + uri: href, + title: `${SEARCH_STRING} high frecency ${i}`, + }); + } + + // Do an unrestricted search to make sure everything appears in it, including + // the visit and bookmark. + let context = createContext(SEARCH_STRING, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + makeBookmarkResult(context, { + uri: "http://example.com/hi3", + title: `${SEARCH_STRING} high frecency 3`, + }), + makeBookmarkResult(context, { + uri: "http://example.com/hi2", + title: `${SEARCH_STRING} high frecency 2`, + }), + makeBookmarkResult(context, { + uri: "http://example.com/hi1", + title: `${SEARCH_STRING} high frecency 1`, + }), + makeBookmarkResult(context, { + uri: "http://example.com/hi0", + title: `${SEARCH_STRING} high frecency 0`, + }), + makeVisitResult(context, { + uri: "http://example.com/lo4", + title: `${SEARCH_STRING} low frecency 4`, + }), + ...makeExpectedSuggestionResults(context), + makeVisitResult(context, { + uri: "http://example.com/lo3", + title: `${SEARCH_STRING} low frecency 3`, + }), + makeVisitResult(context, { + uri: "http://example.com/lo2", + title: `${SEARCH_STRING} low frecency 2`, + }), + makeVisitResult(context, { + uri: "http://example.com/lo1", + title: `${SEARCH_STRING} low frecency 1`, + }), + makeVisitResult(context, { + uri: "http://example.com/lo0", + title: `${SEARCH_STRING} low frecency 0`, + }), + ], + }); + + // Change the "general" context mixup. + Services.prefs.setCharPref( + "browser.urlbar.matchBuckets", + "suggestion:1,general:5,suggestion:1" + ); + + // Do an unrestricted search to make sure everything appears in it, including + // the visits and bookmarks. + context = createContext(SEARCH_STRING, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedSuggestionResults(context).slice(0, 1), + makeBookmarkResult(context, { + uri: "http://example.com/hi3", + title: `${SEARCH_STRING} high frecency 3`, + }), + makeBookmarkResult(context, { + uri: "http://example.com/hi2", + title: `${SEARCH_STRING} high frecency 2`, + }), + makeBookmarkResult(context, { + uri: "http://example.com/hi1", + title: `${SEARCH_STRING} high frecency 1`, + }), + makeBookmarkResult(context, { + uri: "http://example.com/hi0", + title: `${SEARCH_STRING} high frecency 0`, + }), + makeVisitResult(context, { + uri: "http://example.com/lo4", + title: `${SEARCH_STRING} low frecency 4`, + }), + ...makeExpectedSuggestionResults(context).slice(1), + makeVisitResult(context, { + uri: "http://example.com/lo3", + title: `${SEARCH_STRING} low frecency 3`, + }), + makeVisitResult(context, { + uri: "http://example.com/lo2", + title: `${SEARCH_STRING} low frecency 2`, + }), + makeVisitResult(context, { + uri: "http://example.com/lo1", + title: `${SEARCH_STRING} low frecency 1`, + }), + makeVisitResult(context, { + uri: "http://example.com/lo0", + title: `${SEARCH_STRING} low frecency 0`, + }), + ], + }); + + // Change the "search" context mixup. + Services.prefs.setCharPref( + "browser.urlbar.matchBucketsSearch", + "suggestion:2,general:4" + ); + + context = createContext(SEARCH_STRING, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedSuggestionResults(context).slice(0, 2), + makeBookmarkResult(context, { + uri: "http://example.com/hi3", + title: `${SEARCH_STRING} high frecency 3`, + }), + makeBookmarkResult(context, { + uri: "http://example.com/hi2", + title: `${SEARCH_STRING} high frecency 2`, + }), + makeBookmarkResult(context, { + uri: "http://example.com/hi1", + title: `${SEARCH_STRING} high frecency 1`, + }), + makeBookmarkResult(context, { + uri: "http://example.com/hi0", + title: `${SEARCH_STRING} high frecency 0`, + }), + ...makeExpectedSuggestionResults(context).slice(2), + makeVisitResult(context, { + uri: "http://example.com/lo4", + title: `${SEARCH_STRING} low frecency 4`, + }), + makeVisitResult(context, { + uri: "http://example.com/lo3", + title: `${SEARCH_STRING} low frecency 3`, + }), + makeVisitResult(context, { + uri: "http://example.com/lo2", + title: `${SEARCH_STRING} low frecency 2`, + }), + makeVisitResult(context, { + uri: "http://example.com/lo1", + title: `${SEARCH_STRING} low frecency 1`, + }), + makeVisitResult(context, { + uri: "http://example.com/lo0", + title: `${SEARCH_STRING} low frecency 0`, + }), + ], + }); + + Services.prefs.setCharPref( + "browser.urlbar.matchBuckets", + MATCH_BUCKETS_VALUE + ); + Services.prefs.clearUserPref("browser.urlbar.matchBucketsSearch"); + Services.prefs.clearUserPref(MAX_RICH_RESULTS_PREF); + await cleanUpSuggestions(); +}); + +add_task(async function prohibit_suggestions() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + Services.prefs.setBoolPref( + `browser.fixup.domainwhitelist.${SEARCH_STRING}`, + false + ); + + let context = createContext(SEARCH_STRING, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedSuggestionResults(context), + ], + }); + + Services.prefs.setBoolPref( + `browser.fixup.domainwhitelist.${SEARCH_STRING}`, + true + ); + registerCleanupFunction(() => { + Services.prefs.setBoolPref( + `browser.fixup.domainwhitelist.${SEARCH_STRING}`, + false + ); + }); + context = createContext(SEARCH_STRING, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: `http://${SEARCH_STRING}/`, + title: `http://${SEARCH_STRING}/`, + iconUri: "", + heuristic: true, + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + heuristic: false, + }), + ...makeExpectedFormHistoryResults(context), + ], + }); + + // When using multiple words, we should still get suggestions: + let query = `${SEARCH_STRING} world`; + context = createContext(query, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedSuggestionResults(context, { suggestionPrefix: query }), + ], + }); + + // Clear the whitelist for SEARCH_STRING and try preferring DNS for any single + // word instead: + Services.prefs.setBoolPref( + `browser.fixup.domainwhitelist.${SEARCH_STRING}`, + false + ); + Services.prefs.setBoolPref("browser.fixup.dns_first_for_single_words", true); + registerCleanupFunction(() => { + Services.prefs.clearUserPref("browser.fixup.dns_first_for_single_words"); + }); + + context = createContext(SEARCH_STRING, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: `http://${SEARCH_STRING}/`, + title: `http://${SEARCH_STRING}/`, + iconUri: "", + heuristic: true, + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + heuristic: false, + }), + ...makeExpectedFormHistoryResults(context), + ], + }); + + context = createContext("somethingelse", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "http://somethingelse/", + title: "http://somethingelse/", + iconUri: "", + heuristic: true, + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + heuristic: false, + }), + ], + }); + + // When using multiple words, we should still get suggestions: + query = `${SEARCH_STRING} world`; + context = createContext(query, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedSuggestionResults(context, { suggestionPrefix: query }), + ], + }); + + Services.prefs.clearUserPref("browser.fixup.dns_first_for_single_words"); + + context = createContext("http://1.2.3.4/", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "http://1.2.3.4/", + title: "http://1.2.3.4/", + iconUri: "page-icon:http://1.2.3.4/", + heuristic: true, + }), + ], + }); + + context = createContext("[2001::1]:30", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "http://[2001::1]:30/", + title: "http://[2001::1]:30/", + iconUri: "", + heuristic: true, + }), + ], + }); + + context = createContext("user:pass@test", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "http://user:pass@test/", + title: "http://user:pass@test/", + iconUri: "", + heuristic: true, + }), + ], + }); + + context = createContext("data:text/plain,Content", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "data:text/plain,Content", + title: "data:text/plain,Content", + iconUri: "", + heuristic: true, + }), + ], + }); + + context = createContext("a", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + await cleanUpSuggestions(); +}); + +add_task(async function uri_like_queries() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); + + // We should not fetch any suggestions for an actual URL. + let query = "mozilla.org"; + let context = createContext(query, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + title: `http://${query}/`, + uri: `http://${query}/`, + iconUri: "", + heuristic: true, + }), + makeSearchResult(context, { query, engineName: ENGINE_NAME }), + ], + }); + + // We should also not fetch suggestions for a partially-typed URL. + query = "mozilla.o"; + context = createContext(query, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + // Now trying queries that could be confused for URLs. They should return + // results. + const uriLikeQueries = [ + "mozilla.org is a great website", + "I like mozilla.org", + "a/b testing", + "he/him", + "Google vs.", + "5.8 cm", + ]; + for (query of uriLikeQueries) { + context = createContext(query, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedRemoteSuggestionResults(context, { + suggestionPrefix: query, + }), + ], + }); + } + + await cleanUpSuggestions(); +}); + +add_task(async function avoid_remote_url_suggestions_1() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + Services.prefs.setIntPref(MAX_FORM_HISTORY_PREF, 1); + + setSuggestionsFn(searchStr => { + let suffixes = [".com", "/test", ":1]", "@test", ". com"]; + return suffixes.map(s => searchStr + s); + }); + + const query = "test"; + + await UrlbarTestUtils.formHistory.add([`${query}.com`]); + + let context = createContext(query, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + makeFormHistoryResult(context, { + engineName: ENGINE_NAME, + suggestion: `${query}.com`, + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: `${query}. com`, + }), + ], + }); + + await cleanUpSuggestions(); + await UrlbarTestUtils.formHistory.remove([`${query}.com`]); + Services.prefs.clearUserPref(MAX_FORM_HISTORY_PREF); +}); + +add_task(async function avoid_remote_url_suggestions_2() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + Services.prefs.setBoolPref("browser.urlbar.autoFill", false); + + setSuggestionsFn(searchStr => { + let suffixes = ["ed", "eds"]; + return suffixes.map(s => searchStr + s); + }); + + let context = createContext("htt", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "htted", + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "htteds", + }), + ], + }); + + context = createContext("ftp", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "ftped", + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "ftpeds", + }), + ], + }); + + context = createContext("http", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "httped", + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "httpeds", + }), + ], + }); + + context = createContext("http:", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("https", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "httpsed", + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "httpseds", + }), + ], + }); + + context = createContext("https:", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("httpd", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "httpded", + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "httpdeds", + }), + ], + }); + + // Check FTP enabled + Services.prefs.setBoolPref("network.ftp.enabled", true); + registerCleanupFunction(() => + Services.prefs.clearUserPref("network.ftp.enabled") + ); + + context = createContext("ftp:", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("ftp:/", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("ftp://", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("ftp://test", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "ftp://test/", + title: "ftp://test/", + iconUri: "", + heuristic: true, + }), + ], + }); + + // Check FTP disabled + Services.prefs.setBoolPref("network.ftp.enabled", false); + context = createContext("ftp:", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("ftp:/", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("ftp://", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("ftp://test", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "ftp://test/", + title: "ftp://test/", + iconUri: "", + heuristic: true, + }), + ], + }); + + context = createContext("http:/", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("https:/", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("http://", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("https://", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("http://www", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "http://www/", + title: "http://www/", + iconUri: "", + heuristic: true, + }), + ], + }); + + context = createContext("https://www", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "https://www/", + title: "https://www/", + iconUri: "", + heuristic: true, + }), + ], + }); + + context = createContext("http://test", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "http://test/", + title: "http://test/", + iconUri: "", + heuristic: true, + }), + ], + }); + + context = createContext("https://test", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "https://test/", + title: "https://test/", + iconUri: "", + heuristic: true, + }), + ], + }); + + context = createContext("http://www.test", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "http://www.test/", + title: "http://www.test/", + iconUri: "", + heuristic: true, + }), + ], + }); + + context = createContext("http://www.test.com", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "http://www.test.com/", + title: "http://www.test.com/", + iconUri: "", + heuristic: true, + }), + ], + }); + + context = createContext("file", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "fileed", + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "fileeds", + }), + ], + }); + + context = createContext("file:", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("file:///Users", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + uri: "file:///Users", + title: "file:///Users", + iconUri: "", + heuristic: true, + }), + ], + }); + + context = createContext("moz-test://", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("moz+test://", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + context = createContext("about", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "abouted", + }), + makeSearchResult(context, { + engineName: ENGINE_NAME, + suggestion: "abouteds", + }), + ], + }); + + context = createContext("about:", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + await cleanUpSuggestions(); +}); + +add_task(async function restrict_remote_suggestions_after_no_results() { + // We don't fetch remote suggestions if a query with a length over + // maxCharsForSearchSuggestions returns 0 results. We set it to 4 here to + // avoid constructing a 100+ character string. + Services.prefs.setIntPref("browser.urlbar.maxCharsForSearchSuggestions", 4); + setSuggestionsFn(searchStr => { + return []; + }); + + const query = SEARCH_STRING.substring(0, SEARCH_STRING.length - 1); + let context = createContext(query, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedFormHistoryResults(context), + ], + }); + + context = createContext(SEARCH_STRING, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedFormHistoryResults(context), + // Because the previous search returned no suggestions, we will not fetch + // remote suggestions for this query that is just a longer version of the + // previous query. + ], + }); + + // Do one more search before resetting maxCharsForSearchSuggestions to reset + // the search suggestion provider's _lastLowResultsSearchSuggestion property. + // Otherwise it will be stuck at SEARCH_STRING, which interferes with + // subsequent tests. + context = createContext("not the search string", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ], + }); + + Services.prefs.clearUserPref("browser.urlbar.maxCharsForSearchSuggestions"); + + await cleanUpSuggestions(); +}); + +add_task(async function formHistory() { + Services.prefs.setBoolPref(SUGGEST_PREF, true); + Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); + + // Setting maxHistoricalSearchSuggestions = 0 is special and indicates that + // the user has opted out of form history, so we should include form history + // neither before the expected remote results nor after, unlike the other + // checks below, where remaining form history is included after the expected + // remote results. + Services.prefs.setIntPref(MAX_FORM_HISTORY_PREF, 0); + let context = createContext(SEARCH_STRING, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedRemoteSuggestionResults(context), + ], + }); + + Services.prefs.setIntPref(MAX_FORM_HISTORY_PREF, 1); + context = createContext(SEARCH_STRING, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedFormHistoryResults(context, 2).slice(0, 1), + ...makeExpectedRemoteSuggestionResults(context), + ...makeExpectedFormHistoryResults(context, 2).slice(1), + ], + }); + + Services.prefs.setIntPref(MAX_FORM_HISTORY_PREF, 2); + context = createContext(SEARCH_STRING, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedFormHistoryResults(context, 2), + ...makeExpectedRemoteSuggestionResults(context), + ], + }); + + // Do a search for exactly the suggestion of the first form history result. + // The heuristic's query should be the suggestion; the first form history + // result should not be included since it dupes the heuristic; the second form + // history result should not be included since it doesn't match; and both + // remote suggestions should be included. + let firstSuggestion = makeExpectedFormHistoryResults(context)[0].payload + .suggestion; + context = createContext(firstSuggestion, { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + ...makeExpectedRemoteSuggestionResults(context, { + suggestionPrefix: firstSuggestion, + }), + ], + }); + + // Add these form history strings to use below. + let formHistoryStrings = ["foo", "foobar", "fooquux"]; + await UrlbarTestUtils.formHistory.add(formHistoryStrings); + + // Search for "foo". "foo" shouldn't be included since it dupes the + // heuristic. Both "foobar" and "fooquux" should be included even though the + // max form history count is only two and there are three matching form + // history results (including "foo"). + context = createContext("foo", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + makeFormHistoryResult(context, { + suggestion: "foobar", + engineName: ENGINE_NAME, + }), + ...makeExpectedRemoteSuggestionResults(context, { + suggestionPrefix: "foo", + }), + // Note that the second form history result appears after the remote + // suggestions. This isn't ideal because it should appear right after the + // first form history result, but it doesn't because the actual first form + // history result duped the heuristic, so the muxer discarded it. + makeFormHistoryResult(context, { + suggestion: "fooquux", + engineName: ENGINE_NAME, + }), + ], + }); + + // Add a visit that matches "foo" and will autofill so that the heuristic is + // not a search result. Now the "foo" and "foobar" form history should be + // included. + await PlacesTestUtils.addVisits("http://foo.example.com/"); + context = createContext("foo", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeVisitResult(context, { + source: UrlbarUtils.RESULT_SOURCE.HISTORY, + uri: "http://foo.example.com/", + title: "foo.example.com", + heuristic: true, + }), + makeFormHistoryResult(context, { + suggestion: "foo", + engineName: ENGINE_NAME, + }), + makeFormHistoryResult(context, { + suggestion: "foobar", + engineName: ENGINE_NAME, + }), + ...makeExpectedRemoteSuggestionResults(context, { + suggestionPrefix: "foo", + }), + makeFormHistoryResult(context, { + suggestion: "fooquux", + engineName: ENGINE_NAME, + }), + ], + }); + await PlacesUtils.history.clear(); + + // Add SERPs for "foobar" and "food" and search for "foo". The "foo" form + // history should be excluded since it dupes the heuristic; the "foobar" and + // "fooquux" form history should be included; the "food" SERP should be + // included since it doesn't dupe either form history result; and the "foobar" + // SERP depends on the match buckets, see below. + let engine = await Services.search.getDefault(); + let [serpURL1] = UrlbarUtils.getSearchQueryUrl(engine, "foobar"); + let [serpURL2] = UrlbarUtils.getSearchQueryUrl(engine, "food"); + await PlacesTestUtils.addVisits([serpURL1, serpURL2]); + + // First, use the MATCH_BUCKETS_VALUE that the test set above. General + // results appear before suggestions, which means that the muxer visits the + // "foobar" SERP before visiting the "foobar" form history, and so it doesn't + // see that the SERP dupes the form history. The "foobar" SERP is therefore + // included. + context = createContext("foo", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + makeVisitResult(context, { + uri: "http://localhost:9000/search?terms=food", + title: "test visit for http://localhost:9000/search?terms=food", + }), + makeVisitResult(context, { + uri: "http://localhost:9000/search?terms=foobar", + title: "test visit for http://localhost:9000/search?terms=foobar", + }), + makeFormHistoryResult(context, { + suggestion: "foobar", + engineName: ENGINE_NAME, + }), + ...makeExpectedRemoteSuggestionResults(context, { + suggestionPrefix: "foo", + }), + makeFormHistoryResult(context, { + suggestion: "fooquux", + engineName: ENGINE_NAME, + }), + ], + }); + + // Now use Firefox's default match buckets, where suggestions appear before + // general results. Now the muxer will see that the "foobar" SERP dupes the + // "foobar" form history, so it will exclude the SERP. + Services.prefs.setCharPref( + "browser.urlbar.matchBuckets", + "suggestion:4,general:Infinity" + ); + context = createContext("foo", { isPrivate: false }); + await check_results({ + context, + matches: [ + makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }), + // Note that the remote suggestions appear in between the two form history + // results. Ideally the form history would appear together before the + // remote suggestions, but they don't because the actual first form + // history result duped the heuristic, so the muxer discarded it. + makeFormHistoryResult(context, { + suggestion: "foobar", + engineName: ENGINE_NAME, + }), + ...makeExpectedRemoteSuggestionResults(context, { + suggestionPrefix: "foo", + }), + makeFormHistoryResult(context, { + suggestion: "fooquux", + engineName: ENGINE_NAME, + }), + makeVisitResult(context, { + uri: "http://localhost:9000/search?terms=food", + title: "test visit for http://localhost:9000/search?terms=food", + }), + ], + }); + Services.prefs.setCharPref( + "browser.urlbar.matchBuckets", + MATCH_BUCKETS_VALUE + ); + + await PlacesUtils.history.clear(); + + await UrlbarTestUtils.formHistory.remove(formHistoryStrings); + + await cleanUpSuggestions(); + await PlacesUtils.history.clear(); + Services.prefs.clearUserPref(MAX_FORM_HISTORY_PREF); +}); |