tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 7a900dbac9a10eb387737f8de472d884423265e8
parent 5508d7b3a784d1b4c87c46275c95369cb859b5a5
Author: scottdowne <sdowne@mozilla.com>
Date:   Tue,  6 Jan 2026 21:09:55 +0000

Bug 2006769 - Newtab cleaning up deduping logic for frecent boosted shortcuts r=home-newtab-reviewers,ini

Differential Revision: https://phabricator.services.mozilla.com/D277517

Diffstat:
Mbrowser/extensions/newtab/lib/TopSitesFeed.sys.mjs | 264+++++++++++++++++++++++++++++++++++++------------------------------------------
Mbrowser/extensions/newtab/test/xpcshell/test_TopSitesFeed_frecencyDeduping.js | 262++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mbrowser/extensions/newtab/test/xpcshell/test_TopSitesFeed_frecencyRanking.js | 86++++++++++++++++++++++++-------------------------------------------------------
3 files changed, 307 insertions(+), 305 deletions(-)

diff --git a/browser/extensions/newtab/lib/TopSitesFeed.sys.mjs b/browser/extensions/newtab/lib/TopSitesFeed.sys.mjs @@ -985,6 +985,69 @@ export class TopSitesFeed { } /** + * _readContile - sets DEFAULT_TOP_SITES with contile + */ + _readContile() { + // Keep the number of positions in the array in sync with CONTILE_MAX_NUM_SPONSORED. + // sponsored_position is a 1-based index, and contilePositions is a 0-based index, + // so we need to add 1 to each of these. + // Also currently this does not work with SOV. + let contilePositions = lazy.NimbusFeatures.pocketNewtab + .getVariable(NIMBUS_VARIABLE_CONTILE_POSITIONS) + ?.split(",") + .map(item => parseInt(item, 10) + 1) + .filter(item => !Number.isNaN(item)); + if (!contilePositions || contilePositions.length === 0) { + contilePositions = [1, 2]; + } + + let hasContileTiles = false; + + let contilePositionIndex = 0; + // We need to loop through potential spocs and set their positions. + // If we run out of spocs or positions, we stop. + // First, we need to know which array is shortest. This is our exit condition. + const minLength = Math.min( + contilePositions.length, + this._contile.sites.length + ); + // Loop until we run out of spocs or positions. + for (let i = 0; i < minLength; i++) { + let site = this._contile.sites[i]; + let hostname = lazy.NewTabUtils.shortURL(site); + let link = { + isDefault: true, + url: site.url, + hostname, + sendAttributionRequest: false, + label: site.name, + show_sponsored_label: hostname !== "yandex", + sponsored_position: contilePositions[contilePositionIndex++], + sponsored_click_url: site.click_url, + sponsored_impression_url: site.impression_url, + sponsored_tile_id: site.id, + partner: SPONSORED_TILE_PARTNER_AMP, + block_key: site.id, + attribution: site.attribution, + }; + if (site.image_url && site.image_size >= MIN_FAVICON_SIZE) { + // Only use the image from Contile if it's hi-res, otherwise, fallback + // to the built-in favicons. + link.favicon = site.image_url; + link.faviconSize = site.image_size; + } + DEFAULT_TOP_SITES.push(link); + } + hasContileTiles = contilePositionIndex > 0; + // This is to catch where we receive 3 tiles but reduce to 2 early in the filtering, before blocked list applied. + this._telemetryUtility.determineFilteredTilesAndSetToOversold( + DEFAULT_TOP_SITES + ); + + return hasContileTiles; + } + + /** * _readDefaults - sets DEFAULT_TOP_SITES */ async _readDefaults({ isStartup = false } = {}) { @@ -1018,61 +1081,10 @@ export class TopSitesFeed { NIMBUS_VARIABLE_CONTILE_ENABLED ); - // Keep the number of positions in the array in sync with CONTILE_MAX_NUM_SPONSORED. - // sponsored_position is a 1-based index, and contilePositions is a 0-based index, - // so we need to add 1 to each of these. - // Also currently this does not work with SOV. - let contilePositions = lazy.NimbusFeatures.pocketNewtab - .getVariable(NIMBUS_VARIABLE_CONTILE_POSITIONS) - ?.split(",") - .map(item => parseInt(item, 10) + 1) - .filter(item => !Number.isNaN(item)); - if (!contilePositions || contilePositions.length === 0) { - contilePositions = [1, 2]; - } - let hasContileTiles = false; + if (contileEnabled) { - let contilePositionIndex = 0; - // We need to loop through potential spocs and set their positions. - // If we run out of spocs or positions, we stop. - // First, we need to know which array is shortest. This is our exit condition. - const minLength = Math.min( - contilePositions.length, - this._contile.sites.length - ); - // Loop until we run out of spocs or positions. - for (let i = 0; i < minLength; i++) { - let site = this._contile.sites[i]; - let hostname = lazy.NewTabUtils.shortURL(site); - let link = { - isDefault: true, - url: site.url, - hostname, - sendAttributionRequest: false, - label: site.name, - show_sponsored_label: hostname !== "yandex", - sponsored_position: contilePositions[contilePositionIndex++], - sponsored_click_url: site.click_url, - sponsored_impression_url: site.impression_url, - sponsored_tile_id: site.id, - partner: SPONSORED_TILE_PARTNER_AMP, - block_key: site.id, - attribution: site.attribution, - }; - if (site.image_url && site.image_size >= MIN_FAVICON_SIZE) { - // Only use the image from Contile if it's hi-res, otherwise, fallback - // to the built-in favicons. - link.favicon = site.image_url; - link.faviconSize = site.image_size; - } - DEFAULT_TOP_SITES.push(link); - } - hasContileTiles = contilePositionIndex > 0; - //This is to catch where we receive 3 tiles but reduce to 2 early in the filtering, before blocked list applied. - this._telemetryUtility.determineFilteredTilesAndSetToOversold( - DEFAULT_TOP_SITES - ); + hasContileTiles = this._readContile(); } // Read defaults from remote settings. @@ -1411,7 +1423,7 @@ export class TopSitesFeed { async _importFrecencyBoostedSponsor(record) { const { title, domain, redirect_url, attachment } = record; const faviconDataURI = await this._fetchSponsorFaviconAsDataURI(attachment); - const { hostname } = new URL(domain); + const hostname = lazy.NewTabUtils.shortURL({ url: domain }); const sponsorData = { title, @@ -1456,51 +1468,6 @@ export class TopSitesFeed { } /** - * Dedupe sponsored domains against organic topsites. - * - * @param {Array} sponsors - List of sponsor domain objects - * @returns {Array} Filtered list of sponsors not in organic topsites - */ - dedupeSponsorsAgainstTopsites(sponsors = []) { - const topSitesCount = - this.store.getState().Prefs.values[ROWS_PREF] * - TOP_SITES_MAX_SITES_PER_ROW; - - const linksWithDefaults = this._linksWithDefaults || []; - const topsites = new Set( - linksWithDefaults - .slice(0, topSitesCount) - .filter(site => site.type !== "frecency-boost") - .map(site => { - try { - return site.hostname || lazy.NewTabUtils.shortURL(site); - } catch (e) { - return null; - } - }) - .filter(Boolean) - ); - - return sponsors.filter( - ({ hostname }) => - !topsites.has(lazy.NewTabUtils.shortURL({ url: `https://${hostname}` })) - ); - } - - normalizeUrl(url) { - let normalized = url; - if (normalized.startsWith("https://")) { - normalized = normalized.slice(8); - } else if (normalized.startsWith("http://")) { - normalized = normalized.slice(7); - } - if (normalized.startsWith("www.")) { - normalized = normalized.slice(4); - } - return normalized; - } - - /** * Build frecency-boosted spocs from a list of sponsor domains by checking Places history. * Checks if domains exist in history, dedupes against organic topsites, * and returns all matches sorted by frecency. @@ -1508,13 +1475,7 @@ export class TopSitesFeed { * @param {Array} sponsors - List of sponsor domain objects with hostname and title * @returns {Array} Array of sponsored tile objects sorted by frecency, or empty array */ - async buildFrecencyBoostedSpocs(sponsors) { - if (!sponsors || !sponsors.length) { - return []; - } - - const sponsorsToCheck = this.dedupeSponsorsAgainstTopsites(sponsors); - + async buildFrecencyBoostedSpocs(sponsorsToCheck = []) { if (!sponsorsToCheck.length) { return []; } @@ -1532,22 +1493,15 @@ export class TopSitesFeed { const candidates = []; frecent.forEach(site => { - const normalizedSiteUrl = this.normalizeUrl(site.url); - + const normalizedSiteUrl = lazy.NewTabUtils.shortURL(site); for (const domainObj of sponsorsToCheck) { - const normalizedDomain = this.normalizeUrl(domainObj.domain); - if ( - !normalizedSiteUrl.startsWith(normalizedDomain) || + normalizedSiteUrl !== domainObj.hostname || lazy.NewTabUtils.blockedLinks.isBlocked({ url: domainObj.domain }) ) { continue; } - const sponsorData = this._frecencyBoostedSponsors.get( - domainObj.hostname - ); - candidates.push({ hostname: domainObj.hostname, url: domainObj.redirectURL, @@ -1556,7 +1510,7 @@ export class TopSitesFeed { type: "frecency-boost", frecency: site.frecency, show_sponsored_label: true, - favicon: sponsorData.faviconDataURI, + favicon: domainObj.faviconDataURI, faviconSize: 96, }); } @@ -1580,7 +1534,6 @@ export class TopSitesFeed { async fetchFrecencyBoostedSpocs() { if ( !this._contile.sovEnabled() || - !this._linksWithDefaults?.length || !this.store.getState().Prefs.values[SHOW_SPONSORED_PREF] ) { return []; @@ -1729,12 +1682,19 @@ export class TopSitesFeed { : link), hostname, }); + // LinksCache can return the previous cached result + // if it's equal to or greater than the requested amount. + // In this case we can just take what we need. + if (frecent.length >= numFetch) { + break; + } } } // Get defaults. let contileSponsored = []; let notBlockedDefaultSites = []; + for (let link of DEFAULT_TOP_SITES) { // For sponsored Yandex links, default filtering is reversed: we only // show them if Yandex is the default search engine. @@ -1787,17 +1747,6 @@ export class TopSitesFeed { const frecencyBoostedSponsored = await this.fetchFrecencyBoostedSpocs(); this._telemetryUtility.setTiles(discoverySponsored); - const sponsored = this._mergeSponsoredLinks({ - [SPONSORED_TILE_PARTNER_AMP]: contileSponsored, - [SPONSORED_TILE_PARTNER_MOZ_SALES]: discoverySponsored, - [SPONSORED_TILE_PARTNER_FREC_BOOST]: frecencyBoostedSponsored, - }); - - this._maybeCapSponsoredLinks(sponsored); - - // This will set all extra tiles to oversold, including moz-sales. - this._telemetryUtility.determineFilteredTilesAndSetToOversold(sponsored); - // Get pinned links augmented with desired properties let plainPinned = await this.pinnedCache.request(); @@ -1866,10 +1815,37 @@ export class TopSitesFeed { ); // Remove any duplicates from frecent and default sites - const [, dedupedSponsored, dedupedFrecent, dedupedDefaults] = - this.dedupe.group(pinned, sponsored, frecent, notBlockedDefaultSites); + const [ + , + dedupedContileSponsored, + dedupedDiscoverySponsored, + dedupedFrecent, + dedupedFrecencyBoostedSponsored, + dedupedDefaults, + ] = this.dedupe.group( + pinned, + contileSponsored, + discoverySponsored, + frecent, + frecencyBoostedSponsored, + notBlockedDefaultSites + ); + const dedupedUnpinned = [...dedupedFrecent, ...dedupedDefaults]; + const dedupedSponsored = this._mergeSponsoredLinks({ + [SPONSORED_TILE_PARTNER_AMP]: dedupedContileSponsored, + [SPONSORED_TILE_PARTNER_MOZ_SALES]: dedupedDiscoverySponsored, + [SPONSORED_TILE_PARTNER_FREC_BOOST]: dedupedFrecencyBoostedSponsored, + }); + + this._maybeCapSponsoredLinks(dedupedSponsored); + + // This will set all extra tiles to oversold, including moz-sales. + this._telemetryUtility.determineFilteredTilesAndSetToOversold( + dedupedSponsored + ); + // Remove adult sites if we need to const checkedAdult = lazy.FilterAdult.filter(dedupedUnpinned); @@ -1975,22 +1951,26 @@ export class TopSitesFeed { let link = null; const { assignedPartner } = allocation; if (assignedPartner) { - while (sponsoredLinks[assignedPartner].length) { + const candidates = sponsoredLinks[assignedPartner] || []; + while (candidates.length) { // Unknown partners are allowed so that new partners can be added to Shepherd // sooner without waiting for client changes. - const candidate = sponsoredLinks[assignedPartner]?.shift(); - + const candidate = candidates?.shift(); + if (!candidate) { + continue; + } + const candLabel = candidate.label?.trim().toLowerCase(); // Deduplicate against sponsored links that have already been added. - const duplicateSponsor = sponsored.find( - s => - s.label?.toLowerCase() === candidate.label?.toLowerCase() || - s.hostname === candidate.hostname - ); - - if (!duplicateSponsor) { - link = candidate; - break; + if (candLabel) { + const duplicateSponsor = sponsored.some( + s => s.label?.trim().toLowerCase() === candLabel + ); + if (duplicateSponsor) { + continue; // skip this candidate, try next + } } + link = candidate; + break; } } diff --git a/browser/extensions/newtab/test/xpcshell/test_TopSitesFeed_frecencyDeduping.js b/browser/extensions/newtab/test/xpcshell/test_TopSitesFeed_frecencyDeduping.js @@ -6,19 +6,18 @@ ChromeUtils.defineESModuleGetters(this, { sinon: "resource://testing-common/Sinon.sys.mjs", TopSitesFeed: "resource://newtab/lib/TopSitesFeed.sys.mjs", + DEFAULT_TOP_SITES: "resource://newtab/lib/TopSitesFeed.sys.mjs", }); const PREF_SOV_ENABLED = "sov.enabled"; const SHOW_SPONSORED_PREF = "showSponsoredTopSites"; const ROWS_PREF = "topSitesRows"; -function getTopSitesFeedForTest( - sandbox, - { frecent = [], linksWithDefaults = [] } = {} -) { +function getTopSitesFeedForTest(sandbox, { frecent = [], contile = [] } = {}) { let feed = new TopSitesFeed(); feed.store = { + dispatch: sandbox.spy(), getState() { return this.state; }, @@ -31,7 +30,13 @@ function getTopSitesFeedForTest( }, }, TopSites: { - sov: { ready: true }, + sov: { + ready: true, + positions: [ + { position: 1, assignedPartner: "amp" }, + { position: 2, assignedPartner: "frec-boost" }, + ], + }, }, }, }; @@ -43,30 +48,29 @@ function getTopSitesFeedForTest( cache: frecent, }; - feed._linksWithDefaults = linksWithDefaults; - feed._contile = { sov: true, sovEnabled: () => true, + sites: contile, }; const frecencyBoostedSponsors = new Map([ [ - "hostname1", + "domain1", { domain: "https://domain1.com", faviconDataURI: "faviconDataURI1", - hostname: "hostname1", + hostname: "domain1", redirectURL: "https://redirectURL1.com", title: "title1", }, ], [ - "hostname2", + "domain2", { domain: "https://domain2.com", faviconDataURI: "faviconDataURI2", - hostname: "hostname2", + hostname: "domain2", redirectURL: "https://redirectURL2.com", title: "title2", }, @@ -75,147 +79,199 @@ function getTopSitesFeedForTest( sandbox.stub(feed, "_frecencyBoostedSponsors").value(frecencyBoostedSponsors); + // We need to refresh, because TopSitesFeed's + // DEFAULT_TOP_SITES acts like a singleton. + DEFAULT_TOP_SITES.length = 0; + feed._readContile(); + return feed; } -add_task(async function test_dedupeSponsorsAgainstTopsites() { +add_task(async function test_dedupeSponsorsAgainstNothing() { let sandbox = sinon.createSandbox(); { + info("TopSitesFeed.getLinksWithDefaults - Should return all defaults"); + const feed = getTopSitesFeedForTest(sandbox, { + frecent: [ + { url: "https://default1.com", frecency: 1000 }, + { url: "https://default2.com", frecency: 1000 }, + { url: "https://default3.com", frecency: 1000 }, + { url: "https://default4.com", frecency: 1000 }, + { url: "https://default5.com", frecency: 1000 }, + { url: "https://default6.com", frecency: 1000 }, + { url: "https://default7.com", frecency: 1000 }, + { url: "https://default8.com", frecency: 1000 }, + ], + contile: [{ url: "https://contile1.com", name: "contile1" }], + }); + + const withPinned = await feed.getLinksWithDefaults(); + Assert.equal(withPinned.length, 8); + Assert.equal(withPinned[1].hostname, "default1"); + + sandbox.restore(); + } + { + info( + "TopSitesFeed.getLinksWithDefaults - " + + "Should return a frecency match in the second position" + ); + const feed = getTopSitesFeedForTest(sandbox, { + frecent: [ + { url: "https://default1.com", frecency: 1000 }, + { url: "https://default2.com", frecency: 1000 }, + { url: "https://default3.com", frecency: 1000 }, + { url: "https://default4.com", frecency: 1000 }, + { url: "https://default5.com", frecency: 1000 }, + { url: "https://default6.com", frecency: 1000 }, + { url: "https://default7.com", frecency: 1000 }, + { url: "https://default8.com", frecency: 1000 }, + { url: "https://domain1.com", frecency: 1000 }, + ], + contile: [{ url: "https://contile1.com", name: "contile1" }], + }); + + const withPinned = await feed.getLinksWithDefaults(); + Assert.equal(withPinned.length, 8); + Assert.equal(withPinned[1].hostname, "domain1"); + + sandbox.restore(); + } + { info( - "TopSitesFeed.fetchFrecencyBoostedSpocs - " + - "Should return a single match with the right format" + "TopSitesFeed.getLinksWithDefaults - " + + "Should return a frecency match with path in the second position" ); const feed = getTopSitesFeedForTest(sandbox, { - frecent: [{ url: "https://domain1.com", frecency: 1000 }], - linksWithDefaults: [ - { url: "https://otherdomain.com", hostname: "otherdomain" }, + frecent: [ + { url: "https://default1.com", frecency: 1000 }, + { url: "https://default2.com", frecency: 1000 }, + { url: "https://default3.com", frecency: 1000 }, + { url: "https://default4.com", frecency: 1000 }, + { url: "https://default5.com", frecency: 1000 }, + { url: "https://default6.com", frecency: 1000 }, + { url: "https://default7.com", frecency: 1000 }, + { url: "https://default8.com", frecency: 1000 }, + { url: "https://domain1.com/path", frecency: 1000 }, ], + contile: [{ url: "https://contile1.com", name: "contile1" }], }); - const frecencyBoostedSpocs = await feed.fetchFrecencyBoostedSpocs(); - Assert.equal(frecencyBoostedSpocs.length, 1); - Assert.equal(frecencyBoostedSpocs[0].hostname, "hostname1"); + const withPinned = await feed.getLinksWithDefaults(); + Assert.equal(withPinned.length, 8); + Assert.equal(withPinned[1].hostname, "domain1"); sandbox.restore(); } +}); + +add_task(async function test_dedupeSponsorsAgainstTopsites() { + let sandbox = sinon.createSandbox(); { info( - "TopSitesFeed.fetchFrecencyBoostedSpocs - " + + "TopSitesFeed.getLinksWithDefaults - " + "Should dedupe against matching topsite" ); const feed = getTopSitesFeedForTest(sandbox, { - frecent: [{ url: "https://domain1.com", frecency: 1000 }], - linksWithDefaults: [ - { - url: "https://domain1.com", - hostname: "hostname1", - label: "Domain 1", - }, + frecent: [ + { url: "https://default1.com", frecency: 1000 }, + { url: "https://default2.com", frecency: 1000 }, + { url: "https://default3.com", frecency: 1000 }, + { url: "https://default4.com", frecency: 1000 }, + { url: "https://default5.com", frecency: 1000 }, + { url: "https://domain1.com", frecency: 1000 }, + { url: "https://default6.com", frecency: 1000 }, + { url: "https://default7.com", frecency: 1000 }, + { url: "https://default8.com", frecency: 1000 }, ], + contile: [{ url: "https://contile1.com", name: "contile1" }], }); - const frecencyBoostedSpocs = await feed.fetchFrecencyBoostedSpocs(); - Assert.equal(frecencyBoostedSpocs.length, 0); + const withPinned = await feed.getLinksWithDefaults(); + Assert.equal(withPinned.length, 8); + Assert.equal(withPinned[1].hostname, "default1"); sandbox.restore(); } { info( - "TopSitesFeed.fetchFrecencyBoostedSpocs - " + + "TopSitesFeed.getLinksWithDefaults - " + "Should dedupe against matching topsite with path" ); const feed = getTopSitesFeedForTest(sandbox, { - frecent: [{ url: "https://domain1.com", frecency: 1000 }], - linksWithDefaults: [ - { - url: "https://domain1.com/page", - hostname: "hostname1", - label: "Domain 1", - }, + frecent: [ + { url: "https://default1.com", frecency: 1000 }, + { url: "https://default2.com", frecency: 1000 }, + { url: "https://default3.com", frecency: 1000 }, + { url: "https://default4.com", frecency: 1000 }, + { url: "https://default5.com", frecency: 1000 }, + { url: "https://domain1.com/page", frecency: 1000 }, + { url: "https://default6.com", frecency: 1000 }, + { url: "https://default7.com", frecency: 1000 }, + { url: "https://default8.com", frecency: 1000 }, ], + contile: [{ url: "https://contile1.com", name: "contile1" }], }); - const frecencyBoostedSpocs = await feed.fetchFrecencyBoostedSpocs(); - Assert.equal(frecencyBoostedSpocs.length, 0); + const withPinned = await feed.getLinksWithDefaults(); + Assert.equal(withPinned.length, 8); + Assert.equal(withPinned[1].hostname, "default1"); sandbox.restore(); } }); -add_task(async function test_mergeSponsoredLinks_deduplication() { +add_task(async function test_dedupeSponsorsAgainstContile() { + let sandbox = sinon.createSandbox(); { - let sandbox = sinon.createSandbox(); - info("Two sponsored shortcuts with same hostname should dedupe"); - const feed = getTopSitesFeedForTest(sandbox); - - feed.store.state.TopSites.sov = { - ready: true, - positions: [ - { position: 1, assignedPartner: "amp" }, - { position: 2, assignedPartner: "moz-sales" }, - ], - }; - - const sponsoredLinks = { - amp: [ - { - url: "https://sponsor1.com", - hostname: "sponsor1", - label: "Sponsor 1", - }, - ], - "moz-sales": [ - { - url: "https://sponsor1.com", - hostname: "sponsor1", - label: "Different Label", - }, + info( + "TopSitesFeed.getLinksWithDefaults - " + + "Should dedupe against matching contile" + ); + const feed = getTopSitesFeedForTest(sandbox, { + frecent: [ + { url: "https://default1.com", frecency: 1000 }, + { url: "https://default2.com", frecency: 1000 }, + { url: "https://default3.com", frecency: 1000 }, + { url: "https://default4.com", frecency: 1000 }, + { url: "https://default5.com", frecency: 1000 }, + { url: "https://default6.com", frecency: 1000 }, + { url: "https://default7.com", frecency: 1000 }, + { url: "https://default8.com", frecency: 1000 }, + { url: "https://domain1.com", frecency: 1000 }, ], - "frec-boost": [], - }; + contile: [{ url: "https://domain1.com", name: "contile1" }], + }); - const result = feed._mergeSponsoredLinks(sponsoredLinks); - Assert.equal(result.length, 1); - Assert.equal(result[0].label, "Sponsor 1"); + const withPinned = await feed.getLinksWithDefaults(); + Assert.equal(withPinned.length, 8); + Assert.equal(withPinned[1].hostname, "default1"); sandbox.restore(); } { - let sandbox = sinon.createSandbox(); info( - "Two sponsored shortcuts with same label but different hostname should dedupe" + "TopSitesFeed.getLinksWithDefaults - " + + "Should dedupe against matching contile label" ); - const feed = getTopSitesFeedForTest(sandbox); - - feed.store.state.TopSites.sov = { - ready: true, - positions: [ - { position: 1, assignedPartner: "amp" }, - { position: 2, assignedPartner: "moz-sales" }, - ], - }; - - const sponsoredLinks = { - amp: [ - { - url: "https://sponsor1.com", - hostname: "sponsor1", - label: "Brand Name", - }, - ], - "moz-sales": [ - { - url: "https://affiliate.com", - hostname: "affiliate", - label: "Brand Name", - }, + const feed = getTopSitesFeedForTest(sandbox, { + frecent: [ + { url: "https://default1.com", frecency: 1000 }, + { url: "https://default2.com", frecency: 1000 }, + { url: "https://default3.com", frecency: 1000 }, + { url: "https://default4.com", frecency: 1000 }, + { url: "https://default5.com", frecency: 1000 }, + { url: "https://default6.com", frecency: 1000 }, + { url: "https://default7.com", frecency: 1000 }, + { url: "https://default8.com", frecency: 1000 }, + { url: "https://domain1.com", frecency: 1000 }, ], - "frec-boost": [], - }; + contile: [{ url: "https://contile1.com", name: "title1" }], + }); - const result = feed._mergeSponsoredLinks(sponsoredLinks); - Assert.equal(result.length, 1); - Assert.equal(result[0].hostname, "sponsor1"); + const withPinned = await feed.getLinksWithDefaults(); + Assert.equal(withPinned.length, 8); + Assert.equal(withPinned[1].hostname, "default1"); sandbox.restore(); } diff --git a/browser/extensions/newtab/test/xpcshell/test_TopSitesFeed_frecencyRanking.js b/browser/extensions/newtab/test/xpcshell/test_TopSitesFeed_frecencyRanking.js @@ -14,19 +14,7 @@ const PREF_SOV_ENABLED = "sov.enabled"; const SHOW_SPONSORED_PREF = "showSponsoredTopSites"; const ROWS_PREF = "topSitesRows"; -function getTopSitesFeedForTest( - sandbox, - { - frecent = [], - linksWithDefaults = [ - { - url: "url", - hostname: "hostname", - label: "label", - }, - ], - } = {} -) { +function getTopSitesFeedForTest(sandbox, { frecent = [] } = {}) { let feed = new TopSitesFeed(); feed.store = { @@ -49,54 +37,53 @@ function getTopSitesFeedForTest( }, cache: frecent, }; - feed._linksWithDefaults = linksWithDefaults; const frecencyBoostedSponsors = new Map([ [ - "hostname1", + "domain1", { domain: "https://domain1.com", faviconDataURI: "faviconDataURI1", - hostname: "hostname1", + hostname: "domain1", redirectURL: "https://redirectURL1.com", title: "title1", }, ], [ - "hostname2", + "domain2", { domain: "https://domain2.com", faviconDataURI: "faviconDataURI2", - hostname: "hostname2", + hostname: "domain2", redirectURL: "https://redirectURL2.com", title: "title2", }, ], [ - "hostname3", + "domain3", { domain: "https://domain3.com", faviconDataURI: "faviconDataURI3", - hostname: "hostname3", + hostname: "domain3", redirectURL: "https://redirectURL3.com", title: "title3", }, ], [ - "hostname4", + "domain4", { domain: "https://domain4.com", faviconDataURI: "faviconDataURI4", - hostname: "hostname4", + hostname: "domain4", redirectURL: "https://redirectURL4.com", title: "title4", }, ], [ - "hostname1sub", + "sub.domain1", { domain: "https://sub.domain1.com", faviconDataURI: "faviconDataURI1", - hostname: "hostname1sub", + hostname: "sub.domain1", redirectURL: "https://redirectURL1.com", title: "title1", }, @@ -140,7 +127,7 @@ add_task(async function test_frecency_sponsored_topsites() { const frecencyBoostedSpocs = await feed.fetchFrecencyBoostedSpocs(); Assert.equal(frecencyBoostedSpocs.length, 1); Assert.deepEqual(frecencyBoostedSpocs[0], { - hostname: "hostname1", + hostname: "domain1", url: "https://redirectURL1.com", label: "title1", partner: "frec-boost", @@ -173,8 +160,8 @@ add_task(async function test_frecency_sponsored_topsites() { const frecencyBoostedSpocs = await feed.fetchFrecencyBoostedSpocs(); Assert.equal(frecencyBoostedSpocs.length, 2); - Assert.equal(frecencyBoostedSpocs[0].hostname, "hostname1"); - Assert.equal(frecencyBoostedSpocs[1].hostname, "hostname3"); + Assert.equal(frecencyBoostedSpocs[0].hostname, "domain1"); + Assert.equal(frecencyBoostedSpocs[1].hostname, "domain3"); sandbox.restore(); } @@ -194,7 +181,7 @@ add_task(async function test_frecency_sponsored_topsites() { const frecencyBoostedSpocs = await feed.fetchFrecencyBoostedSpocs(); Assert.equal(frecencyBoostedSpocs.length, 1); - Assert.equal(frecencyBoostedSpocs[0].hostname, "hostname1"); + Assert.equal(frecencyBoostedSpocs[0].hostname, "domain1"); sandbox.restore(); } @@ -214,86 +201,65 @@ add_task(async function test_frecency_sponsored_topsites() { const frecencyBoostedSpocs = await feed.fetchFrecencyBoostedSpocs(); Assert.equal(frecencyBoostedSpocs.length, 1); - Assert.equal(frecencyBoostedSpocs[0].hostname, "hostname1"); + Assert.equal(frecencyBoostedSpocs[0].hostname, "domain1"); sandbox.restore(); } { info( "TopSitesFeed.fetchFrecencyBoostedSpocs - " + - "Should return a single match with a subdomain" + "Should not return a match with a different subdomain" ); const feed = getTopSitesFeedForTest(sandbox, { frecent: [ { - url: "https://domain1.com", - frecency: 1234, - }, - { - url: "https://domain2.com", - frecency: 1234, - }, - { - url: "https://domain3.com", + url: "https://bus.domain1.com", frecency: 1234, }, ], - linksWithDefaults: [ - { - url: "", - hostname: "hostname1", - label: "", - }, - { - url: "https://hostname2.com", - hostname: "", - label: "", - }, - ], }); const frecencyBoostedSpocs = await feed.fetchFrecencyBoostedSpocs(); - Assert.equal(frecencyBoostedSpocs.length, 1); - Assert.equal(frecencyBoostedSpocs[0].hostname, "hostname3"); + Assert.equal(frecencyBoostedSpocs.length, 0); sandbox.restore(); } { info( "TopSitesFeed.fetchFrecencyBoostedSpocs - " + - "Should not return a match with a different subdomain" + "Should return a match with the same subdomain" ); const feed = getTopSitesFeedForTest(sandbox, { frecent: [ { - url: "https://bus.domain1.com", + url: "https://sub.domain1.com", frecency: 1234, }, ], }); const frecencyBoostedSpocs = await feed.fetchFrecencyBoostedSpocs(); - Assert.equal(frecencyBoostedSpocs.length, 0); + Assert.equal(frecencyBoostedSpocs.length, 1); + Assert.equal(frecencyBoostedSpocs[0].hostname, "sub.domain1"); sandbox.restore(); } { info( "TopSitesFeed.fetchFrecencyBoostedSpocs - " + - "Should return a match with the same subdomain" + "Should not match a partial domain" ); const feed = getTopSitesFeedForTest(sandbox, { frecent: [ { - url: "https://sub.domain1.com", + url: "https://domain12.com", frecency: 1234, }, ], }); const frecencyBoostedSpocs = await feed.fetchFrecencyBoostedSpocs(); - Assert.equal(frecencyBoostedSpocs.length, 1); - Assert.equal(frecencyBoostedSpocs[0].hostname, "hostname1sub"); + Assert.equal(frecencyBoostedSpocs.length, 0); sandbox.restore(); }