1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
5 * Tests that visit-url and search engine heuristic results are returned by
6 * UrlbarProviderHeuristicFallback.
9 const QUICKACTIONS_PREF = "browser.urlbar.suggest.quickactions";
10 const SUGGEST_ENABLED_PREF = "browser.search.suggest.enabled";
11 const PRIVATE_SEARCH_PREF = "browser.search.separatePrivateDefault.ui.enabled";
13 // We make sure that restriction tokens and search terms are correctly
14 // recognized when they are separated by each of these different types of spaces
15 // and combinations of spaces. U+3000 is the ideographic space in CJK and is
16 // commonly used by CJK speakers.
17 const TEST_SPACES = [" ", "\u3000", " \u3000", "\u3000 "];
21 add_setup(async function () {
22 registerCleanupFunction(async () => {
23 Services.prefs.clearUserPref(QUICKACTIONS_PREF);
24 Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF);
25 Services.prefs.clearUserPref(PRIVATE_SEARCH_PREF);
26 Services.prefs.clearUserPref("keyword.enabled");
28 Services.prefs.setBoolPref(QUICKACTIONS_PREF, false);
29 Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, false);
30 Services.prefs.setBoolPref(PRIVATE_SEARCH_PREF, false);
33 add_task(async function () {
34 info("visit url, no protocol");
35 let query = "mozilla.org";
36 let context = createContext(query, { isPrivate: false });
40 makeVisitResult(context, {
41 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
42 uri: `http://${query}/`,
43 fallbackTitle: `http://${query}/`,
46 makeSearchResult(context, {
47 engineName: SUGGESTIONS_ENGINE_NAME,
52 info("visit url, no protocol but with 2 dots");
53 query = "www.mozilla.org";
54 context = createContext(query, { isPrivate: false });
58 makeVisitResult(context, {
59 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
60 uri: `http://${query}/`,
61 fallbackTitle: `http://${query}/`,
64 makeSearchResult(context, {
65 engineName: SUGGESTIONS_ENGINE_NAME,
70 info("visit url, no protocol, e-mail like");
72 context = createContext(query, { isPrivate: false });
76 makeVisitResult(context, {
77 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
78 uri: `http://${query}/`,
79 fallbackTitle: `http://${query}/`,
82 makeSearchResult(context, {
83 engineName: SUGGESTIONS_ENGINE_NAME,
88 info("visit url, with protocol but with 2 dots");
89 query = "https://www.mozilla.org";
90 context = createContext(query, { isPrivate: false });
94 makeVisitResult(context, {
95 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
97 fallbackTitle: `${query}/`,
103 // info("visit url, with protocol but with 3 dots");
104 query = "https://www.mozilla.org.tw";
105 context = createContext(query, { isPrivate: false });
106 await check_results({
109 makeVisitResult(context, {
110 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
112 fallbackTitle: `${query}/`,
118 info("visit url, with protocol");
119 query = "https://mozilla.org";
120 context = createContext(query, { isPrivate: false });
121 await check_results({
124 makeVisitResult(context, {
125 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
127 fallbackTitle: `${query}/`,
133 info("visit url, about: protocol (no host)");
134 query = "about:nonexistent";
135 context = createContext(query, { isPrivate: false });
136 await check_results({
139 makeVisitResult(context, {
140 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
142 fallbackTitle: query,
148 info("visit url, with non-standard whitespace");
149 query = "https://mozilla.org";
150 context = createContext(`${query}\u2028`, { isPrivate: false });
151 await check_results({
154 makeVisitResult(context, {
155 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
157 fallbackTitle: `${query}/`,
163 // This is distinct because of how we predict being able to url autofill via
165 info("visit url, host matching visited host but not visited url");
166 await PlacesTestUtils.addVisits([
168 uri: Services.io.newURI("http://mozilla.org/wine/"),
169 title: "Mozilla Wine",
170 transition: PlacesUtils.history.TRANSITION_TYPED,
173 query = "mozilla.org/rum";
174 context = createContext(`${query}\u2028`, { isPrivate: false });
175 await check_results({
178 makeVisitResult(context, {
179 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
180 uri: `http://${query}`,
181 fallbackTitle: `http://${query}`,
182 iconUri: "page-icon:http://mozilla.org/",
187 await PlacesUtils.history.clear();
189 // And hosts with no dot in them are special, due to requiring safelisting.
190 info("unknown host");
192 context = createContext(query, { isPrivate: false });
193 await check_results({
196 makeSearchResult(context, {
197 engineName: SUGGESTIONS_ENGINE_NAME,
203 info("string with known host");
204 query = "firefox/get";
205 context = createContext(query, { isPrivate: false });
206 await check_results({
209 makeSearchResult(context, {
210 engineName: SUGGESTIONS_ENGINE_NAME,
216 Services.prefs.setBoolPref("browser.fixup.domainwhitelist.firefox", true);
217 registerCleanupFunction(() => {
218 Services.prefs.clearUserPref("browser.fixup.domainwhitelist.firefox");
223 context = createContext(query, { isPrivate: false });
224 await check_results({
227 makeVisitResult(context, {
228 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
229 uri: `http://${query}/`,
230 fallbackTitle: `http://${query}/`,
233 makeSearchResult(context, {
234 engineName: SUGGESTIONS_ENGINE_NAME,
239 info("url with known host");
240 query = "firefox/get";
241 context = createContext(query, { isPrivate: false });
242 await check_results({
245 makeVisitResult(context, {
246 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
247 uri: `http://${query}`,
248 fallbackTitle: `http://${query}`,
249 iconUri: "page-icon:http://firefox/",
255 info("visit url, host matching visited host but not visited url, known host");
256 Services.prefs.setBoolPref("browser.fixup.domainwhitelist.mozilla", true);
257 registerCleanupFunction(() => {
258 Services.prefs.clearUserPref("browser.fixup.domainwhitelist.mozilla");
260 query = "mozilla/rum";
261 context = createContext(query, { isPrivate: false });
262 await check_results({
265 makeVisitResult(context, {
266 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
267 uri: `http://${query}`,
268 fallbackTitle: `http://${query}`,
269 iconUri: "page-icon:http://mozilla/",
275 // ipv4 and ipv6 literal addresses should offer to visit.
276 info("visit url, ipv4 literal");
278 context = createContext(query, { isPrivate: false });
279 await check_results({
282 makeVisitResult(context, {
283 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
284 uri: `http://${query}/`,
285 fallbackTitle: `http://${query}/`,
291 info("visit url, ipv6 literal");
292 query = "[2001:db8::1]";
293 context = createContext(query, { isPrivate: false });
294 await check_results({
297 makeVisitResult(context, {
298 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
299 uri: `http://${query}/`,
300 fallbackTitle: `http://${query}/`,
306 // Setting keyword.enabled to false should always try to visit.
307 let keywordEnabled = Services.prefs.getBoolPref("keyword.enabled");
308 Services.prefs.setBoolPref("keyword.enabled", false);
309 registerCleanupFunction(() => {
310 Services.prefs.clearUserPref("keyword.enabled");
312 info("visit url, keyword.enabled = false");
314 context = createContext(query, { isPrivate: false });
315 await check_results({
318 makeVisitResult(context, {
319 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
320 uri: `http://${query}/`,
321 fallbackTitle: `http://${query}/`,
327 info("visit two word query, keyword.enabled = false");
328 query = "bacon lovers";
329 context = createContext(query, { isPrivate: false });
330 await check_results({
333 makeVisitResult(context, {
334 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
336 fallbackTitle: query,
342 info("Forced search through a restriction token, keyword.enabled = false");
344 context = createContext(query, { isPrivate: false });
345 await check_results({
348 makeSearchResult(context, {
349 engineName: SUGGESTIONS_ENGINE_NAME,
356 Services.prefs.setBoolPref("keyword.enabled", true);
357 info("visit two word query, keyword.enabled = true");
358 query = "bacon lovers";
359 context = createContext(query, { isPrivate: false });
360 await check_results({
363 makeSearchResult(context, {
364 engineName: SUGGESTIONS_ENGINE_NAME,
370 Services.prefs.setBoolPref("keyword.enabled", keywordEnabled);
372 info("visit url, scheme+host");
373 query = "http://example";
374 context = createContext(query, { isPrivate: false });
375 await check_results({
378 makeVisitResult(context, {
379 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
381 fallbackTitle: `${query}/`,
387 info("visit url, scheme+host");
388 query = "ftp://example";
389 context = createContext(query, { isPrivate: false });
390 await check_results({
393 makeVisitResult(context, {
394 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
396 fallbackTitle: `${query}/`,
402 info("visit url, host+port");
403 query = "example:8080";
404 context = createContext(query, { isPrivate: false });
405 await check_results({
408 makeVisitResult(context, {
409 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
410 uri: `http://${query}/`,
411 fallbackTitle: `http://${query}/`,
417 info("numerical operations that look like urls should search");
419 context = createContext(query, { isPrivate: false });
420 await check_results({
423 makeSearchResult(context, {
424 engineName: SUGGESTIONS_ENGINE_NAME,
430 info("numerical operations that look like urls should search");
431 query = "123.12/12.1";
432 context = createContext(query, { isPrivate: false });
433 await check_results({
436 makeSearchResult(context, {
437 engineName: SUGGESTIONS_ENGINE_NAME,
443 query = "resource:///modules";
444 context = createContext(query, { isPrivate: false });
445 await check_results({
448 makeVisitResult(context, {
449 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
451 fallbackTitle: query,
457 info("access resource://app/modules");
458 query = "resource://app/modules";
459 context = createContext(query, { isPrivate: false });
460 await check_results({
463 makeVisitResult(context, {
464 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
466 fallbackTitle: query,
472 info("protocol with an extra slash");
474 context = createContext(query, { isPrivate: false });
475 await check_results({
478 makeSearchResult(context, {
479 engineName: SUGGESTIONS_ENGINE_NAME,
485 info("change default engine");
486 let originalTestEngine = Services.search.getEngineByName(
487 SUGGESTIONS_ENGINE_NAME
489 await SearchTestUtils.installSearchExtension({
493 let engine2 = Services.search.getEngineByName("AliasEngine");
495 Services.search.defaultEngine,
497 "New engine shouldn't be the current engine yet"
499 await Services.search.setDefault(
501 Ci.nsISearchService.CHANGE_REASON_UNKNOWN
504 context = createContext(query, { isPrivate: false });
505 await check_results({
508 makeSearchResult(context, {
509 engineName: "AliasEngine",
514 await Services.search.setDefault(
516 Ci.nsISearchService.CHANGE_REASON_UNKNOWN
520 "Leading search-mode restriction tokens are removed from the search result."
522 for (let token of UrlbarTokenizer.SEARCH_MODE_RESTRICT) {
523 for (let spaces of TEST_SPACES) {
524 query = token + spaces + "query";
525 info("Testing: " + JSON.stringify({ query, spaces: codePoints(spaces) }));
526 let expectedQuery = query.substring(1).trimStart();
527 context = createContext(query, { isPrivate: false });
528 info(`Searching for "${query}", expecting "${expectedQuery}"`);
530 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
532 query: expectedQuery,
535 if (token == UrlbarTokenizer.RESTRICT.SEARCH) {
536 payload.source = UrlbarUtils.RESULT_SOURCE.SEARCH;
537 payload.engineName = SUGGESTIONS_ENGINE_NAME;
539 await check_results({
541 matches: [makeSearchResult(context, payload)],
547 "Leading search-mode restriction tokens are removed from the search result with keyword.enabled = false."
549 Services.prefs.setBoolPref("keyword.enabled", false);
550 for (let token of UrlbarTokenizer.SEARCH_MODE_RESTRICT) {
551 for (let spaces of TEST_SPACES) {
552 query = token + spaces + "query";
553 info("Testing: " + JSON.stringify({ query, spaces: codePoints(spaces) }));
554 let expectedQuery = query.substring(1).trimStart();
555 context = createContext(query, { isPrivate: false });
556 info(`Searching for "${query}", expecting "${expectedQuery}"`);
558 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
560 query: expectedQuery,
563 if (token == UrlbarTokenizer.RESTRICT.SEARCH) {
564 payload.source = UrlbarUtils.RESULT_SOURCE.SEARCH;
565 payload.engineName = SUGGESTIONS_ENGINE_NAME;
567 await check_results({
569 matches: [makeSearchResult(context, payload)],
573 Services.prefs.clearUserPref("keyword.enabled");
576 "Leading non-search-mode restriction tokens are not removed from the search result."
578 for (let token of Object.values(UrlbarTokenizer.RESTRICT)) {
579 if (UrlbarTokenizer.SEARCH_MODE_RESTRICT.has(token)) {
582 for (let spaces of TEST_SPACES) {
583 query = token + spaces + "query";
584 info("Testing: " + JSON.stringify({ query, spaces: codePoints(spaces) }));
585 let expectedQuery = query;
586 context = createContext(query, { isPrivate: false });
587 info(`Searching for "${query}", expecting "${expectedQuery}"`);
588 await check_results({
591 makeSearchResult(context, {
593 query: expectedQuery,
594 engineName: SUGGESTIONS_ENGINE_NAME,
602 "Test the format inputed is user@host, and the host is in domainwhitelist"
604 Services.prefs.setBoolPref("browser.fixup.domainwhitelist.test-host", true);
605 registerCleanupFunction(() => {
606 Services.prefs.clearUserPref("browser.fixup.domainwhitelist.test-host");
609 query = "any@test-host";
610 context = createContext(query, { isPrivate: false });
611 await check_results({
614 makeVisitResult(context, {
615 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
616 uri: `http://${query}/`,
617 fallbackTitle: `http://${query}/`,
620 makeSearchResult(context, {
621 engineName: SUGGESTIONS_ENGINE_NAME,
627 "Test the format inputed is user@host, but the host is not in domainwhitelist"
629 query = "any@not-host";
630 context = createContext(query, { isPrivate: false });
631 await check_results({
634 makeSearchResult(context, {
637 engineName: SUGGESTIONS_ENGINE_NAME,
643 "Test if the format of user:pass@host is handled as visit even if the host is not in domainwhitelist"
645 query = "user:pass@not-host";
646 context = createContext(query, { isPrivate: false });
647 await check_results({
650 makeVisitResult(context, {
651 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
652 uri: "http://user:pass@not-host/",
653 fallbackTitle: "http://user:pass@not-host/",
659 info("Test if the format of user@ipaddress is handled as visit");
660 query = "user@192.168.0.1";
661 context = createContext(query, { isPrivate: false });
662 await check_results({
665 makeVisitResult(context, {
666 source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
667 uri: "http://user@192.168.0.1/",
668 fallbackTitle: "http://user@192.168.0.1/",
671 makeSearchResult(context, {
674 engineName: SUGGESTIONS_ENGINE_NAME,
681 * Returns an array of code points in the given string. Each code point is
682 * returned as a hexidecimal string.
684 * @param {string} str
685 * The code points of this string will be returned.
687 * Array of code points in the string, where each is a hexidecimal string.
689 function codePoints(str) {
690 return str.split("").map(s => s.charCodeAt(0).toString(16));