Bug 1926241 - Provide tab-to-search results via actions. r=urlbar-reviewers,mak

Differential Revision: https://phabricator.services.mozilla.com/D227236
This commit is contained in:
Dale Harvey
2024-11-08 13:35:12 +00:00
parent fab02dfc13
commit d6bf7c5a2d
22 changed files with 346 additions and 132 deletions

View File

@@ -32,11 +32,10 @@ export class ActionsProvider {
* Query for actions based on the current users input. * Query for actions based on the current users input.
* *
* @param {UrlbarQueryContext} _queryContext The query context object. * @param {UrlbarQueryContext} _queryContext The query context object.
* @param {UrlbarController} _controller The urlbar controller.
* @returns {Array} An array of ActionResult's * @returns {Array} An array of ActionResult's
* @abstract * @abstract
*/ */
async queryActions(_queryContext, _controller) { async queryActions(_queryContext) {
throw new Error("Not implemented."); throw new Error("Not implemented.");
} }
@@ -65,6 +64,7 @@ export class ActionsResult {
#icon; #icon;
#dataset; #dataset;
#onPick; #onPick;
#onSelection;
/** /**
* @param {object} options * @param {object} options
@@ -82,14 +82,17 @@ export class ActionsResult {
* can be used to pass data when it is selected. * can be used to pass data when it is selected.
* @param { Function} options.onPick * @param { Function} options.onPick
* A callback function called when the result has been picked. * A callback function called when the result has been picked.
* @param { Function} options.onSelection
* A callback function called when the result has been selected.
*/ */
constructor({ key, l10nId, l10nArgs, icon, dataset, onPick }) { constructor({ key, l10nId, l10nArgs, icon, dataset, onPick, onSelection }) {
this.#key = key; this.#key = key;
this.#l10nId = l10nId; this.#l10nId = l10nId;
this.#l10nArgs = l10nArgs; this.#l10nArgs = l10nArgs;
this.#icon = icon; this.#icon = icon;
this.#dataset = dataset; this.#dataset = dataset;
this.#onPick = onPick; this.#onPick = onPick;
this.#onSelection = onSelection;
} }
get key() { get key() {
@@ -115,4 +118,8 @@ export class ActionsResult {
get onPick() { get onPick() {
return this.#onPick; return this.#onPick;
} }
get onSelection() {
return this.#onSelection;
}
} }

View File

@@ -17,7 +17,9 @@ ChromeUtils.defineESModuleGetters(lazy, {
loadAndParseOpenSearchEngine: loadAndParseOpenSearchEngine:
"resource://gre/modules/OpenSearchLoader.sys.mjs", "resource://gre/modules/OpenSearchLoader.sys.mjs",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs", UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
UrlbarProviderAutofill: "resource:///modules/UrlbarProviderAutofill.sys.mjs",
UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.sys.mjs", UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.sys.mjs",
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs",
}); });
const ENABLED_PREF = "contextualSearch.enabled"; const ENABLED_PREF = "contextualSearch.enabled";
@@ -31,9 +33,15 @@ const CONTEXTUAL_SEARCH_ENGINE = "contextual-search-engine";
* by the active view if it utilizes OpenSearch. * by the active view if it utilizes OpenSearch.
*/ */
class ProviderContextualSearch extends ActionsProvider { class ProviderContextualSearch extends ActionsProvider {
// Cache the results of engines looked up by host, these can be
// expensive lookups and we don't want to redo the query every time
// the user types when the result will not change.
#hostEngines = new Map();
// Store the engine returned to the user in case they select it.
#resultEngine = null;
constructor() { constructor() {
super(); super();
this.engines = new Map();
} }
get name() { get name() {
@@ -44,33 +52,36 @@ class ProviderContextualSearch extends ActionsProvider {
return ( return (
queryContext.trimmedSearchString && queryContext.trimmedSearchString &&
lazy.UrlbarPrefs.get(ENABLED_PREF) && lazy.UrlbarPrefs.get(ENABLED_PREF) &&
!queryContext.searchMode !queryContext.searchMode &&
queryContext.tokens.length == 1 &&
queryContext.tokens[0].type != lazy.UrlbarTokenizer.TYPE.URL &&
lazy.UrlbarPrefs.get("suggest.engines")
); );
} }
async queryActions(queryContext) { async queryActions(queryContext) {
let instance = this.queryInstance; this.#resultEngine = await this.matchEngine(queryContext);
const hostname = URL.parse(queryContext.currentPage)?.hostname;
// This happens on about pages, which won't have associated engines
if (!hostname) {
return null;
}
let { engine } = await this.fetchEngineDetails();
let icon = engine?.icon || (await engine?.getIconURL?.());
let defaultEngine = lazy.UrlbarSearchUtils.getDefaultEngine(); let defaultEngine = lazy.UrlbarSearchUtils.getDefaultEngine();
if ( if (
!engine || this.#resultEngine &&
engine.name === defaultEngine?.name || this.#resultEngine.engine?.name != defaultEngine?.name
instance != this.queryInstance
) { ) {
return [await this.createActionResult(this.#resultEngine)];
}
return null; return null;
} }
return [ onSearchSessionEnd() {
new ActionsResult({ // We cache the results for a host while the user is typing, clear
// when the search session ends as the results for the host may
// change by the next search session.
this.#hostEngines.clear();
}
async createActionResult({ type, engine }) {
let icon = engine?.icon || (await engine?.getIconURL?.());
return new ActionsResult({
key: "contextual-search", key: "contextual-search",
l10nId: "urlbar-result-search-with", l10nId: "urlbar-result-search-with",
l10nArgs: { engine: engine.name || engine.title }, l10nArgs: { engine: engine.name || engine.title },
@@ -78,56 +89,148 @@ class ProviderContextualSearch extends ActionsProvider {
onPick: (context, controller) => { onPick: (context, controller) => {
this.pickAction(context, controller); this.pickAction(context, controller);
}, },
}), onSelection: async (result, element) => {
]; // We don't enter preview searchMode unless the engine is installed.
if (type != INSTALLED_ENGINE) {
return;
}
result.payload.engine = engine.name;
result.payload.query = "";
element.ownerGlobal.gURLBar.maybeConfirmSearchModeFromResult({
result,
checkValue: false,
startQuery: false,
});
},
});
}
/*
* Searches for engines that we want to present to the user based on their
* current host and the search query they have entered.
*/
async matchEngine(queryContext) {
// First find currently installed engines that match the current query
// if the user has DuckDuckGo installed and types "duck", offer that.
let engine = await this.#matchTabToSearchEngine(queryContext);
if (engine) {
return engine;
} }
async fetchEngineDetails() {
let browser = let browser =
lazy.BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser; lazy.BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser;
let hostname; let host;
try { try {
// currentURI.host will throw on pages without a host ("about:" pages). host = UrlbarUtils.stripPrefixAndTrim(browser.currentURI.host, {
hostname = browser.currentURI.host;
} catch (e) {
return null;
}
if (this.engines.has(hostname)) {
return { type: INSTALLED_ENGINE, engine: this.engines.get(hostname) };
}
// Strip www. to allow for partial matches when looking for an engine.
const [host] = UrlbarUtils.stripPrefixAndTrim(hostname, {
stripWww: true, stripWww: true,
}); })[0];
let engines = await lazy.UrlbarSearchUtils.enginesForDomainPrefix(host, { } catch (e) {
matchAllDomainLevels: true, // about: pages will throw when access currentURI.host, ignore.
});
if (engines.length) {
return { type: INSTALLED_ENGINE, engine: engines[0] };
} }
// Find engines based on the current host.
if (host && !this.#hostEngines.has(host)) {
// Find currently installed engines that match the current host. If
// the user is on wikipedia.com, offer that.
let hostEngine = await this.#matchInstalledEngine(host);
if (!hostEngine) {
// Find engines in the search configuration but not installed that match
// the current host. If the user is on ecosia.com and starts searching
// offer ecosia's search.
let contextualEngineConfig = let contextualEngineConfig =
await Services.search.findContextualSearchEngineByHost(host); await Services.search.findContextualSearchEngineByHost(host);
if (contextualEngineConfig) { if (contextualEngineConfig) {
return { hostEngine = {
type: CONTEXTUAL_SEARCH_ENGINE, type: CONTEXTUAL_SEARCH_ENGINE,
engine: contextualEngineConfig, engine: contextualEngineConfig,
}; };
} }
}
// Cache the result against this host so we do not need to rerun
// the same query every keystroke.
this.#hostEngines.set(host, hostEngine);
if (hostEngine) {
return hostEngine;
}
} else if (host) {
let cachedEngine = this.#hostEngines.get(host);
if (cachedEngine) {
return cachedEngine;
}
}
// Lastly match any openSearch
if (browser?.engines?.length) { if (browser?.engines?.length) {
return { type: OPEN_SEARCH_ENGINE, engine: browser.engines[0] }; return { type: OPEN_SEARCH_ENGINE, engine: browser.engines[0] };
} }
return {}; return null;
}
async #matchInstalledEngine(query) {
let engines = await lazy.UrlbarSearchUtils.enginesForDomainPrefix(query, {
matchAllDomainLevels: true,
});
if (engines.length) {
return { type: INSTALLED_ENGINE, engine: engines[0] };
}
return null;
}
/*
* This logic is copied from `UrlbarProviderTabToSearch.sys.mjs` and
* matches a users search query to an installed engine.
*/
async #matchTabToSearchEngine(queryContext) {
let searchStr = queryContext.trimmedSearchString.toLocaleLowerCase();
let engines = await lazy.UrlbarSearchUtils.enginesForDomainPrefix(
searchStr,
{
matchAllDomainLevels: true,
}
);
if (!engines.length) {
return null;
}
let partialMatchEnginesByHost = new Map();
for (let engine of engines) {
let [host] = UrlbarUtils.stripPrefixAndTrim(engine.searchUrlDomain, {
stripWww: true,
});
if (host.startsWith(searchStr)) {
return { type: INSTALLED_ENGINE, engine };
}
if (host.includes("." + searchStr)) {
partialMatchEnginesByHost.set(engine.searchUrlDomain, engine);
}
let baseDomain = Services.eTLD.getBaseDomainFromHost(
engine.searchUrlDomain
);
if (baseDomain.startsWith(searchStr)) {
partialMatchEnginesByHost.set(baseDomain, engine);
}
}
if (partialMatchEnginesByHost.size) {
let host = await lazy.UrlbarProviderAutofill.getTopHostOverThreshold(
queryContext,
Array.from(partialMatchEnginesByHost.keys())
);
if (host) {
let engine = partialMatchEnginesByHost.get(host);
return { type: INSTALLED_ENGINE, engine };
}
}
return null;
} }
async pickAction(queryContext, controller, _element) { async pickAction(queryContext, controller, _element) {
let { type, engine } = await this.fetchEngineDetails(); let { type, engine } = this.#resultEngine;
let enterSeachMode = true; let enterSearchMode = true;
let engineObj; let engineObj;
if ( if (
@@ -142,7 +245,7 @@ class ProviderContextualSearch extends ActionsProvider {
engineObj = new lazy.OpenSearchEngine({ engineObj = new lazy.OpenSearchEngine({
engineData: openSearchEngineData, engineData: openSearchEngineData,
}); });
enterSeachMode = false; enterSearchMode = false;
} else if (type == INSTALLED_ENGINE || type == CONTEXTUAL_SEARCH_ENGINE) { } else if (type == INSTALLED_ENGINE || type == CONTEXTUAL_SEARCH_ENGINE) {
engineObj = engine; engineObj = engine;
} }
@@ -151,7 +254,7 @@ class ProviderContextualSearch extends ActionsProvider {
engineObj, engineObj,
queryContext.searchString, queryContext.searchString,
controller.input, controller.input,
enterSeachMode enterSearchMode
); );
} }
@@ -168,6 +271,7 @@ class ProviderContextualSearch extends ActionsProvider {
); );
} }
engineObj.setAttr("auto-installed", true); engineObj.setAttr("auto-installed", true);
this.#hostEngines.clear();
return engineObj; return engineObj;
} }
@@ -181,10 +285,6 @@ class ProviderContextualSearch extends ActionsProvider {
}); });
input.window.gBrowser.selectedBrowser.focus(); input.window.gBrowser.selectedBrowser.focus();
} }
resetForTesting() {
this.engines = new Map();
}
} }
export var ActionsProviderContextualSearch = new ProviderContextualSearch(); export var ActionsProviderContextualSearch = new ProviderContextualSearch();

View File

@@ -27,6 +27,8 @@ ChromeUtils.defineESModuleGetters(lazy, {
UrlbarEventBufferer: "resource:///modules/UrlbarEventBufferer.sys.mjs", UrlbarEventBufferer: "resource:///modules/UrlbarEventBufferer.sys.mjs",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs", UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
UrlbarQueryContext: "resource:///modules/UrlbarUtils.sys.mjs", UrlbarQueryContext: "resource:///modules/UrlbarUtils.sys.mjs",
UrlbarProviderGlobalActions:
"resource:///modules/UrlbarProviderGlobalActions.sys.mjs",
UrlbarProviderOpenTabs: "resource:///modules/UrlbarProviderOpenTabs.sys.mjs", UrlbarProviderOpenTabs: "resource:///modules/UrlbarProviderOpenTabs.sys.mjs",
UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.sys.mjs", UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.sys.mjs",
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs", UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs",
@@ -1035,9 +1037,11 @@ export class UrlbarInput {
// manner was agreed on as a compromise between consistent UX and // manner was agreed on as a compromise between consistent UX and
// engineering effort. See review discussion at bug 1667766. // engineering effort. See review discussion at bug 1667766.
if ( if (
result.heuristic && (this.searchMode?.isPreview &&
result.providerName == lazy.UrlbarProviderGlobalActions.name) ||
(result.heuristic &&
this.searchMode?.isPreview && this.searchMode?.isPreview &&
this.view.oneOffSearchButtons.selectedButton this.view.oneOffSearchButtons.selectedButton)
) { ) {
this.confirmSearchMode(); this.confirmSearchMode();
this.search(this.value); this.search(this.value);
@@ -2523,7 +2527,11 @@ export class UrlbarInput {
let engine = Services.search.getEngineByName(this.searchMode.engineName); let engine = Services.search.getEngineByName(this.searchMode.engineName);
// If the host we are navigating to matches the host of the current // If the host we are navigating to matches the host of the current
// searchModes engine host then persist searchMode. // searchModes engine host then persist searchMode.
try {
return uri.host != engine.searchUrlDomain; return uri.host != engine.searchUrlDomain;
} catch (e) {
// Accessing .host will throw on about pages.
}
} }
return true; return true;
} }

View File

@@ -23,6 +23,7 @@ const SUGGESTED_INDEX = 1;
const SCOTCH_BONNET_PREF = "scotchBonnet.enableOverride"; const SCOTCH_BONNET_PREF = "scotchBonnet.enableOverride";
const ACTIONS_PREF = "secondaryActions.featureGate"; const ACTIONS_PREF = "secondaryActions.featureGate";
const QUICK_ACTIONS_PREF = "suggest.quickactions";
ChromeUtils.defineESModuleGetters(lazy, { ChromeUtils.defineESModuleGetters(lazy, {
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs", UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
@@ -54,8 +55,9 @@ class ProviderGlobalActions extends UrlbarProvider {
isActive() { isActive() {
return ( return (
lazy.UrlbarPrefs.get(SCOTCH_BONNET_PREF) || (lazy.UrlbarPrefs.get(SCOTCH_BONNET_PREF) ||
lazy.UrlbarPrefs.get(ACTIONS_PREF) lazy.UrlbarPrefs.get(ACTIONS_PREF)) &&
lazy.UrlbarPrefs.get(QUICK_ACTIONS_PREF)
); );
} }
@@ -87,6 +89,11 @@ class ProviderGlobalActions extends UrlbarProvider {
addCallback(this, result); addCallback(this, result);
} }
onSelection(result, element) {
let key = element.dataset.action;
this.#actions.get(key).onSelection(result, element);
}
onEngagement(queryContext, controller, details) { onEngagement(queryContext, controller, details) {
let key = details.element.dataset.action; let key = details.element.dataset.action;
let options = this.#actions.get(key).onPick(queryContext, controller); let options = this.#actions.get(key).onPick(queryContext, controller);
@@ -96,6 +103,12 @@ class ProviderGlobalActions extends UrlbarProvider {
controller.view.close(); controller.view.close();
} }
onSearchSessionEnd(queryContext, controller, details) {
for (let provider of globalActionsProviders) {
provider.onSearchSessionEnd?.(queryContext, controller, details);
}
}
getViewTemplate(result) { getViewTemplate(result) {
return { return {
children: [ children: [

View File

@@ -86,6 +86,9 @@ class ProviderRecentSearches extends UrlbarProvider {
let engine = lazy.UrlbarSearchUtils.getDefaultEngine( let engine = lazy.UrlbarSearchUtils.getDefaultEngine(
queryContext.isPrivate queryContext.isPrivate
); );
if (!engine) {
return;
}
let results = await lazy.FormHistory.search(["value", "lastUsed"], { let results = await lazy.FormHistory.search(["value", "lastUsed"], {
fieldname: "searchbar-history", fieldname: "searchbar-history",
source: engine.name, source: engine.name,

View File

@@ -15,9 +15,13 @@ import {
const lazy = {}; const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, { ChromeUtils.defineESModuleGetters(lazy, {
ActionsProviderContextualSearch:
"resource:///modules/ActionsProviderContextualSearch.sys.mjs",
UrlbarView: "resource:///modules/UrlbarView.sys.mjs", UrlbarView: "resource:///modules/UrlbarView.sys.mjs",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs", UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
UrlbarProviderAutofill: "resource:///modules/UrlbarProviderAutofill.sys.mjs", UrlbarProviderAutofill: "resource:///modules/UrlbarProviderAutofill.sys.mjs",
UrlbarProviderGlobalActions:
"resource:///modules/UrlbarProviderGlobalActions.sys.mjs",
UrlbarResult: "resource:///modules/UrlbarResult.sys.mjs", UrlbarResult: "resource:///modules/UrlbarResult.sys.mjs",
UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.sys.mjs", UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.sys.mjs",
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs", UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs",
@@ -132,7 +136,11 @@ class ProviderTabToSearch extends UrlbarProvider {
queryContext.searchString && queryContext.searchString &&
queryContext.tokens.length == 1 && queryContext.tokens.length == 1 &&
!queryContext.searchMode && !queryContext.searchMode &&
lazy.UrlbarPrefs.get("suggest.engines") lazy.UrlbarPrefs.get("suggest.engines") &&
!(
lazy.UrlbarProviderGlobalActions.isActive(queryContext) &&
lazy.ActionsProviderContextualSearch.isActive(queryContext)
)
); );
} }

View File

@@ -20,6 +20,15 @@ const CONFIG = [
}, },
}, },
}, },
{
identifier: "non-default-engine",
base: {
urls: {
search: { base: "https://example.net", searchTermParamName: "q" },
},
},
},
{ {
identifier: "config-engine", identifier: "config-engine",
base: { base: {
@@ -27,6 +36,8 @@ const CONFIG = [
search: { base: "https://example.org", searchTermParamName: "q" }, search: { base: "https://example.org", searchTermParamName: "q" },
}, },
}, },
// Only enable in particular locale so it is not installed by default.
variants: [{ environment: { locales: ["sl"] } }],
}, },
]; ];
@@ -40,6 +51,13 @@ let loadUri = async uri => {
await loaded; await loaded;
}; };
let updateConfig = async config => {
await waitForIdle();
await SearchTestUtils.setRemoteSettingsConfig(config);
await Services.search.wrappedJSObject.reset();
await Services.search.init();
};
add_setup(async function setup() { add_setup(async function setup() {
await SpecialPowers.pushPrefEnv({ await SpecialPowers.pushPrefEnv({
set: [ set: [
@@ -48,26 +66,14 @@ add_setup(async function setup() {
], ],
}); });
let ext = await SearchTestUtils.installSearchExtension({ registerCleanupFunction(async () => {
name: "Contextual", await updateConfig(null);
search_url: "https://example.com/browser", Services.search.restoreDefaultEngines();
}); });
await AddonTestUtils.waitForSearchProviderStartup(ext);
}); });
add_task(async function test_no_engine() { add_task(async function test_no_engine() {
const ENGINE_TEST_URL = "https://example.org/"; await loadUri("https://example.org/");
let onLoaded = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
false,
ENGINE_TEST_URL
);
BrowserTestUtils.startLoadingURIString(
gBrowser.selectedBrowser,
ENGINE_TEST_URL
);
await onLoaded;
await UrlbarTestUtils.promiseAutocompleteResultPopup({ await UrlbarTestUtils.promiseAutocompleteResultPopup({
window, window,
value: "test", value: "test",
@@ -80,17 +86,13 @@ add_task(async function test_no_engine() {
}); });
add_task(async function test_selectContextualSearchResult_already_installed() { add_task(async function test_selectContextualSearchResult_already_installed() {
const ENGINE_TEST_URL = "https://example.com/"; let ext = await SearchTestUtils.installSearchExtension({
let onLoaded = BrowserTestUtils.browserLoaded( name: "Contextual",
gBrowser.selectedBrowser, search_url: "https://example.com/browser",
false, });
ENGINE_TEST_URL await AddonTestUtils.waitForSearchProviderStartup(ext);
);
BrowserTestUtils.startLoadingURIString( await loadUri("https://example.com/");
gBrowser.selectedBrowser,
ENGINE_TEST_URL
);
await onLoaded;
const query = "search"; const query = "search";
let engine = Services.search.getEngineByName("Contextual"); let engine = Services.search.getEngineByName("Contextual");
@@ -103,24 +105,35 @@ add_task(async function test_selectContextualSearchResult_already_installed() {
await UrlbarTestUtils.promiseAutocompleteResultPopup({ await UrlbarTestUtils.promiseAutocompleteResultPopup({
window, window,
value: query, value: "contextual",
}); });
let result = (await UrlbarTestUtils.waitForAutocompleteResultAt(window, 1))
.result;
Assert.equal(
result.providerName,
"UrlbarProviderGlobalActions",
"We are shown contextual search action"
);
info("Focus and select the contextual search result"); info("Focus and select the contextual search result");
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_Enter");
await UrlbarTestUtils.promisePopupClose(window);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: "Contextual",
entry: "keywordoffer",
});
let onLoad = BrowserTestUtils.browserLoaded( let onLoad = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser, gBrowser.selectedBrowser,
false, false,
expectedUrl expectedUrl
); );
EventUtils.sendString(query);
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_Enter"); EventUtils.synthesizeKey("KEY_Enter");
await onLoad; await onLoad;
await UrlbarTestUtils.assertSearchMode(window, {
engineName: "Contextual",
entry: "other",
});
Assert.equal( Assert.equal(
gBrowser.selectedBrowser.currentURI.spec, gBrowser.selectedBrowser.currentURI.spec,
expectedUrl, expectedUrl,
@@ -134,17 +147,8 @@ add_task(async function test_selectContextualSearchResult_not_installed() {
"http://mochi.test:8888/browser/browser/components/search/test/browser/opensearch.html"; "http://mochi.test:8888/browser/browser/components/search/test/browser/opensearch.html";
const EXPECTED_URL = const EXPECTED_URL =
"http://mochi.test:8888/browser/browser/components/search/test/browser/?search&test=search"; "http://mochi.test:8888/browser/browser/components/search/test/browser/?search&test=search";
let onLoaded = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
false,
ENGINE_TEST_URL
);
BrowserTestUtils.startLoadingURIString(
gBrowser.selectedBrowser,
ENGINE_TEST_URL
);
await onLoaded;
await loadUri(ENGINE_TEST_URL);
const query = "search"; const query = "search";
await UrlbarTestUtils.promiseAutocompleteResultPopup({ await UrlbarTestUtils.promiseAutocompleteResultPopup({
@@ -190,16 +194,11 @@ add_task(async function test_selectContextualSearchResult_not_installed() {
window.document.querySelector("#searchmode-switcher-close").click(); window.document.querySelector("#searchmode-switcher-close").click();
await UrlbarTestUtils.promisePopupClose(window); await UrlbarTestUtils.promisePopupClose(window);
await Services.search.removeEngine(engine); await Services.search.removeEngine(engine);
ActionsProviderContextualSearch.resetForTesting();
}); });
add_task(async function test_contextual_search_engine() { add_task(async function test_contextual_search_engine() {
await waitForIdle(); await updateConfig(CONFIG);
SearchTestUtils.setRemoteSettingsConfig(CONFIG);
await Services.search.wrappedJSObject.reset();
await Services.search.init();
await loadUri("https://example.org/"); await loadUri("https://example.org/");
await UrlbarTestUtils.promiseAutocompleteResultPopup({ await UrlbarTestUtils.promiseAutocompleteResultPopup({
@@ -231,11 +230,47 @@ add_task(async function test_contextual_search_engine() {
window.document.querySelector("#searchmode-switcher-close").click(); window.document.querySelector("#searchmode-switcher-close").click();
await UrlbarTestUtils.promisePopupClose(window); await UrlbarTestUtils.promisePopupClose(window);
await updateConfig(null);
});
await Services.search.wrappedJSObject.reset(); add_task(async function test_tab_to_search_engine() {
await Services.search.init(); await updateConfig(CONFIG);
await loadUri("https://example.org/");
ActionsProviderContextualSearch.resetForTesting(); await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "example.ne",
});
let expectedUrl = "https://example.net/?q=test";
info("Focus and select the contextual search result");
let onLoad = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
false,
expectedUrl
);
EventUtils.synthesizeKey("KEY_Tab");
await UrlbarTestUtils.assertSearchMode(window, {
engineName: "non-default-engine",
entry: "keywordoffer",
isPreview: true,
source: 3,
});
EventUtils.sendString("test");
EventUtils.synthesizeKey("KEY_Enter");
await onLoad;
Assert.equal(
gBrowser.selectedBrowser.currentURI.spec,
expectedUrl,
"Selecting the contextual search result opens the search URL"
);
window.document.querySelector("#searchmode-switcher-close").click();
await updateConfig(null);
}); });
async function waitForIdle() { async function waitForIdle() {

View File

@@ -42,6 +42,7 @@ add_task(async function test_persist_searchmode() {
info("Focus and select the contextual search result"); info("Focus and select the contextual search result");
let onLoad = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); let onLoad = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
EventUtils.synthesizeKey("KEY_Tab"); EventUtils.synthesizeKey("KEY_Tab");
EventUtils.sendString("test");
EventUtils.synthesizeKey("KEY_Enter"); EventUtils.synthesizeKey("KEY_Enter");
await onLoad; await onLoad;
@@ -94,6 +95,7 @@ add_task(async function test_escape_searchmode() {
info("Focus and select the contextual search result"); info("Focus and select the contextual search result");
let onLoad = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); let onLoad = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
EventUtils.synthesizeKey("KEY_Tab"); EventUtils.synthesizeKey("KEY_Tab");
EventUtils.sendString("test");
EventUtils.synthesizeKey("KEY_Enter"); EventUtils.synthesizeKey("KEY_Enter");
await onLoad; await onLoad;

View File

@@ -71,7 +71,10 @@ async function checkDoesNotOpenOnFocus(win) {
add_setup(async function () { add_setup(async function () {
await SpecialPowers.pushPrefEnv({ await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.autoFill", true]], set: [
["browser.urlbar.autoFill", true],
["browser.urlbar.scotchBonnet.enableOverride", false],
],
}); });
// Add some history for the empty panel and autofill. // Add some history for the empty panel and autofill.
await PlacesTestUtils.addVisits([ await PlacesTestUtils.addVisits([

View File

@@ -162,9 +162,8 @@ add_task(async function test_sitesearch() {
false, false,
expectedUrl expectedUrl
); );
gURLBar.value = query;
UrlbarTestUtils.fireInputEvent(window);
EventUtils.synthesizeKey("KEY_Tab"); EventUtils.synthesizeKey("KEY_Tab");
EventUtils.sendString(query);
EventUtils.synthesizeKey("KEY_Enter"); EventUtils.synthesizeKey("KEY_Enter");
await onLoad; await onLoad;

View File

@@ -80,7 +80,10 @@ async function checkForTabToSearchResult(engineName, isOnboarding) {
add_setup(async function () { add_setup(async function () {
await SpecialPowers.pushPrefEnv({ await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.tabToSearch.onboard.interactionsLeft", 0]], set: [
["browser.urlbar.tabToSearch.onboard.interactionsLeft", 0],
["browser.urlbar.scotchBonnet.enableOverride", false],
],
}); });
await SearchTestUtils.installSearchExtension({ await SearchTestUtils.installSearchExtension({

View File

@@ -163,6 +163,8 @@ add_setup(async function init() {
Ci.nsISearchService.CHANGE_REASON_UNKNOWN Ci.nsISearchService.CHANGE_REASON_UNKNOWN
); );
UrlbarPrefs.set("contextualSearch.enabled", false);
const testDataTypeResults = [ const testDataTypeResults = [
Object.assign({}, REMOTE_SETTINGS_RESULTS[0], { title: "test-data-type" }), Object.assign({}, REMOTE_SETTINGS_RESULTS[0], { title: "test-data-type" }),
]; ];

View File

@@ -361,6 +361,7 @@ function testEngine_setup() {
registerCleanupFunction(async () => { registerCleanupFunction(async () => {
Services.prefs.clearUserPref("browser.urlbar.suggest.searches"); Services.prefs.clearUserPref("browser.urlbar.suggest.searches");
Services.prefs.clearUserPref("browser.urlbar.contextualSearch.enabled");
Services.prefs.clearUserPref( Services.prefs.clearUserPref(
"browser.search.separatePrivateDefault.ui.enabled" "browser.search.separatePrivateDefault.ui.enabled"
); );
@@ -379,6 +380,10 @@ function testEngine_setup() {
false false
); );
Services.prefs.setBoolPref("browser.urlbar.suggest.searches", false); Services.prefs.setBoolPref("browser.urlbar.suggest.searches", false);
Services.prefs.setBoolPref(
"browser.urlbar.contextualSearch.enabled",
false
);
}); });
} }

View File

@@ -3,6 +3,10 @@
"use strict"; "use strict";
add_setup(() => {
UrlbarPrefs.set("suggest.quickactions", false);
});
// Testing that we dedupe results that have the same URL and title as another // Testing that we dedupe results that have the same URL and title as another
// except for their prefix (e.g. http://www.). // except for their prefix (e.g. http://www.).
add_task(async function dedupe_prefix() { add_task(async function dedupe_prefix() {

View File

@@ -1,3 +1,7 @@
add_setup(() => {
UrlbarPrefs.set("suggest.quickactions", false);
});
add_task(async function test_encoded() { add_task(async function test_encoded() {
info("Searching for over encoded url should not break it"); info("Searching for over encoded url should not break it");
let url = "https://www.mozilla.com/search/top/?q=%25%32%35"; let url = "https://www.mozilla.com/search/top/?q=%25%32%35";

View File

@@ -9,6 +9,7 @@
add_task(async function test() { add_task(async function test() {
// Disable search suggestions to avoid hitting the network. // Disable search suggestions to avoid hitting the network.
UrlbarPrefs.set("suggest.searches", false); UrlbarPrefs.set("suggest.searches", false);
UrlbarPrefs.set("suggest.quickactions", false);
let engine = await Services.search.getDefault(); let engine = await Services.search.getDefault();
let pref = "browser.newtabpage.activity-stream.hideTopSitesWithSearchParam"; let pref = "browser.newtabpage.activity-stream.hideTopSitesWithSearchParam";

View File

@@ -13,6 +13,8 @@ const { PromiseTestUtils } = ChromeUtils.importESModule(
const searchService = Services.search.wrappedJSObject; const searchService = Services.search.wrappedJSObject;
add_setup(async function setup() { add_setup(async function setup() {
UrlbarPrefs.set("suggest.quickactions", false);
searchService.errorToThrowInTest = "Settings"; searchService.errorToThrowInTest = "Settings";
// When search service fails, we want the promise rejection to be uncaught // When search service fails, we want the promise rejection to be uncaught

View File

@@ -7,8 +7,10 @@
add_setup(async function () { add_setup(async function () {
Services.prefs.setBoolPref("browser.urlbar.autoFill", false); Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
Services.prefs.setBoolPref("browser.urlbar.suggest.quickactions", false);
registerCleanupFunction(() => { registerCleanupFunction(() => {
Services.prefs.clearUserPref("browser.urlbar.autoFill"); Services.prefs.clearUserPref("browser.urlbar.autoFill");
Services.prefs.clearUserPref("browser.urlbar.suggest.quickactions");
}); });
}); });

View File

@@ -9,16 +9,19 @@
const SUGGEST_PREF = "browser.urlbar.suggest.searches"; const SUGGEST_PREF = "browser.urlbar.suggest.searches";
const SUGGEST_ENABLED_PREF = "browser.search.suggest.enabled"; const SUGGEST_ENABLED_PREF = "browser.search.suggest.enabled";
const QUICKACTIONS_PREF = "browser.urlbar.suggest.quickactions";
add_task(async function test_places() { add_task(async function test_places() {
Services.prefs.setBoolPref(SUGGEST_PREF, true); Services.prefs.setBoolPref(SUGGEST_PREF, true);
Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true); Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, true);
Services.prefs.setBoolPref(QUICKACTIONS_PREF, false);
let engine = await addTestSuggestionsEngine(); let engine = await addTestSuggestionsEngine();
Services.search.defaultEngine = engine; Services.search.defaultEngine = engine;
let oldCurrentEngine = Services.search.defaultEngine; let oldCurrentEngine = Services.search.defaultEngine;
registerCleanupFunction(() => { registerCleanupFunction(() => {
Services.prefs.clearUserPref(SUGGEST_PREF); Services.prefs.clearUserPref(SUGGEST_PREF);
Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF); Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF);
Services.prefs.clearUserPref(QUICKACTIONS_PREF);
Services.search.defaultEngine = oldCurrentEngine; Services.search.defaultEngine = oldCurrentEngine;
}); });

View File

@@ -13,6 +13,11 @@ let testEngine;
add_setup(async () => { add_setup(async () => {
// Disable search suggestions for a less verbose test. // Disable search suggestions for a less verbose test.
Services.prefs.setBoolPref("browser.search.suggest.enabled", false); Services.prefs.setBoolPref("browser.search.suggest.enabled", false);
// Disable ScotchBonnet that provides its own tab to search implementation.
Services.prefs.setBoolPref(
"browser.urlbar.scotchBonnet.enableOverride",
false
);
// Disable tab-to-search onboarding results. Those are covered in // Disable tab-to-search onboarding results. Those are covered in
// browser/components/urlbar/tests/browser/browser_tabToSearch.js. // browser/components/urlbar/tests/browser/browser_tabToSearch.js.
Services.prefs.setIntPref( Services.prefs.setIntPref(
@@ -27,6 +32,7 @@ add_setup(async () => {
"browser.urlbar.tabToSearch.onboard.interactionsLeft" "browser.urlbar.tabToSearch.onboard.interactionsLeft"
); );
Services.prefs.clearUserPref("browser.search.suggest.enabled"); Services.prefs.clearUserPref("browser.search.suggest.enabled");
Services.prefs.clearUserPref("browser.urlbar.scotchBonnet.enableOverride");
}); });
}); });

View File

@@ -24,6 +24,8 @@ add_setup(async function () {
engine = await addTestSuggestionsEngine(); engine = await addTestSuggestionsEngine();
port = engine.getSubmission("abc").uri.port; port = engine.getSubmission("abc").uri.port;
Services.prefs.setBoolPref("browser.urlbar.suggest.quickactions", false);
// Set a mock engine as the default so we don't hit the network below when we // 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. // do searches that return the default engine heuristic result.
await SearchTestUtils.installSearchExtension( await SearchTestUtils.installSearchExtension(

View File

@@ -5,8 +5,10 @@
add_setup(async function () { add_setup(async function () {
registerCleanupFunction(async () => { registerCleanupFunction(async () => {
Services.prefs.clearUserPref("browser.urlbar.suggest.searches"); Services.prefs.clearUserPref("browser.urlbar.suggest.searches");
Services.prefs.clearUserPref("browser.urlbar.suggest.quickactions");
}); });
Services.prefs.setBoolPref("browser.urlbar.suggest.searches", false); Services.prefs.setBoolPref("browser.urlbar.suggest.searches", false);
Services.prefs.setBoolPref("browser.urlbar.suggest.quickactions", false);
}); });
add_task(async function test_untrimmed_secure_www() { add_task(async function test_untrimmed_secure_www() {