test_search_suggestions_tail.js (10960B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 /** 5 * Tests that tailed search engine suggestions are returned by 6 * UrlbarProviderSearchSuggestions when available. 7 */ 8 9 const SUGGEST_ENABLED_PREF = "browser.search.suggest.enabled"; 10 const PRIVATE_SEARCH_PREF = "browser.search.separatePrivateDefault.ui.enabled"; 11 const TAIL_SUGGESTIONS_PREF = "browser.urlbar.richSuggestions.tail"; 12 13 var suggestionsFn; 14 var previousSuggestionsFn; 15 16 /** 17 * Set the current suggestion funciton. 18 * 19 * @param {Function} fn 20 * A function that that a search string and returns an array of strings that 21 * will be used as search suggestions. 22 * Note: `fn` should return > 1 suggestion in most cases. Otherwise, you may 23 * encounter unexceptede behaviour with UrlbarProviderSuggestion's 24 * _lastLowResultsSearchSuggestion safeguard. 25 */ 26 function setSuggestionsFn(fn) { 27 previousSuggestionsFn = suggestionsFn; 28 suggestionsFn = fn; 29 } 30 31 async function cleanup() { 32 await PlacesUtils.bookmarks.eraseEverything(); 33 await PlacesUtils.history.clear(); 34 } 35 36 async function cleanUpSuggestions() { 37 await cleanup(); 38 if (previousSuggestionsFn) { 39 suggestionsFn = previousSuggestionsFn; 40 previousSuggestionsFn = null; 41 } 42 } 43 44 add_setup(async function () { 45 let engine = await addTestTailSuggestionsEngine(searchStr => { 46 return suggestionsFn(searchStr); 47 }); 48 setSuggestionsFn(searchStr => { 49 let suffixes = ["toronto", "tunisia"]; 50 return [ 51 "what time is it in t", 52 suffixes.map(s => searchStr + s.slice(1)), 53 [], 54 { 55 "google:irrelevantparameter": [], 56 "google:suggestdetail": suffixes.map(s => ({ 57 mp: "… ", 58 t: s, 59 })), 60 }, 61 ]; 62 }); 63 64 // Install the test engine. 65 let oldDefaultEngine = await Services.search.getDefault(); 66 registerCleanupFunction(async () => { 67 Services.search.setDefault( 68 oldDefaultEngine, 69 Ci.nsISearchService.CHANGE_REASON_UNKNOWN 70 ); 71 Services.prefs.clearUserPref(PRIVATE_SEARCH_PREF); 72 Services.prefs.clearUserPref(TAIL_SUGGESTIONS_PREF); 73 Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF); 74 }); 75 Services.search.setDefault(engine, Ci.nsISearchService.CHANGE_REASON_UNKNOWN); 76 Services.prefs.setBoolPref(PRIVATE_SEARCH_PREF, false); 77 Services.prefs.setBoolPref(TAIL_SUGGESTIONS_PREF, true); 78 Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); 79 }); 80 81 /** 82 * Tests that non-tail suggestion providers still return results correctly when 83 * the tailSuggestions pref is enabled. 84 */ 85 add_task(async function normal_suggestions_provider() { 86 let engine = await addTestSuggestionsEngine(); 87 let tailEngine = await Services.search.getDefault(); 88 Services.search.setDefault(engine, Ci.nsISearchService.CHANGE_REASON_UNKNOWN); 89 90 const query = "hello world"; 91 let context = createContext(query, { isPrivate: false }); 92 await check_results({ 93 context, 94 matches: [ 95 makeSearchResult(context, { 96 engineName: SUGGESTIONS_ENGINE_NAME, 97 heuristic: true, 98 }), 99 makeSearchResult(context, { 100 engineName: SUGGESTIONS_ENGINE_NAME, 101 suggestion: query + " foo", 102 }), 103 makeSearchResult(context, { 104 engineName: SUGGESTIONS_ENGINE_NAME, 105 suggestion: query + " bar", 106 }), 107 ], 108 }); 109 110 Services.search.setDefault( 111 tailEngine, 112 Ci.nsISearchService.CHANGE_REASON_UNKNOWN 113 ); 114 await cleanUpSuggestions(); 115 }); 116 117 /** 118 * Tests a suggestions provider that returns only tail suggestions. 119 */ 120 add_task(async function basic_tail() { 121 const query = "what time is it in t"; 122 let context = createContext(query, { isPrivate: false }); 123 await check_results({ 124 context, 125 matches: [ 126 makeSearchResult(context, { 127 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 128 heuristic: true, 129 }), 130 makeSearchResult(context, { 131 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 132 suggestion: query + "oronto", 133 tail: "toronto", 134 }), 135 makeSearchResult(context, { 136 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 137 suggestion: query + "unisia", 138 tail: "tunisia", 139 }), 140 ], 141 }); 142 await cleanUpSuggestions(); 143 }); 144 145 /** 146 * Tests a suggestions provider that returns both normal and tail suggestions. 147 * Only normal results should be shown. 148 */ 149 add_task(async function mixed_suggestions() { 150 // When normal suggestions are mixed with tail suggestions, they appear at the 151 // correct position in the google:suggestdetail array as empty objects. 152 setSuggestionsFn(searchStr => { 153 let suffixes = ["toronto", "tunisia"]; 154 return [ 155 "what time is it in t", 156 ["what is the time today texas"].concat( 157 suffixes.map(s => searchStr + s.slice(1)) 158 ), 159 [], 160 { 161 "google:irrelevantparameter": [], 162 "google:suggestdetail": [{}].concat( 163 suffixes.map(s => ({ 164 mp: "… ", 165 t: s, 166 })) 167 ), 168 }, 169 ]; 170 }); 171 172 const query = "what time is it in t"; 173 let context = createContext(query, { isPrivate: false }); 174 await check_results({ 175 context, 176 matches: [ 177 makeSearchResult(context, { 178 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 179 heuristic: true, 180 }), 181 makeSearchResult(context, { 182 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 183 suggestion: "what is the time today texas", 184 tail: undefined, 185 }), 186 ], 187 }); 188 await cleanUpSuggestions(); 189 }); 190 191 /** 192 * Tests a suggestions provider that returns both normal and tail suggestions, 193 * with tail suggestions listed before normal suggestions. In the real world 194 * we don't expect that to happen, but we should handle it by showing only the 195 * normal suggestions. 196 */ 197 add_task(async function mixed_suggestions_tail_first() { 198 setSuggestionsFn(searchStr => { 199 let suffixes = ["toronto", "tunisia"]; 200 return [ 201 "what time is it in t", 202 suffixes 203 .map(s => searchStr + s.slice(1)) 204 .concat(["what is the time today texas"]), 205 [], 206 { 207 "google:irrelevantparameter": [], 208 "google:suggestdetail": suffixes 209 .map(s => ({ 210 mp: "… ", 211 t: s, 212 })) 213 .concat([{}]), 214 }, 215 ]; 216 }); 217 218 const query = "what time is it in t"; 219 let context = createContext(query, { isPrivate: false }); 220 await check_results({ 221 context, 222 matches: [ 223 makeSearchResult(context, { 224 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 225 heuristic: true, 226 }), 227 makeSearchResult(context, { 228 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 229 suggestion: "what is the time today texas", 230 tail: undefined, 231 }), 232 ], 233 }); 234 await cleanUpSuggestions(); 235 }); 236 237 /** 238 * Tests a search that returns history results, bookmark results and tail 239 * suggestions. Only the history and bookmark results should be shown. 240 */ 241 add_task(async function mixed_results() { 242 await PlacesTestUtils.addVisits([ 243 { 244 uri: Services.io.newURI("http://example.com/1"), 245 title: "what time is", 246 }, 247 ]); 248 249 await PlacesUtils.bookmarks.insert({ 250 parentGuid: PlacesUtils.bookmarks.unfiledGuid, 251 url: "http://example.com/2", 252 title: "what time is", 253 }); 254 await PlacesFrecencyRecalculator.recalculateAnyOutdatedFrecencies(); 255 256 // Tail suggestions should not be shown. 257 const query = "what time is"; 258 let context = createContext(query, { isPrivate: false }); 259 await check_results({ 260 context, 261 matches: [ 262 makeSearchResult(context, { 263 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 264 heuristic: true, 265 }), 266 makeBookmarkResult(context, { 267 uri: "http://example.com/2", 268 title: "what time is", 269 }), 270 makeVisitResult(context, { 271 uri: "http://example.com/1", 272 title: "what time is", 273 }), 274 ], 275 }); 276 277 // Once we make the query specific enough to exclude the history and bookmark 278 // results, we should show tail suggestions. 279 const tQuery = "what time is it in t"; 280 context = createContext(tQuery, { isPrivate: false }); 281 await check_results({ 282 context, 283 matches: [ 284 makeSearchResult(context, { 285 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 286 heuristic: true, 287 }), 288 makeSearchResult(context, { 289 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 290 suggestion: tQuery + "oronto", 291 tail: "toronto", 292 }), 293 makeSearchResult(context, { 294 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 295 suggestion: tQuery + "unisia", 296 tail: "tunisia", 297 }), 298 ], 299 }); 300 301 await cleanUpSuggestions(); 302 }); 303 304 /** 305 * Tests that tail suggestions are deduped if their full-text form is a dupe of 306 * a local search suggestion. Remaining tail suggestions should also not be 307 * shown since we do not mix tail and non-tail suggestions. 308 */ 309 add_task(async function dedupe_local() { 310 Services.prefs.setIntPref("browser.urlbar.maxHistoricalSearchSuggestions", 1); 311 await UrlbarTestUtils.formHistory.add(["what time is it in toronto"]); 312 313 const query = "what time is it in t"; 314 let context = createContext(query, { isPrivate: false }); 315 await check_results({ 316 context, 317 matches: [ 318 makeSearchResult(context, { 319 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 320 heuristic: true, 321 }), 322 makeFormHistoryResult(context, { 323 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 324 suggestion: query + "oronto", 325 }), 326 ], 327 }); 328 329 Services.prefs.clearUserPref("browser.urlbar.maxHistoricalSearchSuggestions"); 330 await cleanUpSuggestions(); 331 }); 332 333 /** 334 * Tests that the correct number of suggestion results are displayed if 335 * maxResults is limited, even when tail suggestions are returned. 336 */ 337 add_task(async function limit_results() { 338 await UrlbarTestUtils.formHistory.clear(); 339 const query = "what time is it in t"; 340 let context = createContext(query, { isPrivate: false }); 341 context.maxResults = 2; 342 await check_results({ 343 context, 344 matches: [ 345 makeSearchResult(context, { 346 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 347 heuristic: true, 348 }), 349 makeSearchResult(context, { 350 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 351 suggestion: query + "oronto", 352 tail: "toronto", 353 }), 354 ], 355 }); 356 await cleanUpSuggestions(); 357 }); 358 359 /** 360 * Tests that tail suggestions are hidden if the pref is disabled. 361 */ 362 add_task(async function disable_pref() { 363 let oldPrefValue = Services.prefs.getBoolPref(TAIL_SUGGESTIONS_PREF); 364 Services.prefs.setBoolPref(TAIL_SUGGESTIONS_PREF, false); 365 const query = "what time is it in t"; 366 let context = createContext(query, { isPrivate: false }); 367 await check_results({ 368 context, 369 matches: [ 370 makeSearchResult(context, { 371 engineName: TAIL_SUGGESTIONS_ENGINE_NAME, 372 heuristic: true, 373 }), 374 ], 375 }); 376 377 Services.prefs.setBoolPref(TAIL_SUGGESTIONS_PREF, oldPrefValue); 378 await cleanUpSuggestions(); 379 });