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:
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();
}