/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ /** * Tests that tailed search engine suggestions are returned by * UrlbarProviderSearchSuggestions when available. */ const SUGGEST_ENABLED_PREF = "browser.search.suggest.enabled"; const PRIVATE_SEARCH_PREF = "browser.search.separatePrivateDefault.ui.enabled"; const TAIL_SUGGESTIONS_PREF = "browser.urlbar.richSuggestions.tail"; 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 > 1 suggestion in most cases. Otherwise, you may * encounter unexceptede behaviour with UrlbarProviderSuggestion's * _lastLowResultsSearchSuggestion safeguard. */ function setSuggestionsFn(fn) { previousSuggestionsFn = suggestionsFn; suggestionsFn = fn; } async function cleanup() { await PlacesUtils.bookmarks.eraseEverything(); await PlacesUtils.history.clear(); } async function cleanUpSuggestions() { await cleanup(); if (previousSuggestionsFn) { suggestionsFn = previousSuggestionsFn; previousSuggestionsFn = null; } } add_task(async function setup() { let engine = await addTestTailSuggestionsEngine(searchStr => { return suggestionsFn(searchStr); }); setSuggestionsFn(searchStr => { let suffixes = ["toronto", "tunisia"]; return [ "what time is it in t", suffixes.map(s => searchStr + s.slice(1)), [], { "google:irrelevantparameter": [], "google:suggestdetail": suffixes.map(s => ({ mp: "… ", t: s, })), }, ]; }); // Install the test engine. let oldDefaultEngine = await Services.search.getDefault(); registerCleanupFunction(async () => { Services.search.setDefault( oldDefaultEngine, Ci.nsISearchService.CHANGE_REASON_UNKNOWN ); Services.prefs.clearUserPref(PRIVATE_SEARCH_PREF); Services.prefs.clearUserPref(TAIL_SUGGESTIONS_PREF); Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF); }); Services.search.setDefault(engine, Ci.nsISearchService.CHANGE_REASON_UNKNOWN); Services.prefs.setBoolPref(PRIVATE_SEARCH_PREF, false); Services.prefs.setBoolPref(TAIL_SUGGESTIONS_PREF, true); Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); }); /** * Tests that non-tail suggestion providers still return results correctly when * the tailSuggestions pref is enabled. */ add_task(async function normal_suggestions_provider() { let engine = await addTestSuggestionsEngine(); let tailEngine = await Services.search.getDefault(); Services.search.setDefault(engine, Ci.nsISearchService.CHANGE_REASON_UNKNOWN); const query = "hello world"; let context = createContext(query, { isPrivate: false }); await check_results({ context, matches: [ makeSearchResult(context, { engineName: SUGGESTIONS_ENGINE_NAME, heuristic: true, }), makeSearchResult(context, { engineName: SUGGESTIONS_ENGINE_NAME, suggestion: query + " foo", }), makeSearchResult(context, { engineName: SUGGESTIONS_ENGINE_NAME, suggestion: query + " bar", }), ], }); Services.search.setDefault( tailEngine, Ci.nsISearchService.CHANGE_REASON_UNKNOWN ); await cleanUpSuggestions(); }); /** * Tests a suggestions provider that returns only tail suggestions. */ add_task(async function basic_tail() { const query = "what time is it in t"; let context = createContext(query, { isPrivate: false }); await check_results({ context, matches: [ makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, heuristic: true, }), makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, suggestion: query + "oronto", tail: "toronto", }), makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, suggestion: query + "unisia", tail: "tunisia", }), ], }); await cleanUpSuggestions(); }); /** * Tests a suggestions provider that returns both normal and tail suggestions. * Only normal results should be shown. */ add_task(async function mixed_suggestions() { // When normal suggestions are mixed with tail suggestions, they appear at the // correct position in the google:suggestdetail array as empty objects. setSuggestionsFn(searchStr => { let suffixes = ["toronto", "tunisia"]; return [ "what time is it in t", ["what is the time today texas"].concat( suffixes.map(s => searchStr + s.slice(1)) ), [], { "google:irrelevantparameter": [], "google:suggestdetail": [{}].concat( suffixes.map(s => ({ mp: "… ", t: s, })) ), }, ]; }); const query = "what time is it in t"; let context = createContext(query, { isPrivate: false }); await check_results({ context, matches: [ makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, heuristic: true, }), makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, suggestion: "what is the time today texas", tail: undefined, }), ], }); await cleanUpSuggestions(); }); /** * Tests a suggestions provider that returns both normal and tail suggestions, * with tail suggestions listed before normal suggestions. In the real world * we don't expect that to happen, but we should handle it by showing only the * normal suggestions. */ add_task(async function mixed_suggestions_tail_first() { setSuggestionsFn(searchStr => { let suffixes = ["toronto", "tunisia"]; return [ "what time is it in t", suffixes .map(s => searchStr + s.slice(1)) .concat(["what is the time today texas"]), [], { "google:irrelevantparameter": [], "google:suggestdetail": suffixes .map(s => ({ mp: "… ", t: s, })) .concat([{}]), }, ]; }); const query = "what time is it in t"; let context = createContext(query, { isPrivate: false }); await check_results({ context, matches: [ makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, heuristic: true, }), makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, suggestion: "what is the time today texas", tail: undefined, }), ], }); await cleanUpSuggestions(); }); /** * Tests a search that returns history results, bookmark results and tail * suggestions. Only the history and bookmark results should be shown. */ add_task(async function mixed_results() { await PlacesTestUtils.addVisits([ { uri: Services.io.newURI("http://example.com/1"), title: "what time is", }, ]); await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, url: "http://example.com/2", title: "what time is", }); await PlacesFrecencyRecalculator.recalculateAnyOutdatedFrecencies(); // Tail suggestions should not be shown. const query = "what time is"; let context = createContext(query, { isPrivate: false }); await check_results({ context, matches: [ makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, heuristic: true, }), makeBookmarkResult(context, { uri: "http://example.com/2", title: "what time is", }), makeVisitResult(context, { uri: "http://example.com/1", title: "what time is", }), ], }); // Once we make the query specific enough to exclude the history and bookmark // results, we should show tail suggestions. const tQuery = "what time is it in t"; context = createContext(tQuery, { isPrivate: false }); await check_results({ context, matches: [ makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, heuristic: true, }), makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, suggestion: tQuery + "oronto", tail: "toronto", }), makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, suggestion: tQuery + "unisia", tail: "tunisia", }), ], }); await cleanUpSuggestions(); }); /** * Tests that tail suggestions are deduped if their full-text form is a dupe of * a local search suggestion. Remaining tail suggestions should also not be * shown since we do not mix tail and non-tail suggestions. */ add_task(async function dedupe_local() { Services.prefs.setIntPref("browser.urlbar.maxHistoricalSearchSuggestions", 1); await UrlbarTestUtils.formHistory.add(["what time is it in toronto"]); const query = "what time is it in t"; let context = createContext(query, { isPrivate: false }); await check_results({ context, matches: [ makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, heuristic: true, }), makeFormHistoryResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, suggestion: query + "oronto", }), ], }); Services.prefs.clearUserPref("browser.urlbar.maxHistoricalSearchSuggestions"); await cleanUpSuggestions(); }); /** * Tests that the correct number of suggestion results are displayed if * maxResults is limited, even when tail suggestions are returned. */ add_task(async function limit_results() { await UrlbarTestUtils.formHistory.clear(); const query = "what time is it in t"; let context = createContext(query, { isPrivate: false }); context.maxResults = 2; await check_results({ context, matches: [ makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, heuristic: true, }), makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, suggestion: query + "oronto", tail: "toronto", }), ], }); await cleanUpSuggestions(); }); /** * Tests that tail suggestions are hidden if the pref is disabled. */ add_task(async function disable_pref() { let oldPrefValue = Services.prefs.getBoolPref(TAIL_SUGGESTIONS_PREF); Services.prefs.setBoolPref(TAIL_SUGGESTIONS_PREF, false); const query = "what time is it in t"; let context = createContext(query, { isPrivate: false }); await check_results({ context, matches: [ makeSearchResult(context, { engineName: TAIL_SUGGESTIONS_ENGINE_NAME, heuristic: true, }), ], }); Services.prefs.setBoolPref(TAIL_SUGGESTIONS_PREF, oldPrefValue); await cleanUpSuggestions(); });