Bug 1658964 - Convert local restriction chars to search mode and make other improvements to search mode. r=harry

Summary of major changes:

* Bookmarks, history, and tabs restriction chars now enter search mode. I added
  a method to UrlbarProviderHeuristicFallback to return a result with a keyword
  when one of these is used.
* This fixes other bugs like recognizing aliases that are entered at the
  beginning of non-empty search strings, and not quasi-re-entering search mode
  when search mode is already entered and you type another alias.
* The heuristic now determines whether we enter search mode, similar to how it
  also determines whether we autofill. When the heuristic has a keyword but no
  keyword offer, and the keyword is one of the recognized search mode keywords,
  then we enter search mode, cancel the current query, and start a new query
  with the remainder of the search string after the keyword.
* I slightly changed how we detect an alias, but only when update2 is
  enabled. Now, an alias must be followed by a space; otherwise, the alias is
  not recognized and instead just remains part of the seach string. Because if
  we don't do that, then you end up in a strange situation after typing an alias
  but before pressing space: The heuristic says "Search with <engine with the
  alias>", but we haven't entered search mode yet because you haven't typed a
  space yet. This is true for both @aliaes and non-@aliases.
* A consequence of the previous point is that we can still autofill @aliases
  with a trailing space, which IMO is important. Then, once the user types any
  char (space or not), we immediately enter search mode with the query being
  whatever char they typed. This is less important after bug 1658605 landed, but
  it's still good to have.
* Previously, `UrlbarView.onQueryResults` called UrlbarInput in order to
  autofill after the first result is received. This is circuitous becaue the
  input already has an `onFirstResult` method, which I now use to enter search
  mode when appropriate. So I moved the autofill call from UrlbarView to
  `UrlbarInput.onFirstResult`.
* As I mentioned, I improved some test framework and simplified some related
  product (non-test) code. For example:
    * I removed `UrlbarUtils.KEYWORD_OFFER.NONE` in favor of just leaving
      `keywordOffer` as `undefined`.
    * `tailOffsetIndex` can now be `undefined` if it's not relevant.
    * I removed empty-string `icon` properties from payloads in favor of
      `undefined`.
    * In tests, I ignore `undefined` but present properties in payloads so they
      don't count when comparing payloads with `deepEqual`.
    * We weren't previously comparing `result.source` and `result.type` in
      xpcshell tests, and that's important IMO, so I added checks for those and
      updated tests.
    * `isSearchHistory` is redundant, so I removed it. For form history, we
      should be checking `result.source == HISTORY` and `result.type == SEARCH`.
* A bunch of tests needed to be updated for this new behavior.

Differential Revision: https://phabricator.services.mozilla.com/D87944
This commit is contained in:
Drew Willcoxon 2020-09-02 00:52:12 +00:00
Родитель 7f1c17db7a
Коммит 6d6402fb4e
53 изменённых файлов: 2506 добавлений и 1008 удалений

Просмотреть файл

@ -37,6 +37,16 @@ function promiseUninstallCompleted(extensionId) {
});
}
function getPayload(result) {
let payload = {};
for (let [key, value] of Object.entries(result.payload)) {
if (value !== undefined) {
payload[key] = value;
}
}
return payload;
}
const ORIGINAL_NOTIFICATION_TIMEOUT =
UrlbarProviderExtension.notificationTimeout;
@ -284,14 +294,6 @@ add_task(async function test_onProviderResultsRequested() {
payload: {
query: "test",
engine: "Test engine",
suggestion: undefined,
tailPrefix: undefined,
tail: undefined,
tailOffsetIndex: -1,
keyword: undefined,
isSearchHistory: false,
icon: "",
keywordOffer: false,
},
},
// The second result should be our search suggestion result since the
@ -363,7 +365,7 @@ add_task(async function test_onProviderResultsRequested() {
source: r.source,
title: r.title,
heuristic: r.heuristic,
payload: r.payload,
payload: getPayload(r),
}));
Assert.deepEqual(actualResults, expectedResults);

Просмотреть файл

@ -2,9 +2,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const { UrlbarTestUtils } = ChromeUtils.import(
"resource://testing-common/UrlbarTestUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
});
XPCOMUtils.defineLazyGetter(this, "UrlbarTestUtils", () => {
const { UrlbarTestUtils: module } = ChromeUtils.import(
"resource://testing-common/UrlbarTestUtils.jsm"
);
module.init(this);
return module;
});
/**
* Clicks the given link and checks this opens the given URI in the same tab.
@ -94,6 +102,70 @@ add_task(async function test_search_icon() {
* Tests the search hand-off on character keydown in "about:privatebrowsing".
*/
add_task(async function test_search_handoff_on_keydown() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", true]],
});
let { win, tab } = await openAboutPrivateBrowsing();
await SpecialPowers.spawn(tab, [], async function() {
let btn = content.document.getElementById("search-handoff-button");
btn.click();
ok(btn.classList.contains("focused"), "in-content search has focus styles");
});
ok(urlBarHasHiddenFocus(win), "url bar has hidden focused");
// Expect two searches, one to enter search mode and then another in search
// mode.
let searchPromise = UrlbarTestUtils.promiseSearchComplete(win, 2);
await new Promise(r => EventUtils.synthesizeKey("f", {}, win, r));
await SpecialPowers.spawn(tab, [], async function() {
ok(
content.document
.getElementById("search-handoff-button")
.classList.contains("hidden"),
"in-content search is hidden"
);
});
await searchPromise;
ok(urlBarHasNormalFocus(win), "url bar has normal focused");
await UrlbarTestUtils.assertSearchMode(win, {
engineName: "DuckDuckGo",
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
entry: "typed",
});
is(win.gURLBar.value, "f", "url bar has search text");
// Close the popup.
await UrlbarTestUtils.exitSearchMode(win);
await UrlbarTestUtils.promisePopupClose(win);
// Hitting ESC should reshow the in-content search
await new Promise(r => EventUtils.synthesizeKey("KEY_Escape", {}, win, r));
await SpecialPowers.spawn(tab, [], async function() {
ok(
!content.document
.getElementById("search-handoff-button")
.classList.contains("hidden"),
"in-content search is not hidden"
);
});
await BrowserTestUtils.closeWindow(win);
await SpecialPowers.popPrefEnv();
});
/**
* This task can be removed when browser.urlbar.update2 is enabled by default.
*
* Tests the search hand-off on character keydown in "about:privatebrowsing".
*/
add_task(async function test_search_handoff_on_keydown_legacy() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", false]],
});
let { win, tab } = await openAboutPrivateBrowsing();
await SpecialPowers.spawn(tab, [], async function() {
@ -129,6 +201,7 @@ add_task(async function test_search_handoff_on_keydown() {
});
await BrowserTestUtils.closeWindow(win);
await SpecialPowers.popPrefEnv();
});
/**
@ -153,6 +226,53 @@ add_task(async function test_search_handoff_on_composition_start() {
* Tests the search hand-off on paste in "about:privatebrowsing".
*/
add_task(async function test_search_handoff_on_paste() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", true]],
});
let { win, tab } = await openAboutPrivateBrowsing();
await SpecialPowers.spawn(tab, [], async function() {
content.document.getElementById("search-handoff-button").click();
});
ok(urlBarHasHiddenFocus(win), "url bar has hidden focused");
var helper = SpecialPowers.Cc[
"@mozilla.org/widget/clipboardhelper;1"
].getService(SpecialPowers.Ci.nsIClipboardHelper);
helper.copyString("words");
// Expect two searches, one to enter search mode and then another in search
// mode.
let searchPromise = UrlbarTestUtils.promiseSearchComplete(win, 2);
await new Promise(r =>
EventUtils.synthesizeKey("v", { accelKey: true }, win, r)
);
await searchPromise;
ok(urlBarHasNormalFocus(win), "url bar has normal focused");
await UrlbarTestUtils.assertSearchMode(win, {
engineName: "DuckDuckGo",
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
entry: "typed",
});
is(win.gURLBar.value, "words", "url bar has search text");
await BrowserTestUtils.closeWindow(win);
await SpecialPowers.popPrefEnv();
});
/**
* This task can be removed when browser.urlbar.update2 is enabled by default.
*
* Tests the search hand-off on paste in "about:privatebrowsing".
*/
add_task(async function test_search_handoff_on_paste_legacy() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", false]],
});
let { win, tab } = await openAboutPrivateBrowsing();
await SpecialPowers.spawn(tab, [], async function() {
@ -177,4 +297,5 @@ add_task(async function test_search_handoff_on_paste() {
);
await BrowserTestUtils.closeWindow(win);
await SpecialPowers.popPrefEnv();
});

Просмотреть файл

@ -179,10 +179,13 @@ class UrlbarController {
TelemetryStopwatch.finish(TELEMETRY_6_FIRST_RESULTS, queryContext);
}
if (queryContext.lastResultCount == 0 && queryContext.results.length) {
if (queryContext.results[0].autofill) {
this.input.autofillFirstResult(queryContext.results[0]);
if (queryContext.firstResultChanged) {
// Notify the input so it can make adjustments based on the first result.
if (this.input.onFirstResult(queryContext.results[0])) {
// The input canceled the query and started a new one.
return;
}
// The first time we receive results try to connect to the heuristic
// result.
this.speculativeConnect(

Просмотреть файл

@ -992,7 +992,7 @@ class UrlbarInput {
* @param {UrlbarResult} result
* The first result.
*/
autofillFirstResult(result) {
_autofillFirstResult(result) {
if (!result.autofill) {
return;
}
@ -1020,17 +1020,34 @@ class UrlbarInput {
}
/**
* Invoked by the view when the first result is received.
* @param {UrlbarResult} firstResult The first result received.
* Invoked by the controller when the first result is received.
*
* @param {UrlbarResult} firstResult
* The first result received.
* @returns {boolean}
* True if this method canceled the query and started a new one. False
* otherwise.
*/
onFirstResult(firstResult) {
// If the heuristic result has a keyword but isn't a keyword offer, we may
// need to enter search mode.
if (
firstResult.heuristic &&
firstResult.payload.keyword &&
!firstResult.payload.keywordOffer &&
this.maybePromoteKeywordToSearchMode(firstResult, false)
) {
return true;
}
// To prevent selection flickering, we apply autofill on input through a
// placeholder, without waiting for results. But, if the first result is
// not an autofill one, the autofill prediction was wrong and we should
// restore the original user typed string.
if (
if (firstResult.autofill) {
this._autofillFirstResult(firstResult);
} else if (
this._autofillPlaceholder &&
!firstResult.autofill &&
// Avoid clobbering added spaces (for token aliases, for example).
!this.value.endsWith(" ")
) {
@ -1043,6 +1060,8 @@ class UrlbarInput {
} else if (firstResult.heuristic) {
this._resultForCurrentValue = firstResult;
}
return false;
}
/**
@ -1511,18 +1530,34 @@ class UrlbarInput {
}
/**
* Certain actions can autofill a keyword into searchMode
* @param {UrlbarResult} [result] The currently selected urlbar result.
* @returns {boolean} Whether Search Mode was started.
* Enters search mode and starts a new search if appropriate for the given
* result. See also _searchModeForResult.
*
* @param {UrlbarResult} result
* The currently selected urlbar result.
* @param {boolean} checkValue
* If true, the trimmed input value must equal the result's keyword in order
* to enter search mode.
* @returns {boolean}
* True if we entered search mode and false if not.
*/
maybePromoteKeywordToSearchMode(result = this._resultForCurrentValue) {
let searchMode = this._searchModeForResult(result, "typed");
if (searchMode && this.value.trim() == result.payload.keyword.trim()) {
this.setSearchMode(searchMode);
this.value = "";
return true;
maybePromoteKeywordToSearchMode(
result = this._resultForCurrentValue,
checkValue = true
) {
if (checkValue && this.value.trim() != result.payload.keyword?.trim()) {
return false;
}
return false;
let searchMode = this._searchModeForResult(result, "typed");
if (!searchMode) {
return false;
}
this.setSearchMode(searchMode);
this._setValue(result.payload.query?.trimStart() || "", false);
this.startQuery({ allowAutofill: false });
return true;
}
// Private methods below.
@ -2242,31 +2277,47 @@ class UrlbarInput {
return null;
}
// If result.originalEngine is set, then the user is Alt+Tabbing through the
// one-offs, so the keyword doesn't match the engine.
if (
result &&
result.payload.keywordOffer &&
(!result.payload.originalEngine ||
result.payload.engine == result.payload.originalEngine)
) {
let searchModeEntry;
// Search mode is determined by the result's keyword.
if (!result.payload.keyword) {
return null;
}
let searchMode = null;
switch (result.payload.keyword) {
case UrlbarTokenizer.RESTRICT.BOOKMARK:
searchMode = { source: UrlbarUtils.RESULT_SOURCE.BOOKMARKS };
break;
case UrlbarTokenizer.RESTRICT.HISTORY:
searchMode = { source: UrlbarUtils.RESULT_SOURCE.HISTORY };
break;
case UrlbarTokenizer.RESTRICT.OPENPAGE:
searchMode = { source: UrlbarUtils.RESULT_SOURCE.TABS };
break;
default:
// If result.originalEngine is set, then the user is Alt+Tabbing
// through the one-offs, so the keyword doesn't match the engine.
if (
result.payload.engine &&
(!result.payload.originalEngine ||
result.payload.engine == result.payload.originalEngine)
) {
searchMode = { engineName: result.payload.engine };
}
break;
}
if (searchMode) {
if (entry) {
searchModeEntry = entry;
searchMode.entry = entry;
} else {
searchModeEntry =
searchMode.entry =
result.providerName == "UrlbarProviderTopSites"
? "topsites_urlbar"
: "keywordoffer";
}
return {
engineName: result.payload.engine,
entry: searchModeEntry,
};
}
return null;
return searchMode;
}
/**
@ -2505,13 +2556,6 @@ class UrlbarInput {
}
_on_input(event) {
// We enter search mode when space is typed if there is a selected keyword
// offer result.
let enteredSearchMode = false;
if (event.data == " ") {
enteredSearchMode = this.maybePromoteKeywordToSearchMode();
}
let value = this.value;
this.valueIsTyped = true;
this._untrimmedValue = value;
@ -2549,7 +2593,7 @@ class UrlbarInput {
if (!this.view.isOpen) {
this.view.clear();
} else if (!value && !canShowTopSites && !enteredSearchMode) {
} else if (!value && !canShowTopSites) {
this.view.clear();
if (!this.searchMode) {
this.view.close();

Просмотреть файл

@ -697,7 +697,7 @@ class ProviderAutofill extends UrlbarProvider {
UrlbarUtils.RESULT_SOURCE.SEARCH,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED],
icon: engine.iconURI ? engine.iconURI.spec : "",
icon: engine.iconURI?.spec,
})
);
let autofilledValue =

Просмотреть файл

@ -30,6 +30,16 @@ XPCOMUtils.defineLazyModuleGetters(this, {
class ProviderHeuristicFallback extends UrlbarProvider {
constructor() {
super();
// The Set of local search mode keywords/restriction characters. We use
// this to quickly look them up.
XPCOMUtils.defineLazyGetter(this, "_localSearchModeKeywords", () => {
return new Set(
[...UrlbarTokenizer.SEARCH_MODE_RESTRICT].map(
r => UrlbarTokenizer.RESTRICT[r]
)
);
});
}
/**
@ -105,11 +115,20 @@ class ProviderHeuristicFallback extends UrlbarProvider {
addCallback(this, searchResult);
}
}
} else {
result = await this._defaultEngineSearchResult(queryContext);
if (!result || instance != this.queryInstance) {
return;
}
return;
}
result = this._localSearchModeKeywordResult(queryContext);
if (result) {
addCallback(this, result);
return;
}
result = await this._defaultEngineSearchResult(queryContext);
if (instance != this.queryInstance) {
return;
}
if (result) {
result.heuristic = true;
addCallback(this, result);
}
@ -152,7 +171,6 @@ class ProviderHeuristicFallback extends UrlbarProvider {
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
title: [searchUrl, UrlbarUtils.HIGHLIGHT.TYPED],
url: [searchUrl, UrlbarUtils.HIGHLIGHT.TYPED],
icon: "",
})
);
result.heuristic = true;
@ -196,7 +214,7 @@ class ProviderHeuristicFallback extends UrlbarProvider {
// flicker, since the url keeps changing while the user types.
// By default we won't provide an icon, but for the subset of urls with a
// host we'll check for a typed slash and set favicon for the host part.
let iconUri = "";
let iconUri;
if (hostExpected && (searchUrl.endsWith("/") || uri.pathname.length > 1)) {
// Look for an icon with the entire URL except for the pathname, including
// scheme, usernames, passwords, hostname, and port.
@ -218,6 +236,57 @@ class ProviderHeuristicFallback extends UrlbarProvider {
return result;
}
_localSearchModeKeywordResult(queryContext) {
if (!UrlbarPrefs.get("update2")) {
return null;
}
if (!queryContext.tokens.length) {
return null;
}
let firstToken = queryContext.tokens[0].value;
if (!this._localSearchModeKeywords.has(firstToken)) {
return null;
}
// At this point, the search string starts with a local search mode token.
// Now we need to determine what to do based on the remainder of the search
// string. If the remainder starts with a space, then we should enter
// search mode, so we should continue below and create the result.
// Otherwise, we should not enter search mode, and in that case, the search
// string will look like one of the following:
//
// * The search string ends with the local search mode token (e.g., the user
// has typed only the token by itself, with no trailing spaces).
// * More tokens exist, but there's no space between the local search mode
// token and the following token. This is possible because the tokenizer
// does not require spaces between a restriction token and the remainder
// of the search string. In this case, we should not enter search mode.
//
// If we return null here and thereby do not enter search mode, then we'll
// continue on to _defaultEngineSearchResult, and the heuristic will be a
// default engine search result.
let query = UrlbarUtils.substringAfter(
queryContext.searchString,
firstToken
);
if (!query.startsWith(" ")) {
return null;
}
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
query: [query.trimStart(), UrlbarUtils.HIGHLIGHT.NONE],
keyword: [firstToken, UrlbarUtils.HIGHLIGHT.NONE],
})
);
result.heuristic = true;
return result;
}
async _defaultEngineSearchResult(queryContext) {
let engine;
if (queryContext.searchMode?.engineName) {
@ -249,26 +318,17 @@ class ProviderHeuristicFallback extends UrlbarProvider {
).trim();
}
let result = new UrlbarResult(
return new UrlbarResult(
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_SOURCE.SEARCH,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED],
icon: [engine.iconURI?.spec || ""],
icon: engine.iconURI?.spec,
query: [query, UrlbarUtils.HIGHLIGHT.NONE],
// We're confident that there is no alias, since UnifiedComplete
// handles heuristic searches with aliases.
keyword: undefined,
keywordOffer: UrlbarUtils.KEYWORD_OFFER.NONE,
// For test interoperabilty with UrlbarProviderSearchSuggestions.
suggestion: undefined,
tailPrefix: undefined,
tail: undefined,
tailOffsetIndex: -1,
isSearchHistory: false,
})
);
return result;
}
}

Просмотреть файл

@ -131,7 +131,7 @@ class ProviderPrivateSearch extends UrlbarProvider {
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED],
query: [searchString, UrlbarUtils.HIGHLIGHT.NONE],
icon: [engine.iconURI ? engine.iconURI.spec : null],
icon: engine.iconURI?.spec,
inPrivateWindow: true,
isPrivateEngine,
})

Просмотреть файл

@ -426,12 +426,10 @@ class ProviderSearchSuggestions extends UrlbarProvider {
lowerCaseSuggestion: entry.value.toLocaleLowerCase(),
tailPrefix,
tail: [tail, UrlbarUtils.HIGHLIGHT.SUGGESTED],
tailOffsetIndex: entry.tailOffsetIndex,
tailOffsetIndex: tail ? entry.tailOffsetIndex : undefined,
keyword: [alias ? alias : undefined, UrlbarUtils.HIGHLIGHT.TYPED],
query: [searchString.trim(), UrlbarUtils.HIGHLIGHT.NONE],
isSearchHistory: false,
icon: [engine.iconURI && !entry.value ? engine.iconURI.spec : ""],
keywordOffer: UrlbarUtils.KEYWORD_OFFER.NONE,
icon: !entry.value ? engine.iconURI?.spec : undefined,
})
)
);
@ -465,39 +463,40 @@ class ProviderSearchSuggestions extends UrlbarProvider {
* @returns {nsISearchEngine} aliasEngine.engine
* @returns {string} aliasEngine.alias
* @returns {string} aliasEngine.query
* @returns {boolean} aliasEngine.isTokenAlias
* @returns {object} { engine, alias, query }
*
*/
async _maybeGetAlias(queryContext) {
if (
queryContext.restrictSource &&
queryContext.restrictSource == UrlbarUtils.RESULT_SOURCE.SEARCH &&
queryContext.searchMode?.engineName &&
!queryContext.searchString.startsWith("@")
) {
// If an engineName was passed in from the queryContext in restrict mode,
// we'll set our engine in startQuery based on engineName.
if (queryContext.searchMode) {
// If we're in search mode, don't try to parse an alias at all.
return null;
}
let possibleAlias = queryContext.tokens[0]?.value.trim();
// The "@" character on its own is handled by UnifiedComplete and returns a
// list of every available token alias.
let possibleAlias = queryContext.tokens[0]?.value;
// "@" on its own is handled by UrlbarProviderTokenAliasEngines and returns
// a list of every available token alias.
if (!possibleAlias || possibleAlias == "@") {
return null;
}
let query = UrlbarUtils.substringAfter(
queryContext.searchString,
possibleAlias
);
// Match an alias only when it has a space after it. If there's no trailing
// space, then continue to treat it as part of the search string.
if (UrlbarPrefs.get("update2") && !query.startsWith(" ")) {
return null;
}
// Check if the user entered an engine alias directly.
let engineMatch = await UrlbarSearchUtils.engineForAlias(possibleAlias);
if (engineMatch) {
return {
engine: engineMatch,
alias: possibleAlias,
query: UrlbarUtils.substringAfter(
queryContext.searchString,
possibleAlias
).trim(),
isTokenAlias: possibleAlias.startsWith("@"),
query: query.trim(),
};
}
@ -511,7 +510,6 @@ function makeFormHistoryResult(queryContext, engine, entry) {
UrlbarUtils.RESULT_SOURCE.HISTORY,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
engine: engine.name,
isSearchHistory: true,
suggestion: [entry.value, UrlbarUtils.HIGHLIGHT.SUGGESTED],
lowerCaseSuggestion: entry.value.toLocaleLowerCase(),
})

Просмотреть файл

@ -121,7 +121,7 @@ class ProviderTokenAliasEngines extends UrlbarProvider {
engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED],
keyword: [tokenAliases[0], UrlbarUtils.HIGHLIGHT.TYPED],
query: ["", UrlbarUtils.HIGHLIGHT.TYPED],
icon: engine.iconURI ? engine.iconURI.spec : "",
icon: engine.iconURI?.spec,
keywordOffer: UrlbarUtils.KEYWORD_OFFER.SHOW,
})
);
@ -156,18 +156,30 @@ class ProviderTokenAliasEngines extends UrlbarProvider {
}
_getAutofillResult(queryContext) {
let lowerCaseSearchString = queryContext.searchString.toLowerCase();
// The user is typing a specific engine. We should show a heuristic result.
for (let { engine, tokenAliases } of this._engines) {
for (let alias of tokenAliases) {
if (alias.startsWith(queryContext.searchString.toLowerCase())) {
// We found a specific engine. We will add an autofill result.
if (alias.startsWith(lowerCaseSearchString)) {
// We found the engine.
// Stop adding an autofill result once the user has typed the full
// alias followed by a space. UrlbarProviderUnifiedComplete will take
// over at this point.
if (
UrlbarPrefs.get("update2") &&
lowerCaseSearchString.startsWith(alias + " ")
) {
return null;
}
// Add an autofill result. Append a space so the user can hit enter
// or the right arrow key and immediately start typing their query.
let aliasPreservingUserCase =
queryContext.searchString +
alias.substr(queryContext.searchString.length);
// Don't append a space if update2 is on since selecting this result
// will just enter search mode.
let value =
aliasPreservingUserCase + (UrlbarPrefs.get("update2") ? "" : " ");
let value = aliasPreservingUserCase + " ";
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_SOURCE.SEARCH,
@ -175,14 +187,8 @@ class ProviderTokenAliasEngines extends UrlbarProvider {
engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED],
keyword: [aliasPreservingUserCase, UrlbarUtils.HIGHLIGHT.TYPED],
query: ["", UrlbarUtils.HIGHLIGHT.TYPED],
icon: engine.iconURI ? engine.iconURI.spec : "",
icon: engine.iconURI?.spec,
keywordOffer: UrlbarUtils.KEYWORD_OFFER.HIDE,
// For test interoperabilty with UrlbarProviderSearchSuggestions.
suggestion: undefined,
tailPrefix: undefined,
tail: undefined,
tailOffsetIndex: -1,
isSearchHistory: false,
})
);
result.heuristic = true;

Просмотреть файл

@ -144,7 +144,7 @@ class ProviderTopSites extends UrlbarProvider {
// are stored in `label`, so prefer it. Search top sites currently
// don't have titles but `hostname` instead.
title: link.label || link.title || link.hostname || "",
favicon: link.smallFavicon || link.favicon || null,
favicon: link.smallFavicon || link.favicon || undefined,
sendAttributionRequest: link.sendAttributionRequest,
}));

Просмотреть файл

@ -132,7 +132,10 @@ function convertLegacyAutocompleteResult(context, acResult, urls) {
let isHeuristic = i == 0 && style.includes("heuristic");
let result = makeUrlbarResult(context.tokens, {
url,
icon: acResult.getImageAt(i),
// getImageAt returns an empty string if there is no icon. Use undefined
// instead so that tests can be simplified by not including `icon: ""` in
// all their payloads.
icon: acResult.getImageAt(i) || undefined,
style,
comment: acResult.getCommentAt(i),
firstToken: context.tokens[0],
@ -180,15 +183,43 @@ function makeUrlbarResult(tokens, info) {
if (action) {
switch (action.type) {
case "searchengine": {
let keywordOffer = UrlbarUtils.KEYWORD_OFFER.NONE;
if (action.params.isSearchHistory) {
// Return a form history result.
return new UrlbarResult(
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_SOURCE.HISTORY,
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
engine: action.params.engineName,
suggestion: [
action.params.searchSuggestion,
UrlbarUtils.HIGHLIGHT.SUGGESTED,
],
lowerCaseSuggestion: action.params.searchSuggestion.toLocaleLowerCase(),
})
);
}
let keywordOffer;
if (
action.params.alias &&
!action.params.searchQuery.trim() &&
(UrlbarPrefs.get("update2") || action.params.alias.startsWith("@"))
!UrlbarPrefs.get("update2") &&
action.params.alias?.startsWith("@") &&
!action.params.searchQuery.trim()
) {
keywordOffer = info.isHeuristic
? UrlbarUtils.KEYWORD_OFFER.HIDE
: UrlbarUtils.KEYWORD_OFFER.SHOW;
// This conditional is true only for the heuristic result, when the
// search string is "@alias" followed by any number of spaces. There
// are only three other cases where results will have a token alias
// and empty search string: When autofilling a token alias, which
// UrlbarProviderTokenAliasEngines handles; when the search string is
// "@" and we show all token aliases, which
// UrlbarProviderTokenAliasEngines also handles; and when a top site
// is an alias, which UrlbarProviderTopSites handles.
//
// When update2 is disabled, we want this result to be a keyword offer
// so that the user can pick it and it behaves like an autofilled
// @alias result. The keyword should be hidden. When update2 is
// enabled, we want it not to be an offer so that it causes the input
// to enter search mode.
keywordOffer = UrlbarUtils.KEYWORD_OFFER.HIDE;
}
return new UrlbarResult(
UrlbarUtils.RESULT_TYPE.SEARCH,
@ -199,17 +230,13 @@ function makeUrlbarResult(tokens, info) {
action.params.searchSuggestion,
UrlbarUtils.HIGHLIGHT.SUGGESTED,
],
// For test interoperabilty with UrlbarProviderSearchSuggestions.
tailPrefix: undefined,
tail: undefined,
tailOffsetIndex: -1,
keyword: [action.params.alias, UrlbarUtils.HIGHLIGHT.TYPED],
lowerCaseSuggestion: action.params.searchSuggestion?.toLocaleLowerCase(),
keyword: action.params.alias,
query: [
action.params.searchQuery.trim(),
UrlbarUtils.HIGHLIGHT.NONE,
],
isSearchHistory: !!action.params.isSearchHistory,
icon: [info.icon],
icon: info.icon,
keywordOffer,
})
);
@ -241,7 +268,7 @@ function makeUrlbarResult(tokens, info) {
keyword: [info.firstToken.value, UrlbarUtils.HIGHLIGHT.TYPED],
input: [action.params.input],
postData: [action.params.postData],
icon: [info.icon],
icon: info.icon,
})
);
}
@ -253,7 +280,7 @@ function makeUrlbarResult(tokens, info) {
url: [action.params.url, UrlbarUtils.HIGHLIGHT.TYPED],
title: [info.comment, UrlbarUtils.HIGHLIGHT.TYPED],
device: [action.params.deviceName, UrlbarUtils.HIGHLIGHT.TYPED],
icon: [info.icon],
icon: info.icon,
})
);
case "switchtab":
@ -263,7 +290,7 @@ function makeUrlbarResult(tokens, info) {
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
url: [action.params.url, UrlbarUtils.HIGHLIGHT.TYPED],
title: [info.comment, UrlbarUtils.HIGHLIGHT.TYPED],
icon: [info.icon],
icon: info.icon,
})
);
case "visiturl":
@ -273,7 +300,7 @@ function makeUrlbarResult(tokens, info) {
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
title: [info.comment, UrlbarUtils.HIGHLIGHT.TYPED],
url: [action.params.url, UrlbarUtils.HIGHLIGHT.TYPED],
icon: [info.icon],
icon: info.icon,
})
);
default:
@ -288,7 +315,7 @@ function makeUrlbarResult(tokens, info) {
UrlbarUtils.RESULT_SOURCE.SEARCH,
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
engine: [info.comment, UrlbarUtils.HIGHLIGHT.TYPED],
icon: [info.icon],
icon: info.icon,
})
);
}
@ -340,7 +367,7 @@ function makeUrlbarResult(tokens, info) {
source,
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
url: [info.url, UrlbarUtils.HIGHLIGHT.TYPED],
icon: [info.icon],
icon: info.icon,
title: [comment, UrlbarUtils.HIGHLIGHT.TYPED],
tags: [tags, UrlbarUtils.HIGHLIGHT.TYPED],
})

Просмотреть файл

@ -15,6 +15,7 @@ const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
ObjectUtils: "resource://gre/modules/ObjectUtils.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
SkippableTimer: "resource:///modules/UrlbarUtils.jsm",
UrlbarMuxer: "resource:///modules/UrlbarUtils.jsm",
@ -589,6 +590,12 @@ class Query {
}
}
this.context.firstResultChanged = !ObjectUtils.deepEqual(
this.context.firstResult,
this.context.results[0]
);
this.context.firstResult = this.context.results[0];
if (this.controller) {
this.controller.receiveResults(this.context);
}

Просмотреть файл

@ -81,12 +81,9 @@ class SearchUtils {
await this.init();
let tokenAliasEngines = [];
for (let engine of await Services.search.getVisibleEngines()) {
let tokenAliases = engine.aliases.map(alias => {
if (!alias.startsWith("@")) {
alias = "@" + alias;
}
return alias;
});
let tokenAliases = this._aliasesForEngine(engine).filter(a =>
a.startsWith("@")
);
if (tokenAliases.length) {
tokenAliasEngines.push({ engine, tokenAliases });
}
@ -107,13 +104,38 @@ class SearchUtils {
this._enginesByAlias = new Map();
for (let engine of await Services.search.getVisibleEngines()) {
if (!engine.hidden) {
for (let alias of engine.aliases) {
this._enginesByAlias.set(alias.toLocaleLowerCase(), engine);
for (let alias of this._aliasesForEngine(engine)) {
this._enginesByAlias.set(alias, engine);
}
}
}
}
/**
* Gets the aliases of an engine. For the user's convenience, we recognize
* token versions of all non-token aliases. For example, if the user has an
* alias of "foo", then we recognize both "foo" and "@foo" as aliases for
* foo's engine. The returned list is therefore a superset of
* `engine.aliases`. Additionally, the returned aliases will be lower-cased
* to make lookups and comparisons easier.
*
* @param {nsISearchEngine} engine
* The aliases of this search engine will be returned.
* @returns {array}
* An array of lower-cased string aliases as described above.
*/
_aliasesForEngine(engine) {
return engine.aliases.reduce((aliases, aliasWithCase) => {
// We store lower-cased aliases to make lookups and comparisons easier.
let alias = aliasWithCase.toLocaleLowerCase();
aliases.push(alias);
if (!alias.startsWith("@")) {
aliases.push("@" + alias);
}
return aliases;
}, []);
}
observe(subject, topic, data) {
switch (data) {
case "engine-added":

Просмотреть файл

@ -76,6 +76,9 @@ var UrlbarTokenizer = {
URL: "$",
},
// The keys of characters in RESTRICT that will enter search mode.
SEARCH_MODE_RESTRICT: new Set(["HISTORY", "BOOKMARK", "OPENPAGE"]),
/**
* Returns whether the passed in token looks like a URL.
* This is based on guessing and heuristics, that means if this function

Просмотреть файл

@ -156,13 +156,14 @@ var UrlbarUtils = {
SUGGESTED: 2,
},
// Search results with keywords and empty queries are called "keyword offers".
// When the user selects a keyword offer, the keyword followed by a space is
// put in the input as a hint that the user can search using the keyword.
// Depending on the use case, keyword-offer results can show or not show the
// keyword itself.
// "Keyword offers" are search results with keywords that enter search mode
// when the user picks them. Depending on the use case, a keyword offer can
// visually show or hide the keyword itself in its result. For example,
// typing "@" by itself will show keyword offers for all engines with @
// aliases, and those results will visually show their keywords -- @google,
// @bing, etc. When a keyword offer is a heuristic -- like an autofilled @
// alias -- usually it hides its keyword since the user is already typing it.
KEYWORD_OFFER: {
NONE: 0,
SHOW: 1,
HIDE: 2,
},
@ -464,12 +465,15 @@ var UrlbarUtils = {
: null,
};
case UrlbarUtils.RESULT_TYPE.SEARCH: {
const engine = Services.search.getEngineByName(result.payload.engine);
let [url, postData] = this.getSearchQueryUrl(
engine,
result.payload.suggestion || result.payload.query
);
return { url, postData };
if (result.payload.engine) {
const engine = Services.search.getEngineByName(result.payload.engine);
let [url, postData] = this.getSearchQueryUrl(
engine,
result.payload.suggestion || result.payload.query
);
return { url, postData };
}
break;
}
case UrlbarUtils.RESULT_TYPE.TIP: {
// Return the button URL. Consumers must check payload.helpUrl
@ -907,9 +911,6 @@ UrlbarUtils.RESULT_PAYLOAD_SCHEMA = {
isPrivateEngine: {
type: "boolean",
},
isSearchHistory: {
type: "boolean",
},
keyword: {
type: "string",
},

Просмотреть файл

@ -558,9 +558,6 @@ class UrlbarView {
UrlbarTokenizer.RESTRICT.SEARCH ||
queryContext.trimmedSearchString.length != 1)
);
// Notify the input, so it can make adjustments based on the first result.
this.input.onFirstResult(firstResult);
}
if (
@ -1718,7 +1715,9 @@ class UrlbarView {
if (
result.type != UrlbarUtils.RESULT_TYPE.SEARCH ||
(!result.heuristic &&
(!result.payload.suggestion || result.payload.isSearchHistory) &&
(!result.payload.suggestion ||
(result.type == UrlbarUtils.RESULT_TYPE.SEARCH &&
result.source == UrlbarUtils.RESULT_SOURCE.HISTORY)) &&
(!result.payload.inPrivateWindow || result.payload.isPrivateEngine))
) {
continue;

Просмотреть файл

@ -69,12 +69,17 @@ var UrlbarTestUtils = {
/**
* Waits to a search to be complete.
* @param {object} win The window containing the urlbar
* @param {number} count The number of expected searches to wait for.
* @returns {Promise} Resolved when done.
*/
async promiseSearchComplete(win) {
return this.promisePopupOpen(win, () => {}).then(
async promiseSearchComplete(win, count = 1) {
let promise = this.promisePopupOpen(win, () => {}).then(
() => win.gURLBar.lastQueryContextPromise
);
if (--count > 0) {
promise = promise.then(() => this.promiseSearchComplete(win, count));
}
return promise;
},
/**
@ -138,7 +143,7 @@ var UrlbarTestUtils = {
async waitForAutocompleteResultAt(win, index) {
// TODO Bug 1530338: Quantum Bar doesn't yet implement lazy results replacement.
await this.promiseSearchComplete(win);
if (index >= win.gURLBar.view._rows.length) {
if (index >= win.gURLBar.view._rows.children.length) {
throw new Error("Not enough results");
}
return win.gURLBar.view._rows.children[index];
@ -210,7 +215,6 @@ var UrlbarTestUtils = {
keyword: result.payload.keyword,
query: result.payload.query,
suggestion: result.payload.suggestion,
isSearchHistory: result.payload.isSearchHistory,
inPrivateWindow: result.payload.inPrivateWindow,
isPrivateEngine: result.payload.isPrivateEngine,
};
@ -503,7 +507,8 @@ var UrlbarTestUtils = {
},
/**
* Enters search mode by clicking a one-off.
* Enters search mode by clicking a one-off. The view must already be open
* before you call this.
* @param {object} window
* @param {object} searchMode
* If given, the one-off matching this search mode will be clicked; it
@ -562,13 +567,13 @@ var UrlbarTestUtils = {
* @param {boolean} [waitForSearch]
* Whether the test should wait for a search after exiting search mode.
* Defaults to true.
* @note One and only one of `backspace` and `clickClose` should be passed
* as true.
* @note If neither `backspace` nor `clickClose` is given, we'll default to
* backspacing.
* @note Can only be used if UrlbarTestUtils has been initialized with init().
*/
async exitSearchMode(
window,
{ backspace, clickClose, waitForSearch = true }
{ backspace, clickClose, waitForSearch = true } = {}
) {
let urlbar = window.gURLBar;
// If the Urlbar is not extended, ignore the clickClose parameter. The close
@ -585,6 +590,10 @@ var UrlbarTestUtils = {
return;
}
if (!backspace && !clickClose) {
backspace = true;
}
if (backspace) {
let urlbarValue = urlbar.value;
urlbar.selectionStart = urlbar.selectionEnd = 0;
@ -661,6 +670,9 @@ var UrlbarTestUtils = {
{
input: {
isPrivate: false,
onFirstResult() {
return false;
},
window: {
location: {
href: AppConstants.BROWSER_CHROME_URL,

Просмотреть файл

@ -11,6 +11,7 @@ support-files =
[browser_aboutHomeLoading.js]
[browser_action_searchengine.js]
[browser_action_searchengine_alias.js]
[browser_action_searchengine_alias_legacy.js]
[browser_autocomplete_a11y_label.js]
support-files =
searchSuggestionEngine.xml
@ -209,6 +210,7 @@ support-files =
moz.png
[browser_textruns.js]
[browser_tokenAlias.js]
[browser_tokenAlias_legacy.js]
[browser_top_sites.js]
[browser_typed_value.js]
[browser_updateForDomainCompletion.js]

Просмотреть файл

@ -56,7 +56,6 @@ async function testSearch(win, expectedName, expectedBaseUrl) {
keyword: undefined,
query: "open a search",
suggestion: undefined,
isSearchHistory: false,
inPrivateWindow: undefined,
isPrivateEngine: undefined,
},

Просмотреть файл

@ -7,6 +7,12 @@
*/
add_task(async function() {
// This test requires update2. See also
// browser_action_searchengine_alias_legacy.js.
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", true]],
});
const ICON_URI =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAA" +
"CQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BL" +
@ -30,6 +36,11 @@ add_task(async function() {
"about:mozilla"
);
// Disable autofill so mozilla.org isn't autofilled below.
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.autoFill", false]],
});
registerCleanupFunction(async function() {
await Services.search.setDefault(originalEngine);
await Services.search.removeEngine(engine);
@ -46,18 +57,19 @@ add_task(async function() {
window,
value: "moz",
});
Assert.equal(
gURLBar.value,
"moz",
"Preselected search keyword result shouldn't automatically add a space"
);
Assert.equal(gURLBar.value, "moz", "Value should be unchanged");
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "moz open a search",
});
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
Assert.equal(result.image, ICON_URI, "Should have the correct image");
// Wait for the second new search that starts when search mode is entered.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: engine.name,
entry: "typed",
});
Assert.equal(gURLBar.value, "open a search", "value should be query");
let tabPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
EventUtils.synthesizeKey("KEY_Enter");

Просмотреть файл

@ -0,0 +1,77 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This file can be deleted when update2 is enabled by default.
*
* Tests that search result obtained using a search keyword gives an entry with
* the correct attributes and visits the expected URL for the engine.
*/
add_task(async function() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", false]],
});
const ICON_URI =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAA" +
"CQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BL" +
"i4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkb" +
"G7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1v" +
"bjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlA" +
"fwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FA" +
"EWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC";
await Services.search.addEngineWithDetails("MozSearch", {
iconURL: ICON_URI,
alias: "moz",
method: "GET",
template: "http://example.com/?q={searchTerms}",
});
let engine = Services.search.getEngineByName("MozSearch");
let originalEngine = await Services.search.getDefault();
await Services.search.setDefault(engine);
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"about:mozilla"
);
registerCleanupFunction(async function() {
await Services.search.setDefault(originalEngine);
await Services.search.removeEngine(engine);
try {
BrowserTestUtils.removeTab(tab);
} catch (ex) {
/* tab may have already been closed in case of failure */
}
await PlacesUtils.history.clear();
await UrlbarTestUtils.formHistory.clear();
});
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "moz",
});
Assert.equal(
gURLBar.value,
"moz",
"Preselected search keyword result shouldn't automatically add a space"
);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "moz open a search",
});
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
Assert.equal(result.image, ICON_URI, "Should have the correct image");
let tabPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
EventUtils.synthesizeKey("KEY_Enter");
await tabPromise;
Assert.equal(
gBrowser.selectedBrowser.currentURI.spec,
"http://example.com/?q=open+a+search",
"Should have loaded the correct page"
);
});

Просмотреть файл

@ -214,7 +214,19 @@ add_task(async function clear_placeholder_for_keyword_or_alias() {
await searchAndCheck("ex", "example.com/", "ex");
await searchAndCheck("EXA", "EXAmple.com/", "EXAmple.com/");
// Matches the alias.
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", true]],
});
await searchAndCheck("eXaM", "eXaMple.com/", "eXaMple.com/");
await SpecialPowers.popPrefEnv();
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", false]],
});
await searchAndCheck("eXaM", "eXaMple.com/", "eXaM");
await SpecialPowers.popPrefEnv();
await searchAndCheck("examp", "example.com/", "example.com/");
await cleanUp();

Просмотреть файл

@ -107,7 +107,6 @@ const tests = [
searchParams: {
engine: "Google",
query: "http://",
isSearchHistory: false,
},
},
{
@ -119,7 +118,6 @@ const tests = [
searchParams: {
engine: "Google",
query: "https://",
isSearchHistory: false,
},
},
{

Просмотреть файл

@ -72,6 +72,7 @@ add_task(async function switchToTab() {
);
await UrlbarTestUtils.promisePopupClose(window);
gURLBar.handleRevert();
gBrowser.removeTab(tab);
});

Просмотреть файл

@ -155,5 +155,6 @@ add_task(async function() {
}
await UrlbarTestUtils.promisePopupClose(window);
gURLBar.handleRevert();
}
});

Просмотреть файл

@ -97,6 +97,7 @@ add_task(async function() {
spy.restore();
Assert.ok(spy.called, "invoked getHeuristicResultFor");
Assert.deepEqual(await promise, args, "Check arguments are coherent");
gURLBar.handleRevert();
}
});

Просмотреть файл

@ -34,102 +34,125 @@ add_task(async function setup() {
});
});
// Tests that a fully typed alias is replaced when space is pressed.
add_task(async function replaced_on_space() {
// An incomplete alias should not be replaced.
add_task(async function incompleteAlias() {
// Check that a non-fully typed alias is not replaced.
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS.slice(0, -1),
});
await UrlbarTestUtils.assertSearchMode(window, null);
// Type a space just to make sure it's not replaced.
let searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
EventUtils.synthesizeKey("VK_SPACE");
EventUtils.synthesizeKey(" ");
await searchPromise;
await UrlbarTestUtils.assertSearchMode(window, null);
Assert.equal(
gURLBar.value,
ALIAS.slice(0, -1),
"The typed value should be unchanged."
ALIAS.slice(0, -1) + " ",
"The typed value should be unchanged except for the space."
);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// Test that the alias is replaced when it is fully typed.
// A complete alias without a trailing space should not be replaced.
add_task(async function noTrailingSpace() {
let value = ALIAS;
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: `${ALIAS} `,
value,
});
let keywordOfferResult = await UrlbarTestUtils.getDetailsOfResultAt(
await UrlbarTestUtils.assertSearchMode(window, null);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// A complete typed alias without a trailing space should not be replaced.
add_task(async function noTrailingSpace_typed() {
// Start by searching for the alias minus its last char.
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
0
);
value: ALIAS.slice(0, -1),
});
await UrlbarTestUtils.assertSearchMode(window, null);
// Now type the last char.
let searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
EventUtils.synthesizeKey(ALIAS.slice(-1));
await searchPromise;
await UrlbarTestUtils.assertSearchMode(window, null);
Assert.equal(
keywordOfferResult.searchParams.keyword,
gURLBar.value,
ALIAS,
"The first result should be a keyword search result with the correct alias."
);
Assert.equal(
keywordOfferResult.searchParams.engine,
aliasEngine.name,
"The first result should be a keyword search result with the correct engine."
"The typed value should be the full alias."
);
searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
// Fire an input event simulating typing a space after the ALIAS.
UrlbarTestUtils.fireInputEvent(window);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// A complete alias with a trailing space should be replaced.
add_task(async function trailingSpace() {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS + " ",
});
// Wait for the second new search that starts when search mode is entered.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: aliasEngine.name,
entry: "typed",
});
Assert.ok(!gURLBar.value, "The urlbar value should be cleared.");
await UrlbarTestUtils.exitSearchMode(window);
await UrlbarTestUtils.promisePopupClose(window);
});
// A complete alias should be replaced after typing a space.
add_task(async function trailingSpace_typed() {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS,
});
await UrlbarTestUtils.assertSearchMode(window, null);
// We need to wait for two searches: The first enters search mode, the second
// does the search in search mode.
let searchPromise = UrlbarTestUtils.promiseSearchComplete(window, 2);
EventUtils.synthesizeKey(" ");
await searchPromise;
await UrlbarTestUtils.assertSearchMode(window, {
engineName: aliasEngine.name,
entry: "typed",
});
Assert.ok(!gURLBar.value, "The Urlbar value should be cleared.");
await UrlbarTestUtils.exitSearchMode(window, { backspace: true });
Assert.ok(!gURLBar.value, "The urlbar value should be cleared.");
await UrlbarTestUtils.exitSearchMode(window);
await UrlbarTestUtils.promisePopupClose(window);
});
add_task(async function not_replaced_for_alt_tab() {
// Test that the alias is replaced when it is fully typed.
// A complete alias with a trailing space should be replaced, and the query
// after the trailing space should be the new value of the input.
add_task(async function trailingSpace_query() {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: `${ALIAS} `,
value: ALIAS + " query",
});
let keywordOfferResult = await UrlbarTestUtils.getDetailsOfResultAt(
window,
0
);
Assert.equal(
keywordOfferResult.searchParams.keyword,
ALIAS,
"The first result should be a keyword search result with the correct alias."
);
Assert.equal(
keywordOfferResult.searchParams.engine,
aliasEngine.name,
"The first result should be a keyword search result with the correct engine."
);
EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true, repeat: 2 });
keywordOfferResult = await UrlbarTestUtils.waitForAutocompleteResultAt(
window,
0
);
Assert.ok(
keywordOfferResult.result.payload.originalEngine,
"The keyword offer result now has the originalEngine property."
);
Assert.notEqual(
keywordOfferResult.result.payload.engine,
keywordOfferResult.result.payload.originalEngine,
"engine and originalEngine are different."
);
let searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
// Fire an input event simulating typing a space after the ALIAS.
UrlbarTestUtils.fireInputEvent(window);
await searchPromise;
await UrlbarTestUtils.assertSearchMode(window, null);
// Wait for the second new search that starts when search mode is entered.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: aliasEngine.name,
entry: "typed",
});
Assert.equal(gURLBar.value, "query", "The urlbar value should be the query.");
await UrlbarTestUtils.exitSearchMode(window);
await UrlbarTestUtils.promisePopupClose(window);
});

Просмотреть файл

@ -256,7 +256,9 @@ add_task(async function spaceToEnterSearchMode() {
value: engine.alias,
});
let searchPromise = UrlbarTestUtils.promiseSearchComplete(win);
// We need to wait for two searches: The first enters search mode, the
// second does the search in search mode.
let searchPromise = UrlbarTestUtils.promiseSearchComplete(win, 2);
EventUtils.synthesizeKey(" ", {}, win);
await searchPromise;

Просмотреть файл

@ -48,7 +48,6 @@ add_task(async function setup() {
type: UrlbarUtils.RESULT_TYPE.SEARCH,
source: UrlbarUtils.RESULT_SOURCE.HISTORY,
searchParams: {
isSearchHistory: true,
suggestion: value,
engine: suggestionsEngine.name,
},
@ -109,7 +108,6 @@ add_task(async function nonEmptySearch() {
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
searchParams: {
query,
isSearchHistory: false,
engine: suggestionsEngine.name,
},
},
@ -120,7 +118,6 @@ add_task(async function nonEmptySearch() {
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
searchParams: {
query,
isSearchHistory: false,
suggestion: `${query}foo`,
engine: suggestionsEngine.name,
},
@ -131,7 +128,6 @@ add_task(async function nonEmptySearch() {
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
searchParams: {
query,
isSearchHistory: false,
suggestion: `${query}bar`,
engine: suggestionsEngine.name,
},
@ -162,7 +158,6 @@ add_task(async function nonEmptySearch_nonMatching() {
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
searchParams: {
query,
isSearchHistory: false,
engine: suggestionsEngine.name,
},
},
@ -172,7 +167,6 @@ add_task(async function nonEmptySearch_nonMatching() {
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
searchParams: {
query,
isSearchHistory: false,
suggestion: `${query}foo`,
engine: suggestionsEngine.name,
},
@ -183,7 +177,6 @@ add_task(async function nonEmptySearch_nonMatching() {
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
searchParams: {
query,
isSearchHistory: false,
suggestion: `${query}bar`,
engine: suggestionsEngine.name,
},
@ -218,7 +211,6 @@ add_task(async function nonEmptySearch_withHistory() {
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
searchParams: {
query,
isSearchHistory: false,
engine: suggestionsEngine.name,
},
},
@ -228,7 +220,6 @@ add_task(async function nonEmptySearch_withHistory() {
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
searchParams: {
query,
isSearchHistory: false,
suggestion: `${query}foo`,
engine: suggestionsEngine.name,
},
@ -239,7 +230,6 @@ add_task(async function nonEmptySearch_withHistory() {
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
searchParams: {
query,
isSearchHistory: false,
suggestion: `${query}bar`,
engine: suggestionsEngine.name,
},
@ -283,7 +273,6 @@ add_task(async function nonEmptySearch_url() {
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
searchParams: {
query,
isSearchHistory: false,
engine: suggestionsEngine.name,
},
},

Просмотреть файл

@ -11,6 +11,8 @@ const serverInfo = {
port: 20709, // Must be identical to what is in searchSuggestionEngine2.xml
};
let aliasEngine;
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({
set: [
@ -45,7 +47,7 @@ add_task(async function setup() {
await Services.search.moveEngine(engine2, 0);
// Add an engine with an alias.
let aliasEngine = await Services.search.addEngineWithDetails("MozSearch", {
aliasEngine = await Services.search.addEngineWithDetails("MozSearch", {
alias: "alias",
method: "GET",
template: "http://example.com/?q={searchTerms}",
@ -381,7 +383,56 @@ add_task(async function test_oneoff_selected_with_private_engine_keyboard() {
await SpecialPowers.popPrefEnv();
});
add_task(async function test_alias() {
add_task(async function test_alias_no_query() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", true]],
});
info(
"Test that 'Search in a Private Window' doesn't appear if an alias is typed with no query"
);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "alias ",
});
// Wait for the second new search that starts when search mode is entered.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: aliasEngine.name,
entry: "typed",
});
await AssertNoPrivateResult(window);
await UrlbarTestUtils.exitSearchMode(window);
await UrlbarTestUtils.promisePopupClose(window);
await SpecialPowers.popPrefEnv();
});
add_task(async function test_alias_query() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", true]],
});
info(
"Test that 'Search in a Private Window' appears when an alias is typed with a query"
);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "alias something",
});
// Wait for the second new search that starts when search mode is entered.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: "MozSearch",
entry: "typed",
});
await AssertPrivateResult(window, aliasEngine, true);
await UrlbarTestUtils.exitSearchMode(window);
await UrlbarTestUtils.promisePopupClose(window);
await SpecialPowers.popPrefEnv();
});
add_task(async function test_alias_legacy() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", false]],
});
info(
"Test that 'Search in a Private Window' doesn't appear if an alias is typed"
);
@ -396,6 +447,7 @@ add_task(async function test_alias() {
value: "alias something",
});
await AssertNoPrivateResult(window);
await SpecialPowers.popPrefEnv();
});
add_task(async function test_restrict() {

Просмотреть файл

@ -8,7 +8,18 @@
const ALIAS = "@test";
const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
let testEngine;
add_task(async function init() {
// This test requires update2. See also browser_tokenAlias_legacy.js.
await SpecialPowers.pushPrefEnv({
set: [
["browser.urlbar.update2", true],
["browser.urlbar.update2.localOneOffs", true],
["browser.urlbar.update2.oneOffsRefresh", true],
],
});
// Add a default engine with suggestions, to avoid hitting the network when
// fetching them.
let defaultEngine = await SearchTestUtils.promiseNewSearchEngine(
@ -17,12 +28,12 @@ add_task(async function init() {
defaultEngine.alias = "@default";
let oldDefaultEngine = await Services.search.getDefault();
Services.search.setDefault(defaultEngine);
let engine = await Services.search.addEngineWithDetails("Test", {
testEngine = await Services.search.addEngineWithDetails("Test", {
alias: ALIAS,
template: "http://example.com/?search={searchTerms}",
});
registerCleanupFunction(async function() {
await Services.search.removeEngine(engine);
await Services.search.removeEngine(testEngine);
Services.search.setDefault(oldDefaultEngine);
});
@ -45,39 +56,198 @@ add_task(async function testRevert() {
await doSimpleTest(true);
});
// An alias should be recognized and highlighted even when there are spaces
// before it.
async function doSimpleTest(revertBetweenSteps) {
// When autofill is enabled, searching for "@tes" will autofill to "@test",
// which gets in the way of this test task, so temporarily disable it.
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.autoFill", false]],
});
// "@tes" -- not an alias, no search mode
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS.substr(0, ALIAS.length - 1),
});
await UrlbarTestUtils.assertSearchMode(window, null);
Assert.equal(
gURLBar.value,
ALIAS.substr(0, ALIAS.length - 1),
"value should be alias substring"
);
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@test" -- alias but no trailing space, no search mode
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS,
});
await UrlbarTestUtils.assertSearchMode(window, null);
Assert.equal(gURLBar.value, ALIAS, "value should be alias");
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@test " -- alias with trailing space, search mode
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS + " ",
});
// Wait for the second new search that starts when search mode is entered.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: testEngine.name,
entry: "typed",
});
Assert.equal(gURLBar.value, "", "value should be empty");
await UrlbarTestUtils.exitSearchMode(window);
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@test foo" -- alias, search mode
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS + " foo",
});
// Wait for the second new search that starts when search mode is entered.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: testEngine.name,
entry: "typed",
});
Assert.equal(gURLBar.value, "foo", "value should be query");
await UrlbarTestUtils.exitSearchMode(window);
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@test " -- alias with trailing space, search mode
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS + " ",
});
// Wait for the second new search that starts when search mode is entered.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: testEngine.name,
entry: "typed",
});
Assert.equal(gURLBar.value, "", "value should be empty");
await UrlbarTestUtils.exitSearchMode(window);
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@test" -- alias but no trailing space, no highlight
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS,
});
await UrlbarTestUtils.assertSearchMode(window, null);
Assert.equal(gURLBar.value, ALIAS, "value should be alias");
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@tes" -- not an alias, no highlight
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS.substr(0, ALIAS.length - 1),
});
await UrlbarTestUtils.assertSearchMode(window, null);
Assert.equal(
gURLBar.value,
ALIAS.substr(0, ALIAS.length - 1),
"value should be alias substring"
);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
await SpecialPowers.popPrefEnv();
}
// An alias should be recognized even when there are spaces before it, and
// search mode should be entered.
add_task(async function spacesBeforeAlias() {
gURLBar.search(" " + ALIAS);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: " " + ALIAS + " ",
});
// Wait for the second new search that starts when search mode is entered.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: testEngine.name,
entry: "typed",
});
Assert.equal(gURLBar.value, "", "value should be empty");
await UrlbarTestUtils.exitSearchMode(window);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// An alias in the middle of a string should not be recognized or highlighted.
// An alias in the middle of a string should not be recognized and search mode
// should not be entered.
add_task(async function charsBeforeAlias() {
gURLBar.search("not an alias " + ALIAS);
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(false);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "not an alias " + ALIAS + " ",
});
await UrlbarTestUtils.assertSearchMode(window, null);
Assert.equal(
gURLBar.value,
"not an alias " + ALIAS + " ",
"value should be unchanged"
);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// In a search string that starts with a restriction character followed by an
// alias, the alias should be neither recognized nor highlighted.
add_task(async function restrictionCharBeforeAlias() {
gURLBar.search(UrlbarTokenizer.RESTRICT.BOOKMARK + " " + ALIAS);
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(false);
// While already in search mode, an alias should not be recognized.
add_task(async function alreadyInSearchMode() {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "",
});
await UrlbarTestUtils.enterSearchMode(window, {
source: UrlbarUtils.RESULT_SOURCE.BOOKMARKS,
});
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS + " ",
});
// Search mode source should still be bookmarks.
await UrlbarTestUtils.assertSearchMode(window, {
source: UrlbarUtils.RESULT_SOURCE.BOOKMARKS,
entry: "oneoff",
});
Assert.equal(gURLBar.value, ALIAS + " ", "value should be unchanged");
// Exit search mode, but first remove the value in the input. Since the value
// is "alias ", we'd actually immediately re-enter search mode otherwise.
gURLBar.value = "";
await UrlbarTestUtils.exitSearchMode(window);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
@ -92,83 +262,55 @@ add_task(async function spaceWhileTypingAlias() {
selectionStart: value.length,
selectionEnd: value.length,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
Assert.equal(gURLBar.value, ALIAS + " ", "Alias should be autofilled");
gURLBar.value = value + " ";
let searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
UrlbarTestUtils.fireInputEvent(window);
EventUtils.synthesizeKey(" ");
await searchPromise;
await assertAlias(false);
Assert.equal(gURLBar.value, value + " ", "Alias should not be autofilled");
await UrlbarTestUtils.assertSearchMode(window, null);
await UrlbarTestUtils.promisePopupClose(window);
});
// Aliases are case insensitive, and the alias in the result uses the case that
// the user typed in the input. Make sure that searching with an alias using a
// weird case still causes the alias to be highlighted.
// Aliases are case insensitive. Make sure that searching with an alias using a
// weird case still causes the alias to be recognized and search mode entered.
add_task(async function aliasCase() {
let alias = "@TeSt";
gURLBar.search(alias);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "@TeSt ",
});
// Wait for the second new search that starts when search mode is entered.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true, alias);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: testEngine.name,
entry: "typed",
});
Assert.equal(gURLBar.value, "", "value should be empty");
await UrlbarTestUtils.exitSearchMode(window);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// Even when the heuristic result is a search engine result with an alias, if
// the urlbar value does not match that result, then no alias substring in the
// urlbar should be highlighted. This is the case when the user uses an alias
// to perform a search: The popup closes (preserving the results in it), the
// urlbar value changes to the URL of the search results page, and the search
// results page is loaded.
add_task(async function inputDoesntMatchHeuristicResult() {
// Do a search using the alias.
let searchString = `${ALIAS} aaa`;
gURLBar.search(searchString);
// Same as previous but with a query.
add_task(async function aliasCase_query() {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "@tEsT query",
});
// Wait for the second new search that starts when search mode is entered.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: testEngine.name,
entry: "typed",
});
Assert.equal(gURLBar.value, "query", "value should be query");
await UrlbarTestUtils.exitSearchMode(window);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
// Manually set the urlbar value to a string that contains the alias at the
// beginning but is not the alias.
let value = `${ALIAS}xxx`;
gURLBar.value = `${ALIAS}xxx`;
// The alias substring should not be highlighted.
Assert.equal(gURLBar.untrimmedValue, value);
Assert.ok(gURLBar.untrimmedValue.includes(ALIAS));
assertHighlighted(false, ALIAS);
// Do another search using the alias.
searchString = `${ALIAS} bbb`;
gURLBar.search(searchString);
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
// Manually set the urlbar value to a string that contains the alias, but not
// at the beginning and is not the same as the search string.
value = `bbb ${ALIAS}`;
gURLBar.value = `bbb ${ALIAS}`;
// The alias substring should not be highlighted.
Assert.equal(gURLBar.untrimmedValue, value);
Assert.ok(gURLBar.untrimmedValue.includes(ALIAS));
assertHighlighted(false, ALIAS);
// Reset for the next test.
gURLBar.search("");
});
// Selecting a non-heuristic (non-first) search engine result with an alias and
@ -199,8 +341,10 @@ add_task(async function nonHeuristicAliases() {
// Populate the results with the list of token alias engines by searching for
// "@".
gURLBar.search("@");
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "@",
});
await UrlbarTestUtils.waitForAutocompleteResultAt(
window,
tokenEngines.length - 1
@ -218,90 +362,14 @@ add_task(async function nonHeuristicAliases() {
);
});
// Aliases that don't start with @ shouldn't be highlighted.
add_task(async function nonTokenAlias() {
let alias = "nontokenalias";
let engine = Services.search.getEngineByName("Test");
engine.alias = "nontokenalias";
Assert.equal(engine.alias, alias);
gURLBar.search(alias);
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertFirstResultIsAlias(true, alias);
assertHighlighted(false);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
engine.alias = ALIAS;
});
// Clicking on an @ alias offer (an @ alias with an empty search string) in the
// view should fill it in the urlbar input.
// This subtest can be removed when update2 is on by default.
add_task(async function clickAndFillAlias_legacy() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", false]],
});
// Do a search for "@" to show all the @ aliases.
gURLBar.search("@");
await UrlbarTestUtils.promiseSearchComplete(window);
// Find our test engine in the results. It's probably last, but for
// robustness don't assume it is.
let testEngineItem;
for (let i = 0; !testEngineItem; i++) {
let details = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
if (details.searchParams && details.searchParams.keyword == ALIAS) {
testEngineItem = await UrlbarTestUtils.waitForAutocompleteResultAt(
window,
i
);
}
}
// Click it.
EventUtils.synthesizeMouseAtCenter(testEngineItem, {});
// A new search will start and its result should be the alias.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
// The urlbar input value should be the alias followed by a space so that it's
// ready for the user to start typing.
Assert.equal(gURLBar.value, `${ALIAS} `);
// Press the enter key a couple of times. Nothing should happen except a new
// search will start and its result should be the alias again. The urlbar
// should still contain the alias. An empty search results page should not
// load. The test will hang if that happens.
for (let i = 0; i < 2; i++) {
EventUtils.synthesizeKey("KEY_Enter");
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
Assert.equal(gURLBar.value, `${ALIAS} `);
}
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
await SpecialPowers.popPrefEnv();
});
// Clicking on an @ alias offer (an @ alias with an empty search string) in the
// view should enter search mode.
add_task(async function clickAndFillAlias() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", true]],
});
// Do a search for "@" to show all the @ aliases.
gURLBar.search("@");
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "@",
});
// Find our test engine in the results. It's probably last, but for
// robustness don't assume it is.
@ -326,77 +394,20 @@ add_task(async function clickAndFillAlias() {
entry: "keywordoffer",
});
await UrlbarTestUtils.exitSearchMode(window, { backspace: true });
await UrlbarTestUtils.exitSearchMode(window);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
await SpecialPowers.popPrefEnv();
});
// Pressing enter on an @ alias offer (an @ alias with an empty search string)
// in the view should fill it in the urlbar input.
// This subtest can be removed when update2 is on by default.
add_task(async function enterAndFillAlias_legacy() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", false]],
});
// Do a search for "@" to show all the @ aliases.
gURLBar.search("@");
await UrlbarTestUtils.promiseSearchComplete(window);
// Find our test engine in the results. It's probably last, but for
// robustness don't assume it is.
let index = 0;
for (; ; index++) {
let details = await UrlbarTestUtils.getDetailsOfResultAt(window, index);
if (details.searchParams && details.searchParams.keyword == ALIAS) {
index++;
break;
}
}
// Key down to it and press enter.
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: index });
EventUtils.synthesizeKey("KEY_Enter");
// A new search will start and its result should be the alias.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
// The urlbar input value should be the alias followed by a space so that it's
// ready for the user to start typing.
Assert.equal(gURLBar.value, `${ALIAS} `);
// Press the enter key a couple of times. Nothing should happen except a new
// search will start and its result should be the alias again. The urlbar
// should still contain the alias. An empty search results page should not
// load. The test will hang if that happens.
for (let i = 0; i < 2; i++) {
EventUtils.synthesizeKey("KEY_Enter");
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
Assert.equal(gURLBar.value, `${ALIAS} `);
}
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
await SpecialPowers.popPrefEnv();
});
// Pressing enter on an @ alias offer (an @ alias with an empty search string)
// in the view should enter search mode.
add_task(async function enterAndFillAlias() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", true]],
});
// Do a search for "@" to show all the @ aliases.
gURLBar.search("@");
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "@",
});
// Find our test engine in the results. It's probably last, but for
// robustness don't assume it is.
@ -421,53 +432,14 @@ add_task(async function enterAndFillAlias() {
entry: "keywordoffer",
});
await UrlbarTestUtils.exitSearchMode(window, { backspace: true });
await UrlbarTestUtils.exitSearchMode(window);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
await SpecialPowers.popPrefEnv();
});
// Pressing enter on an @ alias autofill should fill it in the urlbar input
// with a trailing space and move the caret at the end.
// This subtest can be removed when update2 is on by default.
add_task(async function enterAutofillsAlias_legacy() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", false]],
});
let expectedString = `${ALIAS} `;
for (let value of [ALIAS.substring(0, ALIAS.length - 1), ALIAS]) {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value,
selectionStart: value.length,
selectionEnd: value.length,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
// Press Enter.
EventUtils.synthesizeKey("KEY_Enter");
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
// The urlbar input value should be the alias followed by a space so that it's
// ready for the user to start typing.
Assert.equal(gURLBar.value, expectedString);
Assert.equal(gURLBar.selectionStart, expectedString.length);
Assert.equal(gURLBar.selectionEnd, expectedString.length);
await assertAlias(true);
}
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
await SpecialPowers.popPrefEnv();
});
// Pressing Enter on an @ alias autofill should enter search mode.
add_task(async function enterAutofillsAlias() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", true]],
});
for (let value of [ALIAS.substring(0, ALIAS.length - 1), ALIAS]) {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
@ -475,33 +447,26 @@ add_task(async function enterAutofillsAlias() {
selectionStart: value.length,
selectionEnd: value.length,
});
let testEngineItem = await UrlbarTestUtils.waitForAutocompleteResultAt(
window,
0
);
// Press Enter.
let searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
EventUtils.synthesizeKey("KEY_Enter");
await searchPromise;
await UrlbarTestUtils.assertSearchMode(window, {
engineName: testEngineItem.result.payload.engine,
engineName: testEngine.name,
entry: "keywordoffer",
});
await UrlbarTestUtils.exitSearchMode(window, { backspace: true });
await UrlbarTestUtils.exitSearchMode(window);
}
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
await SpecialPowers.popPrefEnv();
});
// Pressing Right on an @ alias autofill should enter search mode.
add_task(async function enterAutofillsAlias() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", true]],
});
add_task(async function rightEntersSearchMode() {
for (let value of [ALIAS.substring(0, ALIAS.length - 1), ALIAS]) {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
@ -509,154 +474,24 @@ add_task(async function enterAutofillsAlias() {
selectionStart: value.length,
selectionEnd: value.length,
});
let testEngineItem = await UrlbarTestUtils.waitForAutocompleteResultAt(
window,
0
);
let searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
EventUtils.synthesizeKey("KEY_ArrowRight");
await searchPromise;
await UrlbarTestUtils.assertSearchMode(window, {
engineName: testEngineItem.result.payload.engine,
engineName: testEngine.name,
entry: "typed",
});
gURLBar.setSearchMode({});
Assert.equal(gURLBar.value, "", "value should be empty");
await UrlbarTestUtils.exitSearchMode(window);
}
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
await SpecialPowers.popPrefEnv();
});
async function doSimpleTest(revertBetweenSteps) {
// When autofill is enabled, searching for "@tes" will autofill to "@test",
// which gets in the way of this test task, so temporarily disable it.
Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("browser.urlbar.autoFill");
});
// "@tes" -- not an alias, no highlight
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS.substr(0, ALIAS.length - 1),
fireInputEvent: true,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(false);
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@test" -- alias, highlight
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS,
fireInputEvent: true,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@test foo" -- alias, highlight
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS + " foo",
fireInputEvent: true,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@test" -- alias, highlight
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS,
fireInputEvent: true,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@tes" -- not an alias, no highlight
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS.substr(0, ALIAS.length - 1),
fireInputEvent: true,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(false);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
Services.prefs.clearUserPref("browser.urlbar.autoFill");
}
async function assertAlias(aliasPresent, expectedAlias = ALIAS) {
await assertFirstResultIsAlias(aliasPresent, expectedAlias);
assertHighlighted(aliasPresent, expectedAlias);
}
async function assertFirstResultIsAlias(isAlias, expectedAlias) {
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
Assert.equal(
result.type,
UrlbarUtils.RESULT_TYPE.SEARCH,
"Should have the correct type"
);
Assert.equal(
"keyword" in result.searchParams && !!result.searchParams.keyword,
isAlias,
"Should have a keyword if expected"
);
if (isAlias) {
Assert.equal(
result.searchParams.keyword,
expectedAlias,
"Should have the correct keyword"
);
}
}
function assertHighlighted(highlighted, expectedAlias) {
let selection = gURLBar.editor.selectionController.getSelection(
Ci.nsISelectionController.SELECTION_FIND
);
Assert.ok(selection);
if (!highlighted) {
Assert.equal(selection.rangeCount, 0);
return;
}
Assert.equal(selection.rangeCount, 1);
let index = gURLBar.value.indexOf(expectedAlias);
Assert.ok(
index >= 0,
`gURLBar.value="${gURLBar.value}" expectedAlias="${expectedAlias}"`
);
let range = selection.getRangeAt(0);
Assert.ok(range);
Assert.equal(range.startOffset, index);
Assert.equal(range.endOffset, index + expectedAlias.length);
}
/**
* This test checks that if an engine is marked as hidden then
* it should not appear in the popup when using the "@" token alias in the search bar.
@ -714,62 +549,6 @@ add_task(async function hiddenEngine() {
defaultEngine.hidden = false;
});
/**
* This test checks that if an engine is marked as hidden then it should not
* appear in the popup when using the "@" token alias in the search bar.
*/
add_task(async function hiddenEngine() {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "@",
});
const defaultEngine = await Services.search.getDefault();
let foundDefaultEngineInPopup = false;
// Checks that the default engine appears in the urlbar's popup.
for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
let details = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
if (defaultEngine.name == details.searchParams.engine) {
foundDefaultEngineInPopup = true;
break;
}
}
Assert.ok(foundDefaultEngineInPopup, "Default engine appears in the popup.");
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
// Checks that a hidden default engine (i.e. an engine removed from
// a user's search settings) does not appear in the urlbar's popup.
defaultEngine.hidden = true;
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "@",
fireInputEvent: true,
});
foundDefaultEngineInPopup = false;
for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
let details = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
if (defaultEngine.name == details.searchParams.engine) {
foundDefaultEngineInPopup = true;
break;
}
}
Assert.ok(
!foundDefaultEngineInPopup,
"Hidden default engine does not appear in the popup"
);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
defaultEngine.hidden = false;
});
/**
* This test checks that if an engines alias is not prefixed with
* @ it still appears in the popup when using the "@" token
@ -818,3 +597,47 @@ add_task(async function nonPrefixedKeyword() {
await Services.search.removeEngine(engine);
});
async function assertFirstResultIsAlias(isAlias, expectedAlias) {
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
Assert.equal(
result.type,
UrlbarUtils.RESULT_TYPE.SEARCH,
"Should have the correct type"
);
if (isAlias) {
Assert.equal(
result.searchParams.keyword,
expectedAlias,
"Payload keyword should be the alias"
);
} else {
Assert.notEqual(
result.searchParams.keyword,
expectedAlias,
"Payload keyword should be absent or not the alias"
);
}
}
function assertHighlighted(highlighted, expectedAlias) {
let selection = gURLBar.editor.selectionController.getSelection(
Ci.nsISelectionController.SELECTION_FIND
);
Assert.ok(selection);
if (!highlighted) {
Assert.equal(selection.rangeCount, 0);
return;
}
Assert.equal(selection.rangeCount, 1);
let index = gURLBar.value.indexOf(expectedAlias);
Assert.ok(
index >= 0,
`gURLBar.value="${gURLBar.value}" expectedAlias="${expectedAlias}"`
);
let range = selection.getRangeAt(0);
Assert.ok(range);
Assert.equal(range.startOffset, index);
Assert.equal(range.endOffset, index + expectedAlias.length);
}

Просмотреть файл

@ -0,0 +1,605 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// This file can be deleted when update2 is enabled by default.
//
// This test checks "@" search engine aliases ("token aliases") in the urlbar.
"use strict";
const ALIAS = "@test";
const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
add_task(async function init() {
// Add a default engine with suggestions, to avoid hitting the network when
// fetching them.
let defaultEngine = await SearchTestUtils.promiseNewSearchEngine(
getRootDirectory(gTestPath) + TEST_ENGINE_BASENAME
);
defaultEngine.alias = "@default";
let oldDefaultEngine = await Services.search.getDefault();
Services.search.setDefault(defaultEngine);
let engine = await Services.search.addEngineWithDetails("Test", {
alias: ALIAS,
template: "http://example.com/?search={searchTerms}",
});
registerCleanupFunction(async function() {
await Services.search.removeEngine(engine);
Services.search.setDefault(oldDefaultEngine);
});
await SpecialPowers.pushPrefEnv({
set: [
// Disable update2.
["browser.urlbar.update2", false],
// Search results aren't shown in quantumbar unless search suggestions are
// enabled.
["browser.urlbar.suggest.searches", true],
],
});
});
// Simple test that tries different variations of an alias, without reverting
// the urlbar value in between.
add_task(async function testNoRevert() {
await doSimpleTest(false);
});
// Simple test that tries different variations of an alias, reverting the urlbar
// value in between.
add_task(async function testRevert() {
await doSimpleTest(true);
});
async function doSimpleTest(revertBetweenSteps) {
// When autofill is enabled, searching for "@tes" will autofill to "@test",
// which gets in the way of this test task, so temporarily disable it.
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.autoFill", false]],
});
// "@tes" -- not an alias, no highlight
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS.substr(0, ALIAS.length - 1),
fireInputEvent: true,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(false);
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@test" -- alias, highlight
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS,
fireInputEvent: true,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@test foo" -- alias, highlight
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS + " foo",
fireInputEvent: true,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@test" -- alias, highlight
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS,
fireInputEvent: true,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
if (revertBetweenSteps) {
gURLBar.handleRevert();
gURLBar.blur();
}
// "@tes" -- not an alias, no highlight
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ALIAS.substr(0, ALIAS.length - 1),
fireInputEvent: true,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(false);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
await SpecialPowers.popPrefEnv();
}
// An alias should be recognized and highlighted even when there are spaces
// before it.
add_task(async function spacesBeforeAlias() {
gURLBar.search(" " + ALIAS);
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// An alias in the middle of a string should not be recognized or highlighted.
add_task(async function charsBeforeAlias() {
gURLBar.search("not an alias " + ALIAS);
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(false);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// In a search string that starts with a restriction character followed by an
// alias, the alias should be neither recognized nor highlighted.
add_task(async function restrictionCharBeforeAlias() {
gURLBar.search(UrlbarTokenizer.RESTRICT.BOOKMARK + " " + ALIAS);
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(false);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// Types a space while typing an alias to ensure we stop autofilling.
add_task(async function spaceWhileTypingAlias() {
let value = ALIAS.substring(0, ALIAS.length - 1);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value,
selectionStart: value.length,
selectionEnd: value.length,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
gURLBar.value = value + " ";
let searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
UrlbarTestUtils.fireInputEvent(window);
await searchPromise;
await assertAlias(false);
});
// Aliases are case insensitive, and the alias in the result uses the case that
// the user typed in the input. Make sure that searching with an alias using a
// weird case still causes the alias to be highlighted.
add_task(async function aliasCase() {
let alias = "@TeSt";
gURLBar.search(alias);
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true, alias);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// Even when the heuristic result is a search engine result with an alias, if
// the urlbar value does not match that result, then no alias substring in the
// urlbar should be highlighted. This is the case when the user uses an alias
// to perform a search: The popup closes (preserving the results in it), the
// urlbar value changes to the URL of the search results page, and the search
// results page is loaded.
add_task(async function inputDoesntMatchHeuristicResult() {
// Do a search using the alias.
let searchString = `${ALIAS} aaa`;
gURLBar.search(searchString);
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
// Manually set the urlbar value to a string that contains the alias at the
// beginning but is not the alias.
let value = `${ALIAS}xxx`;
gURLBar.value = `${ALIAS}xxx`;
// The alias substring should not be highlighted.
Assert.equal(gURLBar.untrimmedValue, value);
Assert.ok(gURLBar.untrimmedValue.includes(ALIAS));
assertHighlighted(false, ALIAS);
// Do another search using the alias.
searchString = `${ALIAS} bbb`;
gURLBar.search(searchString);
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
// Manually set the urlbar value to a string that contains the alias, but not
// at the beginning and is not the same as the search string.
value = `bbb ${ALIAS}`;
gURLBar.value = `bbb ${ALIAS}`;
// The alias substring should not be highlighted.
Assert.equal(gURLBar.untrimmedValue, value);
Assert.ok(gURLBar.untrimmedValue.includes(ALIAS));
assertHighlighted(false, ALIAS);
// Reset for the next test.
gURLBar.search("");
});
// Selecting a non-heuristic (non-first) search engine result with an alias and
// empty query should put the alias in the urlbar and highlight it.
// Also checks that internal aliases appear with the "@" keyword.
add_task(async function nonHeuristicAliases() {
// Get the list of token alias engines (those with aliases that start with
// "@").
let tokenEngines = [];
for (let engine of await Services.search.getEngines()) {
let aliases = [];
if (engine.alias) {
aliases.push(engine.alias);
}
aliases.push(...engine.aliases);
let tokenAliases = aliases.filter(a => a.startsWith("@"));
if (tokenAliases.length) {
tokenEngines.push({ engine, tokenAliases });
}
}
if (!tokenEngines.length) {
Assert.ok(true, "No token alias engines, skipping task.");
return;
}
info(
"Got token alias engines: " + tokenEngines.map(({ engine }) => engine.name)
);
// Populate the results with the list of token alias engines by searching for
// "@".
gURLBar.search("@");
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(
window,
tokenEngines.length - 1
);
// Key down to select each result in turn. The urlbar value should be set to
// each alias, and each should be highlighted.
for (let { tokenAliases } of tokenEngines) {
let alias = tokenAliases[0];
EventUtils.synthesizeKey("KEY_ArrowDown");
assertHighlighted(true, alias);
}
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// Aliases that don't start with @ shouldn't be highlighted.
add_task(async function nonTokenAlias() {
let alias = "nontokenalias";
let engine = Services.search.getEngineByName("Test");
engine.alias = "nontokenalias";
Assert.equal(engine.alias, alias);
gURLBar.search(alias);
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertFirstResultIsAlias(true, alias);
assertHighlighted(false);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
engine.alias = ALIAS;
});
// Clicking on an @ alias offer (an @ alias with an empty search string) in the
// view should fill it in the urlbar input.
add_task(async function clickAndFillAlias_legacy() {
// Do a search for "@" to show all the @ aliases.
gURLBar.search("@");
await UrlbarTestUtils.promiseSearchComplete(window);
// Find our test engine in the results. It's probably last, but for
// robustness don't assume it is.
let testEngineItem;
for (let i = 0; !testEngineItem; i++) {
let details = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
if (details.searchParams && details.searchParams.keyword == ALIAS) {
testEngineItem = await UrlbarTestUtils.waitForAutocompleteResultAt(
window,
i
);
}
}
// Click it.
EventUtils.synthesizeMouseAtCenter(testEngineItem, {});
// A new search will start and its result should be the alias.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
// The urlbar input value should be the alias followed by a space so that it's
// ready for the user to start typing.
Assert.equal(gURLBar.value, `${ALIAS} `);
// Press the enter key a couple of times. Nothing should happen except a new
// search will start and its result should be the alias again. The urlbar
// should still contain the alias. An empty search results page should not
// load. The test will hang if that happens.
for (let i = 0; i < 2; i++) {
EventUtils.synthesizeKey("KEY_Enter");
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
Assert.equal(gURLBar.value, `${ALIAS} `);
}
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// Pressing enter on an @ alias offer (an @ alias with an empty search string)
// in the view should fill it in the urlbar input.
add_task(async function enterAndFillAlias_legacy() {
// Do a search for "@" to show all the @ aliases.
gURLBar.search("@");
await UrlbarTestUtils.promiseSearchComplete(window);
// Find our test engine in the results. It's probably last, but for
// robustness don't assume it is.
let index = 0;
for (; ; index++) {
let details = await UrlbarTestUtils.getDetailsOfResultAt(window, index);
if (details.searchParams && details.searchParams.keyword == ALIAS) {
index++;
break;
}
}
// Key down to it and press enter.
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: index });
EventUtils.synthesizeKey("KEY_Enter");
// A new search will start and its result should be the alias.
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
// The urlbar input value should be the alias followed by a space so that it's
// ready for the user to start typing.
Assert.equal(gURLBar.value, `${ALIAS} `);
// Press the enter key a couple of times. Nothing should happen except a new
// search will start and its result should be the alias again. The urlbar
// should still contain the alias. An empty search results page should not
// load. The test will hang if that happens.
for (let i = 0; i < 2; i++) {
EventUtils.synthesizeKey("KEY_Enter");
await UrlbarTestUtils.promiseSearchComplete(window);
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
await assertAlias(true);
Assert.equal(gURLBar.value, `${ALIAS} `);
}
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
// Pressing enter on an @ alias autofill should fill it in the urlbar input
// with a trailing space and move the caret at the end.
add_task(async function enterAutofillsAlias_legacy() {
let expectedString = `${ALIAS} `;
for (let value of [ALIAS.substring(0, ALIAS.length - 1), ALIAS]) {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value,
selectionStart: value.length,
selectionEnd: value.length,
});
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
// Press Enter.
EventUtils.synthesizeKey("KEY_Enter");
await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
// The urlbar input value should be the alias followed by a space so that it's
// ready for the user to start typing.
Assert.equal(gURLBar.value, expectedString);
Assert.equal(gURLBar.selectionStart, expectedString.length);
Assert.equal(gURLBar.selectionEnd, expectedString.length);
await assertAlias(true);
}
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
});
/**
* This test checks that if an engine is marked as hidden then
* it should not appear in the popup when using the "@" token alias in the search bar.
*/
add_task(async function hiddenEngine() {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "@",
fireInputEvent: true,
});
const defaultEngine = await Services.search.getDefault();
let foundDefaultEngineInPopup = false;
// Checks that the default engine appears in the urlbar's popup.
for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
let details = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
if (defaultEngine.name == details.searchParams.engine) {
foundDefaultEngineInPopup = true;
break;
}
}
Assert.ok(foundDefaultEngineInPopup, "Default engine appears in the popup.");
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
// Checks that a hidden default engine (i.e. an engine removed from
// a user's search settings) does not appear in the urlbar's popup.
defaultEngine.hidden = true;
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "@",
fireInputEvent: true,
});
foundDefaultEngineInPopup = false;
for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
let details = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
if (defaultEngine.name == details.searchParams.engine) {
foundDefaultEngineInPopup = true;
break;
}
}
Assert.ok(
!foundDefaultEngineInPopup,
"Hidden default engine does not appear in the popup"
);
await UrlbarTestUtils.promisePopupClose(window, () =>
EventUtils.synthesizeKey("KEY_Escape")
);
defaultEngine.hidden = false;
});
/**
* This test checks that if an engines alias is not prefixed with
* @ it still appears in the popup when using the "@" token
* alias in the search bar.
*/
add_task(async function nonPrefixedKeyword() {
let name = "Custom";
let alias = "customkeyword";
let engine = await Services.search.addEngineWithDetails(name, {
alias,
template: "http://example.com/?search={searchTerms}",
});
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "@",
});
let foundEngineInPopup = false;
// Checks that the default engine appears in the urlbar's popup.
for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
let details = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
if (details.searchParams.engine === name) {
foundEngineInPopup = true;
break;
}
}
Assert.ok(foundEngineInPopup, "Custom engine appears in the popup.");
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "@" + alias,
});
let keywordOfferResult = await UrlbarTestUtils.getDetailsOfResultAt(
window,
0
);
Assert.equal(
keywordOfferResult.searchParams.engine,
name,
"The first result should be a keyword search result with the correct engine."
);
await Services.search.removeEngine(engine);
});
async function assertAlias(aliasPresent, expectedAlias = ALIAS) {
await assertFirstResultIsAlias(aliasPresent, expectedAlias);
assertHighlighted(aliasPresent, expectedAlias);
}
async function assertFirstResultIsAlias(isAlias, expectedAlias) {
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
Assert.equal(
result.type,
UrlbarUtils.RESULT_TYPE.SEARCH,
"Should have the correct type"
);
if (isAlias) {
Assert.equal(
result.searchParams.keyword,
expectedAlias,
"Payload keyword should be the alias"
);
} else {
Assert.notEqual(
result.searchParams.keyword,
expectedAlias,
"Payload keyword should be absent or not the alias"
);
}
}
function assertHighlighted(highlighted, expectedAlias) {
let selection = gURLBar.editor.selectionController.getSelection(
Ci.nsISelectionController.SELECTION_FIND
);
Assert.ok(selection);
if (!highlighted) {
Assert.equal(selection.rangeCount, 0);
return;
}
Assert.equal(selection.rangeCount, 1);
let index = gURLBar.value.indexOf(expectedAlias);
Assert.ok(
index >= 0,
`gURLBar.value="${gURLBar.value}" expectedAlias="${expectedAlias}"`
);
let range = selection.getRangeAt(0);
Assert.ok(range);
Assert.equal(range.startOffset, index);
Assert.equal(range.endOffset, index + expectedAlias.length);
}

Просмотреть файл

@ -651,23 +651,8 @@ const tests = [
value: `${alias} `,
});
let keywordOfferResult = await UrlbarTestUtils.getDetailsOfResultAt(
window,
0
);
Assert.equal(
keywordOfferResult.searchParams.keyword,
alias,
"The first result should be a keyword search result with the correct alias."
);
// Fire an input event simulating typing a space after the alias.
let searchPromise = UrlbarTestUtils.promiseSearchComplete(window);
UrlbarTestUtils.fireInputEvent(window);
await searchPromise;
await UrlbarTestUtils.assertSearchMode(window, {
engineName: keywordOfferResult.searchParams.engine,
engineName: "AliasTest",
entry: "typed",
});

Просмотреть файл

@ -79,18 +79,19 @@ async function updateTopSites(condition, searchShortcuts = false) {
}
/**
* Simple convenience method to append a space to a token alias if update2 is
* off. When the update2 pref is removed, this method can be removed and its
* callers can simply use the passed string
* (e.g. change foo(getAutofillSearchString("@test")) to foo("@test")).
* Simple convenience method to append a space to token aliases but not to other
* values.
*
* TODO (Bug 1661882): Remove this function and simply use the passed-in string
* directly.
*
* @param {string} val
* @returns {string}
* `val` with a space appended if update2 is disabled. Returns `val` if it
* does not start with "@".
* `val` with a space appended if it's a token alias, or just `val` otherwise.
*/
function getAutofillSearchString(val) {
if (!val.startsWith("@")) {
return val;
}
return val + (UrlbarPrefs.get("update2") ? "" : " ");
return val + " ";
}

Просмотреть файл

@ -394,11 +394,18 @@ function frecencyForUrl(aURI) {
*/
function makeBookmarkResult(
queryContext,
{ title, uri, iconUri, tags = [], heuristic = false }
{
title,
uri,
iconUri,
tags = [],
heuristic = false,
source = UrlbarUtils.RESULT_SOURCE.BOOKMARKS,
}
) {
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.URL,
UrlbarUtils.RESULT_SOURCE.BOOKMARKS,
source,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
url: [uri, UrlbarUtils.HIGHLIGHT.TYPED],
// Check against undefined so consumers can pass in the empty string.
@ -429,7 +436,6 @@ function makeFormHistoryResult(queryContext, { suggestion, engineName }) {
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
engine: engineName,
suggestion: [suggestion, UrlbarUtils.HIGHLIGHT.SUGGESTED],
isSearchHistory: true,
lowerCaseSuggestion: suggestion.toLocaleLowerCase(),
})
);
@ -532,7 +538,7 @@ function makePrioritySearchResult(
UrlbarUtils.RESULT_SOURCE.SEARCH,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
engine: [engineName, UrlbarUtils.HIGHLIGHT.TYPED],
icon: engineIconUri ? engineIconUri : "",
icon: engineIconUri,
})
);
@ -580,51 +586,49 @@ function makeSearchResult(
alias,
query,
engineIconUri,
heuristic = false,
keywordOffer,
providerName,
inPrivateWindow,
isPrivateEngine,
heuristic = false,
type = UrlbarUtils.RESULT_TYPE.SEARCH,
source = UrlbarUtils.RESULT_SOURCE.SEARCH,
}
) {
if (!keywordOffer) {
keywordOffer = UrlbarUtils.KEYWORD_OFFER.NONE;
if (
alias &&
!query.trim() &&
(UrlbarPrefs.get("update2") || alias.startsWith("@"))
) {
keywordOffer = heuristic
? UrlbarUtils.KEYWORD_OFFER.HIDE
: UrlbarUtils.KEYWORD_OFFER.SHOW;
// Tail suggestion common cases, handled here to reduce verbosity in tests.
if (tail) {
if (!tailPrefix) {
tailPrefix = "… ";
}
if (!tailOffsetIndex) {
tailOffsetIndex = suggestion.indexOf(tail);
}
}
// Tail suggestion common cases, handled here to reduce verbosity in tests.
if (tail && !tailPrefix) {
tailPrefix = "… ";
}
if (!tailOffsetIndex) {
tailOffsetIndex = tail ? suggestion.indexOf(tail) : -1;
}
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_SOURCE.SEARCH,
type,
source,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
engine: [engineName, UrlbarUtils.HIGHLIGHT.TYPED],
suggestion: [suggestion, UrlbarUtils.HIGHLIGHT.SUGGESTED],
tailPrefix,
tail: [tail, UrlbarUtils.HIGHLIGHT.SUGGESTED],
tailOffsetIndex,
keyword: [alias, UrlbarUtils.HIGHLIGHT.TYPED],
keyword: [
alias,
keywordOffer == UrlbarUtils.KEYWORD_OFFER.SHOW
? UrlbarUtils.HIGHLIGHT.TYPED
: UrlbarUtils.HIGHLIGHT.NONE,
],
// Check against undefined so consumers can pass in the empty string.
query: [
typeof query != "undefined" ? query : queryContext.trimmedSearchString,
UrlbarUtils.HIGHLIGHT.TYPED,
],
isSearchHistory: false,
icon: [engineIconUri ? engineIconUri : ""],
icon: engineIconUri,
keywordOffer,
inPrivateWindow,
isPrivateEngine,
})
);
@ -661,22 +665,37 @@ function makeSearchResult(
*/
function makeVisitResult(
queryContext,
{ title, uri, iconUri, tags = null, heuristic = false, providerName }
{
title,
uri,
iconUri,
providerName,
tags = null,
heuristic = false,
source = UrlbarUtils.RESULT_SOURCE.HISTORY,
}
) {
let payload = {
url: [uri, UrlbarUtils.HIGHLIGHT.TYPED],
// Check against undefined so consumers can pass in the empty string.
icon: [typeof iconUri != "undefined" ? iconUri : `page-icon:${uri}`],
title: [title, UrlbarUtils.HIGHLIGHT.TYPED],
};
if (iconUri) {
payload.icon = iconUri;
} else if (
iconUri === undefined &&
source != UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL
) {
payload.icon = `page-icon:${uri}`;
}
if (!heuristic || tags) {
payload.tags = [tags || [], UrlbarUtils.HIGHLIGHT.TYPED];
}
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.URL,
UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
source,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, payload)
);
@ -726,12 +745,14 @@ async function check_results({
let controller = UrlbarTestUtils.newMockController({
input: {
isPrivate: context.isPrivate,
onFirstResult() {
return false;
},
window: {
location: {
href: AppConstants.BROWSER_CHROME_URL,
},
},
autofillFirstResult() {},
},
});
@ -763,35 +784,62 @@ async function check_results({
}
}
if (context.results.length != matches.length) {
info("Returned results: " + JSON.stringify(context.results));
Assert.equal(
context.results.length,
matches.length,
"Found the expected number of results."
);
info("Actual results: " + JSON.stringify(context.results));
}
Assert.equal(
context.results.length,
matches.length,
"Found the expected number of results."
);
function getPayload(result) {
let payload = {};
for (let [key, value] of Object.entries(result.payload)) {
if (value !== undefined) {
payload[key] = value;
}
}
return payload;
}
Assert.deepEqual(
matches.map(m => m.payload),
context.results.map(m => m.payload),
"Payloads are the same."
);
Assert.deepEqual(
matches.map(m => m.heuristic),
context.results.map(m => m.heuristic),
"Heuristic results are correctly flagged."
);
matches.forEach((match, i) => {
if (match.providerName) {
for (let i = 0; i < matches.length; i++) {
let actual = context.results[i];
let expected = matches[i];
info(
`Comparing results at index ${i}:` +
" actual=" +
JSON.stringify(actual) +
" expected=" +
JSON.stringify(expected)
);
Assert.equal(
actual.type,
expected.type,
`result.type at result index ${i}`
);
Assert.equal(
actual.source,
expected.source,
`result.source at result index ${i}`
);
Assert.equal(
actual.heuristic,
expected.heuristic,
`result.heuristic at result index ${i}`
);
if (expected.providerName) {
Assert.equal(
match.providerName,
context.results[i].providerName,
`The result at index ${i} is from the correct provider.`
actual.providerName,
expected.providerName,
`result.providerName at result index ${i}`
);
}
});
Assert.deepEqual(
getPayload(actual),
getPayload(expected),
`result.payload at result index ${i}`
);
}
}
/**

Просмотреть файл

@ -176,6 +176,7 @@ add_task(async function portNoMatch1() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${origin}:89/`,
title: `http://${origin}:89/`,
iconUri: "",
@ -199,6 +200,7 @@ add_task(async function portNoMatch2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${origin}:9/`,
title: `http://${origin}:9/`,
iconUri: "",
@ -211,7 +213,7 @@ add_task(async function portNoMatch2() {
});
// "example/" should *not* match http://example.com/.
add_task(async function trailingSlash() {
add_task(async function trailingSlash_2() {
await PlacesTestUtils.addVisits([
{
uri: "http://example.com/",
@ -222,8 +224,10 @@ add_task(async function trailingSlash() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://example/",
title: "http://example/",
iconUri: "page-icon:http://example/",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
@ -562,6 +566,7 @@ add_task(async function suggestHistoryFalse_bookmark_prefix_multiple() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${search}/`,
title: `${search}/`,
iconUri: "",
@ -581,6 +586,7 @@ add_task(async function suggestHistoryFalse_bookmark_prefix_multiple() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${search}/`,
title: `${search}/`,
iconUri: "",
@ -600,6 +606,7 @@ add_task(async function suggestHistoryFalse_bookmark_prefix_multiple() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${search}/`,
title: `${search}/`,
iconUri: "",

Просмотреть файл

@ -35,8 +35,8 @@ const host = "example.com";
let origins;
function add_autofill_task(callback) {
add_task(async () => {
info("Running subtest with origins disabled.");
let func = async () => {
info(`Running subtest with origins disabled: ${callback.name}`);
origins = false;
path = "/foo";
search = "example.com/f";
@ -45,7 +45,7 @@ function add_autofill_task(callback) {
url = host + path;
await callback();
info("Running subtest with origins enabled.");
info(`Running subtest with origins enabled: ${callback.name}`);
origins = true;
path = "/";
search = "ex";
@ -53,7 +53,9 @@ function add_autofill_task(callback) {
title = "example.com";
url = host + path;
await callback();
});
};
Object.defineProperty(func, "name", { value: callback.name });
add_task(func);
}
// "ex" should match http://example.com/.
@ -172,6 +174,7 @@ add_autofill_task(async function wwwShouldNotMatchNoWWW() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://www." + search,
title: "http://www." + search,
iconUri: `page-icon:http://www.${host}/`,
@ -289,6 +292,7 @@ add_autofill_task(async function prefixWWWShouldNotMatchNoWWW() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -313,6 +317,7 @@ add_autofill_task(async function httpPrefixShouldNotMatchHTTPS() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -399,6 +404,7 @@ add_autofill_task(async function httpsWWWShouldNotMatchNoWWW() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://www." + search,
title: "http://www." + search,
iconUri: `page-icon:http://www.${host}/`,
@ -472,6 +478,7 @@ add_autofill_task(async function httpsPrefixWWWShouldNotMatchNoWWW() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -496,6 +503,7 @@ add_autofill_task(async function httpsPrefixShouldNotMatchHTTP() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -790,6 +798,7 @@ add_autofill_task(async function frecency() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://" + search,
title: "http://" + search,
iconUri: `page-icon:http://${host}/`,
@ -990,6 +999,7 @@ add_autofill_task(async function suggestHistoryFalse_visit() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://" + search,
title: "http://" + search,
iconUri: `page-icon:http://${host}/`,
@ -1047,6 +1057,7 @@ add_autofill_task(async function suggestHistoryFalse_visit_prefix() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://" + search,
title: "http://" + search,
iconUri: `page-icon:http://${host}/`,
@ -1147,6 +1158,7 @@ add_autofill_task(async function suggestHistoryFalse_bookmark_1() {
} else {
matches.unshift(
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://" + search,
title: "http://" + search,
iconUri: `page-icon:http://${host}/`,
@ -1241,6 +1253,7 @@ add_autofill_task(async function suggestHistoryFalse_bookmark_prefix_1() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1279,6 +1292,7 @@ add_autofill_task(async function suggestHistoryFalse_bookmark_prefix_2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1317,6 +1331,7 @@ add_autofill_task(async function suggestHistoryFalse_bookmark_prefix_3() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1398,6 +1413,7 @@ add_autofill_task(async function suggestBookmarkFalse_visit_1() {
} else {
matches.unshift(
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1465,6 +1481,7 @@ add_autofill_task(async function suggestBookmarkFalse_visit_prefix_1() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1502,6 +1519,7 @@ add_autofill_task(async function suggestBookmarkFalse_visit_prefix_2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1539,6 +1557,7 @@ add_autofill_task(async function suggestBookmarkFalse_visit_prefix_3() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1602,6 +1621,7 @@ add_autofill_task(async function suggestBookmarkFalse_unvisitedBookmark() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://" + search,
title: "http://" + search,
iconUri: `page-icon:http://${host}/`,
@ -1651,6 +1671,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1687,6 +1708,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1723,6 +1745,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1759,6 +1782,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1866,6 +1890,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1873,6 +1898,7 @@ add_autofill_task(
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
makeBookmarkResult(context, {
source: UrlbarUtils.RESULT_SOURCE.HISTORY,
uri: "ftp://" + url,
title: "A bookmark",
}),
@ -1907,6 +1933,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1914,6 +1941,7 @@ add_autofill_task(
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
makeBookmarkResult(context, {
source: UrlbarUtils.RESULT_SOURCE.HISTORY,
uri: "http://non-matching-" + url,
title: "A bookmark",
}),
@ -1948,6 +1976,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: prefixedUrl,
title: prefixedUrl,
heuristic: true,
@ -1955,6 +1984,7 @@ add_autofill_task(
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
makeBookmarkResult(context, {
source: UrlbarUtils.RESULT_SOURCE.HISTORY,
uri: "ftp://non-matching-" + url,
title: "A bookmark",
}),
@ -2071,6 +2101,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${search}/`,
title: `http://${search}/`,
heuristic: true,
@ -2099,6 +2130,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${search}/`,
title: `http://${search}/`,
heuristic: true,
@ -2149,6 +2181,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${search}/`,
title: `http://${search}/`,
heuristic: true,
@ -2177,6 +2210,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${search}/`,
title: `http://${search}/`,
heuristic: true,
@ -2227,6 +2261,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${search}/`,
title: `http://${search}/`,
heuristic: true,
@ -2255,6 +2290,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${search}/`,
title: `http://${search}/`,
heuristic: true,
@ -2305,6 +2341,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${search}/`,
title: `http://${search}/`,
heuristic: true,
@ -2333,6 +2370,7 @@ add_autofill_task(
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${search}/`,
title: `http://${search}/`,
heuristic: true,

Просмотреть файл

@ -36,8 +36,7 @@ add_task(async function basic() {
0,
Math.round(TEST_ENGINE_ALIAS.length / 2)
);
let autofilledValue =
TEST_ENGINE_ALIAS + (UrlbarPrefs.get("update2") ? "" : " ");
let autofilledValue = TEST_ENGINE_ALIAS + " ";
let context = createContext(search, { isPrivate: false });
await check_results({
context,
@ -72,7 +71,7 @@ add_task(async function preserveCase() {
);
let alias = search + TEST_ENGINE_ALIAS.substr(search.length);
let autofilledValue = alias + (UrlbarPrefs.get("update2") ? "" : " ");
let autofilledValue = alias + " ";
let context = createContext(search, { isPrivate: false });
await check_results({
context,

Просмотреть файл

@ -194,9 +194,9 @@ add_task(async function searchEngines() {
search: otherScheme + "://ex",
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: otherScheme + "://ex/",
title: otherScheme + "://ex/",
iconUri: "",
heuristic: true,
}),
],
@ -207,9 +207,9 @@ add_task(async function searchEngines() {
search: otherScheme + "://www.ex",
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: otherScheme + "://www.ex/",
title: otherScheme + "://www.ex/",
iconUri: "",
heuristic: true,
}),
],
@ -220,8 +220,10 @@ add_task(async function searchEngines() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://example/",
title: "http://example/",
iconUri: "page-icon:http://example/",
heuristic: true,
}),
],

Просмотреть файл

@ -67,6 +67,7 @@ add_task(async function portNoMatch() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://example.com:8999/f",
title: "http://example.com:8999/f",
iconUri: "page-icon:http://example.com:8999/",

Просмотреть файл

@ -179,6 +179,7 @@ add_task(async function test_searchEngine_different_scheme_noautofill() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://pie/",
title: "http://pie/",
iconUri: "",

Просмотреть файл

@ -70,6 +70,7 @@ add_task(async function test_protocol_trimming() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${input.trim()}/`,
title: `${input.trim()}/`,
iconUri: "",

Просмотреть файл

@ -44,6 +44,7 @@ add_task(async function test_casing_2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://mozilla.org/T",
title: "http://mozilla.org/T",
iconUri: "page-icon:http://mozilla.org/",
@ -91,6 +92,7 @@ add_task(async function test_casing_4() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://mozilla.org/t",
title: "http://mozilla.org/t",
iconUri: "page-icon:http://mozilla.org/",
@ -190,6 +192,7 @@ add_task(async function test_untrimmed_path_casing() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://mozilla.org/t",
title: "http://mozilla.org/t",
iconUri: "page-icon:http://mozilla.org/",
@ -237,6 +240,7 @@ add_task(async function test_untrimmed_path_www_casing() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://www.mozilla.org/t",
title: "http://www.mozilla.org/t",
iconUri: "page-icon:http://www.mozilla.org/",

Просмотреть файл

@ -37,9 +37,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${query}/`,
title: `http://${query}/`,
iconUri: "",
heuristic: true,
}),
makeSearchResult(context, {
@ -55,9 +55,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${query}/`,
title: `http://${query}/`,
iconUri: "",
heuristic: true,
}),
makeSearchResult(context, {
@ -73,9 +73,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${query}/`,
title: `http://${query}/`,
iconUri: "",
heuristic: true,
}),
makeSearchResult(context, {
@ -91,9 +91,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${query}/`,
title: `${query}/`,
iconUri: "",
heuristic: true,
}),
],
@ -106,9 +106,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${query}/`,
title: `${query}/`,
iconUri: "",
heuristic: true,
}),
],
@ -121,9 +121,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${query}/`,
title: `${query}/`,
iconUri: "",
heuristic: true,
}),
],
@ -136,9 +136,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: query,
title: query,
iconUri: "",
heuristic: true,
}),
],
@ -151,9 +151,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${query}/`,
title: `${query}/`,
iconUri: "",
heuristic: true,
}),
],
@ -175,6 +175,7 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${query}`,
title: `http://${query}`,
iconUri: "page-icon:http://mozilla.org/",
@ -223,9 +224,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${query}/`,
title: `http://${query}/`,
iconUri: "",
heuristic: true,
}),
makeSearchResult(context, {
@ -241,6 +242,7 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${query}`,
title: `http://${query}`,
iconUri: "page-icon:http://firefox/",
@ -260,6 +262,7 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${query}`,
title: `http://${query}`,
iconUri: "page-icon:http://mozilla/",
@ -276,9 +279,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${query}/`,
title: `http://${query}/`,
iconUri: "",
heuristic: true,
}),
],
@ -291,9 +294,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${query}/`,
title: `http://${query}/`,
iconUri: "",
heuristic: true,
}),
],
@ -312,9 +315,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${query}/`,
title: `http://${query}/`,
iconUri: "",
heuristic: true,
}),
],
@ -327,9 +330,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: query,
title: query,
iconUri: "",
heuristic: true,
}),
],
@ -357,9 +360,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${query}/`,
title: `${query}/`,
iconUri: "",
heuristic: true,
}),
],
@ -372,9 +375,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `${query}/`,
title: `${query}/`,
iconUri: "",
heuristic: true,
}),
],
@ -387,9 +390,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${query}/`,
title: `http://${query}/`,
iconUri: "",
heuristic: true,
}),
],
@ -427,9 +430,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: query,
title: query,
iconUri: "",
heuristic: true,
}),
],
@ -442,9 +445,9 @@ add_task(async function() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: query,
title: query,
iconUri: "",
heuristic: true,
}),
],
@ -489,8 +492,9 @@ add_task(async function() {
});
await Services.search.setDefault(originalTestEngine);
Services.prefs.setBoolPref("browser.urlbar.update2", false);
info(
"Leading restriction tokens are not removed from the search result, apart from the search token."
"With update2 disabled, leading restriction tokens are not removed from the search result, apart from the search token."
);
// Note that we use the alias from AliasEngine in the query. Since we're using
// a restriction token, we expect that the default engine be used.
@ -515,5 +519,59 @@ add_task(async function() {
});
}
}
Services.prefs.clearUserPref("browser.urlbar.update2");
Services.prefs.setBoolPref("browser.urlbar.update2", true);
info(
"Leading search-mode restriction tokens are removed from the search result."
);
for (let restrict of UrlbarTokenizer.SEARCH_MODE_RESTRICT) {
let token = UrlbarTokenizer.RESTRICT[restrict];
query = `${token} query`;
let expectedQuery = query.substring(2);
context = createContext(query, { isPrivate: false });
info(`Searching for "${query}", expecting "${expectedQuery}"`);
await check_results({
context,
matches: [
makeSearchResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
heuristic: true,
query: expectedQuery,
alias: token,
keywordOffer: UrlbarUtils.KEYWORD_OFFER.NONE,
}),
],
});
}
info(
"Leading non-search-mode restriction tokens are not removed from the search result."
);
for (let restrict of Object.keys(UrlbarTokenizer.RESTRICT)) {
if (
UrlbarTokenizer.SEARCH_MODE_RESTRICT.has(restrict) ||
restrict == "SEARCH"
) {
continue;
}
let token = UrlbarTokenizer.RESTRICT[restrict];
query = `${token} query`;
let expectedQuery = query;
context = createContext(query, { isPrivate: false });
info(`Searching for "${query}", expecting "${expectedQuery}"`);
await check_results({
context,
matches: [
makeSearchResult(context, {
heuristic: true,
query: expectedQuery,
engineName: ENGINE_NAME,
}),
],
});
}
Services.prefs.clearUserPref("browser.urlbar.update2");
await Services.search.removeEngine(engine2);
});

Просмотреть файл

@ -436,6 +436,7 @@ add_task(async function restrictToken() {
...makeExpectedFormHistoryResults(context),
],
});
// Also if followed by multiple spaces.
context = createContext(`${UrlbarTokenizer.RESTRICT.SEARCH} `, {
isPrivate: false,
@ -451,6 +452,7 @@ add_task(async function restrictToken() {
...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`, {
@ -470,6 +472,7 @@ add_task(async function restrictToken() {
}),
],
});
// Also if followed by a space and single char.
context = createContext(`${UrlbarTokenizer.RESTRICT.SEARCH} h`, {
isPrivate: false,
@ -488,7 +491,9 @@ add_task(async function restrictToken() {
}),
],
});
// Any other restriction char allows to search for it.
// With update2 disabled, any other restriction char allows to search for it.
Services.prefs.setBoolPref("browser.urlbar.update2", false);
context = createContext(UrlbarTokenizer.RESTRICT.OPENPAGE, {
isPrivate: false,
});
@ -498,6 +503,54 @@ add_task(async function restrictToken() {
makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }),
],
});
Services.prefs.clearUserPref("browser.urlbar.update2");
// Leading search-mode restriction tokens are removed.
Services.prefs.setBoolPref("browser.urlbar.update2", true);
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,
keywordOffer: UrlbarUtils.KEYWORD_OFFER.NONE,
}),
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 restrict;
for (let r of Object.keys(UrlbarTokenizer.RESTRICT)) {
if (!UrlbarTokenizer.SEARCH_MODE_RESTRICT.has(r)) {
restrict = r;
break;
}
}
Assert.ok(
restrict,
"Non-search-mode restrict token exists -- if not, you can probably remove me!"
);
context = createContext(UrlbarTokenizer.RESTRICT[restrict], {
isPrivate: false,
});
await check_results({
context,
matches: [
makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }),
],
});
Services.prefs.clearUserPref("browser.urlbar.update2");
await cleanUpSuggestions();
});
@ -760,6 +813,7 @@ add_task(async function prohibit_suggestions() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${SEARCH_STRING}/`,
title: `http://${SEARCH_STRING}/`,
iconUri: "",
@ -800,6 +854,7 @@ add_task(async function prohibit_suggestions() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: `http://${SEARCH_STRING}/`,
title: `http://${SEARCH_STRING}/`,
iconUri: "",
@ -818,6 +873,7 @@ add_task(async function prohibit_suggestions() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://somethingelse/",
title: "http://somethingelse/",
iconUri: "",
@ -848,8 +904,10 @@ add_task(async function prohibit_suggestions() {
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,
}),
],
@ -860,6 +918,7 @@ add_task(async function prohibit_suggestions() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://[2001::1]:30/",
title: "http://[2001::1]:30/",
iconUri: "",
@ -873,6 +932,7 @@ add_task(async function prohibit_suggestions() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://user:pass@test/",
title: "http://user:pass@test/",
iconUri: "",
@ -886,6 +946,7 @@ add_task(async function prohibit_suggestions() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "data:text/plain,Content",
title: "data:text/plain,Content",
iconUri: "",
@ -916,6 +977,7 @@ add_task(async function uri_like_queries() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
title: `http://${query}/`,
uri: `http://${query}/`,
iconUri: "",
@ -1135,6 +1197,7 @@ add_task(async function avoid_remote_url_suggestions_2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "ftp://test/",
title: "ftp://test/",
iconUri: "",
@ -1174,6 +1237,7 @@ add_task(async function avoid_remote_url_suggestions_2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "ftp://test/",
title: "ftp://test/",
iconUri: "",
@ -1219,6 +1283,7 @@ add_task(async function avoid_remote_url_suggestions_2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://www/",
title: "http://www/",
iconUri: "",
@ -1232,6 +1297,7 @@ add_task(async function avoid_remote_url_suggestions_2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "https://www/",
title: "https://www/",
iconUri: "",
@ -1245,6 +1311,7 @@ add_task(async function avoid_remote_url_suggestions_2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://test/",
title: "http://test/",
iconUri: "",
@ -1258,6 +1325,7 @@ add_task(async function avoid_remote_url_suggestions_2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "https://test/",
title: "https://test/",
iconUri: "",
@ -1271,6 +1339,7 @@ add_task(async function avoid_remote_url_suggestions_2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://www.test/",
title: "http://www.test/",
iconUri: "",
@ -1284,6 +1353,7 @@ add_task(async function avoid_remote_url_suggestions_2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "http://www.test.com/",
title: "http://www.test.com/",
iconUri: "",
@ -1321,6 +1391,7 @@ add_task(async function avoid_remote_url_suggestions_2() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "file:///Users",
title: "file:///Users",
iconUri: "",
@ -1516,6 +1587,7 @@ add_task(async function formHistory() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.HISTORY,
uri: "http://foo.example.com/",
title: "foo.example.com",
heuristic: true,

Просмотреть файл

@ -6,176 +6,338 @@
* behavior.
*/
const DEFAULT_ENGINE_NAME = "TestDefaultEngine";
const SUGGESTIONS_ENGINE_NAME = "engine-suggestions.xml";
const SUGGEST_PREF = "browser.urlbar.suggest.searches";
const SUGGEST_ENABLED_PREF = "browser.search.suggest.enabled";
const HISTORY_TITLE = "fire";
let engine;
add_task(async function setup() {
engine = await addTestSuggestionsEngine();
});
add_task(async function engineWithSuggestions() {
// History matches should not appear with @ aliases, so this visit/match
// should not appear when searching with the @ alias below.
let historyTitle = "fire";
// Set a mock engine as the default so we don't hit the network below when we
// do searches that return the default engine heuristic result.
Services.search.defaultEngine = await Services.search.addEngineWithDetails(
DEFAULT_ENGINE_NAME,
{ template: "http://example.com/?s=%S" }
);
// History matches should not appear with @aliases, so this visit should not
// appear when searching with @aliases below.
await PlacesTestUtils.addVisits({
uri: engine.searchForm,
title: historyTitle,
title: HISTORY_TITLE,
});
// Search in both a non-private and private context.
for (let private of [false, true]) {
// Use a normal alias and then one with an "@". For the @ alias, the only
// matches should be the search suggestions -- no history matches.
for (let alias of ["moz", "@moz"]) {
engine.alias = alias;
Assert.equal(engine.alias, alias);
// Search for "alias"
let context = createContext(`${alias}`, { isPrivate: private });
let expectedMatches = [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: "",
heuristic: true,
}),
];
if (alias[0] != "@") {
expectedMatches.push(
makeVisitResult(context, {
uri: "http://localhost:9000/search?terms=",
title: historyTitle,
})
);
}
await check_results({
context,
matches: expectedMatches,
});
// Search for "alias " (trailing space)
context = createContext(`${alias} `, { isPrivate: private });
expectedMatches = [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: "",
heuristic: true,
}),
];
if (alias[0] != "@") {
expectedMatches.push(
makeVisitResult(context, {
uri: "http://localhost:9000/search?terms=",
title: historyTitle,
})
);
}
await check_results({
context,
matches: expectedMatches,
});
// Search for "alias historyTitle" -- Include the history title so that
// the history result is eligible to be shown. Whether or not it's
// actually shown depends on the alias: If it's an @ alias, it shouldn't
// be shown.
context = createContext(`${alias} ${historyTitle}`, {
isPrivate: private,
});
expectedMatches = [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: historyTitle,
heuristic: true,
}),
];
// Suggestions should be shown in a non-private context but not in a
// private context.
if (!private) {
expectedMatches.push(
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: historyTitle,
suggestion: `${historyTitle} foo`,
}),
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: historyTitle,
suggestion: `${historyTitle} bar`,
})
);
}
if (alias[0] != "@") {
expectedMatches.push(
makeVisitResult(context, {
uri: "http://localhost:9000/search?terms=",
title: historyTitle,
})
);
}
await check_results({
context,
matches: expectedMatches,
});
}
}
engine.alias = "";
await PlacesUtils.bookmarks.eraseEverything();
await PlacesUtils.history.clear();
});
add_task(async function disabled_urlbarSuggestions() {
// A non-token alias without a trailing space shouldn't be recognized as a
// keyword. It should be treated as part of the search string.
add_task(async function nonTokenAlias_noTrailingSpace() {
Services.prefs.setBoolPref("browser.urlbar.update2", true);
let alias = "moz";
engine.alias = alias;
Assert.equal(engine.alias, alias);
let context = createContext(alias, { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: DEFAULT_ENGINE_NAME,
query: alias,
heuristic: true,
}),
makeSearchResult(context, {
engineName: DEFAULT_ENGINE_NAME,
query: alias,
heuristic: false,
inPrivateWindow: true,
isPrivateEngine: false,
}),
],
});
Services.prefs.clearUserPref("browser.urlbar.update2");
});
// With update2 disabled, a non-token alias without a trailing space should be
// recognized as a keyword, and the history result should be included.
add_task(async function nonTokenAlias_noTrailingSpace_legacy() {
Services.prefs.setBoolPref("browser.urlbar.update2", false);
let alias = "moz";
engine.alias = alias;
Assert.equal(engine.alias, alias);
for (let isPrivate of [false, true]) {
let context = createContext(alias, { isPrivate });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: "",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://localhost:9000/search?terms=",
title: HISTORY_TITLE,
}),
],
});
}
Services.prefs.clearUserPref("browser.urlbar.update2");
});
// A non-token alias with a trailing space should be recognized as a keyword,
// and the history result should be included.
add_task(async function nonTokenAlias_trailingSpace() {
let alias = "moz";
engine.alias = alias;
Assert.equal(engine.alias, alias);
for (let isPrivate of [false, true]) {
let context = createContext(alias + " ", { isPrivate });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: "",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://localhost:9000/search?terms=",
title: HISTORY_TITLE,
}),
],
});
}
});
// Search for "alias HISTORY_TITLE" with a non-token alias in a non-private
// context. The remote suggestions and history result should be shown.
add_task(async function nonTokenAlias_history_nonPrivate() {
let alias = "moz";
engine.alias = alias;
Assert.equal(engine.alias, alias);
let context = createContext(`${alias} ${HISTORY_TITLE}`, {
isPrivate: false,
});
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: HISTORY_TITLE,
heuristic: true,
}),
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: HISTORY_TITLE,
suggestion: `${HISTORY_TITLE} foo`,
}),
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: HISTORY_TITLE,
suggestion: `${HISTORY_TITLE} bar`,
}),
makeVisitResult(context, {
uri: "http://localhost:9000/search?terms=",
title: HISTORY_TITLE,
}),
],
});
});
// Search for "alias HISTORY_TITLE" with a non-token alias in a private context.
// The history result should be shown, but not the remote suggestions.
add_task(async function nonTokenAlias_history_private() {
let alias = "moz";
engine.alias = alias;
Assert.equal(engine.alias, alias);
let context = createContext(`${alias} ${HISTORY_TITLE}`, {
isPrivate: true,
});
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: HISTORY_TITLE,
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://localhost:9000/search?terms=",
title: HISTORY_TITLE,
}),
],
});
});
// A token alias without a trailing space should be autofilled with a trailing
// space and recognized as a keyword with a keyword offer.
add_task(async function tokenAlias_noTrailingSpace() {
let alias = "@moz";
engine.alias = alias;
Assert.equal(engine.alias, alias);
for (let isPrivate of [false, true]) {
let context = createContext(alias, { isPrivate });
await check_results({
context,
autofilled: alias + " ",
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
keywordOffer: UrlbarUtils.KEYWORD_OFFER.HIDE,
query: "",
heuristic: true,
}),
],
});
}
});
// A token alias with a trailing space should be recognized as a keyword without
// a keyword offer.
add_task(async function tokenAlias_trailingSpace() {
Services.prefs.setBoolPref("browser.urlbar.update2", true);
let alias = "@moz";
engine.alias = alias;
Assert.equal(engine.alias, alias);
for (let isPrivate of [false, true]) {
let context = createContext(alias + " ", { isPrivate });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: "",
heuristic: true,
}),
],
});
}
Services.prefs.clearUserPref("browser.urlbar.update2");
});
// Search for "alias HISTORY_TITLE" with a token alias in a non-private context.
// The remote suggestions should be shown, but not the history result.
add_task(async function tokenAlias_history_nonPrivate() {
let alias = "@moz";
engine.alias = alias;
Assert.equal(engine.alias, alias);
let context = createContext(`${alias} ${HISTORY_TITLE}`, {
isPrivate: false,
});
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: HISTORY_TITLE,
heuristic: true,
}),
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: HISTORY_TITLE,
suggestion: `${HISTORY_TITLE} foo`,
}),
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: HISTORY_TITLE,
suggestion: `${HISTORY_TITLE} bar`,
}),
],
});
});
// Search for "alias HISTORY_TITLE" with a token alias in a private context.
// Neither the history result nor the remote suggestions should be shown.
add_task(async function tokenAlias_history_private() {
let alias = "@moz";
engine.alias = alias;
Assert.equal(engine.alias, alias);
let context = createContext(`${alias} ${HISTORY_TITLE}`, {
isPrivate: true,
});
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: HISTORY_TITLE,
heuristic: true,
}),
],
});
});
// Even when they're disabled, suggestions should still be returned when using a
// token alias in a non-private context.
add_task(async function suggestionsDisabled_nonPrivate() {
Services.prefs.setBoolPref(SUGGEST_PREF, false);
Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true);
let alias = "@moz";
engine.alias = alias;
Assert.equal(engine.alias, alias);
for (let private of [false, true]) {
let context = createContext(`${alias} term`, { isPrivate: private });
let expectedMatches = [
let context = createContext(`${alias} term`, { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: "term",
heuristic: true,
}),
];
if (!private) {
expectedMatches.push(
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: "term",
suggestion: "term foo",
})
);
expectedMatches.push(
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: "term",
suggestion: "term bar",
})
);
}
await check_results({
context,
matches: expectedMatches,
});
}
engine.alias = "";
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: "term",
suggestion: "term foo",
}),
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: "term",
suggestion: "term bar",
}),
],
});
Services.prefs.clearUserPref(SUGGEST_PREF);
Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF);
});
// Suggestions should not be returned when using a token alias in a private
// context.
add_task(async function suggestionsDisabled_private() {
Services.prefs.setBoolPref(SUGGEST_PREF, false);
Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true);
let alias = "@moz";
engine.alias = alias;
Assert.equal(engine.alias, alias);
let context = createContext(`${alias} term`, { isPrivate: true });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SUGGESTIONS_ENGINE_NAME,
alias,
query: "term",
heuristic: true,
}),
],
});
Services.prefs.clearUserPref(SUGGEST_PREF);
Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF);
});

Просмотреть файл

@ -205,6 +205,7 @@ add_task(async function test_escaped_chars() {
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
uri: "https://www.mozilla.org/%E5%95%8A-test",
title: "https://www.mozilla.org/啊-test",
iconUri: "page-icon:https://www.mozilla.org/",

Просмотреть файл

@ -237,7 +237,102 @@ add_task(async function test_simpleQuery() {
BrowserTestUtils.removeTab(tab);
});
add_task(async function test_searchAlias() {
add_task(async function test_searchMode_enter() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.urlbar.update2", true],
["browser.urlbar.update2.oneOffsRefresh", true],
],
});
Services.telemetry.clearScalars();
Services.telemetry.clearEvents();
let resultIndexHist = TelemetryTestUtils.getAndClearHistogram(
"FX_URLBAR_SELECTED_RESULT_INDEX"
);
let resultTypeHist = TelemetryTestUtils.getAndClearHistogram(
"FX_URLBAR_SELECTED_RESULT_TYPE_2"
);
let resultIndexByTypeHist = TelemetryTestUtils.getAndClearKeyedHistogram(
"FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE_2"
);
let resultMethodHist = TelemetryTestUtils.getAndClearHistogram(
"FX_URLBAR_SELECTED_RESULT_METHOD"
);
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"about:blank"
);
info("Enter search mode using an alias and a query.");
let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
await searchInAwesomebar("mozalias query");
EventUtils.synthesizeKey("KEY_Enter");
await p;
// Check if the scalars contain the expected values.
const scalars = TelemetryTestUtils.getProcessScalars("parent", true, false);
TelemetryTestUtils.assertKeyedScalar(
scalars,
SCALAR_SEARCHMODE,
"search_enter",
1
);
Assert.equal(
Object.keys(scalars[SCALAR_SEARCHMODE]).length,
1,
"This search must only increment one entry in the scalar."
);
// Also check events.
TelemetryTestUtils.assertEvents(
[
[
"navigation",
"search",
"urlbar_searchmode",
"enter",
{ engine: "other-MozSearch" },
],
],
{ category: "navigation", method: "search" }
);
// Check the histograms as well.
TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
TelemetryTestUtils.assertHistogram(
resultTypeHist,
UrlbarUtils.SELECTED_RESULT_TYPES.searchengine,
1
);
TelemetryTestUtils.assertKeyedHistogramValue(
resultIndexByTypeHist,
"searchengine",
0,
1
);
TelemetryTestUtils.assertHistogram(
resultMethodHist,
UrlbarTestUtils.SELECTED_RESULT_METHODS.enter,
1
);
BrowserTestUtils.removeTab(tab);
await SpecialPowers.popPrefEnv();
});
// This subtest can be removed with the update2 pref.
add_task(async function test_searchAlias_legacy() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.urlbar.update2", false],
["browser.urlbar.update2.oneOffsRefresh", false],
],
});
Services.telemetry.clearScalars();
Services.telemetry.clearEvents();
@ -316,6 +411,7 @@ add_task(async function test_searchAlias() {
);
BrowserTestUtils.removeTab(tab);
await SpecialPowers.popPrefEnv();
});
// Performs a search using the first result, a one-off button, and the Return

Просмотреть файл

@ -50,7 +50,11 @@ function assertSearchModeScalar(entry, key) {
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.update2", true]],
set: [
["browser.urlbar.update2", true],
["browser.urlbar.update2.localOneOffs", true],
["browser.urlbar.update2.oneOffsRefresh", true],
],
});
// Create a new search engine.
@ -290,10 +294,13 @@ add_task(async function test_keywordoffer() {
"about:blank"
);
// Enter search mode by selecting a keywordoffer result.
// Do a search for "@" + our test alias. It should autofill with a trailing
// space, and the heuristic result should be an autofill result with a keyword
// offer.
let alias = "@" + ENGINE_ALIAS;
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: ENGINE_ALIAS,
value: alias,
});
let keywordOfferResult = await UrlbarTestUtils.getDetailsOfResultAt(
window,
@ -301,7 +308,7 @@ add_task(async function test_keywordoffer() {
);
Assert.equal(
keywordOfferResult.searchParams.keyword,
ENGINE_ALIAS,
alias,
"The first result should be a keyword search result with the correct alias."
);

Просмотреть файл

@ -395,22 +395,6 @@ function makeKeyForMatch(match) {
return [key, prefix, action];
}
/**
* Returns the portion of a string starting at the index where another string
* ends.
*
* @param {string} sourceStr
* The string to search within.
* @param {string} targetStr
* The string to search for.
* @returns {string} The substring within sourceStr where targetStr ends, or the
* empty string if targetStr does not occur in sourceStr.
*/
function substringAfter(sourceStr, targetStr) {
let index = sourceStr.indexOf(targetStr);
return index < 0 ? "" : sourceStr.substr(index + targetStr.length);
}
/**
* Makes a moz-action url for the given action and set of parameters.
*
@ -493,6 +477,7 @@ function Search(
this._userContextId = queryContext.userContextId;
this._currentPage = queryContext.currentPage;
this._searchModeEngine = queryContext.searchMode?.engineName;
this._searchMode = queryContext.searchMode;
} else {
let params = new Set(searchParam.split(" "));
this._enableActions = params.has("enable-actions");
@ -1009,6 +994,11 @@ Search.prototype = {
},
async _matchFirstHeuristicResult(conn) {
if (this._searchMode) {
// Use UrlbarProviderHeuristicFallback.
return false;
}
// We always try to make the first result a special "heuristic" result. The
// heuristics below determine what type of result it will be, if any.
@ -1047,7 +1037,7 @@ Search.prototype = {
return false;
}
let searchString = substringAfter(
let searchString = UrlbarUtils.substringAfter(
this._originalSearchString,
keyword
).trim();
@ -1106,11 +1096,18 @@ Search.prototype = {
return false;
}
let query = UrlbarUtils.substringAfter(this._originalSearchString, alias);
// Match an alias only when it has a space after it. If there's no trailing
// space, then continue to treat it as part of the search string.
if (UrlbarPrefs.get("update2") && !query.startsWith(" ")) {
return false;
}
this._searchEngineAliasMatch = {
engine,
alias,
query: substringAfter(this._originalSearchString, alias).trim(),
isTokenAlias: alias.startsWith("@"),
query: query.trimStart(),
};
this._addSearchEngineMatch(this._searchEngineAliasMatch);
if (!this._keywordSubstitute) {

Просмотреть файл

@ -11,6 +11,9 @@ const SUGGESTIONS_ENGINE_NAME = "engine-suggestions.xml";
// Basic test that uses two engines, a GET engine and a POST engine, neither
// providing search suggestions.
add_task(async function basicGetAndPost() {
// This test requires update2. See also test_search_engine_alias_legacy.js.
Services.prefs.setBoolPref("browser.urlbar.update2", true);
// Note that head_autocomplete.js has already added a MozSearch engine.
// Here we add another engine with a search alias.
await Services.search.addEngineWithDetails("AliasedGETMozSearch", {
@ -34,15 +37,7 @@ add_task(async function basicGetAndPost() {
await check_autocomplete({
search: alias,
searchParam: "enable-actions",
matches: [
makeSearchMatch(`${alias} `, {
engineName: `Aliased${alias.toUpperCase()}MozSearch`,
searchQuery: "",
alias,
heuristic: true,
}),
historyMatch,
],
matches: [],
});
await check_autocomplete({

Просмотреть файл

@ -0,0 +1,120 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const SUGGESTIONS_ENGINE_NAME = "engine-suggestions.xml";
/**
* This file can be deleted when update2 is enabled by default.
*
* Tests search engine aliases. See
* browser/components/urlbar/tests/browser/browser_tokenAlias.js for tests of
* the token alias list (i.e. showing all aliased engines on a "@" query).
*/
// Basic test that uses two engines, a GET engine and a POST engine, neither
// providing search suggestions.
add_task(async function basicGetAndPost() {
Services.prefs.setBoolPref("browser.urlbar.update2", false);
// Note that head_autocomplete.js has already added a MozSearch engine.
// Here we add another engine with a search alias.
await Services.search.addEngineWithDetails("AliasedGETMozSearch", {
alias: "get",
method: "GET",
template: "http://s.example.com/search",
});
await Services.search.addEngineWithDetails("AliasedPOSTMozSearch", {
alias: "post",
method: "POST",
template: "http://s.example.com/search",
});
await PlacesTestUtils.addVisits("http://s.example.com/search?q=firefox");
let historyMatch = {
value: "http://s.example.com/search?q=firefox",
comment: "test visit for http://s.example.com/search?q=firefox",
};
for (let alias of ["get", "post"]) {
await check_autocomplete({
search: alias,
searchParam: "enable-actions",
matches: [
makeSearchMatch(`${alias} `, {
engineName: `Aliased${alias.toUpperCase()}MozSearch`,
searchQuery: "",
alias,
heuristic: true,
}),
historyMatch,
],
});
await check_autocomplete({
search: `${alias} `,
searchParam: "enable-actions",
matches: [
makeSearchMatch(`${alias} `, {
engineName: `Aliased${alias.toUpperCase()}MozSearch`,
searchQuery: "",
alias,
heuristic: true,
}),
historyMatch,
],
});
await check_autocomplete({
search: `${alias} fire`,
searchParam: "enable-actions",
matches: [
makeSearchMatch(`${alias} fire`, {
engineName: `Aliased${alias.toUpperCase()}MozSearch`,
searchQuery: "fire",
alias,
heuristic: true,
}),
historyMatch,
],
});
await check_autocomplete({
search: `${alias} mozilla`,
searchParam: "enable-actions",
matches: [
makeSearchMatch(`${alias} mozilla`, {
engineName: `Aliased${alias.toUpperCase()}MozSearch`,
searchQuery: "mozilla",
alias,
heuristic: true,
}),
],
});
await check_autocomplete({
search: `${alias} MoZiLlA`,
searchParam: "enable-actions",
matches: [
makeSearchMatch(`${alias} MoZiLlA`, {
engineName: `Aliased${alias.toUpperCase()}MozSearch`,
searchQuery: "MoZiLlA",
alias,
heuristic: true,
}),
],
});
await check_autocomplete({
search: `${alias} mozzarella mozilla`,
searchParam: "enable-actions",
matches: [
makeSearchMatch(`${alias} mozzarella mozilla`, {
engineName: `Aliased${alias.toUpperCase()}MozSearch`,
searchQuery: "mozzarella mozilla",
alias,
heuristic: true,
}),
],
});
}
await cleanup();
});

Просмотреть файл

@ -26,6 +26,7 @@ support-files =
[test_remote_tab_matches.js]
skip-if = !sync
[test_search_engine_alias.js]
[test_search_engine_alias_legacy.js]
[test_search_engine_restyle.js]
[test_special_search.js]
[test_swap_protocol.js]