browser_top_sites.js (17656B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 ChromeUtils.defineESModuleGetters(this, { 7 AboutNewTab: "resource:///modules/AboutNewTab.sys.mjs", 8 NewTabUtils: "resource://gre/modules/NewTabUtils.sys.mjs", 9 TopSites: "resource:///modules/topsites/TopSites.sys.mjs", 10 }); 11 12 const EN_US_TOPSITES = 13 "https://www.youtube.com/,https://www.facebook.com/,https://www.amazon.com/,https://www.reddit.com/,about:robots,https://twitter.com/"; 14 15 async function addTestVisits() { 16 // Add some visits to a URL. 17 for (let i = 0; i < 5; i++) { 18 await PlacesTestUtils.addVisits("http://example.com/"); 19 } 20 21 // Wait for example.com to be listed first. 22 await updateTopSites(sites => { 23 return sites && sites[0] && sites[0].url == "http://example.com/"; 24 }); 25 26 await PlacesUtils.bookmarks.insert({ 27 parentGuid: PlacesUtils.bookmarks.unfiledGuid, 28 url: "https://www.youtube.com/", 29 title: "YouTube", 30 }); 31 32 // Adding a bookmark will refresh the TopSites feed. 33 if (Services.prefs.getBoolPref("browser.topsites.component.enabled")) { 34 await TestUtils.topicObserved("topsites-refreshed"); 35 } 36 } 37 38 async function getTopSites() { 39 if (Services.prefs.getBoolPref("browser.topsites.component.enabled")) { 40 return await TopSites.getSites(); 41 } 42 return AboutNewTab.getTopSites(); 43 } 44 45 async function checkDoesNotOpenOnFocus(win = window) { 46 // The view should not open when the input is focused programmatically. 47 win.gURLBar.blur(); 48 win.gURLBar.focus(); 49 Assert.ok(!win.gURLBar.view.isOpen, "check urlbar panel is not open"); 50 win.gURLBar.blur(); 51 52 // Check the keyboard shortcut. 53 win.document.getElementById("Browser:OpenLocation").doCommand(); 54 // Because the panel opening may not be immediate, we must wait a bit. 55 // eslint-disable-next-line mozilla/no-arbitrary-setTimeout 56 await new Promise(resolve => setTimeout(resolve, 500)); 57 Assert.ok(!win.gURLBar.view.isOpen, "check urlbar panel is not open"); 58 win.gURLBar.blur(); 59 60 // Focus with the mouse. 61 EventUtils.synthesizeMouseAtCenter(win.gURLBar.inputField, {}, win); 62 // Because the panel opening may not be immediate, we must wait a bit. 63 // eslint-disable-next-line mozilla/no-arbitrary-setTimeout 64 await new Promise(resolve => setTimeout(resolve, 500)); 65 Assert.ok(!win.gURLBar.view.isOpen, "check urlbar panel is not open"); 66 win.gURLBar.blur(); 67 } 68 69 add_setup(async function () { 70 await SpecialPowers.pushPrefEnv({ 71 set: [ 72 ["browser.urlbar.suggest.topsites", true], 73 ["browser.urlbar.suggest.quickactions", false], 74 ["browser.newtabpage.activity-stream.default.sites", EN_US_TOPSITES], 75 ], 76 }); 77 78 await updateTopSites( 79 sites => sites && sites.length == EN_US_TOPSITES.split(",").length 80 ); 81 82 let tab = await BrowserTestUtils.openNewForegroundTab( 83 gBrowser, 84 "http://example.com/" 85 ); 86 87 registerCleanupFunction(() => { 88 BrowserTestUtils.removeTab(tab); 89 }); 90 }); 91 92 add_task(async function topSitesShown() { 93 let sites = await getTopSites(); 94 95 for (let prefVal of [true, false]) { 96 // This test should work regardless of whether Top Sites are enabled on 97 // about:newtab. 98 await SpecialPowers.pushPrefEnv({ 99 set: [["browser.newtabpage.activity-stream.feeds.topsites", prefVal]], 100 }); 101 // We don't expect this to change, but we run updateTopSites just in case 102 // feeds.topsites were to have an effect on the composition of Top Sites. 103 await updateTopSites(siteList => siteList.length == 6); 104 105 await UrlbarTestUtils.promisePopupOpen(window, () => { 106 if (gURLBar.getAttribute("pageproxystate") == "invalid") { 107 gURLBar.handleRevert(); 108 } 109 EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {}); 110 }); 111 Assert.ok(gURLBar.view.isOpen, "UrlbarView should be open."); 112 await UrlbarTestUtils.promiseSearchComplete(window); 113 Assert.equal( 114 UrlbarTestUtils.getResultCount(window), 115 sites.length, 116 "The number of results should be the same as the number of Top Sites (6)." 117 ); 118 119 for (let i = 0; i < sites.length; i++) { 120 let site = sites[i]; 121 let result = await UrlbarTestUtils.getDetailsOfResultAt(window, i); 122 if (site.searchTopSite) { 123 Assert.equal( 124 result.searchParams.keyword, 125 site.label, 126 "The search Top Site should have an alias." 127 ); 128 continue; 129 } 130 131 Assert.equal( 132 site.url, 133 result.url, 134 "The Top Site URL and the result URL shoud match." 135 ); 136 Assert.equal( 137 site.label || site.title || site.hostname, 138 result.title, 139 "The Top Site title and the result title shoud match." 140 ); 141 } 142 await UrlbarTestUtils.promisePopupClose(window, () => { 143 gURLBar.blur(); 144 }); 145 // This pops updateTopSites changes. 146 await SpecialPowers.popPrefEnv(); 147 await SpecialPowers.popPrefEnv(); 148 } 149 }); 150 151 add_task(async function selectSearchTopSite() { 152 await updateTopSites( 153 sites => sites && sites[0] && sites[0].searchTopSite, 154 true 155 ); 156 await UrlbarTestUtils.promisePopupOpen(window, () => { 157 if (gURLBar.getAttribute("pageproxystate") == "invalid") { 158 gURLBar.handleRevert(); 159 } 160 EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {}); 161 }); 162 await UrlbarTestUtils.promiseSearchComplete(window); 163 164 let amazonSearch = await UrlbarTestUtils.waitForAutocompleteResultAt( 165 window, 166 0 167 ); 168 169 Assert.equal( 170 amazonSearch.result.type, 171 UrlbarUtils.RESULT_TYPE.SEARCH, 172 "First result should have SEARCH type." 173 ); 174 175 Assert.equal( 176 amazonSearch.result.payload.keyword, 177 "@amazon", 178 "First result should have the Amazon keyword." 179 ); 180 181 let searchPromise = UrlbarTestUtils.promiseSearchComplete(window); 182 EventUtils.synthesizeMouseAtCenter(amazonSearch, {}); 183 await searchPromise; 184 await UrlbarTestUtils.assertSearchMode(window, { 185 engineName: amazonSearch.result.payload.engine, 186 entry: "topsites_urlbar", 187 }); 188 await UrlbarTestUtils.exitSearchMode(window, { backspace: true }); 189 190 await UrlbarTestUtils.promisePopupClose(window, () => { 191 gURLBar.blur(); 192 }); 193 }); 194 195 add_task(async function topSitesBookmarksAndTabs() { 196 await addTestVisits(); 197 let sites = await getTopSites(); 198 Assert.equal( 199 sites.length, 200 7, 201 "The test suite browser should have 7 Top Sites." 202 ); 203 204 await UrlbarTestUtils.promisePopupOpen(window, () => { 205 if (gURLBar.getAttribute("pageproxystate") == "invalid") { 206 gURLBar.handleRevert(); 207 } 208 EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {}); 209 }); 210 Assert.ok(gURLBar.view.isOpen, "UrlbarView should be open."); 211 await UrlbarTestUtils.promiseSearchComplete(window); 212 213 Assert.equal( 214 UrlbarTestUtils.getResultCount(window), 215 7, 216 "The number of results should be the same as the number of Top Sites (7)." 217 ); 218 219 let exampleResult = await UrlbarTestUtils.getDetailsOfResultAt(window, 0); 220 Assert.equal( 221 exampleResult.url, 222 "http://example.com/", 223 "The example.com Top Site should be the first result." 224 ); 225 226 Assert.equal( 227 exampleResult.source, 228 UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, 229 "The example.com Top Site should not appear in the view as an open tab result since it is the current tab." 230 ); 231 232 let youtubeResult = await UrlbarTestUtils.getDetailsOfResultAt(window, 1); 233 Assert.equal( 234 youtubeResult.url, 235 "https://www.youtube.com/", 236 "The YouTube Top Site should be the second result." 237 ); 238 Assert.equal( 239 youtubeResult.source, 240 UrlbarUtils.RESULT_SOURCE.BOOKMARKS, 241 "The YouTube Top Site should appear in the view as a bookmark result." 242 ); 243 await UrlbarTestUtils.promisePopupClose(window, () => { 244 gURLBar.blur(); 245 }); 246 247 await PlacesUtils.bookmarks.eraseEverything(); 248 await PlacesUtils.history.clear(); 249 }); 250 251 add_task(async function topSitesKeywordNavigationPageproxystate() { 252 await addTestVisits(); 253 Assert.equal( 254 gURLBar.getAttribute("pageproxystate"), 255 "valid", 256 "Sanity check initial state" 257 ); 258 259 await UrlbarTestUtils.promisePopupOpen(window, () => { 260 if (gURLBar.getAttribute("pageproxystate") == "invalid") { 261 gURLBar.handleRevert(); 262 } 263 EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {}); 264 }); 265 Assert.ok(gURLBar.view.isOpen, "UrlbarView should be open."); 266 await UrlbarTestUtils.promiseSearchComplete(window); 267 268 let count = UrlbarTestUtils.getResultCount(window); 269 Assert.equal(count, 7, "The number of results should be the expected one."); 270 271 for (let i = 0; i < count; ++i) { 272 EventUtils.synthesizeKey("KEY_ArrowDown"); 273 Assert.equal( 274 gURLBar.getAttribute("pageproxystate"), 275 "invalid", 276 "Moving through results" 277 ); 278 } 279 for (let i = 0; i < count; ++i) { 280 EventUtils.synthesizeKey("KEY_ArrowUp"); 281 Assert.equal( 282 gURLBar.getAttribute("pageproxystate"), 283 "invalid", 284 "Moving through results" 285 ); 286 } 287 288 // Double ESC should restore state. 289 await UrlbarTestUtils.promisePopupClose(window, () => { 290 EventUtils.synthesizeKey("KEY_Escape"); 291 }); 292 EventUtils.synthesizeKey("KEY_Escape"); 293 Assert.equal( 294 gURLBar.getAttribute("pageproxystate"), 295 "valid", 296 "Double ESC should restore state" 297 ); 298 await PlacesUtils.bookmarks.eraseEverything(); 299 await PlacesUtils.history.clear(); 300 }); 301 302 add_task(async function topSitesPinned() { 303 await addTestVisits(); 304 let info = { url: "http://example.com/" }; 305 NewTabUtils.pinnedLinks.pin(info, 0); 306 307 await updateTopSites(sites => sites && sites[0] && sites[0].isPinned); 308 309 let sites = await getTopSites(); 310 Assert.equal( 311 sites.length, 312 7, 313 "The test suite browser should have 7 Top Sites." 314 ); 315 316 await UrlbarTestUtils.promisePopupOpen(window, () => { 317 EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {}); 318 }); 319 Assert.ok(gURLBar.view.isOpen, "UrlbarView should be open."); 320 await UrlbarTestUtils.promiseSearchComplete(window); 321 322 Assert.equal( 323 UrlbarTestUtils.getResultCount(window), 324 7, 325 "The number of results should be the same as the number of Top Sites (7)." 326 ); 327 328 let exampleResult = await UrlbarTestUtils.getDetailsOfResultAt(window, 0); 329 Assert.equal( 330 exampleResult.url, 331 "http://example.com/", 332 "The example.com Top Site should be the first result." 333 ); 334 335 Assert.equal( 336 exampleResult.source, 337 UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, 338 "The example.com Top Site should not appear in the view as an open tab result since it is the current tab." 339 ); 340 341 Assert.ok( 342 exampleResult.element.row.hasAttribute("pinned"), 343 "The example.com Top Site should have the pinned property." 344 ); 345 346 await UrlbarTestUtils.promisePopupClose(window, () => { 347 gURLBar.blur(); 348 }); 349 NewTabUtils.pinnedLinks.unpin(info); 350 351 await PlacesUtils.bookmarks.eraseEverything(); 352 await PlacesUtils.history.clear(); 353 }); 354 355 add_task(async function topSitesBookmarksAndTabsDisabled() { 356 await addTestVisits(); 357 await SpecialPowers.pushPrefEnv({ 358 set: [ 359 ["browser.urlbar.suggest.openpage", false], 360 ["browser.urlbar.suggest.bookmark", false], 361 ], 362 }); 363 364 let sites = await getTopSites(); 365 Assert.equal( 366 sites.length, 367 7, 368 "The test suite browser should have 7 Top Sites." 369 ); 370 371 await UrlbarTestUtils.promisePopupOpen(window, () => { 372 if (gURLBar.getAttribute("pageproxystate") == "invalid") { 373 gURLBar.handleRevert(); 374 } 375 EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {}); 376 }); 377 Assert.ok(gURLBar.view.isOpen, "UrlbarView should be open."); 378 await UrlbarTestUtils.promiseSearchComplete(window); 379 380 Assert.equal( 381 UrlbarTestUtils.getResultCount(window), 382 7, 383 "The number of results should be the same as the number of Top Sites (7)." 384 ); 385 386 let exampleResult = await UrlbarTestUtils.getDetailsOfResultAt(window, 0); 387 Assert.equal( 388 exampleResult.url, 389 "http://example.com/", 390 "The example.com Top Site should be the second result." 391 ); 392 Assert.equal( 393 exampleResult.source, 394 UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, 395 "The example.com Top Site should appear as a normal result even though it's open in a tab." 396 ); 397 398 let youtubeResult = await UrlbarTestUtils.getDetailsOfResultAt(window, 1); 399 Assert.equal( 400 youtubeResult.url, 401 "https://www.youtube.com/", 402 "The YouTube Top Site should be the third result." 403 ); 404 Assert.equal( 405 youtubeResult.source, 406 UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, 407 "The YouTube Top Site should appear as a normal result even though it's bookmarked." 408 ); 409 await UrlbarTestUtils.promisePopupClose(window, () => { 410 gURLBar.blur(); 411 }); 412 413 await PlacesUtils.bookmarks.eraseEverything(); 414 await PlacesUtils.history.clear(); 415 await SpecialPowers.popPrefEnv(); 416 }); 417 418 add_task(async function topSitesDisabled() { 419 // Disable Top Sites feed. 420 await SpecialPowers.pushPrefEnv({ 421 set: [["browser.newtabpage.activity-stream.feeds.system.topsites", false]], 422 }); 423 await checkDoesNotOpenOnFocus(); 424 await SpecialPowers.popPrefEnv(); 425 426 // Top Sites should also not be shown when Urlbar Top Sites are disabled. 427 await SpecialPowers.pushPrefEnv({ 428 set: [["browser.urlbar.suggest.topsites", false]], 429 }); 430 await checkDoesNotOpenOnFocus(); 431 await SpecialPowers.popPrefEnv(); 432 }); 433 434 add_task(async function topSitesNumber() { 435 // Add some visits 436 for (let i = 0; i < 5; i++) { 437 await PlacesTestUtils.addVisits([ 438 "http://example-a.com/", 439 "http://example-b.com/", 440 "http://example-c.com/", 441 "http://example-d.com/", 442 "http://example-e.com/", 443 ]); 444 } 445 446 // Wait for the expected number of Top sites. 447 await updateTopSites(sites => sites && sites.length == 8); 448 Assert.equal( 449 (await getTopSites()).length, 450 8, 451 "The test suite browser should have 8 Top Sites." 452 ); 453 454 await UrlbarTestUtils.promisePopupOpen(window, () => { 455 EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {}); 456 }); 457 Assert.ok(gURLBar.view.isOpen, "UrlbarView should be open."); 458 await UrlbarTestUtils.promiseSearchComplete(window); 459 Assert.equal( 460 UrlbarTestUtils.getResultCount(window), 461 8, 462 "The number of results should be the default (8)." 463 ); 464 await UrlbarTestUtils.promisePopupClose(window); 465 466 await SpecialPowers.pushPrefEnv({ 467 set: [["browser.newtabpage.activity-stream.topSitesRows", 2]], 468 }); 469 // Wait for the expected number of Top sites. 470 await updateTopSites(sites => sites && sites.length == 11); 471 Assert.equal( 472 (await getTopSites()).length, 473 11, 474 "The test suite browser should have 11 Top Sites." 475 ); 476 477 await UrlbarTestUtils.promisePopupOpen(window, () => { 478 EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {}); 479 }); 480 Assert.ok(gURLBar.view.isOpen, "UrlbarView should be open."); 481 await UrlbarTestUtils.promiseSearchComplete(window); 482 483 Assert.equal( 484 UrlbarTestUtils.getResultCount(window), 485 10, 486 "The number of results should be maxRichResults (10)." 487 ); 488 await UrlbarTestUtils.promisePopupClose(window); 489 490 await SpecialPowers.popPrefEnv(); 491 await PlacesUtils.history.clear(); 492 }); 493 494 add_task(async function tabSwitchBehavior() { 495 let exampleTab = gBrowser.selectedTab; 496 let aboutRobotsTab = await BrowserTestUtils.openNewForegroundTab( 497 gBrowser, 498 "about:robots" 499 ); 500 501 registerCleanupFunction(() => { 502 BrowserTestUtils.removeTab(aboutRobotsTab); 503 }); 504 505 await BrowserTestUtils.switchTab(gBrowser, exampleTab); 506 507 let sites = AboutNewTab.getTopSites(); 508 Assert.equal( 509 sites.length, 510 6, 511 "The test suite browser should have 6 Top Sites." 512 ); 513 514 await UrlbarTestUtils.promisePopupOpen(window, () => { 515 if (gURLBar.getAttribute("pageproxystate") == "invalid") { 516 gURLBar.handleRevert(); 517 } 518 EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {}); 519 }); 520 Assert.ok(gURLBar.view.isOpen, "UrlbarView should be open."); 521 await UrlbarTestUtils.promiseSearchComplete(window); 522 523 Assert.equal( 524 UrlbarTestUtils.getResultCount(window), 525 6, 526 "The number of results should be the same as the number of Top Sites (6)." 527 ); 528 529 let aboutRobotsResult = await UrlbarTestUtils.getDetailsOfResultAt(window, 4); 530 Assert.equal( 531 aboutRobotsResult.url, 532 "about:robots", 533 "The about:robots Top Site should be the 5th result." 534 ); 535 Assert.equal( 536 aboutRobotsResult.source, 537 UrlbarUtils.RESULT_SOURCE.TABS, 538 "The about:robots Top Site should appear as an open tab result." 539 ); 540 541 await UrlbarTestUtils.promisePopupClose(window, () => { 542 gURLBar.blur(); 543 }); 544 545 await BrowserTestUtils.switchTab(gBrowser, aboutRobotsTab); 546 547 sites = AboutNewTab.getTopSites(); 548 Assert.equal( 549 sites.length, 550 6, 551 "The test suite browser should have 6 Top Sites." 552 ); 553 554 await UrlbarTestUtils.promisePopupOpen(window, () => { 555 if (gURLBar.getAttribute("pageproxystate") == "invalid") { 556 gURLBar.handleRevert(); 557 } 558 EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {}); 559 }); 560 Assert.ok(gURLBar.view.isOpen, "UrlbarView should be open."); 561 await UrlbarTestUtils.promiseSearchComplete(window); 562 563 Assert.equal( 564 UrlbarTestUtils.getResultCount(window), 565 6, 566 "The number of results should be the same as the number of Top Sites (6)." 567 ); 568 569 aboutRobotsResult = await UrlbarTestUtils.getDetailsOfResultAt(window, 4); 570 Assert.equal( 571 aboutRobotsResult.url, 572 "about:robots", 573 "The about:robots Top Site should be the 5th result." 574 ); 575 Assert.equal( 576 aboutRobotsResult.source, 577 UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, 578 "The about:robots Top Site should appear as a regular result." 579 ); 580 581 await UrlbarTestUtils.promisePopupClose(window, () => { 582 gURLBar.blur(); 583 }); 584 585 await PlacesUtils.history.clear(); 586 });