test_TopSitesFeed_glean.js (59863B)
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 ContileIntegration: "resource://newtab/lib/TopSitesFeed.sys.mjs", 8 NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs", 9 sinon: "resource://testing-common/Sinon.sys.mjs", 10 SearchService: "resource://gre/modules/SearchService.sys.mjs", 11 TopSitesFeed: "resource://newtab/lib/TopSitesFeed.sys.mjs", 12 }); 13 14 const SHOW_SPONSORED_PREF = "showSponsoredTopSites"; 15 const TOP_SITES_BLOCKED_SPONSORS_PREF = "browser.topsites.blockedSponsors"; 16 const CONTILE_CACHE_VALID_FOR_PREF = "browser.topsites.contile.cacheValidFor"; 17 const CONTILE_CACHE_LAST_FETCH_PREF = "browser.topsites.contile.lastFetch"; 18 const NIMBUS_VARIABLE_MAX_SPONSORED = "topSitesMaxSponsored"; 19 const NIMBUS_VARIABLE_CONTILE_POSITIONS = "contileTopsitesPositions"; 20 const NIMBUS_VARIABLE_CONTILE_ENABLED = "topSitesContileEnabled"; 21 const NIMBUS_VARIABLE_CONTILE_MAX_NUM_SPONSORED = "topSitesContileMaxSponsored"; 22 23 let contileTile1 = { 24 id: 74357, 25 name: "Brand1", 26 url: "https://www.brand1.com", 27 click_url: "https://clickurl.com", 28 image_url: "https://contile-images.jpg", 29 image_size: 200, 30 impression_url: "https://impression_url.com", 31 }; 32 let contileTile2 = { 33 id: 74925, 34 name: "Brand2", 35 url: "https://www.brand2.com", 36 click_url: "https://click_url.com", 37 image_url: "https://contile-images.jpg", 38 image_size: 200, 39 impression_url: "https://impression_url.com", 40 }; 41 let contileTile3 = { 42 id: 75001, 43 name: "Brand3", 44 url: "https://www.brand3.com", 45 click_url: "https://click_url.com", 46 image_url: "https://contile-images.jpg", 47 image_size: 200, 48 impression_url: "https://impression_url.com", 49 }; 50 let contileTile4 = { 51 id: 75899, 52 name: "Brand4", 53 url: "https://www.brand4.com", 54 click_url: "https://click_url.com", 55 image_url: "https://contile-images.jpg", 56 image_size: 200, 57 impression_url: "https://impression_url.com", 58 }; 59 let mozSalesTile = [ 60 { 61 label: "MozSales Title", 62 title: "MozSales Title", 63 url: "https://mozsale.net", 64 sponsored_position: 1, 65 partner: "moz-sales", 66 }, 67 ]; 68 69 function getTopSitesFeedForTest(sandbox) { 70 sandbox.stub(ContileIntegration.prototype, "PersistentCache").returns({ 71 set: sandbox.stub(), 72 get: sandbox.stub(), 73 }); 74 75 let feed = new TopSitesFeed(); 76 const storage = { 77 init: sandbox.stub().resolves(), 78 get: sandbox.stub().resolves(), 79 set: sandbox.stub().resolves(), 80 }; 81 82 feed._storage = storage; 83 feed.store = { 84 dispatch: sinon.spy(), 85 getState() { 86 return this.state; 87 }, 88 state: { 89 Prefs: { values: { topSitesRows: 2 } }, 90 TopSites: { rows: Array(12).fill("site") }, 91 }, 92 dbStorage: { getDbTable: sandbox.stub().returns(storage) }, 93 }; 94 95 return feed; 96 } 97 98 function prepFeed(feed, sandbox) { 99 feed.store.state.Prefs.values[SHOW_SPONSORED_PREF] = true; 100 let fetchStub = sandbox.stub(feed, "fetch"); 101 return { feed, fetchStub }; 102 } 103 104 function setNimbusVariablesForNumTiles(nimbusPocketStub, numTiles) { 105 nimbusPocketStub.withArgs(NIMBUS_VARIABLE_MAX_SPONSORED).returns(numTiles); 106 nimbusPocketStub 107 .withArgs(NIMBUS_VARIABLE_CONTILE_MAX_NUM_SPONSORED) 108 .returns(numTiles); 109 // when setting num tiles to > 2 need to set the positions or the > 2 has no effect. 110 // can be defaulted to undefined 111 let positionsArray = Array.from( 112 { length: numTiles }, 113 (value, index) => index 114 ); 115 nimbusPocketStub 116 .withArgs(NIMBUS_VARIABLE_CONTILE_POSITIONS) 117 .returns(positionsArray.toString()); 118 } 119 120 add_setup(async () => { 121 do_get_profile(); 122 Services.fog.initializeFOG(); 123 124 let sandbox = sinon.createSandbox(); 125 sandbox.stub(SearchService.prototype, "init").resolves(); 126 127 const nimbusStub = sandbox.stub(NimbusFeatures.newtab, "getVariable"); 128 nimbusStub.withArgs(NIMBUS_VARIABLE_CONTILE_ENABLED).returns(true); 129 130 sandbox.spy(Glean.topsites.sponsoredTilesConfigured, "set"); 131 sandbox.spy(Glean.topsites.sponsoredTilesReceived, "set"); 132 133 // Temporarily setting isInAutomation to false. 134 // If Cu.isInAutomation is true then the check for Cu.isInAutomation in 135 // ContileIntegration._readDefaults passes, bypassing Contile, resulting in 136 // not being able use stubbed values. 137 if (Cu.isInAutomation) { 138 Services.prefs.setBoolPref( 139 "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", 140 false 141 ); 142 143 if (Cu.isInAutomation) { 144 // This condition is unexpected, because it is enforced at: 145 // https://searchfox.org/mozilla-central/rev/ea65de7c/js/xpconnect/src/xpcpublic.h#753-759 146 throw new Error("Failed to set isInAutomation to false"); 147 } 148 } 149 registerCleanupFunction(() => { 150 if (!Cu.isInAutomation) { 151 Services.prefs.setBoolPref( 152 "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", 153 true 154 ); 155 156 if (!Cu.isInAutomation) { 157 // This condition is unexpected, because it is enforced at: 158 // https://searchfox.org/mozilla-central/rev/ea65de7c/js/xpconnect/src/xpcpublic.h#753-759 159 throw new Error("Failed to set isInAutomation to true"); 160 } 161 } 162 163 sandbox.restore(); 164 }); 165 }); 166 167 add_task(async function test_set_contile_tile_to_oversold() { 168 let sandbox = sinon.createSandbox(); 169 let feed = getTopSitesFeedForTest(sandbox); 170 171 feed._telemetryUtility.setSponsoredTilesConfigured(); 172 feed._telemetryUtility.setTiles([ 173 contileTile1, 174 contileTile2, 175 contileTile3, 176 contileTile4, 177 ]); 178 179 let mergedTiles = [ 180 { 181 url: "https://www.brand1.com", 182 label: "brand1", 183 sponsored_position: 1, 184 partner: "amp", 185 }, 186 { 187 url: "https://www.brand2.com", 188 label: "brand2", 189 sponsored_position: 2, 190 partner: "amp", 191 }, 192 { 193 url: "https://www.brand3.com", 194 label: "brand3", 195 sponsored_position: 3, 196 partner: "amp", 197 }, 198 ]; 199 200 feed._telemetryUtility.determineFilteredTilesAndSetToOversold(mergedTiles); 201 feed._telemetryUtility.finalizeNewtabPingFields(mergedTiles); 202 203 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 204 205 let expectedResult = { 206 sponsoredTilesReceived: [ 207 { 208 advertiser: "brand1", 209 provider: "amp", 210 display_position: 1, 211 display_fail_reason: null, 212 }, 213 { 214 advertiser: "brand2", 215 provider: "amp", 216 display_position: 2, 217 display_fail_reason: null, 218 }, 219 { 220 advertiser: "brand3", 221 provider: "amp", 222 display_position: 3, 223 display_fail_reason: null, 224 }, 225 { 226 advertiser: "brand4", 227 provider: "amp", 228 display_position: null, 229 display_fail_reason: "oversold", 230 }, 231 ], 232 }; 233 Assert.equal( 234 Glean.topsites.sponsoredTilesReceived.testGetValue(), 235 JSON.stringify(expectedResult) 236 ); 237 sandbox.restore(); 238 }); 239 240 add_task(async function test_set_moz_sale_tile_to_oversold() { 241 let sandbox = sinon.createSandbox(); 242 info( 243 "determineFilteredTilesAndSetToOversold should set moz-sale tile to oversold when_contile tiles are displayed" 244 ); 245 let feed = getTopSitesFeedForTest(sandbox); 246 247 feed._telemetryUtility.setSponsoredTilesConfigured(); 248 feed._telemetryUtility.setTiles([contileTile1, contileTile2]); 249 feed._telemetryUtility.setTiles(mozSalesTile); 250 251 let mergedTiles = [ 252 { 253 url: "https://www.brand1.com", 254 label: "brand1", 255 sponsored_position: 1, 256 partner: "amp", 257 }, 258 { 259 url: "https://www.brand2.com", 260 label: "brand2", 261 sponsored_position: 2, 262 partner: "amp", 263 }, 264 ]; 265 266 feed._telemetryUtility.determineFilteredTilesAndSetToOversold(mergedTiles); 267 feed._telemetryUtility.finalizeNewtabPingFields(mergedTiles); 268 269 let expectedResult = { 270 sponsoredTilesReceived: [ 271 { 272 advertiser: "brand1", 273 provider: "amp", 274 display_position: 1, 275 display_fail_reason: null, 276 }, 277 { 278 advertiser: "brand2", 279 provider: "amp", 280 display_position: 2, 281 display_fail_reason: null, 282 }, 283 { 284 advertiser: "mozsales title", 285 provider: "moz-sales", 286 display_position: null, 287 display_fail_reason: "oversold", 288 }, 289 ], 290 }; 291 Assert.equal( 292 Glean.topsites.sponsoredTilesReceived.testGetValue(), 293 JSON.stringify(expectedResult) 294 ); 295 sandbox.restore(); 296 }); 297 298 add_task(async function test_set_contile_tile_to_oversold() { 299 let sandbox = sinon.createSandbox(); 300 info( 301 "determineFilteredTilesAndSetToOversold should set contile tile to oversold when moz-sale tile is displayed" 302 ); 303 let feed = getTopSitesFeedForTest(sandbox); 304 305 feed._telemetryUtility.setSponsoredTilesConfigured(); 306 feed._telemetryUtility.setTiles([contileTile1, contileTile2]); 307 feed._telemetryUtility.setTiles(mozSalesTile); 308 let mergedTiles = [ 309 { 310 url: "https://www.brand1.com", 311 label: "brand1", 312 sponsored_position: 1, 313 partner: "amp", 314 }, 315 { 316 label: "MozSales Title", 317 title: "MozSales Title", 318 url: "https://mozsale.net", 319 sponsored_position: 2, 320 partner: "moz-sales", 321 }, 322 ]; 323 324 feed._telemetryUtility.determineFilteredTilesAndSetToOversold(mergedTiles); 325 feed._telemetryUtility.finalizeNewtabPingFields(mergedTiles); 326 327 let expectedResult = { 328 sponsoredTilesReceived: [ 329 { 330 advertiser: "brand1", 331 provider: "amp", 332 display_position: 1, 333 display_fail_reason: null, 334 }, 335 { 336 advertiser: "brand2", 337 provider: "amp", 338 display_position: null, 339 display_fail_reason: "oversold", 340 }, 341 { 342 advertiser: "mozsales title", 343 provider: "moz-sales", 344 display_position: 2, 345 display_fail_reason: null, 346 }, 347 ], 348 }; 349 Assert.equal( 350 Glean.topsites.sponsoredTilesReceived.testGetValue(), 351 JSON.stringify(expectedResult) 352 ); 353 sandbox.restore(); 354 }); 355 356 add_task(async function test_set_contile_tiles_to_dismissed() { 357 let sandbox = sinon.createSandbox(); 358 let feed = getTopSitesFeedForTest(sandbox); 359 360 feed._telemetryUtility.setSponsoredTilesConfigured(); 361 feed._telemetryUtility.setTiles([contileTile1, contileTile2, contileTile3]); 362 363 let mergedTiles = [ 364 { 365 url: "https://www.brand1.com", 366 label: "brand1", 367 sponsored_position: 1, 368 partner: "amp", 369 }, 370 { 371 url: "https://www.brand2.com", 372 label: "brand2", 373 sponsored_position: 2, 374 partner: "amp", 375 }, 376 ]; 377 378 feed._telemetryUtility.determineFilteredTilesAndSetToDismissed(mergedTiles); 379 feed._telemetryUtility.finalizeNewtabPingFields(mergedTiles); 380 381 let expectedResult = { 382 sponsoredTilesReceived: [ 383 { 384 advertiser: "brand1", 385 provider: "amp", 386 display_position: 1, 387 display_fail_reason: null, 388 }, 389 { 390 advertiser: "brand2", 391 provider: "amp", 392 display_position: 2, 393 display_fail_reason: null, 394 }, 395 { 396 advertiser: "brand3", 397 provider: "amp", 398 display_position: null, 399 display_fail_reason: "dismissed", 400 }, 401 ], 402 }; 403 Assert.equal( 404 Glean.topsites.sponsoredTilesReceived.testGetValue(), 405 JSON.stringify(expectedResult) 406 ); 407 sandbox.restore(); 408 }); 409 410 add_task(async function test_set_all_contile_tiles_to_dismissed() { 411 let sandbox = sinon.createSandbox(); 412 let feed = getTopSitesFeedForTest(sandbox); 413 414 feed._telemetryUtility.setSponsoredTilesConfigured(); 415 feed._telemetryUtility.setTiles([contileTile1, contileTile2, contileTile3]); 416 417 let mergedTiles = []; 418 419 feed._telemetryUtility.determineFilteredTilesAndSetToDismissed(mergedTiles); 420 feed._telemetryUtility.finalizeNewtabPingFields(mergedTiles); 421 422 let expectedResult = { 423 sponsoredTilesReceived: [ 424 { 425 advertiser: "brand1", 426 provider: "amp", 427 display_position: null, 428 display_fail_reason: "dismissed", 429 }, 430 { 431 advertiser: "brand2", 432 provider: "amp", 433 display_position: null, 434 display_fail_reason: "dismissed", 435 }, 436 { 437 advertiser: "brand3", 438 provider: "amp", 439 display_position: null, 440 display_fail_reason: "dismissed", 441 }, 442 ], 443 }; 444 Assert.equal( 445 Glean.topsites.sponsoredTilesReceived.testGetValue(), 446 JSON.stringify(expectedResult) 447 ); 448 sandbox.restore(); 449 }); 450 451 add_task(async function test_set_moz_sales_tiles_to_dismissed() { 452 let sandbox = sinon.createSandbox(); 453 let feed = getTopSitesFeedForTest(sandbox); 454 455 feed._telemetryUtility.setSponsoredTilesConfigured(); 456 feed._telemetryUtility.setTiles([contileTile1, contileTile2]); 457 feed._telemetryUtility.setTiles(mozSalesTile); 458 let mergedTiles = [ 459 { 460 url: "https://www.brand1.com", 461 label: "brand1", 462 sponsored_position: 1, 463 partner: "amp", 464 }, 465 { 466 url: "https://www.brand2.com", 467 label: "brand2", 468 sponsored_position: 2, 469 partner: "amp", 470 }, 471 ]; 472 473 feed._telemetryUtility.determineFilteredTilesAndSetToDismissed(mergedTiles); 474 feed._telemetryUtility.finalizeNewtabPingFields(mergedTiles); 475 476 let expectedResult = { 477 sponsoredTilesReceived: [ 478 { 479 advertiser: "brand1", 480 provider: "amp", 481 display_position: 1, 482 display_fail_reason: null, 483 }, 484 { 485 advertiser: "brand2", 486 provider: "amp", 487 display_position: 2, 488 display_fail_reason: null, 489 }, 490 { 491 advertiser: "mozsales title", 492 provider: "moz-sales", 493 display_position: null, 494 display_fail_reason: "dismissed", 495 }, 496 ], 497 }; 498 Assert.equal( 499 Glean.topsites.sponsoredTilesReceived.testGetValue(), 500 JSON.stringify(expectedResult) 501 ); 502 sandbox.restore(); 503 }); 504 505 add_task(async function test_set_tiles_to_dismissed_then_updated() { 506 let sandbox = sinon.createSandbox(); 507 let feed = getTopSitesFeedForTest(sandbox); 508 feed._telemetryUtility.setSponsoredTilesConfigured(); 509 510 // Step 1: Set initial tiles 511 feed._telemetryUtility.setTiles([ 512 contileTile1, 513 contileTile2, 514 contileTile3, 515 contileTile4, 516 ]); 517 518 // Step 2: Set all tiles to dismissed 519 feed._telemetryUtility.determineFilteredTilesAndSetToDismissed([]); 520 521 let updatedTiles = [ 522 { 523 url: "https://www.brand1.com", 524 label: "brand1", 525 sponsored_position: 1, 526 partner: "amp", 527 }, 528 { 529 url: "https://www.brand2.com", 530 label: "brand2", 531 sponsored_position: 2, 532 partner: "amp", 533 }, 534 { 535 url: "https://www.brand3.com", 536 label: "brand3", 537 sponsored_position: 3, 538 partner: "amp", 539 }, 540 ]; 541 542 // Step 3: Finalize with the updated list of tiles. 543 feed._telemetryUtility.finalizeNewtabPingFields(updatedTiles); 544 545 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 546 547 let expectedResult = { 548 sponsoredTilesReceived: [ 549 { 550 advertiser: "brand1", 551 provider: "amp", 552 display_position: null, 553 display_fail_reason: "dismissed", 554 }, 555 { 556 advertiser: "brand2", 557 provider: "amp", 558 display_position: null, 559 display_fail_reason: "dismissed", 560 }, 561 { 562 advertiser: "brand3", 563 provider: "amp", 564 display_position: null, 565 display_fail_reason: "dismissed", 566 }, 567 { 568 advertiser: "brand4", 569 provider: "amp", 570 display_position: null, 571 display_fail_reason: "dismissed", 572 }, 573 ], 574 }; 575 Assert.equal( 576 Glean.topsites.sponsoredTilesReceived.testGetValue(), 577 JSON.stringify(expectedResult) 578 ); 579 sandbox.restore(); 580 }); 581 582 add_task(async function test_set_tile_positions_after_updated_list() { 583 let sandbox = sinon.createSandbox(); 584 let feed = getTopSitesFeedForTest(sandbox); 585 feed._telemetryUtility.setSponsoredTilesConfigured(); 586 587 // Step 1: Set initial tiles 588 feed._telemetryUtility.setTiles([ 589 contileTile1, 590 contileTile2, 591 contileTile3, 592 contileTile4, 593 ]); 594 595 // Step 2: Set 1 tile to oversold (brand3) 596 let mergedTiles = [ 597 { 598 url: "https://www.brand1.com", 599 label: "brand1", 600 sponsored_position: 1, 601 partner: "amp", 602 }, 603 { 604 url: "https://www.brand2.com", 605 label: "brand2", 606 sponsored_position: 2, 607 partner: "amp", 608 }, 609 { 610 url: "https://www.brand3.com", 611 label: "brand3", 612 sponsored_position: 3, 613 partner: "amp", 614 }, 615 ]; 616 feed._telemetryUtility.determineFilteredTilesAndSetToOversold(mergedTiles); 617 618 // Step 3: Finalize with the updated list of tiles. 619 let updatedTiles = [ 620 { 621 url: "https://www.replacement.com", 622 label: "replacement", 623 sponsored_position: 1, 624 partner: "amp", 625 }, 626 { 627 url: "https://www.brand2.com", 628 label: "brand2", 629 sponsored_position: 2, 630 partner: "amp", 631 }, 632 { 633 url: "https://www.brand3.com", 634 label: "brand3", 635 sponsored_position: 3, 636 partner: "amp", 637 }, 638 ]; 639 feed._telemetryUtility.finalizeNewtabPingFields(updatedTiles); 640 641 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 642 643 let expectedResult = { 644 sponsoredTilesReceived: [ 645 { 646 advertiser: "brand1", 647 provider: "amp", 648 display_position: 1, 649 display_fail_reason: null, 650 }, 651 { 652 advertiser: "brand2", 653 provider: "amp", 654 display_position: 2, 655 display_fail_reason: null, 656 }, 657 { 658 advertiser: "brand3", 659 provider: "amp", 660 display_position: 3, 661 display_fail_reason: null, 662 }, 663 { 664 advertiser: "brand4", 665 provider: "amp", 666 display_position: null, 667 display_fail_reason: "oversold", 668 }, 669 ], 670 }; 671 Assert.equal( 672 Glean.topsites.sponsoredTilesReceived.testGetValue(), 673 JSON.stringify(expectedResult) 674 ); 675 sandbox.restore(); 676 }); 677 678 add_task(async function test_set_tile_positions_after_updated_list_all_tiles() { 679 let sandbox = sinon.createSandbox(); 680 let feed = getTopSitesFeedForTest(sandbox); 681 feed._telemetryUtility.setSponsoredTilesConfigured(); 682 683 // Step 1: Set initial tiles 684 feed._telemetryUtility.setTiles([ 685 contileTile1, 686 contileTile2, 687 contileTile3, 688 contileTile4, 689 ]); 690 691 // Step 2: Set 1 tile to oversold (brand3) 692 let mergedTiles = [ 693 { 694 url: "https://www.brand1.com", 695 label: "brand1", 696 sponsored_position: 1, 697 partner: "amp", 698 }, 699 { 700 url: "https://www.brand2.com", 701 label: "brand2", 702 sponsored_position: 2, 703 partner: "amp", 704 }, 705 { 706 url: "https://www.brand3.com", 707 label: "brand3", 708 sponsored_position: 3, 709 partner: "amp", 710 }, 711 ]; 712 feed._telemetryUtility.determineFilteredTilesAndSetToOversold(mergedTiles); 713 714 // Step 3: Finalize with the updated list of tiles. 715 let updatedTiles = [ 716 { 717 url: "https://www.replacement.com", 718 label: "replacement", 719 sponsored_position: 1, 720 partner: "amp", 721 }, 722 { 723 url: "https://www.replacement2.com", 724 label: "replacement2", 725 sponsored_position: 2, 726 partner: "amp", 727 }, 728 { 729 url: "https://www.replacement3.com", 730 label: "replacement3", 731 sponsored_position: 3, 732 partner: "amp", 733 }, 734 ]; 735 feed._telemetryUtility.finalizeNewtabPingFields(updatedTiles); 736 737 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 738 739 let expectedResult = { 740 sponsoredTilesReceived: [ 741 { 742 advertiser: "brand1", 743 provider: "amp", 744 display_position: 1, 745 display_fail_reason: null, 746 }, 747 { 748 advertiser: "brand2", 749 provider: "amp", 750 display_position: 2, 751 display_fail_reason: null, 752 }, 753 { 754 advertiser: "brand3", 755 provider: "amp", 756 display_position: 3, 757 display_fail_reason: null, 758 }, 759 { 760 advertiser: "brand4", 761 provider: "amp", 762 display_position: null, 763 display_fail_reason: "oversold", 764 }, 765 ], 766 }; 767 Assert.equal( 768 Glean.topsites.sponsoredTilesReceived.testGetValue(), 769 JSON.stringify(expectedResult) 770 ); 771 sandbox.restore(); 772 }); 773 774 add_task( 775 async function test_set_tile_positions_after_no_refresh_no_tiles_changed() { 776 let sandbox = sinon.createSandbox(); 777 let feed = getTopSitesFeedForTest(sandbox); 778 feed._telemetryUtility.setSponsoredTilesConfigured(); 779 780 // Step 1: Set initial tiles 781 feed._telemetryUtility.setTiles([ 782 contileTile1, 783 contileTile2, 784 contileTile3, 785 contileTile4, 786 ]); 787 788 // Step 2: Set 1 tile to oversold (brand3) 789 let mergedTiles = [ 790 { 791 url: "https://www.brand1.com", 792 label: "brand1", 793 sponsored_position: 1, 794 partner: "amp", 795 }, 796 { 797 url: "https://www.brand2.com", 798 label: "brand2", 799 sponsored_position: 2, 800 partner: "amp", 801 }, 802 { 803 url: "https://www.brand3.com", 804 label: "brand3", 805 sponsored_position: 3, 806 partner: "amp", 807 }, 808 ]; 809 feed._telemetryUtility.determineFilteredTilesAndSetToOversold(mergedTiles); 810 811 // Step 3: Finalize with the updated list of tiles. 812 let updatedTiles = [ 813 { 814 url: "https://www.brand1.com", 815 label: "brand1", 816 sponsored_position: 1, 817 partner: "amp", 818 }, 819 { 820 url: "https://www.brand2.com", 821 label: "brand2", 822 sponsored_position: 2, 823 partner: "amp", 824 }, 825 { 826 url: "https://www.brand3.com", 827 label: "brand3", 828 sponsored_position: 3, 829 partner: "amp", 830 }, 831 ]; 832 feed._telemetryUtility.finalizeNewtabPingFields(updatedTiles); 833 834 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 835 836 let expectedResult = { 837 sponsoredTilesReceived: [ 838 { 839 advertiser: "brand1", 840 provider: "amp", 841 display_position: 1, 842 display_fail_reason: null, 843 }, 844 { 845 advertiser: "brand2", 846 provider: "amp", 847 display_position: 2, 848 display_fail_reason: null, 849 }, 850 { 851 advertiser: "brand3", 852 provider: "amp", 853 display_position: 3, 854 display_fail_reason: null, 855 }, 856 { 857 advertiser: "brand4", 858 provider: "amp", 859 display_position: null, 860 display_fail_reason: "oversold", 861 }, 862 ], 863 }; 864 Assert.equal( 865 Glean.topsites.sponsoredTilesReceived.testGetValue(), 866 JSON.stringify(expectedResult) 867 ); 868 sandbox.restore(); 869 } 870 ); 871 872 add_task(async function test_set_contile_tile_to_unresolved() { 873 let sandbox = sinon.createSandbox(); 874 let feed = getTopSitesFeedForTest(sandbox); 875 876 // Create the error state, need to bypass existing checks. 877 feed._telemetryUtility.allSponsoredTiles = { 878 ampbrand1: { 879 advertiser: "brand1", 880 provider: "amp", 881 display_position: 1, 882 display_fail_reason: "oversold", 883 }, 884 ampbrand2: { 885 advertiser: "brand2", 886 provider: "amp", 887 display_position: null, 888 display_fail_reason: null, 889 }, 890 }; 891 892 feed._telemetryUtility._detectErrorConditionAndSetUnresolved(); 893 894 let result = JSON.stringify({ 895 sponsoredTilesReceived: Object.values( 896 feed._telemetryUtility.allSponsoredTiles 897 ), 898 }); 899 900 let expectedResult = { 901 sponsoredTilesReceived: [ 902 { 903 advertiser: "brand1", 904 provider: "amp", 905 display_position: null, 906 display_fail_reason: "unresolved", 907 }, 908 { 909 advertiser: "brand2", 910 provider: "amp", 911 display_position: null, 912 display_fail_reason: "unresolved", 913 }, 914 ], 915 }; 916 Assert.equal(result, JSON.stringify(expectedResult)); 917 sandbox.restore(); 918 }); 919 920 add_task(async function test_set_position_to_value_gt_3() { 921 let sandbox = sinon.createSandbox(); 922 info("Test setTilePositions uses sponsored_position value, not array index."); 923 let feed = getTopSitesFeedForTest(sandbox); 924 925 feed._telemetryUtility.setSponsoredTilesConfigured(); 926 feed._telemetryUtility.setTiles([contileTile1, contileTile2, contileTile3]); 927 928 let filteredContileTiles = [ 929 { 930 url: "https://www.brand1.com", 931 label: "brand1", 932 sponsored_position: 1, 933 partner: "amp", 934 }, 935 { 936 url: "https://www.brand2.com", 937 label: "brand2", 938 sponsored_position: 2, 939 partner: "amp", 940 }, 941 { 942 url: "https://www.brand3.com", 943 label: "brand3", 944 sponsored_position: 6, 945 partner: "amp", 946 }, 947 ]; 948 949 feed._telemetryUtility.determineFilteredTilesAndSetToOversold( 950 filteredContileTiles 951 ); 952 feed._telemetryUtility.finalizeNewtabPingFields(filteredContileTiles); 953 954 let expectedResult = { 955 sponsoredTilesReceived: [ 956 { 957 advertiser: "brand1", 958 provider: "amp", 959 display_position: 1, 960 display_fail_reason: null, 961 }, 962 { 963 advertiser: "brand2", 964 provider: "amp", 965 display_position: 2, 966 display_fail_reason: null, 967 }, 968 { 969 advertiser: "brand3", 970 provider: "amp", 971 display_position: 6, 972 display_fail_reason: null, 973 }, 974 ], 975 }; 976 Assert.equal( 977 Glean.topsites.sponsoredTilesReceived.testGetValue(), 978 JSON.stringify(expectedResult) 979 ); 980 sandbox.restore(); 981 }); 982 983 add_task(async function test_all_tiles_displayed() { 984 let sandbox = sinon.createSandbox(); 985 info("if all provided tiles are displayed, the display_fail_reason is null"); 986 let { feed, fetchStub } = prepFeed(getTopSitesFeedForTest(sandbox), sandbox); 987 988 fetchStub.resolves({ 989 ok: true, 990 status: 200, 991 headers: new Map([ 992 ["cache-control", "private, max-age=859, stale-if-error=10463"], 993 ]), 994 json: () => 995 Promise.resolve({ 996 tiles: [ 997 { 998 url: "https://www.brand1.com", 999 image_url: "images/brand1-com.png", 1000 click_url: "https://www.brand1-click.com", 1001 impression_url: "https://www.brand1-impression.com", 1002 name: "brand1", 1003 }, 1004 { 1005 url: "https://www.brand2.com", 1006 image_url: "images/brand2-com.png", 1007 click_url: "https://www.brand2-click.com", 1008 impression_url: "https://www.brand2-impression.com", 1009 name: "brand2", 1010 }, 1011 ], 1012 }), 1013 }); 1014 1015 const fetched = await feed._contile._fetchSites(); 1016 Assert.ok(fetched); 1017 Assert.equal(feed._contile.sites.length, 2); 1018 1019 await feed._readDefaults(); 1020 await feed.getLinksWithDefaults(false); 1021 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1022 1023 let expectedResult = { 1024 sponsoredTilesReceived: [ 1025 { 1026 advertiser: "brand1", 1027 provider: "amp", 1028 display_position: 1, 1029 display_fail_reason: null, 1030 }, 1031 { 1032 advertiser: "brand2", 1033 provider: "amp", 1034 display_position: 2, 1035 display_fail_reason: null, 1036 }, 1037 ], 1038 }; 1039 Assert.equal( 1040 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1041 JSON.stringify(expectedResult) 1042 ); 1043 sandbox.restore(); 1044 }); 1045 1046 add_task(async function test_set_one_tile_display_fail_reason_to_oversold() { 1047 let sandbox = sinon.createSandbox(); 1048 1049 let { feed, fetchStub } = prepFeed(getTopSitesFeedForTest(sandbox), sandbox); 1050 1051 fetchStub.resolves({ 1052 ok: true, 1053 status: 200, 1054 headers: new Map([ 1055 ["cache-control", "private, max-age=859, stale-if-error=10463"], 1056 ]), 1057 json: () => 1058 Promise.resolve({ 1059 tiles: [ 1060 { 1061 url: "https://www.brand1.com", 1062 image_url: "images/brand1-com.png", 1063 click_url: "https://www.brand1-click.com", 1064 impression_url: "https://www.brand1-impression.com", 1065 name: "brand1", 1066 }, 1067 { 1068 url: "https://www.brand2.com", 1069 image_url: "images/brand2-com.png", 1070 click_url: "https://www.brand2-click.com", 1071 impression_url: "https://www.brand2-impression.com", 1072 name: "brand2", 1073 }, 1074 { 1075 url: "https://www.brand3.com", 1076 image_url: "images/brnad3-com.png", 1077 click_url: "https://www.brand3-click.com", 1078 impression_url: "https://www.brand3-impression.com", 1079 name: "brand3", 1080 }, 1081 { 1082 url: "https://www.brand4.com", 1083 image_url: "images/brnad4-com.png", 1084 click_url: "https://www.brand4-click.com", 1085 impression_url: "https://www.brand4-impression.com", 1086 name: "brand4", 1087 }, 1088 ], 1089 }), 1090 }); 1091 1092 const fetched = await feed._contile._fetchSites(); 1093 Assert.ok(fetched); 1094 Assert.equal(feed._contile.sites.length, 3); 1095 1096 await feed._readDefaults(); 1097 await feed.getLinksWithDefaults(false); 1098 1099 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1100 let expectedResult = { 1101 sponsoredTilesReceived: [ 1102 { 1103 advertiser: "brand1", 1104 provider: "amp", 1105 display_position: 1, 1106 display_fail_reason: null, 1107 }, 1108 { 1109 advertiser: "brand2", 1110 provider: "amp", 1111 display_position: 2, 1112 display_fail_reason: null, 1113 }, 1114 { 1115 advertiser: "brand3", 1116 provider: "amp", 1117 display_position: 3, 1118 display_fail_reason: null, 1119 }, 1120 { 1121 advertiser: "brand4", 1122 provider: "amp", 1123 display_position: null, 1124 display_fail_reason: "oversold", 1125 }, 1126 ], 1127 }; 1128 Assert.equal( 1129 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1130 JSON.stringify(expectedResult) 1131 ); 1132 sandbox.restore(); 1133 }); 1134 1135 add_task(async function test_set_one_tile_display_fail_reason_to_dismissed() { 1136 let sandbox = sinon.createSandbox(); 1137 let { feed, fetchStub } = prepFeed(getTopSitesFeedForTest(sandbox), sandbox); 1138 1139 fetchStub.resolves({ 1140 ok: true, 1141 status: 200, 1142 headers: new Map([ 1143 ["cache-control", "private, max-age=859, stale-if-error=10463"], 1144 ]), 1145 json: () => 1146 Promise.resolve({ 1147 tiles: [ 1148 { 1149 url: "https://foo.com", 1150 image_url: "images/foo.png", 1151 click_url: "https://www.foo-click.com", 1152 impression_url: "https://www.foo-impression.com", 1153 name: "foo", 1154 }, 1155 { 1156 url: "https://www.brand2.com", 1157 image_url: "images/brnad2-com.png", 1158 click_url: "https://www.brand2-click.com", 1159 impression_url: "https://www.brand2-impression.com", 1160 name: "brand2", 1161 }, 1162 { 1163 url: "https://www.brand3.com", 1164 image_url: "images/brand3-com.png", 1165 click_url: "https://www.brand3-click.com", 1166 impression_url: "https://www.brand3-impression.com", 1167 name: "brand3", 1168 }, 1169 ], 1170 }), 1171 }); 1172 1173 Services.prefs.setStringPref( 1174 TOP_SITES_BLOCKED_SPONSORS_PREF, 1175 `["foo","bar"]` 1176 ); 1177 1178 const fetched = await feed._contile._fetchSites(); 1179 Assert.ok(fetched); 1180 Assert.equal(feed._contile.sites.length, 2); 1181 1182 await feed._readDefaults(); 1183 await feed.getLinksWithDefaults(false); 1184 1185 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1186 1187 let expectedResult = { 1188 sponsoredTilesReceived: [ 1189 { 1190 advertiser: "foo", 1191 provider: "amp", 1192 display_position: null, 1193 display_fail_reason: "dismissed", 1194 }, 1195 { 1196 advertiser: "brand2", 1197 provider: "amp", 1198 display_position: 1, 1199 display_fail_reason: null, 1200 }, 1201 { 1202 advertiser: "brand3", 1203 provider: "amp", 1204 display_position: 2, 1205 display_fail_reason: null, 1206 }, 1207 ], 1208 }; 1209 Assert.equal( 1210 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1211 JSON.stringify(expectedResult) 1212 ); 1213 Services.prefs.clearUserPref(TOP_SITES_BLOCKED_SPONSORS_PREF); 1214 sandbox.restore(); 1215 }); 1216 1217 add_task( 1218 async function test_set_one_tile_to_dismissed_and_one_tile_to_oversold() { 1219 let sandbox = sinon.createSandbox(); 1220 let { feed, fetchStub } = prepFeed( 1221 getTopSitesFeedForTest(sandbox), 1222 sandbox 1223 ); 1224 1225 fetchStub.resolves({ 1226 ok: true, 1227 status: 200, 1228 headers: new Map([ 1229 ["cache-control", "private, max-age=859, stale-if-error=10463"], 1230 ]), 1231 json: () => 1232 Promise.resolve({ 1233 tiles: [ 1234 { 1235 url: "https://foo.com", 1236 image_url: "images/foo.png", 1237 click_url: "https://www.foo-click.com", 1238 impression_url: "https://www.foo-impression.com", 1239 name: "foo", 1240 }, 1241 { 1242 url: "https://www.brand2.com", 1243 image_url: "images/brand2-com.png", 1244 click_url: "https://www.brand2-click.com", 1245 impression_url: "https://www.brand2-impression.com", 1246 name: "brand2", 1247 }, 1248 { 1249 url: "https://www.brand3.com", 1250 image_url: "images/brand3-com.png", 1251 click_url: "https://www.brand3-click.com", 1252 impression_url: "https://www.brand3-impression.com", 1253 name: "brand3", 1254 }, 1255 { 1256 url: "https://www.brand4.com", 1257 image_url: "images/brand4-com.png", 1258 click_url: "https://www.brand4-click.com", 1259 impression_url: "https://www.brand4-impression.com", 1260 name: "brand4", 1261 }, 1262 { 1263 url: "https://www.brand5.com", 1264 image_url: "images/brand5-com.png", 1265 click_url: "https://www.brand5-click.com", 1266 impression_url: "https://www.brand5-impression.com", 1267 name: "brand5", 1268 }, 1269 ], 1270 }), 1271 }); 1272 1273 Services.prefs.setStringPref( 1274 TOP_SITES_BLOCKED_SPONSORS_PREF, 1275 `["foo","bar"]` 1276 ); 1277 1278 const fetched = await feed._contile._fetchSites(); 1279 Assert.ok(fetched); 1280 Assert.equal(feed._contile.sites.length, 3); 1281 1282 await feed._readDefaults(); 1283 await feed.getLinksWithDefaults(false); 1284 1285 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1286 1287 let expectedResult = { 1288 sponsoredTilesReceived: [ 1289 { 1290 advertiser: "foo", 1291 provider: "amp", 1292 display_position: null, 1293 display_fail_reason: "dismissed", 1294 }, 1295 { 1296 advertiser: "brand2", 1297 provider: "amp", 1298 display_position: 1, 1299 display_fail_reason: null, 1300 }, 1301 { 1302 advertiser: "brand3", 1303 provider: "amp", 1304 display_position: 2, 1305 display_fail_reason: null, 1306 }, 1307 { 1308 advertiser: "brand4", 1309 provider: "amp", 1310 display_position: 3, 1311 display_fail_reason: null, 1312 }, 1313 { 1314 advertiser: "brand5", 1315 provider: "amp", 1316 display_position: null, 1317 display_fail_reason: "oversold", 1318 }, 1319 ], 1320 }; 1321 Assert.equal( 1322 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1323 JSON.stringify(expectedResult) 1324 ); 1325 Services.prefs.clearUserPref(TOP_SITES_BLOCKED_SPONSORS_PREF); 1326 sandbox.restore(); 1327 } 1328 ); 1329 1330 add_task( 1331 async function test_set_one_cached_tile_display_fail_reason_to_dismissed() { 1332 let sandbox = sinon.createSandbox(); 1333 info("confirm the telemetry is valid when using cached tiles."); 1334 1335 let { feed, fetchStub } = prepFeed( 1336 getTopSitesFeedForTest(sandbox), 1337 sandbox 1338 ); 1339 1340 const tiles = [ 1341 { 1342 url: "https://www.brand1.com", 1343 image_url: "images/brand1-com.png", 1344 click_url: "https://www.brand1-click.com", 1345 impression_url: "https://www.brand1-impression.com", 1346 name: "brand1", 1347 }, 1348 { 1349 url: "https://foo.com", 1350 image_url: "images/foo-com.png", 1351 click_url: "https://www.foo-click.com", 1352 impression_url: "https://www.foo-impression.com", 1353 name: "foo", 1354 }, 1355 ]; 1356 1357 feed._contile.cache.get.returns({ contile: tiles }); 1358 Services.prefs.setIntPref(CONTILE_CACHE_VALID_FOR_PREF, 60 * 15); 1359 Services.prefs.setIntPref( 1360 CONTILE_CACHE_LAST_FETCH_PREF, 1361 Math.round(Date.now() / 1000) 1362 ); 1363 Services.prefs.setStringPref( 1364 TOP_SITES_BLOCKED_SPONSORS_PREF, 1365 `["foo","bar"]` 1366 ); 1367 1368 fetchStub.resolves({ 1369 status: 304, 1370 }); 1371 1372 const fetched = await feed._contile._fetchSites(); 1373 Assert.ok(fetched); 1374 Assert.equal(feed._contile.sites.length, 1); 1375 1376 await feed._readDefaults(); 1377 await feed.getLinksWithDefaults(false); 1378 1379 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1380 1381 let expectedResult = { 1382 sponsoredTilesReceived: [ 1383 { 1384 advertiser: "brand1", 1385 provider: "amp", 1386 display_position: 1, 1387 display_fail_reason: null, 1388 }, 1389 { 1390 advertiser: "foo", 1391 provider: "amp", 1392 display_position: null, 1393 display_fail_reason: "dismissed", 1394 }, 1395 ], 1396 }; 1397 Assert.equal( 1398 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1399 JSON.stringify(expectedResult) 1400 ); 1401 Services.prefs.clearUserPref(TOP_SITES_BLOCKED_SPONSORS_PREF); 1402 sandbox.restore(); 1403 } 1404 ); 1405 1406 add_task(async function test_update_tile_count() { 1407 let sandbox = sinon.createSandbox(); 1408 info( 1409 "the tile count should update when topSitesMaxSponsored is updated by Nimbus" 1410 ); 1411 let { feed, fetchStub } = prepFeed(getTopSitesFeedForTest(sandbox), sandbox); 1412 1413 fetchStub.resolves({ 1414 ok: true, 1415 status: 200, 1416 headers: new Map([ 1417 ["cache-control", "private, max-age=859, stale-if-error=10463"], 1418 ]), 1419 json: () => 1420 Promise.resolve({ 1421 tiles: [ 1422 { 1423 url: "https://www.brand1.com", 1424 image_url: "images/brand1-com.png", 1425 click_url: "https://www.brand1-click.com", 1426 impression_url: "https://www.brand1-impression.com", 1427 name: "brand1", 1428 }, 1429 { 1430 url: "https://www.brand2.com", 1431 image_url: "images/brand2-com.png", 1432 click_url: "https://www.brand2-click.com", 1433 impression_url: "https://www.brand2-impression.com", 1434 name: "brand2", 1435 }, 1436 { 1437 url: "https://www.brand3.com", 1438 image_url: "images/brand3-com.png", 1439 click_url: "https://www.brand3-click.com", 1440 impression_url: "https://www.brand3-impression.com", 1441 name: "brand3", 1442 }, 1443 { 1444 url: "https://www.brand4.com", 1445 image_url: "images/brand4-com.png", 1446 click_url: "https://www.brand4-click.com", 1447 impression_url: "https://www.brand4-impression.com", 1448 name: "brand4", 1449 }, 1450 ], 1451 }), 1452 }); 1453 1454 // 1. Initially the Nimbus pref is set to 2 tiles 1455 let fetched = await feed._contile._fetchSites(); 1456 Assert.ok(fetched); 1457 Assert.equal(feed._contile.sites.length, 3); 1458 await feed._readDefaults(); 1459 await feed.getLinksWithDefaults(false); 1460 1461 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1462 1463 let expectedResult = { 1464 sponsoredTilesReceived: [ 1465 { 1466 advertiser: "brand1", 1467 provider: "amp", 1468 display_position: 1, 1469 display_fail_reason: null, 1470 }, 1471 { 1472 advertiser: "brand2", 1473 provider: "amp", 1474 display_position: 2, 1475 display_fail_reason: null, 1476 }, 1477 { 1478 advertiser: "brand3", 1479 provider: "amp", 1480 display_position: 3, 1481 display_fail_reason: null, 1482 }, 1483 { 1484 advertiser: "brand4", 1485 provider: "amp", 1486 display_position: null, 1487 display_fail_reason: "oversold", 1488 }, 1489 ], 1490 }; 1491 Assert.equal( 1492 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1493 JSON.stringify(expectedResult) 1494 ); 1495 1496 // 2. Set the Numbus pref to 3, confirm previous count still used. 1497 const nimbusPocketStub = sandbox.stub( 1498 NimbusFeatures.pocketNewtab, 1499 "getVariable" 1500 ); 1501 setNimbusVariablesForNumTiles(nimbusPocketStub, 3); 1502 1503 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1504 1505 expectedResult = { 1506 sponsoredTilesReceived: [ 1507 { 1508 advertiser: "brand1", 1509 provider: "amp", 1510 display_position: 1, 1511 display_fail_reason: null, 1512 }, 1513 { 1514 advertiser: "brand2", 1515 provider: "amp", 1516 display_position: 2, 1517 display_fail_reason: null, 1518 }, 1519 { 1520 advertiser: "brand3", 1521 provider: "amp", 1522 display_position: 3, 1523 display_fail_reason: null, 1524 }, 1525 { 1526 advertiser: "brand4", 1527 provider: "amp", 1528 display_position: null, 1529 display_fail_reason: "oversold", 1530 }, 1531 ], 1532 }; 1533 Assert.equal( 1534 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1535 JSON.stringify(expectedResult) 1536 ); 1537 1538 // 3. Confirm the new count is applied when data pulled from Contile., 3 tiles displayed 1539 fetched = await feed._contile._fetchSites(); 1540 Assert.ok(fetched); 1541 Assert.equal(feed._contile.sites.length, 3); 1542 await feed._readDefaults(); 1543 await feed.getLinksWithDefaults(false); 1544 1545 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1546 1547 expectedResult = { 1548 sponsoredTilesReceived: [ 1549 { 1550 advertiser: "brand1", 1551 provider: "amp", 1552 display_position: 1, 1553 display_fail_reason: null, 1554 }, 1555 { 1556 advertiser: "brand2", 1557 provider: "amp", 1558 display_position: 2, 1559 display_fail_reason: null, 1560 }, 1561 { 1562 advertiser: "brand3", 1563 provider: "amp", 1564 display_position: 3, 1565 display_fail_reason: null, 1566 }, 1567 { 1568 advertiser: "brand4", 1569 provider: "amp", 1570 display_position: null, 1571 display_fail_reason: "oversold", 1572 }, 1573 ], 1574 }; 1575 Assert.equal( 1576 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1577 JSON.stringify(expectedResult) 1578 ); 1579 1580 sandbox.restore(); 1581 }); 1582 1583 add_task(async function test_update_tile_count_sourced_from_cache() { 1584 let sandbox = sinon.createSandbox(); 1585 1586 info( 1587 "the tile count should update from cache when topSitesMaxSponsored is updated by Nimbus" 1588 ); 1589 let { feed, fetchStub } = prepFeed(getTopSitesFeedForTest(sandbox), sandbox); 1590 1591 const tiles = [ 1592 { 1593 url: "https://www.brand1.com", 1594 image_url: "images/brand1-com.png", 1595 click_url: "https://www.brand1-click.com", 1596 impression_url: "https://www.brand1-impression.com", 1597 name: "brand1", 1598 }, 1599 { 1600 url: "https://www.brand2.com", 1601 image_url: "images/brand2-com.png", 1602 click_url: "https://www.brand2-click.com", 1603 impression_url: "https://www.brand2-impression.com", 1604 name: "brand2", 1605 }, 1606 { 1607 url: "https://www.brand3.com", 1608 image_url: "images/brand3-com.png", 1609 click_url: "https://www.brand3-click.com", 1610 impression_url: "https://www.brand3-impression.com", 1611 name: "brand3", 1612 }, 1613 { 1614 url: "https://www.brand4.com", 1615 image_url: "images/brand4-com.png", 1616 click_url: "https://www.brand4-click.com", 1617 impression_url: "https://www.brand4-impression.com", 1618 name: "brand4", 1619 }, 1620 ]; 1621 1622 feed._contile.cache.get.returns({ contile: tiles }); 1623 Services.prefs.setIntPref(CONTILE_CACHE_VALID_FOR_PREF, 60 * 15); 1624 Services.prefs.setIntPref( 1625 CONTILE_CACHE_LAST_FETCH_PREF, 1626 Math.round(Date.now() / 1000) 1627 ); 1628 1629 fetchStub.resolves({ 1630 status: 304, 1631 }); 1632 1633 // 1. Initially the Nimbus pref is set to 2 tiles 1634 // Ensure ContileIntegration._fetchSites is working populate _sites and initilize TelemetryUtility 1635 let fetched = await feed._contile._fetchSites(); 1636 Assert.ok(fetched); 1637 Assert.equal(feed._contile.sites.length, 4); 1638 await feed._readDefaults(); 1639 await feed.getLinksWithDefaults(false); 1640 1641 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1642 1643 let expectedResult = { 1644 sponsoredTilesReceived: [ 1645 { 1646 advertiser: "brand1", 1647 provider: "amp", 1648 display_position: 1, 1649 display_fail_reason: null, 1650 }, 1651 { 1652 advertiser: "brand2", 1653 provider: "amp", 1654 display_position: 2, 1655 display_fail_reason: null, 1656 }, 1657 { 1658 advertiser: "brand3", 1659 provider: "amp", 1660 display_position: 3, 1661 display_fail_reason: null, 1662 }, 1663 { 1664 advertiser: "brand4", 1665 provider: "amp", 1666 display_position: null, 1667 display_fail_reason: "oversold", 1668 }, 1669 ], 1670 }; 1671 Assert.equal( 1672 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1673 JSON.stringify(expectedResult) 1674 ); 1675 1676 // 2. Set the Numbus pref to 3, confirm previous count still used. 1677 const nimbusPocketStub = sandbox.stub( 1678 NimbusFeatures.pocketNewtab, 1679 "getVariable" 1680 ); 1681 setNimbusVariablesForNumTiles(nimbusPocketStub, 3); 1682 1683 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1684 1685 // 3. Confirm the new count is applied when data pulled from Contile, 3 tiles displayed 1686 fetched = await feed._contile._fetchSites(); 1687 Assert.ok(fetched); 1688 Assert.equal(feed._contile.sites.length, 4); 1689 await feed._readDefaults(); 1690 await feed.getLinksWithDefaults(false); 1691 1692 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1693 1694 expectedResult = { 1695 sponsoredTilesReceived: [ 1696 { 1697 advertiser: "brand1", 1698 provider: "amp", 1699 display_position: 1, 1700 display_fail_reason: null, 1701 }, 1702 { 1703 advertiser: "brand2", 1704 provider: "amp", 1705 display_position: 2, 1706 display_fail_reason: null, 1707 }, 1708 { 1709 advertiser: "brand3", 1710 provider: "amp", 1711 display_position: 3, 1712 display_fail_reason: null, 1713 }, 1714 { 1715 advertiser: "brand4", 1716 provider: "amp", 1717 display_position: null, 1718 display_fail_reason: "oversold", 1719 }, 1720 ], 1721 }; 1722 Assert.equal( 1723 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1724 JSON.stringify(expectedResult) 1725 ); 1726 sandbox.restore(); 1727 }); 1728 1729 add_task( 1730 async function test_update_telemetry_fields_if_dismissed_brands_list_is_updated() { 1731 let sandbox = sinon.createSandbox(); 1732 info( 1733 "if the user dismisses a brand, that dismissed tile shoudl be represented in the next ping." 1734 ); 1735 let { feed, fetchStub } = prepFeed( 1736 getTopSitesFeedForTest(sandbox), 1737 sandbox 1738 ); 1739 1740 fetchStub.resolves({ 1741 ok: true, 1742 status: 200, 1743 headers: new Map([ 1744 ["cache-control", "private, max-age=859, stale-if-error=10463"], 1745 ]), 1746 json: () => 1747 Promise.resolve({ 1748 tiles: [ 1749 { 1750 url: "https://foo.com", 1751 image_url: "images/foo.png", 1752 click_url: "https://www.foo-click.com", 1753 impression_url: "https://www.foo-impression.com", 1754 name: "foo", 1755 }, 1756 { 1757 url: "https://www.brand2.com", 1758 image_url: "images/brand2-com.png", 1759 click_url: "https://www.brand2-click.com", 1760 impression_url: "https://www.brand2-impression.com", 1761 name: "brand2", 1762 }, 1763 { 1764 url: "https://www.brand3.com", 1765 image_url: "images/brand3-com.png", 1766 click_url: "https://www.brand3-click.com", 1767 impression_url: "https://www.brand3-impression.com", 1768 name: "brand3", 1769 }, 1770 ], 1771 }), 1772 }); 1773 Services.prefs.setStringPref( 1774 TOP_SITES_BLOCKED_SPONSORS_PREF, 1775 `["foo","bar"]` 1776 ); 1777 1778 let fetched = await feed._contile._fetchSites(); 1779 Assert.ok(fetched); 1780 Assert.equal(feed._contile.sites.length, 2); 1781 1782 await feed._readDefaults(); 1783 await feed.getLinksWithDefaults(false); 1784 1785 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1786 1787 let expectedResult = { 1788 sponsoredTilesReceived: [ 1789 { 1790 advertiser: "foo", 1791 provider: "amp", 1792 display_position: null, 1793 display_fail_reason: "dismissed", 1794 }, 1795 { 1796 advertiser: "brand2", 1797 provider: "amp", 1798 display_position: 1, 1799 display_fail_reason: null, 1800 }, 1801 { 1802 advertiser: "brand3", 1803 provider: "amp", 1804 display_position: 2, 1805 display_fail_reason: null, 1806 }, 1807 ], 1808 }; 1809 Assert.equal( 1810 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1811 JSON.stringify(expectedResult) 1812 ); 1813 1814 Services.prefs.setStringPref( 1815 TOP_SITES_BLOCKED_SPONSORS_PREF, 1816 `["foo","bar","brand2"]` 1817 ); 1818 1819 fetched = await feed._contile._fetchSites(); 1820 Assert.ok(fetched); 1821 Assert.equal(feed._contile.sites.length, 1); 1822 1823 await feed._readDefaults(); 1824 await feed.getLinksWithDefaults(false); 1825 1826 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1827 1828 expectedResult = { 1829 sponsoredTilesReceived: [ 1830 { 1831 advertiser: "foo", 1832 provider: "amp", 1833 display_position: null, 1834 display_fail_reason: "dismissed", 1835 }, 1836 { 1837 advertiser: "brand2", 1838 provider: "amp", 1839 display_position: null, 1840 display_fail_reason: "dismissed", 1841 }, 1842 { 1843 advertiser: "brand3", 1844 provider: "amp", 1845 display_position: 1, 1846 display_fail_reason: null, 1847 }, 1848 ], 1849 }; 1850 Assert.equal( 1851 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1852 JSON.stringify(expectedResult) 1853 ); 1854 1855 Services.prefs.clearUserPref(TOP_SITES_BLOCKED_SPONSORS_PREF); 1856 sandbox.restore(); 1857 } 1858 ); 1859 1860 add_task(async function test_sponsoredTilesReceived_not_set() { 1861 let sandbox = sinon.createSandbox(); 1862 info("sponsoredTilesReceived should be empty if tiles service returns 204"); 1863 let { feed, fetchStub } = prepFeed(getTopSitesFeedForTest(sandbox), sandbox); 1864 1865 fetchStub.resolves({ ok: true, status: 204 }); 1866 1867 const fetched = await feed._contile._fetchSites(); 1868 Assert.ok(!fetched); 1869 Assert.ok(!feed._contile.sites.length); 1870 1871 await feed._readDefaults(); 1872 await feed.getLinksWithDefaults(false); 1873 1874 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1875 let expectedResult = { sponsoredTilesReceived: [] }; 1876 1877 Assert.equal( 1878 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1879 JSON.stringify(expectedResult) 1880 ); 1881 sandbox.restore(); 1882 }); 1883 1884 add_task(async function test_telemetry_data_updates() { 1885 let sandbox = sinon.createSandbox(); 1886 info("sponsoredTilesReceived should update when new tiles received."); 1887 let { feed, fetchStub } = prepFeed(getTopSitesFeedForTest(sandbox), sandbox); 1888 1889 fetchStub.resolves({ 1890 ok: true, 1891 status: 200, 1892 headers: new Map([ 1893 ["cache-control", "private, max-age=859, stale-if-error=10463"], 1894 ]), 1895 json: () => 1896 Promise.resolve({ 1897 tiles: [ 1898 { 1899 url: "https://foo.com", 1900 image_url: "images/foo.png", 1901 click_url: "https://www.foo-click.com", 1902 impression_url: "https://www.foo-impression.com", 1903 name: "foo", 1904 }, 1905 { 1906 url: "https://www.brand2.com", 1907 image_url: "images/brand2-com.png", 1908 click_url: "https://www.brand2-click.com", 1909 impression_url: "https://www.brand2-impression.com", 1910 name: "brand2", 1911 }, 1912 { 1913 url: "https://www.brand3.com", 1914 image_url: "images/brand3-com.png", 1915 click_url: "https://www.brand3-click.com", 1916 impression_url: "https://www.brand3-impression.com", 1917 name: "brand3", 1918 }, 1919 ], 1920 }), 1921 }); 1922 Services.prefs.setStringPref( 1923 TOP_SITES_BLOCKED_SPONSORS_PREF, 1924 `["foo","bar"]` 1925 ); 1926 1927 const fetched = await feed._contile._fetchSites(); 1928 Assert.ok(fetched); 1929 Assert.equal(feed._contile.sites.length, 2); 1930 1931 await feed._readDefaults(); 1932 await feed.getLinksWithDefaults(false); 1933 1934 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 1935 1936 let expectedResult = { 1937 sponsoredTilesReceived: [ 1938 { 1939 advertiser: "foo", 1940 provider: "amp", 1941 display_position: null, 1942 display_fail_reason: "dismissed", 1943 }, 1944 { 1945 advertiser: "brand2", 1946 provider: "amp", 1947 display_position: 1, 1948 display_fail_reason: null, 1949 }, 1950 { 1951 advertiser: "brand3", 1952 provider: "amp", 1953 display_position: 2, 1954 display_fail_reason: null, 1955 }, 1956 ], 1957 }; 1958 Assert.equal( 1959 Glean.topsites.sponsoredTilesReceived.testGetValue(), 1960 JSON.stringify(expectedResult) 1961 ); 1962 1963 fetchStub.resolves({ 1964 ok: true, 1965 status: 200, 1966 headers: new Map([ 1967 ["cache-control", "private, max-age=859, stale-if-error=10463"], 1968 ]), 1969 json: () => 1970 Promise.resolve({ 1971 tiles: [ 1972 { 1973 url: "https://foo.com", 1974 image_url: "images/foo.png", 1975 click_url: "https://www.foo-click.com", 1976 impression_url: "https://www.foo-impression.com", 1977 name: "foo", 1978 }, 1979 { 1980 url: "https://bar.com", 1981 image_url: "images/bar-com.png", 1982 click_url: "https://www.bar-click.com", 1983 impression_url: "https://www.bar-impression.com", 1984 name: "bar", 1985 }, 1986 { 1987 url: "https://www.brand3.com", 1988 image_url: "images/brand3-com.png", 1989 click_url: "https://www.brand3-click.com", 1990 impression_url: "https://www.brand3-impression.com", 1991 name: "brand3", 1992 }, 1993 ], 1994 }), 1995 }); 1996 1997 await feed._contile._fetchSites(); 1998 Assert.ok(fetched); 1999 Assert.equal(feed._contile.sites.length, 1); 2000 2001 await feed._readDefaults(); 2002 await feed.getLinksWithDefaults(false); 2003 2004 expectedResult = { 2005 sponsoredTilesReceived: [ 2006 { 2007 advertiser: "foo", 2008 provider: "amp", 2009 display_position: null, 2010 display_fail_reason: "dismissed", 2011 }, 2012 { 2013 advertiser: "bar", 2014 provider: "amp", 2015 display_position: null, 2016 display_fail_reason: "dismissed", 2017 }, 2018 { 2019 advertiser: "brand3", 2020 provider: "amp", 2021 display_position: 1, 2022 display_fail_reason: null, 2023 }, 2024 ], 2025 }; 2026 Assert.equal( 2027 Glean.topsites.sponsoredTilesReceived.testGetValue(), 2028 JSON.stringify(expectedResult) 2029 ); 2030 Services.prefs.clearUserPref(TOP_SITES_BLOCKED_SPONSORS_PREF); 2031 sandbox.restore(); 2032 }); 2033 2034 add_task(async function test_reset_telemetry_data() { 2035 let sandbox = sinon.createSandbox(); 2036 info( 2037 "sponsoredTilesReceived should be cleared when no tiles received and cache refreshed." 2038 ); 2039 let { feed, fetchStub } = prepFeed(getTopSitesFeedForTest(sandbox), sandbox); 2040 2041 fetchStub.resolves({ 2042 ok: true, 2043 status: 200, 2044 headers: new Map([ 2045 ["cache-control", "private, max-age=859, stale-if-error=10463"], 2046 ]), 2047 json: () => 2048 Promise.resolve({ 2049 tiles: [ 2050 { 2051 url: "https://foo.com", 2052 image_url: "images/foo.png", 2053 click_url: "https://www.foo-click.com", 2054 impression_url: "https://www.foo-impression.com", 2055 name: "foo", 2056 }, 2057 { 2058 url: "https://www.brand2.com", 2059 image_url: "images/brand2-com.png", 2060 click_url: "https://www.brand2-click.com", 2061 impression_url: "https://www.brand2-impression.com", 2062 name: "brand2", 2063 }, 2064 { 2065 url: "https://www.brand3.com", 2066 image_url: "images/brand3-com.png", 2067 click_url: "https://www.brand3-click.com", 2068 impression_url: "https://www.brand3-impression.com", 2069 name: "test3", 2070 }, 2071 ], 2072 }), 2073 }); 2074 Services.prefs.setStringPref( 2075 TOP_SITES_BLOCKED_SPONSORS_PREF, 2076 `["foo","bar"]` 2077 ); 2078 2079 let fetched = await feed._contile._fetchSites(); 2080 Assert.ok(fetched); 2081 Assert.equal(feed._contile.sites.length, 2); 2082 2083 await feed._readDefaults(); 2084 await feed.getLinksWithDefaults(false); 2085 2086 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 2087 2088 let expectedResult = { 2089 sponsoredTilesReceived: [ 2090 { 2091 advertiser: "foo", 2092 provider: "amp", 2093 display_position: null, 2094 display_fail_reason: "dismissed", 2095 }, 2096 { 2097 advertiser: "brand2", 2098 provider: "amp", 2099 display_position: 1, 2100 display_fail_reason: null, 2101 }, 2102 { 2103 advertiser: "brand3", 2104 provider: "amp", 2105 display_position: 2, 2106 display_fail_reason: null, 2107 }, 2108 ], 2109 }; 2110 Assert.equal( 2111 Glean.topsites.sponsoredTilesReceived.testGetValue(), 2112 JSON.stringify(expectedResult) 2113 ); 2114 2115 fetchStub.resolves({ ok: true, status: 204 }); 2116 2117 fetched = await feed._contile._fetchSites(); 2118 Assert.ok(fetched); 2119 Assert.ok(!feed._contile.sites.length); 2120 2121 await feed._readDefaults(); 2122 await feed.getLinksWithDefaults(false); 2123 2124 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 2125 2126 expectedResult = { sponsoredTilesReceived: [] }; 2127 Assert.equal( 2128 Glean.topsites.sponsoredTilesReceived.testGetValue(), 2129 JSON.stringify(expectedResult) 2130 ); 2131 Services.prefs.clearUserPref(TOP_SITES_BLOCKED_SPONSORS_PREF); 2132 sandbox.restore(); 2133 }); 2134 2135 add_task(async function test_set_telemetry_for_moz_sales_tiles() { 2136 let sandbox = sinon.createSandbox(); 2137 let { feed, fetchStub } = prepFeed(getTopSitesFeedForTest(sandbox), sandbox); 2138 2139 sandbox.stub(feed, "fetchDiscoveryStreamSpocs").returns([ 2140 { 2141 label: "MozSales Title", 2142 title: "MozSales Title", 2143 url: "https://mozsale.net", 2144 sponsored_position: 1, 2145 partner: "moz-sales", 2146 }, 2147 ]); 2148 2149 fetchStub.resolves({ 2150 ok: true, 2151 status: 200, 2152 headers: new Map([ 2153 ["cache-control", "private, max-age=859, stale-if-error=10463"], 2154 ]), 2155 json: () => 2156 Promise.resolve({ 2157 tiles: [ 2158 { 2159 url: "https://www.brand1.com", 2160 image_url: "images/brand1-com.png", 2161 click_url: "https://www.brand1-click.com", 2162 impression_url: "https://www.brand1-impression.com", 2163 name: "brand1", 2164 }, 2165 { 2166 url: "https://www.brand2.com", 2167 image_url: "images/brand2-com.png", 2168 click_url: "https://www.brand2-click.com", 2169 impression_url: "https://www.brand2-impression.com", 2170 name: "brand2", 2171 }, 2172 { 2173 url: "https://www.brand3.com", 2174 image_url: "images/brand3-com.png", 2175 click_url: "https://www.brand3-click.com", 2176 impression_url: "https://www.brand3-impression.com", 2177 name: "brand2", 2178 }, 2179 ], 2180 }), 2181 }); 2182 const fetched = await feed._contile._fetchSites(); 2183 Assert.ok(fetched); 2184 Assert.equal(feed._contile.sites.length, 3); 2185 2186 await feed._readDefaults(); 2187 await feed.getLinksWithDefaults(false); 2188 2189 Assert.equal(Glean.topsites.sponsoredTilesConfigured.testGetValue(), 3); 2190 let expectedResult = { 2191 sponsoredTilesReceived: [ 2192 { 2193 advertiser: "brand1", 2194 provider: "amp", 2195 display_position: 1, 2196 display_fail_reason: null, 2197 }, 2198 { 2199 advertiser: "brand2", 2200 provider: "amp", 2201 display_position: 2, 2202 display_fail_reason: null, 2203 }, 2204 { 2205 advertiser: "brand3", 2206 provider: "amp", 2207 display_position: 3, 2208 display_fail_reason: null, 2209 }, 2210 { 2211 advertiser: "mozsales title", 2212 provider: "moz-sales", 2213 display_position: null, 2214 display_fail_reason: "oversold", 2215 }, 2216 ], 2217 }; 2218 Assert.equal( 2219 Glean.topsites.sponsoredTilesReceived.testGetValue(), 2220 JSON.stringify(expectedResult) 2221 ); 2222 sandbox.restore(); 2223 });