browser_searchTips_interaction.js (15973B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 // Tests the Search Tips feature, which displays a prompt to use the Urlbar on 5 // the newtab page and on the user's default search engine's homepage. 6 // Specifically, it tests that the Tips appear when they should be appearing. 7 // This doesn't test the max-shown-count limit because it requires restarting 8 // the browser. 9 10 "use strict"; 11 12 ChromeUtils.defineESModuleGetters(this, { 13 AppMenuNotifications: "resource://gre/modules/AppMenuNotifications.sys.mjs", 14 HttpServer: "resource://testing-common/httpd.sys.mjs", 15 UrlbarPrefs: "moz-src:///browser/components/urlbar/UrlbarPrefs.sys.mjs", 16 UrlbarProviderSearchTips: 17 "moz-src:///browser/components/urlbar/UrlbarProviderSearchTips.sys.mjs", 18 UrlbarUtils: "moz-src:///browser/components/urlbar/UrlbarUtils.sys.mjs", 19 }); 20 21 XPCOMUtils.defineLazyServiceGetter( 22 this, 23 "clipboardHelper", 24 "@mozilla.org/widget/clipboardhelper;1", 25 Ci.nsIClipboardHelper 26 ); 27 28 // These should match the same consts in UrlbarProviderSearchTips.sys.mjs. 29 const MAX_SHOWN_COUNT = 4; 30 const LAST_UPDATE_THRESHOLD_MS = 24 * 60 * 60 * 1000; 31 32 // We test some of the bigger Google domains. 33 const GOOGLE_DOMAINS = [ 34 "www.google.com", 35 "www.google.ca", 36 "www.google.co.uk", 37 "www.google.com.au", 38 "www.google.co.nz", 39 ]; 40 let tipsProviderInstance = UrlbarProvidersManager.getProvider( 41 "UrlbarProviderSearchTips" 42 ); 43 44 add_setup(async function () { 45 await PlacesUtils.history.clear(); 46 await PlacesUtils.bookmarks.eraseEverything(); 47 48 await SpecialPowers.pushPrefEnv({ 49 set: [ 50 [ 51 `browser.urlbar.tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.ONBOARD}`, 52 0, 53 ], 54 [ 55 `browser.urlbar.tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.REDIRECT}`, 56 0, 57 ], 58 // Set following prefs so tips are actually shown. 59 ["browser.laterrun.bookkeeping.profileCreationTime", 0], 60 ["browser.laterrun.bookkeeping.updateAppliedTime", 0], 61 ], 62 }); 63 64 // Remove update history and the current active update so tips are shown. 65 let updateRootDir = Services.dirsvc.get("UpdRootD", Ci.nsIFile); 66 let updatesFile = updateRootDir.clone(); 67 updatesFile.append("updates.xml"); 68 let activeUpdateFile = updateRootDir.clone(); 69 activeUpdateFile.append("active-update.xml"); 70 try { 71 updatesFile.remove(false); 72 } catch (e) {} 73 try { 74 activeUpdateFile.remove(false); 75 } catch (e) {} 76 77 let defaultEngine = await Services.search.getDefault(); 78 let defaultEngineName = defaultEngine.name; 79 Assert.equal(defaultEngineName, "Google", "Default engine should be Google."); 80 81 // Add a mock engine so we don't hit the network loading the SERP. 82 await SearchTestUtils.installSearchExtension(); 83 84 registerCleanupFunction(async () => { 85 await setDefaultEngine(defaultEngineName); 86 resetSearchTipsProvider(); 87 }); 88 }); 89 90 // Picking the tip's button should cause the Urlbar to blank out and the tip to 91 // be not to be shown again in any session. 92 add_task(async function pickButton_onboard() { 93 tipsProviderInstance.disableTipsForCurrentSession = false; 94 let tab = await BrowserTestUtils.openNewForegroundTab({ 95 gBrowser, 96 url: "about:newtab", 97 waitForLoad: false, 98 }); 99 await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.ONBOARD, false); 100 101 // Click the tip button. 102 let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0); 103 let button = result.element.row._buttons.get("0"); 104 await UrlbarTestUtils.promisePopupClose(window, () => { 105 EventUtils.synthesizeMouseAtCenter(button, {}); 106 }); 107 gURLBar.blur(); 108 109 Assert.equal( 110 UrlbarPrefs.get( 111 `tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.ONBOARD}` 112 ), 113 MAX_SHOWN_COUNT, 114 "Onboarding tips are disabled after tip button is picked." 115 ); 116 Assert.equal(gURLBar.value, "", "The Urlbar should be empty."); 117 resetSearchTipsProvider(); 118 119 BrowserTestUtils.removeTab(tab); 120 }); 121 122 // Picking the tip's button should cause the Urlbar to blank out and the tip to 123 // be not to be shown again in any session. 124 add_task(async function pickButton_redirect() { 125 tipsProviderInstance.disableTipsForCurrentSession = false; 126 await setDefaultEngine("Google"); 127 await BrowserTestUtils.withNewTab("about:blank", async () => { 128 await withDNSRedirect("www.google.com", "/", async url => { 129 BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, url); 130 await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); 131 await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT, false); 132 133 // Click the tip button. 134 let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0); 135 let button = result.element.row._buttons.get("0"); 136 await UrlbarTestUtils.promisePopupClose(window, () => { 137 EventUtils.synthesizeMouseAtCenter(button, {}); 138 }); 139 gURLBar.blur(); 140 }); 141 }); 142 143 Assert.equal( 144 UrlbarPrefs.get( 145 `tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.REDIRECT}` 146 ), 147 MAX_SHOWN_COUNT, 148 "Redirect tips are disabled after tip button is picked." 149 ); 150 Assert.equal(gURLBar.value, "", "The Urlbar should be empty."); 151 resetSearchTipsProvider(); 152 }); 153 154 // Clicking in the input while the onboard tip is showing should have the same 155 // effect as picking the tip. 156 add_task(async function clickInInput_onboard() { 157 tipsProviderInstance.disableTipsForCurrentSession = false; 158 await setDefaultEngine("Google"); 159 let tab = await BrowserTestUtils.openNewForegroundTab({ 160 gBrowser, 161 url: "about:newtab", 162 waitForLoad: false, 163 }); 164 await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.ONBOARD, false); 165 166 // Click in the input. 167 await UrlbarTestUtils.promisePopupClose(window, () => { 168 EventUtils.synthesizeMouseAtCenter(gURLBar.parentNode, {}); 169 }); 170 gURLBar.blur(); 171 172 Assert.equal( 173 UrlbarPrefs.get( 174 `tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.ONBOARD}` 175 ), 176 MAX_SHOWN_COUNT, 177 "Onboarding tips are disabled after tip button is picked." 178 ); 179 Assert.equal(gURLBar.value, "", "The Urlbar should be empty."); 180 resetSearchTipsProvider(); 181 BrowserTestUtils.removeTab(tab); 182 }); 183 184 // Pressing Ctrl+L (the open location command) while the onboard tip is showing 185 // should have the same effect as picking the tip. 186 add_task(async function openLocation_onboard() { 187 tipsProviderInstance.disableTipsForCurrentSession = false; 188 await setDefaultEngine("Google"); 189 let tab = await BrowserTestUtils.openNewForegroundTab({ 190 gBrowser, 191 url: "about:newtab", 192 waitForLoad: false, 193 }); 194 await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.ONBOARD, false); 195 196 // Trigger the open location command. 197 await UrlbarTestUtils.promisePopupClose(window, () => { 198 document.getElementById("Browser:OpenLocation").doCommand(); 199 }); 200 gURLBar.blur(); 201 202 Assert.equal( 203 UrlbarPrefs.get( 204 `tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.ONBOARD}` 205 ), 206 MAX_SHOWN_COUNT, 207 "Onboarding tips are disabled after tip button is picked." 208 ); 209 Assert.equal(gURLBar.value, "", "The Urlbar should be empty."); 210 resetSearchTipsProvider(); 211 BrowserTestUtils.removeTab(tab); 212 }); 213 214 // Clicking in the input while the redirect tip is showing should have the same 215 // effect as picking the tip. 216 add_task(async function clickInInput_redirect() { 217 tipsProviderInstance.disableTipsForCurrentSession = false; 218 await setDefaultEngine("Google"); 219 await BrowserTestUtils.withNewTab("about:blank", async () => { 220 await withDNSRedirect("www.google.com", "/", async url => { 221 BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, url); 222 await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); 223 await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT, false); 224 225 // Click in the input. 226 await UrlbarTestUtils.promisePopupClose(window, () => { 227 EventUtils.synthesizeMouseAtCenter(gURLBar.parentNode, {}); 228 }); 229 gURLBar.blur(); 230 }); 231 }); 232 233 Assert.equal( 234 UrlbarPrefs.get( 235 `tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.REDIRECT}` 236 ), 237 MAX_SHOWN_COUNT, 238 "Redirect tips are disabled after tip button is picked." 239 ); 240 Assert.equal(gURLBar.value, "", "The Urlbar should be empty."); 241 resetSearchTipsProvider(); 242 }); 243 244 // Pressing Ctrl+L (the open location command) while the redirect tip is showing 245 // should have the same effect as picking the tip. 246 add_task(async function openLocation_redirect() { 247 tipsProviderInstance.disableTipsForCurrentSession = false; 248 await setDefaultEngine("Google"); 249 await BrowserTestUtils.withNewTab("about:blank", async () => { 250 await withDNSRedirect("www.google.com", "/", async url => { 251 BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, url); 252 await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); 253 await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT, false); 254 255 // Trigger the open location command. 256 await UrlbarTestUtils.promisePopupClose(window, () => { 257 document.getElementById("Browser:OpenLocation").doCommand(); 258 }); 259 gURLBar.blur(); 260 }); 261 }); 262 263 Assert.equal( 264 UrlbarPrefs.get( 265 `tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.REDIRECT}` 266 ), 267 MAX_SHOWN_COUNT, 268 "Redirect tips are disabled after tip button is picked." 269 ); 270 Assert.equal(gURLBar.value, "", "The Urlbar should be empty."); 271 resetSearchTipsProvider(); 272 }); 273 274 add_task(async function pickingTipDoesNotDisableOtherKinds() { 275 tipsProviderInstance.disableTipsForCurrentSession = false; 276 await setDefaultEngine("Google"); 277 let tab = await BrowserTestUtils.openNewForegroundTab({ 278 gBrowser, 279 url: "about:newtab", 280 waitForLoad: false, 281 }); 282 await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.ONBOARD, false); 283 284 // Click the tip button. 285 let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0); 286 let button = result.element.row._buttons.get("0"); 287 await UrlbarTestUtils.promisePopupClose(window, () => { 288 EventUtils.synthesizeMouseAtCenter(button, {}); 289 }); 290 291 gURLBar.blur(); 292 Assert.equal( 293 UrlbarPrefs.get( 294 `tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.ONBOARD}` 295 ), 296 MAX_SHOWN_COUNT, 297 "Onboarding tips are disabled after tip button is picked." 298 ); 299 300 BrowserTestUtils.removeTab(tab); 301 302 // Simulate a new session. 303 tipsProviderInstance.disableTipsForCurrentSession = false; 304 305 // Onboarding tips should no longer be shown. 306 let tab2 = await BrowserTestUtils.openNewForegroundTab({ 307 gBrowser, 308 url: "about:newtab", 309 waitForLoad: false, 310 }); 311 await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.NONE); 312 313 // We should still show redirect tips. 314 await withDNSRedirect("www.google.com", "/", async url => { 315 await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT); 316 }); 317 318 BrowserTestUtils.removeTab(tab2); 319 resetSearchTipsProvider(); 320 }); 321 322 // The tip shouldn't be shown when there's another notification present. 323 add_task(async function notification() { 324 await BrowserTestUtils.withNewTab("about:blank", async () => { 325 let box = gBrowser.getNotificationBox(); 326 let note = await box.appendNotification("urlbar-test", { 327 label: "Test", 328 priority: box.PRIORITY_INFO_HIGH, 329 }); 330 // Give it a big persistence so it doesn't go away on page load. 331 note.persistence = 100; 332 await withDNSRedirect("www.google.com", "/", async url => { 333 BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, url); 334 await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); 335 await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.NONE); 336 box.removeNotification(note, true); 337 }); 338 }); 339 resetSearchTipsProvider(); 340 }); 341 342 // The tip should be shown when switching to a tab where it should be shown. 343 add_task(async function tabSwitch() { 344 let tab = BrowserTestUtils.addTab(gBrowser, "about:newtab"); 345 tipsProviderInstance.disableTipsForCurrentSession = false; 346 await BrowserTestUtils.switchTab(gBrowser, tab); 347 await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.ONBOARD); 348 BrowserTestUtils.removeTab(tab); 349 resetSearchTipsProvider(); 350 }); 351 352 // The engagement event should be ended if the user ignores a tip. 353 // See bug 1610024. 354 add_task(async function ignoreEndsEngagement() { 355 await setDefaultEngine("Google"); 356 await BrowserTestUtils.withNewTab("about:blank", async () => { 357 await withDNSRedirect("www.google.com", "/", async url => { 358 BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, url); 359 await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); 360 await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT, false); 361 // We're just looking for any target outside the Urlbar. 362 let spring = gURLBar.inputField 363 .closest("#nav-bar") 364 .querySelector("toolbarspring"); 365 await UrlbarTestUtils.promisePopupClose(window, async () => { 366 // We intentionally turn off this a11y check, because the following 367 // click is purposefully targeting a non-interactive element to dismiss 368 // the opened URL Bar with a mouse which can be done by assistive 369 // technology and keyboard by pressing `Esc` key, this rule check shall 370 // be ignored by a11y_checks suite. 371 AccessibilityUtils.setEnv({ mustHaveAccessibleRule: false }); 372 await EventUtils.synthesizeMouseAtCenter(spring, {}); 373 AccessibilityUtils.resetEnv(); 374 }); 375 Assert.equal( 376 tipsProviderInstance.showedTipTypeInCurrentEngagement, 377 UrlbarProviderSearchTips.TIP_TYPE.NONE, 378 "The engagement should have ended after the tip was ignored." 379 ); 380 }); 381 }); 382 resetSearchTipsProvider(); 383 }); 384 385 add_task(async function pasteAndGo_url() { 386 await doPasteAndGoTest("http://example.com/", "http://example.com/"); 387 }); 388 389 add_task(async function pasteAndGo_nonURL() { 390 await setDefaultEngine("Example"); 391 await doPasteAndGoTest( 392 "pasteAndGo_nonURL", 393 "https://example.com/?q=pasteAndGo_nonURL" 394 ); 395 await setDefaultEngine("Google"); 396 }); 397 398 async function doPasteAndGoTest(searchString, expectedURL) { 399 tipsProviderInstance.disableTipsForCurrentSession = false; 400 let tab = await BrowserTestUtils.openNewForegroundTab({ 401 gBrowser, 402 url: "about:newtab", 403 waitForLoad: false, 404 }); 405 await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.ONBOARD, false); 406 407 await SimpleTest.promiseClipboardChange(searchString, () => { 408 clipboardHelper.copyString(searchString); 409 }); 410 411 let textBox = gURLBar.querySelector("moz-input-box"); 412 let cxmenu = textBox.menupopup; 413 let cxmenuPromise = BrowserTestUtils.waitForEvent(cxmenu, "popupshown"); 414 EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, { 415 type: "contextmenu", 416 button: 2, 417 }); 418 await cxmenuPromise; 419 let menuitem = textBox.getMenuItem("paste-and-go"); 420 421 let browserLoadedPromise = BrowserTestUtils.browserLoaded( 422 gBrowser.selectedBrowser, 423 false, 424 expectedURL 425 ); 426 cxmenu.activateItem(menuitem); 427 await browserLoadedPromise; 428 BrowserTestUtils.removeTab(tab); 429 resetSearchTipsProvider(); 430 } 431 432 // Since we coupled the logic that decides whether to show the tip with our 433 // gURLBar.search call, we should make sure search isn't called when 434 // the conditions for a tip are met but the provider is disabled. 435 add_task(async function noActionWhenDisabled() { 436 await setDefaultEngine("Bing"); 437 await withDNSRedirect("www.bing.com", "/", async url => { 438 await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT); 439 }); 440 441 await SpecialPowers.pushPrefEnv({ 442 set: [ 443 [ 444 "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features", 445 false, 446 ], 447 ], 448 }); 449 450 await withDNSRedirect("www.bing.com", "/", async () => { 451 Assert.ok( 452 !UrlbarTestUtils.isPopupOpen(window), 453 "The UrlbarView should not be open." 454 ); 455 }); 456 457 await SpecialPowers.popPrefEnv(); 458 });