Bug 1810647 - Prepare for enable urlbar result menu in Nightly. r=mak,fluent-reviewers,flod

Differential Revision: https://phabricator.services.mozilla.com/D167004
This commit is contained in:
Dão Gottwald 2023-01-23 15:54:53 +00:00
parent dcf59d8716
commit 05e5fefb46
33 changed files with 807 additions and 296 deletions

View File

@ -46,7 +46,7 @@ function isEventForMenuItem(event) {
return event.accessible.role == ROLE_MENUITEM;
}
function isEventForTipButton(event) {
function isEventForResultButton(event) {
let parent = event.accessible.parent;
return (
event.accessible.role == ROLE_PUSHBUTTON &&
@ -403,14 +403,14 @@ async function runTipTests() {
info("Ensuring the tip button is focused on down arrow");
info("Also ensuring that the tip button is a part of a labelled group");
focused = waitForEvent(EVENT_FOCUS, isEventForTipButton);
focused = waitForEvent(EVENT_FOCUS, isEventForResultButton);
EventUtils.synthesizeKey("KEY_ArrowDown");
event = await focused;
testStates(event.accessible, STATE_FOCUSED);
info("Ensuring the help button is focused on tab");
info("Also ensuring that the help button is a part of a labelled group");
focused = waitForEvent(EVENT_FOCUS, isEventForTipButton);
focused = waitForEvent(EVENT_FOCUS, isEventForResultButton);
EventUtils.synthesizeKey("KEY_Tab");
event = await focused;
testStates(event.accessible, STATE_FOCUSED);
@ -422,7 +422,7 @@ async function runTipTests() {
testStates(event.accessible, STATE_FOCUSED);
info("Ensuring the help button is focused on shift+tab");
focused = waitForEvent(EVENT_FOCUS, isEventForTipButton);
focused = waitForEvent(EVENT_FOCUS, isEventForResultButton);
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
event = await focused;
testStates(event.accessible, STATE_FOCUSED);

View File

@ -3,6 +3,7 @@
ChromeUtils.defineESModuleGetters(this, {
PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs",
PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
UrlbarProvidersManager: "resource:///modules/UrlbarProvidersManager.sys.mjs",
UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.sys.mjs",
});
@ -91,8 +92,10 @@ async function updateTopSites(condition, searchShortcuts = false) {
}
add_setup(async function() {
UrlbarTestUtils.init(this);
Services.prefs.setBoolPref("browser.urlbar.suggest.quickactions", false);
registerCleanupFunction(async () => {
UrlbarTestUtils.uninit();
Services.prefs.clearUserPref("browser.urlbar.suggest.quickactions");
});
// Set the notification timeout to a really high value to avoid intermittent
@ -188,16 +191,27 @@ add_task(async function tip_onResultPicked_helpButton_url_enter() {
waitForFocus,
value: "test",
});
let loadedPromise = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser
);
ext.onMessage("onResultPicked received", () => {
Assert.ok(false, "onResultPicked should not be called");
});
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_Enter");
await loadedPromise;
Assert.equal(gBrowser.currentURI.spec, "http://example.com/");
if (UrlbarPrefs.get("resultMenu")) {
let tabOpenPromise = BrowserTestUtils.waitForNewTab(
gBrowser,
"http://example.com/"
);
await UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "h");
info("Waiting for help URL to load in a new tab");
await tabOpenPromise;
gBrowser.removeCurrentTab();
} else {
let loadedPromise = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser
);
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_Enter");
await loadedPromise;
Assert.equal(gBrowser.currentURI.spec, "http://example.com/");
}
});
await ext.unload();
});
@ -211,17 +225,30 @@ add_task(async function tip_onResultPicked_helpButton_url_mouse() {
waitForFocus,
value: "test",
});
let helpButton = gURLBar.querySelector(".urlbarView-button-help");
Assert.ok(helpButton);
let loadedPromise = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser
);
ext.onMessage("onResultPicked received", () => {
Assert.ok(false, "onResultPicked should not be called");
});
EventUtils.synthesizeMouseAtCenter(helpButton, {});
await loadedPromise;
Assert.equal(gBrowser.currentURI.spec, "http://example.com/");
if (UrlbarPrefs.get("resultMenu")) {
let tabOpenPromise = BrowserTestUtils.waitForNewTab(
gBrowser,
"http://example.com/"
);
await UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "h", {
openByMouse: true,
});
info("Waiting for help URL to load in a new tab");
await tabOpenPromise;
gBrowser.removeCurrentTab();
} else {
let loadedPromise = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser
);
let helpButton = gURLBar.querySelector(".urlbarView-button-help");
Assert.ok(helpButton);
EventUtils.synthesizeMouseAtCenter(helpButton, {});
await loadedPromise;
Assert.equal(gBrowser.currentURI.spec, "http://example.com/");
}
});
await ext.unload();
});

View File

@ -382,6 +382,11 @@ add_task(async function test_onProviderResultsRequested() {
buttonText: "Test tip-local result button text",
buttonUrl: "https://example.com/tip-button",
helpUrl: "https://example.com/tip-help",
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-tip-get-help"
: "urlbar-tip-help-icon",
},
type: "extension",
},
},

View File

@ -362,7 +362,12 @@ export class UrlbarProviderExtension extends UrlbarProvider {
let type = UrlbarProviderExtension.RESULT_TYPES[extResult.type];
if (type == UrlbarUtils.RESULT_TYPE.TIP) {
extResult.payload.type = extResult.payload.type || "extension";
extResult.payload.type ||= "extension";
extResult.payload.helpL10n = {
id: lazy.UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-tip-get-help"
: "urlbar-tip-help-icon",
};
}
let result = new lazy.UrlbarResult(

View File

@ -15,6 +15,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
NLP: "resource://gre/modules/NLP.sys.mjs",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
ResetProfile: "resource://gre/modules/ResetProfile.sys.mjs",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
UrlbarResult: "resource:///modules/UrlbarResult.sys.mjs",
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs",
});
@ -660,7 +661,11 @@ class ProviderInterventions extends UrlbarProvider {
...getPayloadForTip(this.currentTip),
type: this.currentTip,
icon: UrlbarUtils.ICON.TIP,
helpL10n: { id: "urlbar-tip-help-icon" },
helpL10n: {
id: lazy.UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-tip-get-help"
: "urlbar-tip-help-icon",
},
}
);
result.suggestedIndex = 1;

View File

@ -1105,7 +1105,6 @@ export class UrlbarView {
#createRow() {
let item = this.#createElement("div");
item.className = "urlbarView-row";
item.setAttribute("role", "option");
item._elements = new Map();
item._buttons = new Map();
return item;
@ -1372,6 +1371,7 @@ export class UrlbarView {
while (item.lastChild) {
item.lastChild.remove();
}
item.setAttribute("role", "option");
item._elements.clear();
item._buttons.clear();
item._content = this.#createElement("span");
@ -2285,7 +2285,8 @@ export class UrlbarView {
if (result.type != lazy.UrlbarUtils.RESULT_TYPE.TIP) {
return false;
}
let tipButton = this.#rows.firstElementChild._buttons.get("0");
let buttons = this.#rows.firstElementChild._buttons;
let tipButton = buttons.get("tip") || buttons.get("0");
if (!tipButton) {
throw new Error("Expected a tip button");
}

View File

@ -200,12 +200,87 @@ export var UrlbarTestUtils = {
return win.gURLBar.view.oneOffSearchButtons;
},
/**
* Returns a specific button of a result.
*
* @param {object} win The window containing the urlbar
* @param {string} buttonName The name of the button, e.g. "menu", "0", etc.
* @param {number} resultIndex The index of the result
* @returns {HtmlElement} The button
*/
getButtonForResultIndex(win, buttonName, resultIndex) {
return this.getRowAt(win, resultIndex).querySelector(
`.urlbarView-button-${buttonName}`
);
},
/**
* Opens the result menu of a specific result and presses an access key to
* activate a menu item.
*
* @param {object} win The window containing the urlbar
* @param {string} accesskey The access key to press once the menu is open
* @param {object} [options] The options object.
* @param {number} [options.resultIndex] The index of the result. Defaults
* to the current selected index.
* @param {boolean} [options.openByMouse] Whether to open the menu by mouse
* or keyboard.
*/
async openResultMenuAndPressAccesskey(
win,
accesskey,
{
resultIndex = win.gURLBar.view.selectedRowIndex,
openByMouse = false,
} = {}
) {
let menuButton = this.getButtonForResultIndex(win, "menu", resultIndex);
this.Assert?.ok(
menuButton,
`found the menu button at result index ${resultIndex}`
);
let promiseMenuOpen = lazy.BrowserTestUtils.waitForEvent(
win.gURLBar.view.resultMenu,
"popupshown"
);
this._testScope?.info(`selecting the result at index ${resultIndex}`);
while (win.gURLBar.view.selectedRowIndex != resultIndex) {
this.EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
}
if (openByMouse) {
this.EventUtils.synthesizeMouseAtCenter(menuButton, {}, win);
} else {
this.EventUtils.synthesizeKey("KEY_Tab", {}, win);
this.Assert?.equal(
this.getSelectedElement(win),
menuButton,
`selected the menu button at result index ${resultIndex}`
);
this.EventUtils.synthesizeKey("KEY_Enter", {}, win);
}
this._testScope?.info("waiting for the menu to open");
await promiseMenuOpen;
await lazy.BrowserTestUtils.waitForCondition(
() =>
win.gURLBar.view.resultMenu.querySelector(
`menuitem[accesskey=${accesskey}]`
),
"Waiting for strings to load"
);
this._testScope?.info(
`pressing access key (${accesskey}) to activate menu item`
);
let promiseCommand = lazy.BrowserTestUtils.waitForEvent(
win.gURLBar.view.resultMenu,
"command"
);
this.EventUtils.synthesizeKey(accesskey, {}, win);
this._testScope?.info("waiting for command event");
await promiseCommand;
this._testScope?.info("got the command event");
},
/**
* Returns true if the oneOffSearchButtons are visible.
*

View File

@ -247,7 +247,11 @@ add_task(async function pickHelpButton() {
},
],
helpUrl,
helpL10n: { id: "urlbar-tip-help-icon" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-tip-get-help"
: "urlbar-tip-help-icon",
},
}
),
];
@ -268,17 +272,38 @@ add_task(async function pickHelpButton() {
UrlbarProviderInterventions.TIP_TYPE.CLEAR
);
let helpButton = element._buttons.get("help");
Assert.ok(helpButton, "Help button exists");
Assert.ok(
BrowserTestUtils.is_visible(helpButton),
"Help button is visible"
);
EventUtils.synthesizeMouseAtCenter(helpButton, {});
if (UrlbarPrefs.get("resultMenu")) {
let tabOpenPromise = BrowserTestUtils.waitForNewTab(
gBrowser,
"http://example.com/"
);
await UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "h", {
openByMouse: true,
resultIndex: 1,
});
info("Waiting for help URL to load in a new tab");
await tabOpenPromise;
gBrowser.removeCurrentTab();
} else {
let helpButton = element._buttons.get("help");
Assert.ok(helpButton, "Help button exists");
Assert.ok(
BrowserTestUtils.is_visible(helpButton),
"Help button is visible"
);
EventUtils.synthesizeMouseAtCenter(helpButton, {});
BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, helpUrl);
await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, helpUrl);
await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
}
if (UrlbarPrefs.get("resultMenu")) {
todo(
false,
"help telemetry for the result menu to be implemented in bug 1790020"
);
return;
}
const scalars = TelemetryTestUtils.getProcessScalars("parent", true, true);
TelemetryTestUtils.assertKeyedScalar(
scalars,

View File

@ -105,6 +105,14 @@ add_task(async function mouse_insideTipButNotOnButtons() {
* to pick the main button instead.
*/
async function doTest({ click, buttonUrl = undefined, helpUrl = undefined }) {
if (UrlbarPrefs.get("resultMenu") && helpUrl) {
todo(
false,
"help telemetry for the result menu to be implemented in bug 1790020"
);
return;
}
// Open a new tab for the test if we expect to load a URL.
let tab;
if (buttonUrl || helpUrl) {

View File

@ -45,7 +45,7 @@ add_task(async function tipIsSecondResult() {
"The first element should be selected."
);
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_ArrowDown");
Assert.ok(
UrlbarTestUtils.getSelectedElement(window).classList.contains(
"urlbarView-button-0"
@ -54,26 +54,32 @@ add_task(async function tipIsSecondResult() {
);
Assert.equal(
UrlbarTestUtils.getSelectedElementIndex(window),
1,
"The first element should be selected."
UrlbarPrefs.get("resultMenu") ? 2 : 1,
"Selected element index"
);
EventUtils.synthesizeKey("KEY_Tab");
Assert.ok(
UrlbarTestUtils.getSelectedElement(window).classList.contains(
"urlbarView-button-help"
UrlbarPrefs.get("resultMenu")
? "urlbarView-button-menu"
: "urlbarView-button-help"
),
"The selected element should be the tip help button."
UrlbarPrefs.get("resultMenu")
? "The selected element should be the tip menu button."
: "The selected element should be the tip help button."
);
Assert.equal(
UrlbarTestUtils.getSelectedRowIndex(window),
1,
"getSelectedRowIndex should return 1 even though the help button is selected."
UrlbarPrefs.get("resultMenu")
? "getSelectedRowIndex should return 1 even though the menu button is selected."
: "getSelectedRowIndex should return 1 even though the help button is selected."
);
Assert.equal(
UrlbarTestUtils.getSelectedElementIndex(window),
2,
"The third element should be selected."
UrlbarPrefs.get("resultMenu") ? 3 : 2,
"Selected element index"
);
// If this test is running alone, the one-offs will rebuild themselves when
@ -101,9 +107,13 @@ add_task(async function tipIsSecondResult() {
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
Assert.ok(
UrlbarTestUtils.getSelectedElement(window).classList.contains(
"urlbarView-button-help"
UrlbarPrefs.get("resultMenu")
? "urlbarView-button-menu"
: "urlbarView-button-help"
),
"The selected element should be the tip help button."
UrlbarPrefs.get("resultMenu")
? "The selected element should be the tip menu button."
: "The selected element should be the tip help button."
);
gURLBar.view.close();
@ -149,9 +159,13 @@ add_task(async function tipIsOnlyResult() {
EventUtils.synthesizeKey("KEY_Tab");
Assert.ok(
UrlbarTestUtils.getSelectedElement(window).classList.contains(
"urlbarView-button-help"
UrlbarPrefs.get("resultMenu")
? "urlbarView-button-menu"
: "urlbarView-button-help"
),
"The selected element should be the tip help button."
UrlbarPrefs.get("resultMenu")
? "The selected element should be the tip menu button."
: "The selected element should be the tip help button."
);
Assert.equal(
UrlbarTestUtils.getSelectedElementIndex(window),
@ -169,9 +183,13 @@ add_task(async function tipIsOnlyResult() {
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
Assert.ok(
UrlbarTestUtils.getSelectedElement(window).classList.contains(
"urlbarView-button-help"
UrlbarPrefs.get("resultMenu")
? "urlbarView-button-menu"
: "urlbarView-button-help"
),
"The selected element should be the tip help button."
UrlbarPrefs.get("resultMenu")
? "The selected element should be the tip menu button."
: "The selected element should be the tip help button."
);
gURLBar.view.close();
@ -224,8 +242,8 @@ add_task(async function tipHasNoHelpButton() {
);
Assert.equal(
UrlbarTestUtils.getSelectedElementIndex(window),
1,
"The first element should be selected."
UrlbarPrefs.get("resultMenu") ? 2 : 1,
"Selected element index"
);
EventUtils.synthesizeKey("KEY_ArrowDown");

View File

@ -333,7 +333,11 @@ async function doUpdateTest({
Assert.ok(button.test(actualButton), "Button regexp");
}
Assert.ok(element._buttons.has("help"), "Tip has a help button");
if (UrlbarPrefs.get("resultMenu")) {
Assert.ok(element._buttons.has("menu"), "Tip has a menu button");
} else {
Assert.ok(element._buttons.has("help"), "Tip has a help button");
}
// Pick the tip and wait for the action.
let values = await Promise.all([awaitCallback(), pickTip()]);
@ -488,12 +492,21 @@ function checkIntervention({
Assert.ok(button.test(actualButton), "Button regexp");
}
let helpButton = element._buttons.get("help");
Assert.ok(helpButton, "Help button exists");
Assert.ok(
BrowserTestUtils.is_visible(helpButton),
"Help button is visible"
);
if (UrlbarPrefs.get("resultMenu")) {
let menuButton = element._buttons.get("menu");
Assert.ok(menuButton, "Menu button exists");
Assert.ok(
BrowserTestUtils.is_visible(menuButton),
"Menu button is visible"
);
} else {
let helpButton = element._buttons.get("help");
Assert.ok(helpButton, "Help button exists");
Assert.ok(
BrowserTestUtils.is_visible(helpButton),
"Help button is visible"
);
}
let values = await Promise.all([awaitCallback(), pickTip()]);
Assert.ok(true, "Refresh dialog opened");

View File

@ -241,7 +241,13 @@ add_suggestedIndex_task({
type: UrlbarUtils.RESULT_TYPE.URL,
suggestedIndex: 1,
},
{ count: 8, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{ count: 1, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{
count: 7,
type: UrlbarPrefs.get("resultMenu")
? UrlbarUtils.RESULT_TYPE.URL
: UrlbarUtils.RESULT_TYPE.SEARCH,
},
],
});
@ -516,7 +522,13 @@ add_suggestedIndex_task({
},
duringUpdate: [
{ count: 1 },
{ count: 8, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{ count: 1, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{
count: 7,
type: UrlbarPrefs.get("resultMenu")
? UrlbarUtils.RESULT_TYPE.URL
: UrlbarUtils.RESULT_TYPE.SEARCH,
},
{
count: 1,
type: UrlbarUtils.RESULT_TYPE.URL,
@ -708,7 +720,13 @@ add_suggestedIndex_task({
},
duringUpdate: [
{ count: 1 },
{ count: 8, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{ count: 1, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{
count: 7,
type: UrlbarPrefs.get("resultMenu")
? UrlbarUtils.RESULT_TYPE.URL
: UrlbarUtils.RESULT_TYPE.SEARCH,
},
{
count: 1,
type: UrlbarUtils.RESULT_TYPE.URL,
@ -909,7 +927,13 @@ add_suggestedIndex_task({
type: UrlbarUtils.RESULT_TYPE.URL,
suggestedIndex: -9,
},
{ count: 8, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{ count: 1, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{
count: 7,
type: UrlbarPrefs.get("resultMenu")
? UrlbarUtils.RESULT_TYPE.URL
: UrlbarUtils.RESULT_TYPE.SEARCH,
},
],
});

View File

@ -207,7 +207,13 @@ add_suggestedIndex_task({
type: UrlbarUtils.RESULT_TYPE.URL,
suggestedIndex: 1,
},
{ count: 3, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{ count: 1, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{
count: 2,
type: UrlbarPrefs.get("resultMenu")
? UrlbarUtils.RESULT_TYPE.URL
: UrlbarUtils.RESULT_TYPE.SEARCH,
},
],
});
@ -524,7 +530,13 @@ add_suggestedIndex_task({
},
duringUpdate: [
{ count: 1 },
{ count: 3, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{ count: 1, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{
count: 2,
type: UrlbarPrefs.get("resultMenu")
? UrlbarUtils.RESULT_TYPE.URL
: UrlbarUtils.RESULT_TYPE.SEARCH,
},
{
count: 1,
type: UrlbarUtils.RESULT_TYPE.URL,
@ -798,7 +810,13 @@ add_suggestedIndex_task({
},
duringUpdate: [
{ count: 1 },
{ count: 3, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{ count: 1, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{
count: 2,
type: UrlbarPrefs.get("resultMenu")
? UrlbarUtils.RESULT_TYPE.URL
: UrlbarUtils.RESULT_TYPE.SEARCH,
},
{
count: 1,
type: UrlbarUtils.RESULT_TYPE.URL,
@ -1037,13 +1055,24 @@ add_suggestedIndex_task({
},
duringUpdate: [
{ count: 1 },
{ count: 2, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{ count: 1, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{
count: 1,
type: UrlbarPrefs.get("resultMenu")
? UrlbarUtils.RESULT_TYPE.URL
: UrlbarUtils.RESULT_TYPE.SEARCH,
},
{
count: 1,
type: UrlbarUtils.RESULT_TYPE.URL,
suggestedIndex: -2,
},
{ count: 1, type: UrlbarUtils.RESULT_TYPE.SEARCH },
{
count: 1,
type: UrlbarPrefs.get("resultMenu")
? UrlbarUtils.RESULT_TYPE.URL
: UrlbarUtils.RESULT_TYPE.SEARCH,
},
],
});

View File

@ -20,13 +20,6 @@ function assertSelected(index) {
index,
"Should have selected the correct item"
);
// Also check the "selected" attribute, to ensure it is not a "fake" selection
// due to binding misbehaviors.
let element = UrlbarTestUtils.getSelectedRow(window);
Assert.ok(
element.hasAttribute("selected"),
"Should have the selected attribute on the row element"
);
// This is true because although both the listbox and the one-offs can have
// selections, the test doesn't check that.

View File

@ -32,7 +32,7 @@ add_task(async function nonsponsoredHelpButton() {
window,
value: "test",
});
await checkBestMatchRow({ result, hasHelpButton: true });
await checkBestMatchRow({ result, hasHelpUrl: true });
await UrlbarTestUtils.promisePopupClose(window);
});
});
@ -61,7 +61,7 @@ add_task(async function sponsoredHelpButton() {
window,
value: "test",
});
await checkBestMatchRow({ result, isSponsored: true, hasHelpButton: true });
await checkBestMatchRow({ result, isSponsored: true, hasHelpUrl: true });
await UrlbarTestUtils.promisePopupClose(window);
});
});
@ -75,7 +75,12 @@ add_task(async function keySelection() {
await withProvider(result, async () => {
// Ordered list of class names of the elements that should be selected.
let expectedClassNames = ["urlbarView-row-inner", "urlbarView-button-help"];
let expectedClassNames = [
"urlbarView-row-inner",
UrlbarPrefs.get("resultMenu")
? "urlbarView-button-menu"
: "urlbarView-button-help",
];
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
@ -84,7 +89,7 @@ add_task(async function keySelection() {
await checkBestMatchRow({
result,
isSponsored: true,
hasHelpButton: true,
hasHelpUrl: true,
});
// Test with the tab key in order vs. reverse order.
@ -126,7 +131,7 @@ add_task(async function keySelection() {
async function checkBestMatchRow({
result,
isSponsored = false,
hasHelpButton = false,
hasHelpUrl = false,
}) {
Assert.equal(
UrlbarTestUtils.getResultCount(window),
@ -177,16 +182,21 @@ async function checkBestMatchRow({
);
}
let helpButton = row._buttons.get("help");
let button = row._buttons.get(
UrlbarPrefs.get("resultMenu") ? "menu" : "help"
);
Assert.equal(
!!result.payload.helpUrl,
hasHelpButton,
"Sanity check: Row's expected hasHelpButton matches result"
hasHelpUrl,
"Sanity check: Row's expected hasHelpUrl matches result"
);
if (hasHelpButton) {
Assert.ok(helpButton, "Row with helpUrl has a helpButton");
if (hasHelpUrl) {
Assert.ok(button, "Row with helpUrl has a help or menu button");
} else {
Assert.ok(!helpButton, "Row without helpUrl does not have a helpButton");
Assert.ok(
!button,
"Row without helpUrl does not have a help or menu button"
);
}
}

View File

@ -24,8 +24,10 @@ add_setup(async function() {
// Sets `helpL10n` on the result payload and makes sure the help button ends
// up with a corresponding l10n attribute.
add_task(async function title_helpL10n() {
let helpL10n = { id: "urlbar-tip-help-icon" };
let provider = registerTestProvider(1, { helpL10n });
if (UrlbarPrefs.get("resultMenu")) {
return;
}
let provider = registerTestProvider(1);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
value: "example",
window,
@ -40,7 +42,7 @@ add_task(async function title_helpL10n() {
let l10nAttrs = document.l10n.getAttributes(helpButton);
Assert.deepEqual(
l10nAttrs,
{ id: helpL10n.id, args: null },
{ id: "urlbar-tip-help-icon", args: null },
"The l10n ID attribute was correctly set"
);
@ -70,28 +72,30 @@ add_task(async function keyboardSelection_secondResult() {
);
await assertIsTestResult(1);
// TAB to the main part of the result.
let resultMenuOffset = UrlbarPrefs.get("resultMenu") ? 1 : 0;
info("Arrow down to the main part of the result.");
EventUtils.synthesizeKey("KEY_ArrowDown");
assertMainPartSelected(1 + resultMenuOffset);
info("TAB to the button.");
EventUtils.synthesizeKey("KEY_Tab");
assertMainPartSelected(1);
assertButtonSelected(2 + resultMenuOffset);
// TAB to the help button.
info("TAB to the next (third) result.");
EventUtils.synthesizeKey("KEY_Tab");
assertHelpButtonSelected(2);
assertOtherResultSelected(3 + resultMenuOffset, "next result");
// TAB to the next (third) result.
EventUtils.synthesizeKey("KEY_Tab");
assertOtherResultSelected(3, "next result");
// SHIFT+TAB to the help button.
info("SHIFT+TAB to the help button.");
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
assertHelpButtonSelected(2);
assertButtonSelected(2 + resultMenuOffset);
// SHIFT+TAB to the main part of the result.
info("SHIFT+TAB to the main part of the result.");
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
assertMainPartSelected(1);
assertMainPartSelected(1 + resultMenuOffset);
// SHIFT+TAB to the previous (first) result.
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
info("Arrow up to the previous (first) result.");
EventUtils.synthesizeKey("KEY_ArrowUp");
assertOtherResultSelected(0, "previous result");
await UrlbarTestUtils.promisePopupClose(window);
@ -120,13 +124,17 @@ add_task(async function keyboardSelection_lastResult() {
);
await assertIsTestResult(MAX_RESULTS - 1);
// TAB to the main part of the result.
EventUtils.synthesizeKey("KEY_Tab", { repeat: MAX_RESULTS - 1 });
assertMainPartSelected(MAX_RESULTS - 1);
let numSelectable = UrlbarPrefs.get("resultMenu")
? MAX_RESULTS * 2 - 1
: MAX_RESULTS;
// Arrow down to the main part of the result.
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: MAX_RESULTS - 1 });
assertMainPartSelected(numSelectable - 1);
// TAB to the help button.
EventUtils.synthesizeKey("KEY_Tab");
assertHelpButtonSelected(MAX_RESULTS);
assertButtonSelected(numSelectable);
// Arrow down to the first one-off. If this test is running alone, the
// one-offs will rebuild themselves when the view is opened above, and they
@ -153,15 +161,18 @@ add_task(async function keyboardSelection_lastResult() {
// SHIFT+TAB to the help button.
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
assertHelpButtonSelected(MAX_RESULTS);
assertButtonSelected(numSelectable);
// SHIFT+TAB to the main part of the result.
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
assertMainPartSelected(MAX_RESULTS - 1);
assertMainPartSelected(numSelectable - 1);
// SHIFT+TAB to the previous result.
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
assertOtherResultSelected(MAX_RESULTS - 2, "previous result");
// Arrow up to the previous result.
EventUtils.synthesizeKey("KEY_ArrowUp");
assertOtherResultSelected(
numSelectable - (UrlbarPrefs.get("resultMenu") ? 3 : 2),
"previous result"
);
await UrlbarTestUtils.promisePopupClose(window);
UrlbarProvidersManager.unregisterProvider(provider);
@ -170,26 +181,26 @@ add_task(async function keyboardSelection_lastResult() {
// Picks the main part of the test result -- the non-help-button part -- with
// the keyboard.
add_task(async function pick_mainPart_keyboard() {
await doPickTest({ pickHelpButton: false, useKeyboard: true });
await doPickTest({ pickButton: false, useKeyboard: true });
});
// Picks the help button with the keyboard.
add_task(async function pick_helpButton_keyboard() {
await doPickTest({ pickHelpButton: true, useKeyboard: true });
await doPickTest({ pickButton: true, useKeyboard: true });
});
// Picks the main part of the test result -- the non-help-button part -- with
// the mouse.
add_task(async function pick_mainPart_mouse() {
await doPickTest({ pickHelpButton: false, useKeyboard: false });
await doPickTest({ pickButton: false, useKeyboard: false });
});
// Picks the help button with the mouse.
add_task(async function pick_helpButton_mouse() {
await doPickTest({ pickHelpButton: true, useKeyboard: false });
await doPickTest({ pickButton: true, useKeyboard: false });
});
async function doPickTest({ pickHelpButton, useKeyboard }) {
async function doPickTest({ pickButton, useKeyboard }) {
await BrowserTestUtils.withNewTab("about:blank", async () => {
let index = 1;
let provider = registerTestProvider(index);
@ -204,51 +215,57 @@ async function doPickTest({ pickHelpButton, useKeyboard }) {
0,
"The heuristic result should be selected"
);
await assertIsTestResult(1);
await assertIsTestResult(index);
let clickTarget;
if (useKeyboard) {
// TAB to the result.
if (pickHelpButton) {
EventUtils.synthesizeKey("KEY_Tab", { repeat: index + 1 });
assertHelpButtonSelected(index + 1);
} else {
EventUtils.synthesizeKey("KEY_Tab", { repeat: index });
assertMainPartSelected(index);
}
} else {
// Get the click target.
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, index);
clickTarget = pickHelpButton
? result.element.row._buttons.get("help")
: result.element.row._content;
Assert.ok(
clickTarget,
"Click target found, pickHelpButton=" + pickHelpButton
);
// Arrow down to the result.
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: index });
assertMainPartSelected(UrlbarPrefs.get("resultMenu") ? index * 2 : index);
}
// Pick the result. The appropriate URL should load.
let loadPromise = pickHelpButton
let loadPromise = pickButton
? BrowserTestUtils.waitForNewTab(gBrowser)
: BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
await Promise.all([
loadPromise,
UrlbarTestUtils.promisePopupClose(window, () => {
if (useKeyboard) {
UrlbarTestUtils.promisePopupClose(window, async () => {
if (pickButton && UrlbarPrefs.get("resultMenu")) {
await UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "h", {
openByMouse: !useKeyboard,
resultIndex: index,
});
} else if (useKeyboard) {
if (pickButton) {
// TAB to the button.
EventUtils.synthesizeKey("KEY_Tab");
assertButtonSelected(index + 1);
}
EventUtils.synthesizeKey("KEY_Enter");
} else {
// Get the click target.
let result = await UrlbarTestUtils.getDetailsOfResultAt(
window,
index
);
let clickTarget = pickButton
? result.element.row._buttons.get("help")
: result.element.row._content;
Assert.ok(
clickTarget,
"Click target found, pickButton=" + pickButton
);
EventUtils.synthesizeMouseAtCenter(clickTarget, {});
}
}),
]);
Assert.equal(
gBrowser.selectedBrowser.currentURI.spec,
pickHelpButton ? RESULT_HELP_URL : RESULT_URL,
pickButton ? RESULT_HELP_URL : RESULT_URL,
"Expected URL should have loaded"
);
if (pickHelpButton) {
if (pickButton) {
BrowserTestUtils.removeTab(gBrowser.selectedTab);
}
UrlbarProvidersManager.unregisterProvider(provider);
@ -263,24 +280,24 @@ async function doPickTest({ pickHelpButton, useKeyboard }) {
*
* @param {number} suggestedIndex
* The result's suggestedIndex.
* @param {object} [extraPayloadProperties]
* Properties other than `url` and `helpUrl` to set on the payload.
* @returns {UrlbarProvider}
* The new provider.
*/
function registerTestProvider(suggestedIndex, extraPayloadProperties = {}) {
function registerTestProvider(suggestedIndex) {
let results = [
Object.assign(
new UrlbarResult(
UrlbarUtils.RESULT_TYPE.URL,
UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
Object.assign(
{
url: RESULT_URL,
helpUrl: RESULT_HELP_URL,
{
url: RESULT_URL,
helpUrl: RESULT_HELP_URL,
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-tip-get-help"
: "urlbar-tip-help-icon",
},
extraPayloadProperties
)
}
),
{ suggestedIndex }
),
@ -311,9 +328,13 @@ async function assertIsTestResult(index) {
);
let { row } = result.element;
let helpButton = row._buttons.get("help");
Assert.ok(helpButton, "The result should have a help button");
Assert.ok(helpButton.id, "Help button has an ID");
if (UrlbarPrefs.get("resultMenu")) {
Assert.ok(row._buttons.get("menu"), "The result should have a menu button");
} else {
let helpButton = row._buttons.get("help");
Assert.ok(helpButton, "The result should have a help button");
Assert.ok(helpButton.id, "Help button has an ID");
}
Assert.ok(row._content.id, "Row-inner has an ID");
Assert.equal(
row.getAttribute("role"),
@ -347,7 +368,9 @@ function assertSelection(expectedSelectedElementIndex, expectedClassName, msg) {
UrlbarTestUtils.getSelectedElement(window).classList.contains(
expectedClassName
),
"Expected selected element: " + msg
`Expected selected element: ${msg} (${
UrlbarTestUtils.getSelectedElement(window).classList
} == ${expectedClassName})`
);
}
@ -367,17 +390,25 @@ function assertMainPartSelected(expectedSelectedElementIndex) {
}
/**
* Asserts that the help button part of our test resut is selected.
* Asserts that the help button part of our test result is selected.
*
* @param {number} expectedSelectedElementIndex
* The expected selected element index.
*/
function assertHelpButtonSelected(expectedSelectedElementIndex) {
assertSelection(
expectedSelectedElementIndex,
"urlbarView-button-help",
"help button"
);
function assertButtonSelected(expectedSelectedElementIndex) {
if (UrlbarPrefs.get("resultMenu")) {
assertSelection(
expectedSelectedElementIndex,
"urlbarView-button-menu",
"menu button"
);
} else {
assertSelection(
expectedSelectedElementIndex,
"urlbarView-button-help",
"help button"
);
}
}
/**
@ -389,5 +420,9 @@ function assertHelpButtonSelected(expectedSelectedElementIndex) {
* A string to include in the assertion message.
*/
function assertOtherResultSelected(expectedSelectedElementIndex, msg) {
assertSelection(expectedSelectedElementIndex, "urlbarView-row", msg);
assertSelection(
expectedSelectedElementIndex,
UrlbarPrefs.get("resultMenu") ? "urlbarView-row-inner" : "urlbarView-row",
msg
);
}

View File

@ -219,6 +219,11 @@ add_task(async function test_searchMode_removeRestyledHistory() {
});
add_task(async function blockButton() {
if (UrlbarPrefs.get("resultMenu")) {
// This case is covered by browser_result_menu.js.
return;
}
let url = "https://example.com/has-block-button";
let provider = new UrlbarTestUtils.TestProvider({
priority: Infinity,

View File

@ -7,41 +7,6 @@ add_setup(async function() {
});
});
async function openResultMenuAndPressAccesskey(resultIndex, accesskey) {
let menuButton = UrlbarTestUtils.getButtonForResultIndex(
window,
"menu",
resultIndex
);
ok(menuButton, `found the menu button at result index ${resultIndex}`);
while (gURLBar.view.selectedRowIndex != resultIndex) {
EventUtils.synthesizeKey("KEY_ArrowDown");
}
EventUtils.synthesizeKey("KEY_Tab");
is(
UrlbarTestUtils.getSelectedElement(window),
menuButton,
`selected the menu button at result index ${resultIndex}`
);
let promiseMenuOpen = BrowserTestUtils.waitForEvent(
gURLBar.view.resultMenu,
"popupshown"
);
EventUtils.synthesizeKey("KEY_Enter", {});
info("waiting for the menu to open");
await promiseMenuOpen;
info(`pressing access key (${accesskey}) to activate menu item`);
let promiseCommand = BrowserTestUtils.waitForEvent(
gURLBar.view.resultMenu,
"command"
);
EventUtils.synthesizeKey(accesskey);
info("waiting for command event");
await promiseCommand;
}
add_task(async function test_remove_history() {
const TEST_URL = "https://remove.me/from_urlbar/";
await PlacesTestUtils.addVisits(TEST_URL);
@ -67,7 +32,9 @@ add_task(async function test_remove_history() {
let expectedResultCount = UrlbarTestUtils.getResultCount(window) - 1;
await openResultMenuAndPressAccesskey(resultIndex, "R");
await UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "R", {
resultIndex,
});
const removeEvents = await promiseVisitRemoved;
Assert.ok(
@ -124,10 +91,13 @@ add_task(async function test_remove_search_history() {
value: "foo",
});
let index = 1;
let resultIndex = 1;
let count = UrlbarTestUtils.getResultCount(window);
for (; index < count; index++) {
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, index);
for (; resultIndex < count; resultIndex++) {
let result = await UrlbarTestUtils.getDetailsOfResultAt(
window,
resultIndex
);
if (
result.type == UrlbarUtils.RESULT_TYPE.SEARCH &&
result.source == UrlbarUtils.RESULT_SOURCE.HISTORY
@ -135,9 +105,11 @@ add_task(async function test_remove_search_history() {
break;
}
}
Assert.ok(index < count, "Result found");
Assert.ok(resultIndex < count, "Result found");
await openResultMenuAndPressAccesskey(index, "R");
await UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "R", {
resultIndex,
});
await promiseRemoved;
await TestUtils.waitForCondition(
@ -224,13 +196,17 @@ add_task(async function firefoxSuggest() {
await openResults();
let tabOpenPromise = BrowserTestUtils.waitForNewTab(gBrowser, helpUrl);
await openResultMenuAndPressAccesskey(0, "L");
await UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "L", {
resultIndex: 0,
});
info("Waiting for help URL to load in a new tab");
await tabOpenPromise;
gBrowser.removeCurrentTab();
await openResults();
await openResultMenuAndPressAccesskey(0, "D");
await UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "D", {
resultIndex: 0,
});
Assert.equal(
blockResultCallCount,

View File

@ -49,13 +49,19 @@ add_task(async function test() {
value: "test",
});
EventUtils.synthesizeKey("KEY_Tab", { repeat: 3 });
EventUtils.synthesizeKey("KEY_Tab", {
repeat: UrlbarPrefs.get("resultMenu") ? 5 : 3,
});
EventUtils.synthesizeKey("KEY_ArrowDown");
ok(
UrlbarTestUtils.getOneOffSearchButtons(window).selectedButton,
"a one off button is selected"
);
Assert.equal(selectionCount, 4, "We selected the four elements in the view.");
Assert.equal(
selectionCount,
UrlbarPrefs.get("resultMenu") ? 6 : 4,
"Number of elements selected in the view."
);
UrlbarProvidersManager.unregisterProvider(provider);
});

View File

@ -297,13 +297,18 @@ async function expectTabThroughResults(options = { reverse: false }) {
for (let i = initiallySelectedIndex + 1; i < resultCount; i++) {
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: options.reverse });
if (UrlbarTestUtils.getButtonForResultIndex(window, "menu")) {
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: options.reverse });
}
Assert.equal(
UrlbarTestUtils.getSelectedRowIndex(window),
options.reverse ? resultCount - i : i
);
}
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_Tab", {
repeat: UrlbarPrefs.get("resultMenu") && result.heuristic ? 2 : 1,
});
if (!options.reverse) {
Assert.equal(

View File

@ -97,7 +97,7 @@ add_task(async function basic() {
"The correct action text is displayed in the tab-to-search result."
);
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_ArrowDown");
Assert.equal(
UrlbarTestUtils.getSelectedRowIndex(window),
1,
@ -142,7 +142,9 @@ add_task(async function activedescendant_tab() {
"The second result is a tab-to-search result."
);
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_Tab", {
repeat: UrlbarPrefs.get("resultMenu") ? 2 : 1,
});
await UrlbarTestUtils.assertSearchMode(window, {
engineName: TEST_ENGINE_NAME,
@ -150,7 +152,7 @@ add_task(async function activedescendant_tab() {
isPreview: true,
});
let aadID = gURLBar.inputField.getAttribute("aria-activedescendant");
Assert.ok(!aadID, "aria-activedescendant was not set.");
Assert.equal(aadID, null, "aria-activedescendant was not set.");
// Cycle through all the results then return to the tab-to-search result. It
// should be announced.
@ -159,10 +161,14 @@ add_task(async function activedescendant_tab() {
let firstRow = await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
Assert.equal(
aadID,
firstRow.id,
UrlbarTestUtils.getButtonForResultIndex(window, "menu", 0)
? firstRow._content.id
: firstRow.id,
"aria-activedescendant was set to the row after the tab-to-search result."
);
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_Tab", {
repeat: UrlbarPrefs.get("resultMenu") ? 2 : 1,
});
aadID = gURLBar.inputField.getAttribute("aria-activedescendant");
Assert.equal(
aadID,
@ -186,7 +192,9 @@ add_task(async function activedescendant_tab() {
"The second result is a tab-to-search result."
);
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_Tab", {
repeat: UrlbarPrefs.get("resultMenu") ? 2 : 1,
});
await UrlbarTestUtils.assertSearchMode(window, {
engineName: TEST_ENGINE_NAME,
@ -194,7 +202,7 @@ add_task(async function activedescendant_tab() {
isPreview: true,
});
aadID = gURLBar.inputField.getAttribute("aria-activedescendant");
Assert.ok(!aadID, "aria-activedescendant was not set.");
Assert.equal(aadID, null, "aria-activedescendant was not set.");
await UrlbarTestUtils.exitSearchMode(window);
await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur());
@ -262,7 +270,7 @@ add_task(async function tab_key_race() {
return;
}
info(
"Test typing a letter followed shortly by Tab consistently selects a tab-to-search result"
"Test typing a letter followed shortly by down arrow consistently selects a tab-to-search result"
);
Assert.equal(gURLBar.value, "", "Sanity check urlbar is empty");
let promiseQueryStarted = new Promise(resolve => {
@ -307,11 +315,11 @@ add_task(async function tab_key_race() {
EventUtils.synthesizeKey(TEST_ENGINE_DOMAIN.slice(0, 1));
info("Awaiting for the query to start");
await promiseQueryStarted;
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_ArrowDown");
await UrlbarTestUtils.promiseSearchComplete(window);
await TestUtils.waitForCondition(
() => UrlbarTestUtils.getSelectedRowIndex(window) == 1,
"Wait for tab key to be handled"
"Wait for down arrow key to be handled"
);
await UrlbarTestUtils.assertSearchMode(window, {
engineName: TEST_ENGINE_NAME,
@ -342,7 +350,7 @@ add_task(async function onboard() {
`https://${TEST_ENGINE_DOMAIN}/`,
"The autofilled URL matches the engine domain."
);
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_ArrowDown");
Assert.equal(
UrlbarTestUtils.getSelectedRowIndex(window),
1,

View File

@ -339,9 +339,17 @@ add_task(async function buttons() {
{
url: mainResultUrl,
helpUrl: mainResultHelpUrl,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: true,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
}
),
new UrlbarResult(
@ -383,12 +391,26 @@ add_task(async function buttons() {
JSON.stringify(rowUrls)
);
};
let assertResultMenuOpen = () => {
Assert.equal(
gURLBar.view.resultMenu.state,
"showing",
"Result menu is open"
);
EventUtils.synthesizeKey("KEY_Escape");
};
let testData = [
{
description: "Block button to block button",
mousedown: ".urlbarView-row:nth-child(1) .urlbarView-button-block",
afterMouseupCallback: assertBlockResultCalled,
description: UrlbarPrefs.get("resultMenu")
? "Menu button to menu button"
: "Block button to block button",
mousedown: UrlbarPrefs.get("resultMenu")
? ".urlbarView-row:nth-child(1) .urlbarView-button-menu"
: ".urlbarView-row:nth-child(1) .urlbarView-button-block",
afterMouseupCallback: UrlbarPrefs.get("resultMenu")
? assertResultMenuOpen
: assertBlockResultCalled,
expected: {
mousedownSelected: false,
topSites: {
@ -402,6 +424,7 @@ add_task(async function buttons() {
},
},
{
skip: UrlbarPrefs.get("resultMenu"),
description: "Help button to help button",
mousedown: ".urlbarView-row:nth-child(1) .urlbarView-button-help",
expected: {
@ -411,25 +434,35 @@ add_task(async function buttons() {
},
},
{
description: "Row-inner to block button",
description: UrlbarPrefs.get("resultMenu")
? "Row-inner to menu button"
: "Row-inner to block button",
mousedown: ".urlbarView-row:nth-child(1) > .urlbarView-row-inner",
mouseup: ".urlbarView-row:nth-child(1) .urlbarView-button-block",
afterMouseupCallback: assertBlockResultCalled,
mouseup: UrlbarPrefs.get("resultMenu")
? ".urlbarView-row:nth-child(1) .urlbarView-button-menu"
: ".urlbarView-row:nth-child(1) .urlbarView-button-block",
afterMouseupCallback: UrlbarPrefs.get("resultMenu")
? assertResultMenuOpen
: assertBlockResultCalled,
expected: {
mousedownSelected: true,
topSites: {
pageProxyState: "invalid",
value: otherResultUrl,
value: UrlbarPrefs.get("resultMenu") ? initialTabUrl : otherResultUrl,
},
searchString: {
pageProxyState: "invalid",
value: otherResultUrl,
value: UrlbarPrefs.get("resultMenu") ? searchString : otherResultUrl,
},
},
},
{
description: "Block button to row-inner",
mousedown: ".urlbarView-row:nth-child(1) .urlbarView-button-block",
description: UrlbarPrefs.get("resultMenu")
? "Menu button to row-inner"
: "Block button to row-inner",
mousedown: UrlbarPrefs.get("resultMenu")
? ".urlbarView-row:nth-child(1) .urlbarView-button-menu"
: ".urlbarView-row:nth-child(1) .urlbarView-button-block",
mouseup: ".urlbarView-row:nth-child(1) > .urlbarView-row-inner",
expected: {
mousedownSelected: false,
@ -440,9 +473,22 @@ add_task(async function buttons() {
];
for (let showTopSites of [true, false]) {
for (let { description, mousedown, mouseup, expected } of testData) {
for (let {
description,
mousedown,
mouseup,
expected,
afterMouseupCallback = null,
skip = false,
} of testData) {
if (skip) {
info(
`Skipping test with showTopSites = ${showTopSites}: ${description}`
);
continue;
}
info(`Running test with showTopSites = ${showTopSites}: ${description}`);
mouseup = mouseup || mousedown;
mouseup ||= mousedown;
await BrowserTestUtils.withNewTab(initialTabUrl, async () => {
Assert.equal(
@ -525,8 +571,8 @@ add_task(async function buttons() {
return;
}
if (expected.afterMouseupCallback) {
await expected.afterMouseupCallback();
if (afterMouseupCallback) {
await afterMouseupCallback();
}
let state = showTopSites ? expected.topSites : expected.searchString;
@ -551,7 +597,17 @@ async function waitForElements(selectors) {
let elements;
await BrowserTestUtils.waitForCondition(() => {
elements = selectors.map(s => document.querySelector(s));
return elements.every(e => e && BrowserTestUtils.is_visible(e));
return elements.every(e => {
if (e?.classList.contains("urlbarView-button-menu")) {
// Hover the row to make the menu button visible.
let row = e.closest(".urlbarView-row");
EventUtils.synthesizeMouse(row, 1, 1, { type: "mouseover" });
EventUtils.synthesizeMouse(row, 2, 2, { type: "mousemove" });
EventUtils.synthesizeMouse(row, 3, 3, { type: "mousemove" });
EventUtils.synthesizeMouse(row, 4, 4, { type: "mousemove" });
}
return e && BrowserTestUtils.is_visible(e);
});
}, "Waiting for elements to become visible: " + JSON.stringify(selectors));
return elements;
}

View File

@ -399,27 +399,35 @@ class _QuickSuggestTestUtils {
"Result sponsored label"
);
let helpButton = row._buttons.get("help");
this.Assert.ok(helpButton, "The help button should be present");
this.Assert.equal(
result.payload.helpUrl,
lazy.QuickSuggest.HELP_URL,
"Result helpURL"
);
let blockButton = row._buttons.get("block");
if (!isBestMatch) {
this.Assert.equal(
!!blockButton,
lazy.UrlbarPrefs.get("quickSuggestBlockingEnabled"),
"The block button is present iff quick suggest blocking is enabled"
if (lazy.UrlbarPrefs.get("resultMenu")) {
this.Assert.ok(
row._buttons.get("menu"),
"The menu button should be present"
);
} else {
this.Assert.equal(
!!blockButton,
lazy.UrlbarPrefs.get("bestMatchBlockingEnabled"),
"The block button is present iff best match blocking is enabled"
);
let helpButton = row._buttons.get("help");
this.Assert.ok(helpButton, "The help button should be present");
let blockButton = row._buttons.get("block");
if (!isBestMatch) {
this.Assert.equal(
!!blockButton,
lazy.UrlbarPrefs.get("quickSuggestBlockingEnabled"),
"The block button is present iff quick suggest blocking is enabled"
);
} else {
this.Assert.equal(
!!blockButton,
lazy.UrlbarPrefs.get("bestMatchBlockingEnabled"),
"The block button is present iff best match blocking is enabled"
);
}
}
return details;

View File

@ -102,11 +102,17 @@ add_combo_task(async function basic_keyboard({ result, isBestMatch }) {
await doBasicBlockTest({
result,
isBestMatch,
block: () => {
// TAB twice to select the block button: once to select the main
// part of the row, once to select the block button.
EventUtils.synthesizeKey("KEY_Tab", { repeat: 2 });
EventUtils.synthesizeKey("KEY_Enter");
block: async () => {
if (UrlbarPrefs.get("resultMenu")) {
await UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "D", {
resultIndex: 1,
});
} else {
// TAB twice to select the block button: once to select the main
// part of the row, once to select the block button.
EventUtils.synthesizeKey("KEY_Tab", { repeat: 2 });
EventUtils.synthesizeKey("KEY_Enter");
}
},
});
});
@ -116,8 +122,18 @@ add_combo_task(async function basic_mouse({ result, isBestMatch }) {
await doBasicBlockTest({
result,
isBestMatch,
block: blockButton => {
EventUtils.synthesizeMouseAtCenter(blockButton, {});
block: async () => {
if (UrlbarPrefs.get("resultMenu")) {
await UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "D", {
resultIndex: 1,
openByMouse: true,
});
} else {
EventUtils.synthesizeMouseAtCenter(
UrlbarTestUtils.getButtonForResultIndex(window, "block", 1),
{}
);
}
},
});
});
@ -150,7 +166,7 @@ async function doBasicBlockTest({ result, isBestMatch, block }) {
);
let isSponsored = result.keywords[0] == "sponsored";
let details = await QuickSuggestTestUtils.assertIsQuickSuggest({
await QuickSuggestTestUtils.assertIsQuickSuggest({
window,
isBestMatch,
isSponsored,
@ -158,8 +174,7 @@ async function doBasicBlockTest({ result, isBestMatch, block }) {
});
// Block the suggestion.
let blockButton = details.element.row._buttons.get("block");
await block(blockButton);
await block();
// The row should have been removed.
Assert.ok(
@ -268,8 +283,14 @@ add_task(async function blockMultiple() {
});
// Block it.
EventUtils.synthesizeKey("KEY_Tab", { repeat: 2 });
EventUtils.synthesizeKey("KEY_Enter");
if (UrlbarPrefs.get("resultMenu")) {
await UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "D", {
resultIndex: 1,
});
} else {
EventUtils.synthesizeKey("KEY_Tab", { repeat: 2 });
EventUtils.synthesizeKey("KEY_Enter");
}
Assert.ok(
await QuickSuggest.blockedSuggestions.has(url),
"Suggestion is blocked after picking block button"
@ -357,7 +378,6 @@ async function doDisabledTest({
originalUrl: result.url,
isSponsored: result.keywords[0] == "sponsored",
});
let blockButton = details.element.row._buttons.get("block");
// Arrow down to select the suggestion and press the key shortcut to block.
EventUtils.synthesizeKey("KEY_ArrowDown");
@ -372,7 +392,12 @@ async function doDisabledTest({
(!isBestMatch && !quickSuggestBlockingEnabled)
) {
// Blocking is disabled. The key shortcut shouldn't have done anything.
Assert.ok(!blockButton, "Block button is not present");
if (!UrlbarPrefs.get("resultMenu")) {
Assert.ok(
!details.element.row._buttons.get("block"),
"Block button is not present"
);
}
Assert.equal(
UrlbarTestUtils.getResultCount(window),
expectedResultCount,
@ -390,7 +415,12 @@ async function doDisabledTest({
);
} else {
// Blocking is enabled. The suggestion should have been blocked.
Assert.ok(blockButton, "Block button is present");
if (!UrlbarPrefs.get("resultMenu")) {
Assert.ok(
details.element.row._buttons.get("block"),
"Block button is present"
);
}
Assert.equal(
UrlbarTestUtils.getResultCount(window),
1,

View File

@ -97,6 +97,15 @@ async function setUpTelemetryTest({
merinoSuggestions = null,
config = QuickSuggestTestUtils.DEFAULT_CONFIG,
}) {
if (UrlbarPrefs.get("resultMenu")) {
todo(
false,
"telemetry for the result menu to be implemented in bug 1790020"
);
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.resultMenu", false]],
});
}
await SpecialPowers.pushPrefEnv({
set: [
// Enable blocking on primary sponsored and nonsponsored suggestions so we

View File

@ -92,9 +92,17 @@ const EXPECTED_SPONSORED_RESULT = {
sponsoredIabCategory: "22 - Shopping",
isSponsored: true,
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
displayUrl: "http://test.com/q=frabbits",
source: "remote-settings",
},
@ -117,9 +125,17 @@ const EXPECTED_NONSPONSORED_RESULT = {
sponsoredIabCategory: "5 - Education",
isSponsored: false,
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
displayUrl: "http://test.com/?q=nonsponsored",
source: "remote-settings",
},
@ -142,9 +158,17 @@ const EXPECTED_HTTP_RESULT = {
sponsoredIabCategory: "22 - Shopping",
isSponsored: true,
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
displayUrl: "http://" + PREFIX_SUGGESTIONS_STRIPPED_URL,
source: "remote-settings",
},
@ -167,9 +191,17 @@ const EXPECTED_HTTPS_RESULT = {
sponsoredIabCategory: "22 - Shopping",
isSponsored: true,
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
displayUrl: PREFIX_SUGGESTIONS_STRIPPED_URL,
source: "remote-settings",
},
@ -948,9 +980,17 @@ add_task(async function dedupeAgainstURL_timestamps() {
sponsoredIabCategory: "22 - Shopping",
isSponsored: true,
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
source: "remote-settings",
},
};

View File

@ -63,9 +63,17 @@ const EXPECTED_BEST_MATCH_URLBAR_RESULT = {
sponsoredBlockId: 1,
sponsoredAdvertiser: "TestAdvertiser",
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
displayUrl: "http://example.com",
source: "remote-settings",
},
@ -87,9 +95,17 @@ const EXPECTED_NON_BEST_MATCH_URLBAR_RESULT = {
sponsoredBlockId: 1,
sponsoredAdvertiser: "TestAdvertiser",
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
displayUrl: "http://example.com",
source: "remote-settings",
},
@ -111,9 +127,17 @@ const EXPECTED_BEST_MATCH_POSITION_URLBAR_RESULT = {
sponsoredBlockId: 2,
sponsoredAdvertiser: "TestAdvertiser",
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
displayUrl: "http://example.com/best-match-position",
source: "remote-settings",
},

View File

@ -52,9 +52,17 @@ const EXPECTED_SPONSORED_URLBAR_RESULT = {
sponsoredAdvertiser: "TestAdvertiser",
sponsoredIabCategory: "22 - Shopping",
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
source: "remote-settings",
},
};
@ -77,9 +85,17 @@ const EXPECTED_NONSPONSORED_URLBAR_RESULT = {
sponsoredAdvertiser: "TestAdvertiser",
sponsoredIabCategory: "5 - Education",
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
source: "remote-settings",
},
};

View File

@ -41,9 +41,17 @@ const EXPECTED_REMOTE_SETTINGS_URLBAR_RESULT = {
sponsoredAdvertiser: "TestAdvertiser",
isSponsored: true,
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
displayUrl: "http://test.com/q=frabbits",
source: "remote-settings",
},
@ -65,9 +73,17 @@ const EXPECTED_MERINO_URLBAR_RESULT = {
sponsoredAdvertiser: "advertiser",
isSponsored: true,
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
displayUrl: "url",
requestId: "request_id",
source: "merino",
@ -463,9 +479,17 @@ add_task(async function multipleMerinoSuggestions() {
sponsoredAdvertiser: "multipleMerinoSuggestions 1 advertiser",
isSponsored: true,
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
displayUrl: "multipleMerinoSuggestions 1 url",
requestId: "request_id",
source: "merino",
@ -682,9 +706,17 @@ add_task(async function topPick() {
sponsoredAdvertiser: "multipleMerinoSuggestions 2 advertiser",
isSponsored: true,
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
displayUrl: "multipleMerinoSuggestions 2 url",
requestId: "request_id",
source: "merino",

View File

@ -188,9 +188,17 @@ add_task(async function() {
sponsoredIabCategory: qsResult.iab_category,
icon: null,
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
source: "remote-settings",
},
});

View File

@ -157,9 +157,17 @@ function createExpectedQuickSuggestResult(suggest) {
sponsoredIabCategory: suggest.iab_category,
isSponsored: suggest.iab_category !== "5 - Education",
helpUrl: QuickSuggest.HELP_URL,
helpL10n: { id: "firefox-suggest-urlbar-learn-more" },
helpL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: false,
blockL10n: { id: "firefox-suggest-urlbar-block" },
blockL10n: {
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
displayUrl: suggest.url,
source: "remote-settings",
},

View File

@ -762,11 +762,15 @@ function makeExpectedResult(temperatureUnit = undefined) {
iconId: "6",
helpUrl: QuickSuggest.HELP_URL,
helpL10n: {
id: "firefox-suggest-urlbar-learn-more",
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-learn-more-about-firefox-suggest"
: "firefox-suggest-urlbar-learn-more",
},
isBlockable: true,
blockL10n: {
id: "firefox-suggest-urlbar-block",
id: UrlbarPrefs.get("resultMenu")
? "urlbar-result-menu-dismiss-firefox-suggest"
: "firefox-suggest-urlbar-block",
},
requestId: MerinoTestUtils.server.response.body.request_id,
source: "merino",

View File

@ -117,6 +117,9 @@ urlbar-result-menu-button =
urlbar-result-menu-remove-from-history =
.label = Remove from history
.accesskey = R
urlbar-result-menu-tip-get-help =
.label = Get help
.accesskey = h
## Prompts users to use the Urlbar when they open a new tab or visit the
## homepage of their default search engine.