test_search_suggestions_aliases.js (11210B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 /** 5 * Tests that an engine with suggestions works with our alias autocomplete 6 * behavior. 7 */ 8 9 const DEFAULT_ENGINE_NAME = "TestDefaultEngine"; 10 const SUGGEST_PREF = "browser.urlbar.suggest.searches"; 11 const SUGGEST_ENABLED_PREF = "browser.search.suggest.enabled"; 12 const HISTORY_TITLE = "fire"; 13 14 // We make sure that aliases and search terms are correctly recognized when they 15 // are separated by each of these different types of spaces and combinations of 16 // spaces. U+3000 is the ideographic space in CJK and is commonly used by CJK 17 // speakers. 18 const TEST_SPACES = [" ", "\u3000", " \u3000", "\u3000 "]; 19 20 let engine; 21 let port; 22 23 add_setup(async function () { 24 engine = await addTestSuggestionsEngine(); 25 port = engine.getSubmission("abc").uri.port; 26 27 Services.prefs.setBoolPref("browser.urlbar.suggest.quickactions", false); 28 29 // Set a mock engine as the default so we don't hit the network below when we 30 // do searches that return the default engine heuristic result. 31 await SearchTestUtils.installSearchExtension( 32 { 33 name: DEFAULT_ENGINE_NAME, 34 search_url: "https://my.search.com/", 35 }, 36 { setAsDefault: true } 37 ); 38 39 // History matches should not appear with @aliases, so this visit should not 40 // appear when searching with @aliases below. 41 await PlacesTestUtils.addVisits({ 42 uri: engine.getSubmission("abc").uri, 43 title: HISTORY_TITLE, 44 }); 45 }); 46 47 // A non-token alias without a trailing space shouldn't be recognized as a 48 // keyword. It should be treated as part of the search string. 49 add_task(async function nonTokenAlias_noTrailingSpace() { 50 Services.prefs.setBoolPref( 51 "browser.search.separatePrivateDefault.ui.enabled", 52 false 53 ); 54 55 let alias = "moz"; 56 engine.alias = alias; 57 Assert.equal(engine.alias, alias); 58 let context = createContext(alias, { isPrivate: false }); 59 await check_results({ 60 context, 61 matches: [ 62 makeSearchResult(context, { 63 engineName: DEFAULT_ENGINE_NAME, 64 query: alias, 65 heuristic: true, 66 }), 67 ], 68 }); 69 Services.prefs.clearUserPref( 70 "browser.search.separatePrivateDefault.ui.enabled" 71 ); 72 }); 73 74 // A non-token alias with a trailing space should be recognized as a keyword, 75 // and the history result should be included. 76 add_task(async function nonTokenAlias_trailingSpace() { 77 let alias = "moz"; 78 engine.alias = alias; 79 Assert.equal(engine.alias, alias); 80 81 for (let isPrivate of [false, true]) { 82 for (let spaces of TEST_SPACES) { 83 info( 84 "Testing: " + JSON.stringify({ isPrivate, spaces: codePoints(spaces) }) 85 ); 86 let context = createContext(alias + spaces, { isPrivate }); 87 await check_results({ 88 context, 89 matches: [ 90 makeSearchResult(context, { 91 engineName: SUGGESTIONS_ENGINE_NAME, 92 alias, 93 query: "", 94 heuristic: true, 95 }), 96 makeVisitResult(context, { 97 uri: `http://localhost:${port}/search?q=abc`, 98 title: HISTORY_TITLE, 99 }), 100 ], 101 }); 102 } 103 } 104 }); 105 106 // Search for "alias HISTORY_TITLE" with a non-token alias in a non-private 107 // context. The remote suggestions and history result should be shown. 108 add_task(async function nonTokenAlias_history_nonPrivate() { 109 let alias = "moz"; 110 engine.alias = alias; 111 Assert.equal(engine.alias, alias); 112 for (let spaces of TEST_SPACES) { 113 info("Testing: " + JSON.stringify({ spaces: codePoints(spaces) })); 114 let context = createContext(alias + spaces + HISTORY_TITLE, { 115 isPrivate: false, 116 }); 117 await check_results({ 118 context, 119 matches: [ 120 makeSearchResult(context, { 121 engineName: SUGGESTIONS_ENGINE_NAME, 122 alias, 123 query: HISTORY_TITLE, 124 heuristic: true, 125 }), 126 makeSearchResult(context, { 127 engineName: SUGGESTIONS_ENGINE_NAME, 128 alias, 129 query: HISTORY_TITLE, 130 suggestion: `${HISTORY_TITLE} foo`, 131 }), 132 makeSearchResult(context, { 133 engineName: SUGGESTIONS_ENGINE_NAME, 134 alias, 135 query: HISTORY_TITLE, 136 suggestion: `${HISTORY_TITLE} bar`, 137 }), 138 makeVisitResult(context, { 139 uri: `http://localhost:${port}/search?q=abc`, 140 title: HISTORY_TITLE, 141 }), 142 ], 143 }); 144 } 145 }); 146 147 // Search for "alias HISTORY_TITLE" with a non-token alias in a private context. 148 // The history result should be shown, but not the remote suggestions. 149 add_task(async function nonTokenAlias_history_private() { 150 let alias = "moz"; 151 engine.alias = alias; 152 Assert.equal(engine.alias, alias); 153 for (let spaces of TEST_SPACES) { 154 info("Testing: " + JSON.stringify({ spaces: codePoints(spaces) })); 155 let context = createContext(alias + spaces + HISTORY_TITLE, { 156 isPrivate: true, 157 }); 158 await check_results({ 159 context, 160 matches: [ 161 makeSearchResult(context, { 162 engineName: SUGGESTIONS_ENGINE_NAME, 163 alias, 164 query: HISTORY_TITLE, 165 heuristic: true, 166 }), 167 makeVisitResult(context, { 168 uri: `http://localhost:${port}/search?q=abc`, 169 title: HISTORY_TITLE, 170 }), 171 ], 172 }); 173 } 174 }); 175 176 // A token alias without a trailing space should be autofilled with a trailing 177 // space and recognized as a keyword with a keyword offer. 178 add_task(async function tokenAlias_noTrailingSpace() { 179 let alias = "@moz"; 180 engine.alias = alias; 181 Assert.equal(engine.alias, alias); 182 for (let isPrivate of [false, true]) { 183 let context = createContext(alias, { isPrivate }); 184 await check_results({ 185 context, 186 autofilled: alias + " ", 187 matches: [ 188 makeSearchResult(context, { 189 engineName: SUGGESTIONS_ENGINE_NAME, 190 alias, 191 providesSearchMode: true, 192 query: "", 193 heuristic: false, 194 providerName: "UrlbarProviderTokenAliasEngines", 195 }), 196 ], 197 }); 198 } 199 }); 200 201 // A token alias with a trailing space should be recognized as a keyword without 202 // a keyword offer. 203 add_task(async function tokenAlias_trailingSpace() { 204 let alias = "@moz"; 205 engine.alias = alias; 206 Assert.equal(engine.alias, alias); 207 for (let isPrivate of [false, true]) { 208 for (let spaces of TEST_SPACES) { 209 info( 210 "Testing: " + JSON.stringify({ isPrivate, spaces: codePoints(spaces) }) 211 ); 212 let context = createContext(alias + spaces, { isPrivate }); 213 await check_results({ 214 context, 215 matches: [ 216 makeSearchResult(context, { 217 engineName: SUGGESTIONS_ENGINE_NAME, 218 alias, 219 query: "", 220 heuristic: true, 221 }), 222 ], 223 }); 224 } 225 } 226 }); 227 228 // Search for "alias HISTORY_TITLE" with a token alias in a non-private context. 229 // The remote suggestions should be shown, but not the history result. 230 add_task(async function tokenAlias_history_nonPrivate() { 231 let alias = "@moz"; 232 engine.alias = alias; 233 Assert.equal(engine.alias, alias); 234 for (let spaces of TEST_SPACES) { 235 info("Testing: " + JSON.stringify({ spaces: codePoints(spaces) })); 236 let context = createContext(alias + spaces + HISTORY_TITLE, { 237 isPrivate: false, 238 }); 239 await check_results({ 240 context, 241 matches: [ 242 makeSearchResult(context, { 243 engineName: SUGGESTIONS_ENGINE_NAME, 244 alias, 245 query: HISTORY_TITLE, 246 heuristic: true, 247 }), 248 makeSearchResult(context, { 249 engineName: SUGGESTIONS_ENGINE_NAME, 250 alias, 251 query: HISTORY_TITLE, 252 suggestion: `${HISTORY_TITLE} foo`, 253 }), 254 makeSearchResult(context, { 255 engineName: SUGGESTIONS_ENGINE_NAME, 256 alias, 257 query: HISTORY_TITLE, 258 suggestion: `${HISTORY_TITLE} bar`, 259 }), 260 ], 261 }); 262 } 263 }); 264 265 // Search for "alias HISTORY_TITLE" with a token alias in a private context. 266 // Neither the history result nor the remote suggestions should be shown. 267 add_task(async function tokenAlias_history_private() { 268 let alias = "@moz"; 269 engine.alias = alias; 270 Assert.equal(engine.alias, alias); 271 for (let spaces of TEST_SPACES) { 272 info("Testing: " + JSON.stringify({ spaces: codePoints(spaces) })); 273 let context = createContext(alias + spaces + HISTORY_TITLE, { 274 isPrivate: true, 275 }); 276 await check_results({ 277 context, 278 matches: [ 279 makeSearchResult(context, { 280 engineName: SUGGESTIONS_ENGINE_NAME, 281 alias, 282 query: HISTORY_TITLE, 283 heuristic: true, 284 }), 285 ], 286 }); 287 } 288 }); 289 290 // Even when they're disabled, suggestions should still be returned when using a 291 // token alias in a non-private context. 292 add_task(async function suggestionsDisabled_nonPrivate() { 293 Services.prefs.setBoolPref(SUGGEST_PREF, false); 294 Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); 295 let alias = "@moz"; 296 engine.alias = alias; 297 Assert.equal(engine.alias, alias); 298 for (let spaces of TEST_SPACES) { 299 info("Testing: " + JSON.stringify({ spaces: codePoints(spaces) })); 300 let context = createContext(alias + spaces + "term", { isPrivate: false }); 301 await check_results({ 302 context, 303 matches: [ 304 makeSearchResult(context, { 305 engineName: SUGGESTIONS_ENGINE_NAME, 306 alias, 307 query: "term", 308 heuristic: true, 309 }), 310 makeSearchResult(context, { 311 engineName: SUGGESTIONS_ENGINE_NAME, 312 alias, 313 query: "term", 314 suggestion: "term foo", 315 }), 316 makeSearchResult(context, { 317 engineName: SUGGESTIONS_ENGINE_NAME, 318 alias, 319 query: "term", 320 suggestion: "term bar", 321 }), 322 ], 323 }); 324 } 325 Services.prefs.clearUserPref(SUGGEST_PREF); 326 Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF); 327 }); 328 329 // Suggestions should not be returned when using a token alias in a private 330 // context. 331 add_task(async function suggestionsDisabled_private() { 332 Services.prefs.setBoolPref(SUGGEST_PREF, false); 333 Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); 334 let alias = "@moz"; 335 engine.alias = alias; 336 Assert.equal(engine.alias, alias); 337 for (let spaces of TEST_SPACES) { 338 info("Testing: " + JSON.stringify({ spaces: codePoints(spaces) })); 339 let context = createContext(alias + spaces + "term", { isPrivate: true }); 340 await check_results({ 341 context, 342 matches: [ 343 makeSearchResult(context, { 344 engineName: SUGGESTIONS_ENGINE_NAME, 345 alias, 346 query: "term", 347 heuristic: true, 348 }), 349 ], 350 }); 351 Services.prefs.clearUserPref(SUGGEST_PREF); 352 Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF); 353 } 354 }); 355 356 /** 357 * Returns an array of code points in the given string. Each code point is 358 * returned as a hexidecimal string. 359 * 360 * @param {string} str 361 * The code points of this string will be returned. 362 * @returns {Array} 363 * Array of code points in the string, where each is a hexidecimal string. 364 */ 365 function codePoints(str) { 366 return str.split("").map(s => s.charCodeAt(0).toString(16)); 367 }