1 /* Any copyright is dedicated to the Public Domain.
2 * http://creativecommons.org/publicdomain/zero/1.0/ */
5 * Checks the local shortcut rows in the engines list of the search pane.
10 ChromeUtils.defineESModuleGetters(this, {
11 UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
12 UrlbarUtils: "resource:///modules/UrlbarUtils.sys.mjs",
17 add_setup(async function () {
18 let prefs = await openPreferencesViaOpenPreferencesAPI("search", {
21 registerCleanupFunction(() => {
22 BrowserTestUtils.removeTab(gBrowser.selectedTab);
28 "Sanity check: Search pane is selected by default"
31 gTree = gBrowser.contentDocument.querySelector("#engineList");
32 gTree.scrollIntoView();
36 // The rows should be visible and checked by default.
37 add_task(async function visible() {
38 await checkRowVisibility(true);
39 await forEachLocalShortcutRow(async (row, shortcut) => {
41 gTree.view.getCellValue(row, gTree.columns.getNamedColumn("engineShown")),
43 "Row is checked initially"
48 // Toggling the browser.urlbar.shortcuts.* prefs should toggle the corresponding
49 // checkboxes in the rows.
50 add_task(async function syncFromPrefs() {
51 let col = gTree.columns.getNamedColumn("engineShown");
52 await forEachLocalShortcutRow(async (row, shortcut) => {
54 gTree.view.getCellValue(row, col),
56 "Row is checked initially"
58 await SpecialPowers.pushPrefEnv({
59 set: [[getUrlbarPrefName(shortcut.pref), false]],
62 gTree.view.getCellValue(row, col),
64 "Row is unchecked after disabling pref"
66 await SpecialPowers.popPrefEnv();
68 gTree.view.getCellValue(row, col),
70 "Row is checked after re-enabling pref"
75 // Pressing the space key while a row is selected should toggle its checkbox
77 add_task(async function syncToPrefs_spaceKey() {
78 let col = gTree.columns.getNamedColumn("engineShown");
79 await forEachLocalShortcutRow(async (row, shortcut) => {
81 UrlbarPrefs.get(shortcut.pref),
82 "Sanity check: Pref is enabled initially"
85 gTree.view.getCellValue(row, col),
87 "Row is checked initially"
89 gTree.view.selection.select(row);
90 EventUtils.synthesizeKey(" ", {}, gTree.ownerGlobal);
92 !UrlbarPrefs.get(shortcut.pref),
93 "Pref is disabled after pressing space key"
96 gTree.view.getCellValue(row, col),
98 "Row is unchecked after pressing space key"
100 Services.prefs.clearUserPref(getUrlbarPrefName(shortcut.pref));
104 // Clicking the checkbox in a local shortcut row should toggle the checkbox and
106 add_task(async function syncToPrefs_click() {
107 let col = gTree.columns.getNamedColumn("engineShown");
108 await forEachLocalShortcutRow(async (row, shortcut) => {
110 UrlbarPrefs.get(shortcut.pref),
111 "Sanity check: Pref is enabled initially"
114 gTree.view.getCellValue(row, col),
116 "Row is checked initially"
119 let rect = gTree.getCoordsForCellItem(row, col, "cell");
120 let x = rect.x + rect.width / 2;
121 let y = rect.y + rect.height / 2;
122 EventUtils.synthesizeMouse(gTree.body, x, y, {}, gTree.ownerGlobal);
125 !UrlbarPrefs.get(shortcut.pref),
126 "Pref is disabled after clicking checkbox"
129 gTree.view.getCellValue(row, col),
131 "Row is unchecked after clicking checkbox"
133 Services.prefs.clearUserPref(getUrlbarPrefName(shortcut.pref));
137 // The keyword column should not be editable according to isEditable().
138 add_task(async function keywordNotEditable_isEditable() {
139 await forEachLocalShortcutRow(async (row, shortcut) => {
141 !gTree.view.isEditable(
143 gTree.columns.getNamedColumn("engineKeyword")
145 "Keyword column is not editable"
150 // Pressing the enter key while a row is selected shouldn't allow the keyword to
152 add_task(async function keywordNotEditable_enterKey() {
153 let col = gTree.columns.getNamedColumn("engineKeyword");
154 await forEachLocalShortcutRow(async (row, shortcut) => {
157 "Sanity check: Shortcut restriction char is non-empty"
160 gTree.view.getCellText(row, col),
162 "Sanity check: Keyword column has correct restriction char initially"
165 gTree.view.selection.select(row);
166 EventUtils.synthesizeKey("KEY_Enter", {}, gTree.ownerGlobal);
167 EventUtils.sendString("newkeyword");
168 EventUtils.synthesizeKey("KEY_Enter", {}, gTree.ownerGlobal);
170 // Wait a moment to allow for any possible asynchronicity.
171 // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
172 await new Promise(r => setTimeout(r, 500));
175 gTree.view.getCellText(row, col),
177 "Keyword column is still restriction char"
182 // Double-clicking the keyword column shouldn't allow the keyword to be edited.
183 add_task(async function keywordNotEditable_click() {
184 let col = gTree.columns.getNamedColumn("engineKeyword");
185 await forEachLocalShortcutRow(async (row, shortcut) => {
188 "Sanity check: Shortcut restriction char is non-empty"
191 gTree.view.getCellText(row, col),
193 "Sanity check: Keyword column has correct restriction char initially"
196 let rect = gTree.getCoordsForCellItem(row, col, "text");
197 let x = rect.x + rect.width / 2;
198 let y = rect.y + rect.height / 2;
200 let promise = BrowserTestUtils.waitForEvent(gTree, "dblclick");
202 // Click once to select the row.
203 EventUtils.synthesizeMouse(
211 // Now double-click the keyword column.
212 EventUtils.synthesizeMouse(
222 EventUtils.sendString("newkeyword");
223 EventUtils.synthesizeKey("KEY_Enter", {}, gTree.ownerGlobal);
225 // Wait a moment to allow for any possible asynchronicity.
226 // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
227 await new Promise(r => setTimeout(r, 500));
230 gTree.view.getCellText(row, col),
232 "Keyword column is still restriction char"
238 * Asserts that the engine and local shortcut rows are present in the tree.
240 async function checkRowVisibility() {
241 let engines = await Services.search.getVisibleEngines();
245 engines.length + UrlbarUtils.LOCAL_SEARCH_MODES.length,
246 "Expected number of tree rows"
249 // Check the engine rows.
250 for (let row = 0; row < engines.length; row++) {
251 let engine = engines[row];
252 let text = gTree.view.getCellText(
254 gTree.columns.getNamedColumn("engineName")
259 `Sanity check: Tree row ${row} has expected engine name`
263 // Check the shortcut rows.
264 await forEachLocalShortcutRow(async (row, shortcut) => {
265 let text = gTree.view.getCellText(
267 gTree.columns.getNamedColumn("engineName")
269 let name = UrlbarUtils.getResultSourceName(shortcut.source);
270 let l10nName = await gTree.ownerDocument.l10n.formatValue(
271 `urlbar-search-mode-${name}`
273 Assert.ok(l10nName, "Sanity check: l10n name is non-empty");
274 Assert.equal(text, l10nName, `Tree row ${row} has expected shortcut name`);
279 * Calls a callback for each local shortcut row in the tree.
281 * @param {function} callback
282 * Called for each local shortcut row like: callback(rowIndex, shortcutObject)
284 async function forEachLocalShortcutRow(callback) {
285 let engines = await Services.search.getVisibleEngines();
286 for (let i = 0; i < UrlbarUtils.LOCAL_SEARCH_MODES.length; i++) {
287 let shortcut = UrlbarUtils.LOCAL_SEARCH_MODES[i];
288 let row = engines.length + i;
289 // These tests assume LOCAL_SEARCH_MODES are enabled, this can be removed
290 // when we enable QuickActions. We cant just enable the pref in browser.ini
291 // as this test calls clearUserPref.
292 if (shortcut.pref == "shortcuts.quickactions") {
295 await callback(row, shortcut);
300 * Prepends the `browser.urlbar.` branch to the given relative pref.
302 * @param {string} relativePref
303 * A pref name relative to the `browser.urlbar.`.
305 * The full pref name with `browser.urlbar.` prepended.
307 function getUrlbarPrefName(relativePref) {
308 return `browser.urlbar.${relativePref}`;