Bug 1801298 - Fix down/up arrow behavior with multiple selectable elements per row. r=adw

Differential Revision: https://phabricator.services.mozilla.com/D166803
This commit is contained in:
Dão Gottwald 2023-01-19 10:26:53 +00:00
Родитель ef53bf13fa
Коммит 477eb99f64
15 изменённых файлов: 142 добавлений и 159 удалений

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

@ -408,10 +408,10 @@ async function runTipTests() {
event = await focused;
testStates(event.accessible, STATE_FOCUSED);
info("Ensuring the help button is focused on down arrow");
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);
EventUtils.synthesizeKey("KEY_ArrowDown");
EventUtils.synthesizeKey("KEY_Tab");
event = await focused;
testStates(event.accessible, STATE_FOCUSED);
@ -421,9 +421,9 @@ async function runTipTests() {
event = await focused;
testStates(event.accessible, STATE_FOCUSED);
info("Ensuring the help button is focused on up arrow");
info("Ensuring the help button is focused on shift+tab");
focused = waitForEvent(EVENT_FOCUS, isEventForTipButton);
EventUtils.synthesizeKey("KEY_ArrowUp");
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
event = await focused;
testStates(event.accessible, STATE_FOCUSED);

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

@ -194,7 +194,7 @@ add_task(async function tip_onResultPicked_helpButton_url_enter() {
ext.onMessage("onResultPicked received", () => {
Assert.ok(false, "onResultPicked should not be called");
});
EventUtils.synthesizeKey("KEY_ArrowDown");
EventUtils.synthesizeKey("KEY_Tab");
EventUtils.synthesizeKey("KEY_Enter");
await loadedPromise;
Assert.equal(gBrowser.currentURI.spec, "http://example.com/");

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

@ -308,7 +308,7 @@ export class UrlbarController {
let { queryContext } = this._lastQueryContextWrapper;
let handled = this.view.oneOffSearchButtons.handleKeyDown(
event,
this.view.visibleElementCount,
this.view.visibleRowCount,
this.view.allowEmptySelection,
queryContext.searchString
);

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

@ -149,10 +149,10 @@ export class UrlbarSearchOneOffs extends SearchOneOffs {
* @returns {number}
*/
get selectedViewIndex() {
return this.view.selectedElementIndex;
return this.view.selectedRowIndex;
}
set selectedViewIndex(val) {
this.view.selectedElementIndex = val;
this.view.selectedRowIndex = val;
}
/**

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

@ -183,30 +183,6 @@ export class UrlbarView {
return this.#selectedElement.elementIndex;
}
set selectedElementIndex(val) {
if (!this.isOpen) {
throw new Error(
"UrlbarView: Cannot select an item if the view isn't open."
);
}
if (val < 0) {
this.#selectElement(null);
return;
}
let selectableElement = this.#getFirstSelectableElement();
while (selectableElement && selectableElement.elementIndex != val) {
selectableElement = this.#getNextSelectableElement(selectableElement);
}
if (!selectableElement) {
throw new Error(`UrlbarView: Index ${val} is out of bounds.`);
}
this.#selectElement(selectableElement);
}
/**
* @returns {UrlbarResult}
* The currently selected result.
@ -252,22 +228,6 @@ export class UrlbarView {
return sum;
}
/**
* @returns {number}
* The number of selectable elements in the view.
*/
get visibleElementCount() {
let sum = 0;
let element = this.#getFirstSelectableElement();
while (element) {
if (this.#isElementVisible(element)) {
sum++;
}
element = this.#getNextSelectableElement(element);
}
return sum;
}
/**
* Returns the result of the row containing the given element, or the result
* of the element if it itself is a row.
@ -331,6 +291,37 @@ export class UrlbarView {
);
}
// Freeze results as the user is interacting with them, unless we are
// deferring events while waiting for critical results.
if (!this.input.eventBufferer.isDeferringEvents) {
this.controller.cancelQuery();
}
if (!userPressedTab) {
let { selectedRowIndex } = this;
let end = this.visibleRowCount - 1;
if (selectedRowIndex == -1) {
this.selectedRowIndex = reverse ? end : 0;
return;
}
let endReached = selectedRowIndex == (reverse ? 0 : end);
if (endReached) {
if (this.allowEmptySelection) {
this.#selectElement(null);
} else {
this.selectedRowIndex = reverse ? end : 0;
}
return;
}
this.selectedRowIndex = Math.max(
0,
Math.min(end, selectedRowIndex + amount * (reverse ? -1 : 1))
);
return;
}
// Tab key handling below.
// Do not set aria-activedescendant if the user is moving to a
// tab-to-search result with the Tab key. If
// accessibility.tabToSearch.announceResults is set, the tab-to-search
@ -341,7 +332,6 @@ export class UrlbarView {
let skipAnnouncement =
selectedElt?.result?.providerName == "TabToSearch" &&
!this.#announceTabToSearchOnSelection &&
userPressedTab &&
lazy.UrlbarPrefs.get("accessibility.tabToSearch.announceResults");
if (skipAnnouncement) {
// Once we skip setting aria-activedescendant once, we should not skip
@ -351,12 +341,6 @@ export class UrlbarView {
return skipAnnouncement;
};
// Freeze results as the user is interacting with them, unless we are
// deferring events while waiting for critical results.
if (!this.input.eventBufferer.isDeferringEvents) {
this.controller.cancelQuery();
}
let selectedElement = this.#selectedElement;
// We cache the first and last rows since they will not change while
@ -399,9 +383,6 @@ export class UrlbarView {
if (!next) {
break;
}
if (!this.#isElementVisible(next)) {
continue;
}
selectedElement = next;
}
this.#selectElement(selectedElement, {
@ -1938,7 +1919,7 @@ export class UrlbarView {
if (!element || element.style.display == "none") {
return false;
}
let row = element.closest(".urlbarView-row");
let row = this.#getRowFromElement(element);
return row && row.style.display != "none";
}
@ -1989,7 +1970,7 @@ export class UrlbarView {
this.#setAccessibleFocus(setAccessibleFocus && element);
this.#selectedElement = element;
let result = element?.closest(".urlbarView-row")?.result;
let result = this.#getRowFromElement(element)?.result;
if (updateInput) {
let urlOverride = null;
if (element?.classList?.contains("urlbarView-button-help")) {
@ -2078,7 +2059,7 @@ export class UrlbarView {
* last selectable element.
*/
#getNextSelectableElement(element) {
let row = element.closest(".urlbarView-row");
let row = this.#getRowFromElement(element);
if (!row) {
return null;
}
@ -2110,7 +2091,7 @@ export class UrlbarView {
* the first selectable element.
*/
#getPreviousSelectableElement(element) {
let row = element.closest(".urlbarView-row");
let row = this.#getRowFromElement(element);
if (!row) {
return null;
}

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

@ -139,10 +139,10 @@ async function doTest({ click, buttonUrl = undefined, helpUrl = undefined }) {
let helpButton = row._buttons.get("help");
let target = helpUrl ? helpButton : mainButton;
// If we're picking the tip with the keyboard, arrow down to select the proper
// If we're picking the tip with the keyboard, TAB to select the proper
// target.
if (!click) {
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: helpUrl ? 2 : 1 });
EventUtils.synthesizeKey("KEY_Tab", { repeat: helpUrl ? 2 : 1 });
Assert.equal(
UrlbarTestUtils.getSelectedElement(window),
target,

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

@ -45,7 +45,7 @@ add_task(async function tipIsSecondResult() {
"The first element should be selected."
);
EventUtils.synthesizeKey("KEY_ArrowDown");
EventUtils.synthesizeKey("KEY_Tab");
Assert.ok(
UrlbarTestUtils.getSelectedElement(window).classList.contains(
"urlbarView-button-0"
@ -58,7 +58,7 @@ add_task(async function tipIsSecondResult() {
"The first element should be selected."
);
EventUtils.synthesizeKey("KEY_ArrowDown");
EventUtils.synthesizeKey("KEY_Tab");
Assert.ok(
UrlbarTestUtils.getSelectedElement(window).classList.contains(
"urlbarView-button-help"
@ -98,7 +98,7 @@ add_task(async function tipIsSecondResult() {
"No results should be selected."
);
EventUtils.synthesizeKey("KEY_ArrowUp");
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
Assert.ok(
UrlbarTestUtils.getSelectedElement(window).classList.contains(
"urlbarView-button-help"
@ -133,7 +133,7 @@ add_task(async function tipIsOnlyResult() {
"The first and only result should be a tip."
);
EventUtils.synthesizeKey("KEY_ArrowDown");
EventUtils.synthesizeKey("KEY_Tab");
Assert.ok(
UrlbarTestUtils.getSelectedElement(window).classList.contains(
"urlbarView-button-0"
@ -146,7 +146,7 @@ add_task(async function tipIsOnlyResult() {
"The first element should be selected."
);
EventUtils.synthesizeKey("KEY_ArrowDown");
EventUtils.synthesizeKey("KEY_Tab");
Assert.ok(
UrlbarTestUtils.getSelectedElement(window).classList.contains(
"urlbarView-button-help"
@ -166,7 +166,7 @@ add_task(async function tipIsOnlyResult() {
"There should be no selection."
);
EventUtils.synthesizeKey("KEY_ArrowUp");
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
Assert.ok(
UrlbarTestUtils.getSelectedElement(window).classList.contains(
"urlbarView-button-help"

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

@ -87,44 +87,36 @@ add_task(async function keySelection() {
hasHelpButton: true,
});
// Test with the tab key vs. arrow keys and in order vs. reverse order.
for (let useTabKey of [false, true]) {
for (let reverse of [false, true]) {
info("Doing key selection: " + JSON.stringify({ useTabKey, reverse }));
// Test with the tab key in order vs. reverse order.
for (let reverse of [false, true]) {
info("Doing TAB key selection: " + JSON.stringify({ reverse }));
let classNames = [...expectedClassNames];
if (reverse) {
classNames.reverse();
}
let classNames = [...expectedClassNames];
if (reverse) {
classNames.reverse();
}
let sendKey = () => {
if (useTabKey) {
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: reverse });
} else if (reverse) {
EventUtils.synthesizeKey("KEY_ArrowUp");
} else {
EventUtils.synthesizeKey("KEY_ArrowDown");
}
};
let sendKey = () => {
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: reverse });
};
// Move selection through each expected element.
for (let className of classNames) {
info("Expecting selection: " + className);
sendKey();
Assert.ok(gURLBar.view.isOpen, "View remains open");
let { selectedElement } = gURLBar.view;
Assert.ok(selectedElement, "Selected element exists");
Assert.ok(
selectedElement.classList.contains(className),
"Expected element is selected"
);
}
// Move selection through each expected element.
for (let className of classNames) {
info("Expecting selection: " + className);
sendKey();
Assert.ok(gURLBar.view.isOpen, "View remains open");
let { selectedElement } = gURLBar.view;
Assert.ok(selectedElement, "Selected element exists");
Assert.ok(
gURLBar.view.isOpen,
"View remains open after keying through best match row"
selectedElement.classList.contains(className),
"Expected element is selected"
);
}
sendKey();
Assert.ok(
gURLBar.view.isOpen,
"View remains open after keying through best match row"
);
}
await UrlbarTestUtils.promisePopupClose(window);

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

@ -327,15 +327,15 @@ add_task(async function selection() {
"row.result.type"
);
// The heuristic result will be selected. Arrow down from the heuristic
// through all the selectable elements in the dynamic result.
// The heuristic result will be selected. TAB from the heuristic through
// all the selectable elements in the dynamic result.
let selectables = ["selectable", "button1", "button2"];
for (let name of selectables) {
let element = row.querySelector(
`.urlbarView-dynamic-${DYNAMIC_TYPE_NAME}-${name}`
);
Assert.ok(element, "Sanity check element");
EventUtils.synthesizeKey("KEY_ArrowDown");
EventUtils.synthesizeKey("KEY_Tab");
Assert.equal(
UrlbarTestUtils.getSelectedElement(window),
element,
@ -349,8 +349,8 @@ add_task(async function selection() {
Assert.equal(UrlbarTestUtils.getSelectedRow(window), row, "Row selected");
}
// Arrow down again to select the result after the dynamic result.
EventUtils.synthesizeKey("KEY_ArrowDown");
// TAB again to select the result after the dynamic result.
EventUtils.synthesizeKey("KEY_Tab");
Assert.equal(
UrlbarTestUtils.getSelectedRowIndex(window),
2,
@ -362,13 +362,13 @@ add_task(async function selection() {
"Row is not selected"
);
// Arrow back up through the dynamic result.
// SHIFT+TAB back through the dynamic result.
for (let name of selectables.reverse()) {
let element = row.querySelector(
`.urlbarView-dynamic-${DYNAMIC_TYPE_NAME}-${name}`
);
Assert.ok(element, "Sanity check element");
EventUtils.synthesizeKey("KEY_ArrowUp");
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
Assert.equal(
UrlbarTestUtils.getSelectedElement(window),
element,
@ -382,8 +382,8 @@ add_task(async function selection() {
Assert.equal(UrlbarTestUtils.getSelectedRow(window), row, "Row selected");
}
// Arrow up again to select the heuristic result.
EventUtils.synthesizeKey("KEY_ArrowUp");
// SHIFT+TAB again to select the heuristic result.
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
Assert.equal(
UrlbarTestUtils.getSelectedRowIndex(window),
0,
@ -422,13 +422,13 @@ add_task(async function pick() {
"row.result.type"
);
// The heuristic result will be selected. Arrow down from the heuristic
// The heuristic result will be selected. TAB from the heuristic
// to the selectable element.
let element = row.querySelector(
`.urlbarView-dynamic-${DYNAMIC_TYPE_NAME}-${selectable}`
);
Assert.ok(element, "Sanity check element");
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: i + 1 });
EventUtils.synthesizeKey("KEY_Tab", { repeat: i + 1 });
Assert.equal(
UrlbarTestUtils.getSelectedElement(window),
element,
@ -483,13 +483,13 @@ add_task(async function shouldNavigate() {
"row.result.type"
);
// The heuristic result will be selected. Arrow down from the heuristic
// The heuristic result will be selected. TAB from the heuristic
// to the selectable element.
let element = row.querySelector(
`.urlbarView-dynamic-${DYNAMIC_TYPE_NAME}-selectable`
);
Assert.ok(element, "Sanity check element");
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: 1 });
EventUtils.synthesizeKey("KEY_Tab", { repeat: 1 });
Assert.equal(
UrlbarTestUtils.getSelectedElement(window),
element,

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

@ -48,7 +48,7 @@ add_task(async function title_helpL10n() {
UrlbarProvidersManager.unregisterProvider(provider);
});
// Arrows up and down through a result with a help button. The result is the
// (SHIFT+)TABs through a result with a help button. The result is the
// second result and has other results after it.
add_task(async function keyboardSelection_secondResult() {
let provider = registerTestProvider(1);
@ -70,35 +70,35 @@ add_task(async function keyboardSelection_secondResult() {
);
await assertIsTestResult(1);
// Arrow down to the main part of the result.
EventUtils.synthesizeKey("KEY_ArrowDown");
// TAB to the main part of the result.
EventUtils.synthesizeKey("KEY_Tab");
assertMainPartSelected(1);
// Arrow down to the help button.
EventUtils.synthesizeKey("KEY_ArrowDown");
// TAB to the help button.
EventUtils.synthesizeKey("KEY_Tab");
assertHelpButtonSelected(2);
// Arrow down to the next (third) result.
EventUtils.synthesizeKey("KEY_ArrowDown");
// TAB to the next (third) result.
EventUtils.synthesizeKey("KEY_Tab");
assertOtherResultSelected(3, "next result");
// Arrow up to the help button.
EventUtils.synthesizeKey("KEY_ArrowUp");
// SHIFT+TAB to the help button.
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
assertHelpButtonSelected(2);
// Arrow up to the main part of the result.
EventUtils.synthesizeKey("KEY_ArrowUp");
// SHIFT+TAB to the main part of the result.
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
assertMainPartSelected(1);
// Arrow up to the previous (first) result.
EventUtils.synthesizeKey("KEY_ArrowUp");
// SHIFT+TAB to the previous (first) result.
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
assertOtherResultSelected(0, "previous result");
await UrlbarTestUtils.promisePopupClose(window);
UrlbarProvidersManager.unregisterProvider(provider);
});
// Arrows up and down through a result with a help button. The result is the
// (SHIFT+)TABs through a result with a help button. The result is the
// last result.
add_task(async function keyboardSelection_lastResult() {
let provider = registerTestProvider(MAX_RESULTS - 1);
@ -120,12 +120,12 @@ add_task(async function keyboardSelection_lastResult() {
);
await assertIsTestResult(MAX_RESULTS - 1);
// Arrow down to the main part of the result.
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: MAX_RESULTS - 1 });
// TAB to the main part of the result.
EventUtils.synthesizeKey("KEY_Tab", { repeat: MAX_RESULTS - 1 });
assertMainPartSelected(MAX_RESULTS - 1);
// Arrow down to the help button.
EventUtils.synthesizeKey("KEY_ArrowDown");
// TAB to the help button.
EventUtils.synthesizeKey("KEY_Tab");
assertHelpButtonSelected(MAX_RESULTS);
// Arrow down to the first one-off. If this test is running alone, the
@ -151,16 +151,16 @@ add_task(async function keyboardSelection_lastResult() {
"No results should be selected."
);
// Arrow up to the help button.
EventUtils.synthesizeKey("KEY_ArrowUp");
// SHIFT+TAB to the help button.
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
assertHelpButtonSelected(MAX_RESULTS);
// Arrow up to the main part of the result.
EventUtils.synthesizeKey("KEY_ArrowUp");
// SHIFT+TAB to the main part of the result.
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
assertMainPartSelected(MAX_RESULTS - 1);
// Arrow up to the previous result.
EventUtils.synthesizeKey("KEY_ArrowUp");
// SHIFT+TAB to the previous result.
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
assertOtherResultSelected(MAX_RESULTS - 2, "previous result");
await UrlbarTestUtils.promisePopupClose(window);
@ -208,12 +208,12 @@ async function doPickTest({ pickHelpButton, useKeyboard }) {
let clickTarget;
if (useKeyboard) {
// Arrow down to the result.
// TAB to the result.
if (pickHelpButton) {
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: index + 1 });
EventUtils.synthesizeKey("KEY_Tab", { repeat: index + 1 });
assertHelpButtonSelected(index + 1);
} else {
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: index });
EventUtils.synthesizeKey("KEY_Tab", { repeat: index });
assertMainPartSelected(index);
}
} else {

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

@ -105,7 +105,7 @@ add_task(async function test_remove_form_history() {
}
Assert.ok(index < count, "Result found");
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: index });
EventUtils.synthesizeKey("KEY_Tab", { repeat: index });
Assert.equal(UrlbarTestUtils.getSelectedRowIndex(window), index);
EventUtils.synthesizeKey("KEY_Delete", { shiftKey: true });
await promiseRemoved;
@ -266,13 +266,13 @@ add_task(async function blockButton() {
let button = row.querySelector(".urlbarView-button-block");
Assert.ok(button, "The row should have a block button");
info("Arrowing down to block button");
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: 2 });
info("Tabbing down to block button");
EventUtils.synthesizeKey("KEY_Tab", { repeat: 2 });
Assert.equal(
UrlbarTestUtils.getSelectedElement(window),
button,
"The block button should be selected after arrowing down"
"The block button should be selected after tabbing down"
);
info("Pressing Enter on block button");

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

@ -14,12 +14,21 @@ async function openResultMenuAndPressAccesskey(resultIndex, accesskey) {
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"
);
await EventUtils.synthesizeMouseAtCenter(menuButton, {}, window);
EventUtils.synthesizeKey("KEY_Enter", {});
info("waiting for the menu to open");
await promiseMenuOpen;

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

@ -49,11 +49,12 @@ add_task(async function test() {
value: "test",
});
let oneOffs = UrlbarTestUtils.getOneOffSearchButtons(window);
while (!oneOffs.selectedButton) {
EventUtils.synthesizeKey("KEY_ArrowDown");
}
EventUtils.synthesizeKey("KEY_Tab", { repeat: 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.");
UrlbarProvidersManager.unregisterProvider(provider);

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

@ -236,8 +236,8 @@ const tests = [
info("Selecting a tip's main button, enter.");
win.gURLBar.search("x");
await UrlbarTestUtils.promiseSearchComplete(win);
EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
EventUtils.synthesizeKey("KEY_Tab", {}, win);
EventUtils.synthesizeKey("KEY_Tab", {}, win);
EventUtils.synthesizeKey("VK_RETURN", {}, win);
unregisterTipProvider(tipProvider);
return {
@ -262,9 +262,9 @@ const tests = [
let promise = BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
win.gURLBar.search("x");
await UrlbarTestUtils.promiseSearchComplete(win);
EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
EventUtils.synthesizeKey("KEY_Tab", {}, win);
EventUtils.synthesizeKey("KEY_Tab", {}, win);
EventUtils.synthesizeKey("KEY_Tab", {}, win);
EventUtils.synthesizeKey("VK_RETURN", {}, win);
await promise;
unregisterTipProvider(tipProvider);

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

@ -103,9 +103,9 @@ add_combo_task(async function basic_keyboard({ result, isBestMatch }) {
result,
isBestMatch,
block: () => {
// Arrow down twice to select the block button: once to select the main
// 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_ArrowDown", { repeat: 2 });
EventUtils.synthesizeKey("KEY_Tab", { repeat: 2 });
EventUtils.synthesizeKey("KEY_Enter");
},
});
@ -268,7 +268,7 @@ add_task(async function blockMultiple() {
});
// Block it.
EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: 2 });
EventUtils.synthesizeKey("KEY_Tab", { repeat: 2 });
EventUtils.synthesizeKey("KEY_Enter");
Assert.ok(
await QuickSuggest.blockedSuggestions.has(url),