forked from mirrors/gecko-dev
This modifies `ActivityStreamProvider.getTopFrecentSites()` so it excludes URLs with a given search param. There are two questions I considered when writing this patch: * The top-sites code is a little complex and there are multiple places where this logic could be implemented. I chose the bottommost layer, where the top sites are fetched from Places and some other exclusion logic already exists, because we don't want these URLs to appear in any list of top sites in Firefox AFAIK -- not on the new-tab page and not in the urlbar. * How should we encode this new exclusion logic? We don't want to hardcode a specific search param. We may not even want to base it on search params at all but instead make it more general somehow. For now, I did the simple thing and went ahead and based it on a search param, and I added a new option to `getTopFrecentSites()` that specifies the param and that falls back to a new pref. Callers can override the pref fallback by passing in an option. The pref value and option to `getTopFrecentSites()` supports the following forms: * `""` (empty) - Disable this feature * `"key"` - Search param named "key" with any or no value * `"key="` - Search param named "key" with no value * `"key=value"` - Search param named "key" with value "value" Differential Revision: https://phabricator.services.mozilla.com/D146139
1511 lines
44 KiB
JavaScript
1511 lines
44 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
// See also browser/base/content/test/newtab/.
|
|
|
|
const { AppConstants } = ChromeUtils.import(
|
|
"resource://gre/modules/AppConstants.jsm"
|
|
);
|
|
|
|
// A small 1x1 test png
|
|
const image1x1 =
|
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==";
|
|
|
|
function getBookmarksSize() {
|
|
return NewTabUtils.activityStreamProvider.executePlacesQuery(
|
|
"SELECT count(*) FROM moz_bookmarks WHERE type = :type",
|
|
{ params: { type: PlacesUtils.bookmarks.TYPE_BOOKMARK } }
|
|
);
|
|
}
|
|
|
|
function getHistorySize() {
|
|
return NewTabUtils.activityStreamProvider.executePlacesQuery(
|
|
"SELECT count(*) FROM moz_places WHERE hidden = 0 AND last_visit_date NOT NULL"
|
|
);
|
|
}
|
|
|
|
add_task(async function validCacheMidPopulation() {
|
|
let expectedLinks = makeLinks(0, 3, 1);
|
|
|
|
let provider = new TestProvider(done => done(expectedLinks));
|
|
provider.maxNumLinks = expectedLinks.length;
|
|
|
|
NewTabUtils.initWithoutProviders();
|
|
NewTabUtils.links.addProvider(provider);
|
|
let promise = new Promise(resolve =>
|
|
NewTabUtils.links.populateCache(resolve)
|
|
);
|
|
|
|
// isTopSiteGivenProvider() and getProviderLinks() should still return results
|
|
// even when cache is empty or being populated.
|
|
Assert.ok(!NewTabUtils.isTopSiteGivenProvider("example1.com", provider));
|
|
do_check_links(NewTabUtils.getProviderLinks(provider), []);
|
|
|
|
await promise;
|
|
|
|
// Once the cache is populated, we get the expected results
|
|
Assert.ok(NewTabUtils.isTopSiteGivenProvider("example1.com", provider));
|
|
do_check_links(NewTabUtils.getProviderLinks(provider), expectedLinks);
|
|
NewTabUtils.links.removeProvider(provider);
|
|
});
|
|
|
|
add_task(async function notifyLinkDelete() {
|
|
let expectedLinks = makeLinks(0, 3, 1);
|
|
|
|
let provider = new TestProvider(done => done(expectedLinks));
|
|
provider.maxNumLinks = expectedLinks.length;
|
|
|
|
NewTabUtils.initWithoutProviders();
|
|
NewTabUtils.links.addProvider(provider);
|
|
await new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
|
|
|
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
|
|
|
// Remove a link.
|
|
let removedLink = expectedLinks[2];
|
|
provider.notifyLinkChanged(removedLink, 2, true);
|
|
let links = NewTabUtils.links._providers.get(provider);
|
|
|
|
// Check that sortedLinks is correctly updated.
|
|
do_check_links(NewTabUtils.links.getLinks(), expectedLinks.slice(0, 2));
|
|
|
|
// Check that linkMap is accurately updated.
|
|
Assert.equal(links.linkMap.size, 2);
|
|
Assert.ok(links.linkMap.get(expectedLinks[0].url));
|
|
Assert.ok(links.linkMap.get(expectedLinks[1].url));
|
|
Assert.ok(!links.linkMap.get(removedLink.url));
|
|
|
|
// Check that siteMap is correctly updated.
|
|
Assert.equal(links.siteMap.size, 2);
|
|
Assert.ok(links.siteMap.has(NewTabUtils.extractSite(expectedLinks[0].url)));
|
|
Assert.ok(links.siteMap.has(NewTabUtils.extractSite(expectedLinks[1].url)));
|
|
Assert.ok(!links.siteMap.has(NewTabUtils.extractSite(removedLink.url)));
|
|
|
|
NewTabUtils.links.removeProvider(provider);
|
|
});
|
|
|
|
add_task(async function populatePromise() {
|
|
let count = 0;
|
|
let expectedLinks = makeLinks(0, 10, 2);
|
|
|
|
let getLinksFcn = async function(callback) {
|
|
// Should not be calling getLinksFcn twice
|
|
count++;
|
|
Assert.equal(count, 1);
|
|
await Promise.resolve();
|
|
callback(expectedLinks);
|
|
};
|
|
|
|
let provider = new TestProvider(getLinksFcn);
|
|
|
|
NewTabUtils.initWithoutProviders();
|
|
NewTabUtils.links.addProvider(provider);
|
|
|
|
NewTabUtils.links.populateProviderCache(provider, () => {});
|
|
NewTabUtils.links.populateProviderCache(provider, () => {
|
|
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
|
NewTabUtils.links.removeProvider(provider);
|
|
});
|
|
});
|
|
|
|
add_task(async function isTopSiteGivenProvider() {
|
|
let expectedLinks = makeLinks(0, 10, 2);
|
|
|
|
// The lowest 2 frecencies have the same base domain.
|
|
expectedLinks[expectedLinks.length - 2].url =
|
|
expectedLinks[expectedLinks.length - 1].url + "Test";
|
|
|
|
let provider = new TestProvider(done => done(expectedLinks));
|
|
provider.maxNumLinks = expectedLinks.length;
|
|
|
|
NewTabUtils.initWithoutProviders();
|
|
NewTabUtils.links.addProvider(provider);
|
|
await new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
|
|
|
Assert.equal(
|
|
NewTabUtils.isTopSiteGivenProvider("example2.com", provider),
|
|
true
|
|
);
|
|
Assert.equal(
|
|
NewTabUtils.isTopSiteGivenProvider("example1.com", provider),
|
|
false
|
|
);
|
|
|
|
// Push out frecency 2 because the maxNumLinks is reached when adding frecency 3
|
|
let newLink = makeLink(3);
|
|
provider.notifyLinkChanged(newLink);
|
|
|
|
// There is still a frecent url with example2 domain, so it's still frecent.
|
|
Assert.equal(
|
|
NewTabUtils.isTopSiteGivenProvider("example3.com", provider),
|
|
true
|
|
);
|
|
Assert.equal(
|
|
NewTabUtils.isTopSiteGivenProvider("example2.com", provider),
|
|
true
|
|
);
|
|
|
|
// Push out frecency 3
|
|
newLink = makeLink(5);
|
|
provider.notifyLinkChanged(newLink);
|
|
|
|
// Push out frecency 4
|
|
newLink = makeLink(9);
|
|
provider.notifyLinkChanged(newLink);
|
|
|
|
// Our count reached 0 for the example2.com domain so it's no longer a frecent site.
|
|
Assert.equal(
|
|
NewTabUtils.isTopSiteGivenProvider("example5.com", provider),
|
|
true
|
|
);
|
|
Assert.equal(
|
|
NewTabUtils.isTopSiteGivenProvider("example2.com", provider),
|
|
false
|
|
);
|
|
|
|
NewTabUtils.links.removeProvider(provider);
|
|
});
|
|
|
|
add_task(async function multipleProviders() {
|
|
// Make each provider generate NewTabUtils.links.maxNumLinks links to check
|
|
// that no more than maxNumLinks are actually returned in the merged list.
|
|
let evenLinks = makeLinks(0, 2 * NewTabUtils.links.maxNumLinks, 2);
|
|
let evenProvider = new TestProvider(done => done(evenLinks));
|
|
let oddLinks = makeLinks(0, 2 * NewTabUtils.links.maxNumLinks - 1, 2);
|
|
let oddProvider = new TestProvider(done => done(oddLinks));
|
|
|
|
NewTabUtils.initWithoutProviders();
|
|
NewTabUtils.links.addProvider(evenProvider);
|
|
NewTabUtils.links.addProvider(oddProvider);
|
|
|
|
await new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
|
|
|
let links = NewTabUtils.links.getLinks();
|
|
let expectedLinks = makeLinks(
|
|
NewTabUtils.links.maxNumLinks,
|
|
2 * NewTabUtils.links.maxNumLinks,
|
|
1
|
|
);
|
|
Assert.equal(links.length, NewTabUtils.links.maxNumLinks);
|
|
do_check_links(links, expectedLinks);
|
|
|
|
NewTabUtils.links.removeProvider(evenProvider);
|
|
NewTabUtils.links.removeProvider(oddProvider);
|
|
});
|
|
|
|
add_task(async function changeLinks() {
|
|
let expectedLinks = makeLinks(0, 20, 2);
|
|
let provider = new TestProvider(done => done(expectedLinks));
|
|
|
|
NewTabUtils.initWithoutProviders();
|
|
NewTabUtils.links.addProvider(provider);
|
|
|
|
await new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
|
|
|
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
|
|
|
// Notify of a new link.
|
|
let newLink = makeLink(19);
|
|
expectedLinks.splice(1, 0, newLink);
|
|
provider.notifyLinkChanged(newLink);
|
|
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
|
|
|
// Notify of a link that's changed sort criteria.
|
|
newLink.frecency = 17;
|
|
expectedLinks.splice(1, 1);
|
|
expectedLinks.splice(2, 0, newLink);
|
|
provider.notifyLinkChanged({
|
|
url: newLink.url,
|
|
frecency: 17,
|
|
});
|
|
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
|
|
|
// Notify of a link that's changed title.
|
|
newLink.title = "My frecency is now 17";
|
|
provider.notifyLinkChanged({
|
|
url: newLink.url,
|
|
title: newLink.title,
|
|
});
|
|
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
|
|
|
// Notify of a new link again, but this time make it overflow maxNumLinks.
|
|
provider.maxNumLinks = expectedLinks.length;
|
|
newLink = makeLink(21);
|
|
expectedLinks.unshift(newLink);
|
|
expectedLinks.pop();
|
|
Assert.equal(expectedLinks.length, provider.maxNumLinks); // Sanity check.
|
|
provider.notifyLinkChanged(newLink);
|
|
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
|
|
|
// Notify of many links changed.
|
|
expectedLinks = makeLinks(0, 3, 1);
|
|
provider.notifyManyLinksChanged();
|
|
|
|
// Since _populateProviderCache() is async, we must wait until the provider's
|
|
// populate promise has been resolved.
|
|
await NewTabUtils.links._providers.get(provider).populatePromise;
|
|
|
|
// NewTabUtils.links will now repopulate its cache
|
|
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
|
|
|
NewTabUtils.links.removeProvider(provider);
|
|
});
|
|
|
|
add_task(async function oneProviderAlreadyCached() {
|
|
let links1 = makeLinks(0, 10, 1);
|
|
let provider1 = new TestProvider(done => done(links1));
|
|
|
|
NewTabUtils.initWithoutProviders();
|
|
NewTabUtils.links.addProvider(provider1);
|
|
|
|
await new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
|
do_check_links(NewTabUtils.links.getLinks(), links1);
|
|
|
|
let links2 = makeLinks(10, 20, 1);
|
|
let provider2 = new TestProvider(done => done(links2));
|
|
NewTabUtils.links.addProvider(provider2);
|
|
|
|
await new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
|
do_check_links(NewTabUtils.links.getLinks(), links2.concat(links1));
|
|
|
|
NewTabUtils.links.removeProvider(provider1);
|
|
NewTabUtils.links.removeProvider(provider2);
|
|
});
|
|
|
|
add_task(async function newLowRankedLink() {
|
|
// Init a provider with 10 links and make its maximum number also 10.
|
|
let links = makeLinks(0, 10, 1);
|
|
let provider = new TestProvider(done => done(links));
|
|
provider.maxNumLinks = links.length;
|
|
|
|
NewTabUtils.initWithoutProviders();
|
|
NewTabUtils.links.addProvider(provider);
|
|
|
|
await new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
|
do_check_links(NewTabUtils.links.getLinks(), links);
|
|
|
|
// Notify of a new link that's low-ranked enough not to make the list.
|
|
let newLink = makeLink(0);
|
|
provider.notifyLinkChanged(newLink);
|
|
do_check_links(NewTabUtils.links.getLinks(), links);
|
|
|
|
// Notify about the new link's title change.
|
|
provider.notifyLinkChanged({
|
|
url: newLink.url,
|
|
title: "a new title",
|
|
});
|
|
do_check_links(NewTabUtils.links.getLinks(), links);
|
|
|
|
NewTabUtils.links.removeProvider(provider);
|
|
});
|
|
|
|
add_task(async function extractSite() {
|
|
// All these should extract to the same site
|
|
[
|
|
"mozilla.org",
|
|
"m.mozilla.org",
|
|
"mobile.mozilla.org",
|
|
"www.mozilla.org",
|
|
"www3.mozilla.org",
|
|
].forEach(host => {
|
|
let url = "http://" + host;
|
|
Assert.equal(
|
|
NewTabUtils.extractSite(url),
|
|
"mozilla.org",
|
|
"extracted same " + host
|
|
);
|
|
});
|
|
|
|
// All these should extract to the same subdomain
|
|
["bugzilla.mozilla.org", "www.bugzilla.mozilla.org"].forEach(host => {
|
|
let url = "http://" + host;
|
|
Assert.equal(
|
|
NewTabUtils.extractSite(url),
|
|
"bugzilla.mozilla.org",
|
|
"extracted eTLD+2 " + host
|
|
);
|
|
});
|
|
|
|
// All these should not extract to the same site
|
|
[
|
|
"bugzilla.mozilla.org",
|
|
"bug123.bugzilla.mozilla.org",
|
|
"too.many.levels.bugzilla.mozilla.org",
|
|
"m2.mozilla.org",
|
|
"mobile30.mozilla.org",
|
|
"ww.mozilla.org",
|
|
"ww2.mozilla.org",
|
|
"wwwww.mozilla.org",
|
|
"wwwww50.mozilla.org",
|
|
"wwws.mozilla.org",
|
|
"secure.mozilla.org",
|
|
"secure10.mozilla.org",
|
|
"many.levels.deep.mozilla.org",
|
|
"just.check.in",
|
|
"192.168.0.1",
|
|
"localhost",
|
|
].forEach(host => {
|
|
let url = "http://" + host;
|
|
Assert.notEqual(
|
|
NewTabUtils.extractSite(url),
|
|
"mozilla.org",
|
|
"extracted diff " + host
|
|
);
|
|
});
|
|
|
|
// All these should not extract to the same site
|
|
[
|
|
"about:blank",
|
|
"file:///Users/user/file",
|
|
"chrome://browser/something",
|
|
"ftp://ftp.mozilla.org/",
|
|
].forEach(url => {
|
|
Assert.notEqual(
|
|
NewTabUtils.extractSite(url),
|
|
"mozilla.org",
|
|
"extracted diff url " + url
|
|
);
|
|
});
|
|
});
|
|
|
|
add_task(async function faviconBytesToDataURI() {
|
|
let tests = [
|
|
[{ favicon: "bar".split("").map(s => s.charCodeAt(0)), mimeType: "foo" }],
|
|
[
|
|
{
|
|
favicon: "bar".split("").map(s => s.charCodeAt(0)),
|
|
mimeType: "foo",
|
|
xxyy: "quz",
|
|
},
|
|
],
|
|
];
|
|
let provider = NewTabUtils.activityStreamProvider;
|
|
|
|
for (let test of tests) {
|
|
let clone = JSON.parse(JSON.stringify(test));
|
|
delete clone[0].mimeType;
|
|
clone[0].favicon = `data:foo;base64,${btoa("bar")}`;
|
|
let result = provider._faviconBytesToDataURI(test);
|
|
Assert.deepEqual(
|
|
JSON.stringify(clone),
|
|
JSON.stringify(result),
|
|
"favicon converted to data uri"
|
|
);
|
|
}
|
|
});
|
|
|
|
add_task(async function addFavicons() {
|
|
await setUpActivityStreamTest();
|
|
let provider = NewTabUtils.activityStreamProvider;
|
|
|
|
// start by passing in a bad uri and check that we get a null favicon back
|
|
let links = [{ url: "mozilla.com" }];
|
|
await provider._addFavicons(links);
|
|
Assert.equal(
|
|
links[0].favicon,
|
|
null,
|
|
"Got a null favicon because we passed in a bad url"
|
|
);
|
|
Assert.equal(
|
|
links[0].mimeType,
|
|
null,
|
|
"Got a null mime type because we passed in a bad url"
|
|
);
|
|
Assert.equal(
|
|
links[0].faviconSize,
|
|
null,
|
|
"Got a null favicon size because we passed in a bad url"
|
|
);
|
|
|
|
// now fix the url and try again - this time we get good favicon data back
|
|
// a 1x1 favicon as a data URI of mime type image/png
|
|
const base64URL = image1x1;
|
|
links[0].url = "https://mozilla.com";
|
|
|
|
let visit = [
|
|
{
|
|
uri: links[0].url,
|
|
visitDate: timeDaysAgo(0),
|
|
transition: PlacesUtils.history.TRANSITION_TYPED,
|
|
},
|
|
];
|
|
await PlacesTestUtils.addVisits(visit);
|
|
|
|
let faviconData = new Map();
|
|
faviconData.set("https://mozilla.com", `${base64URL}#tippytop`);
|
|
await PlacesTestUtils.addFavicons(faviconData);
|
|
|
|
await provider._addFavicons(links);
|
|
Assert.equal(
|
|
links[0].mimeType,
|
|
"image/png",
|
|
"Got the right mime type before deleting it"
|
|
);
|
|
Assert.equal(
|
|
links[0].faviconLength,
|
|
links[0].favicon.length,
|
|
"Got the right length for the byte array"
|
|
);
|
|
Assert.equal(
|
|
provider._faviconBytesToDataURI(links)[0].favicon,
|
|
base64URL,
|
|
"Got the right favicon"
|
|
);
|
|
Assert.equal(
|
|
links[0].faviconSize,
|
|
1,
|
|
"Got the right favicon size (width and height of favicon)"
|
|
);
|
|
Assert.equal(links[0].faviconRef, "tippytop", "Got the favicon url ref");
|
|
|
|
// Check with http version of the link that doesn't have its own
|
|
const nonHttps = [{ url: links[0].url.replace("https", "http") }];
|
|
await provider._addFavicons(nonHttps);
|
|
Assert.equal(
|
|
provider._faviconBytesToDataURI(nonHttps)[0].favicon,
|
|
base64URL,
|
|
"Got the same favicon"
|
|
);
|
|
Assert.equal(
|
|
nonHttps[0].faviconLength,
|
|
links[0].faviconLength,
|
|
"Got the same favicon length"
|
|
);
|
|
Assert.equal(
|
|
nonHttps[0].faviconSize,
|
|
links[0].faviconSize,
|
|
"Got the same favicon size"
|
|
);
|
|
Assert.equal(
|
|
nonHttps[0].mimeType,
|
|
links[0].mimeType,
|
|
"Got the same mime type"
|
|
);
|
|
|
|
// Check that we do not collect favicons for pocket items
|
|
const pocketItems = [
|
|
{ url: links[0].url },
|
|
{ url: "https://mozilla1.com", type: "pocket" },
|
|
];
|
|
await provider._addFavicons(pocketItems);
|
|
Assert.equal(
|
|
provider._faviconBytesToDataURI(pocketItems)[0].favicon,
|
|
base64URL,
|
|
"Added favicon data only to the non-pocket item"
|
|
);
|
|
Assert.equal(
|
|
pocketItems[1].favicon,
|
|
null,
|
|
"Did not add a favicon to the pocket item"
|
|
);
|
|
Assert.equal(
|
|
pocketItems[1].mimeType,
|
|
null,
|
|
"Did not add mimeType to the pocket item"
|
|
);
|
|
Assert.equal(
|
|
pocketItems[1].faviconSize,
|
|
null,
|
|
"Did not add a faviconSize to the pocket item"
|
|
);
|
|
});
|
|
|
|
add_task(async function getHighlightsWithoutPocket() {
|
|
const addMetadata = url =>
|
|
PlacesUtils.history.update({
|
|
description: "desc",
|
|
previewImageURL: "https://image/",
|
|
url,
|
|
});
|
|
|
|
await setUpActivityStreamTest();
|
|
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
let links = await provider.getHighlights();
|
|
Assert.equal(links.length, 0, "empty history yields empty links");
|
|
|
|
// Add bookmarks
|
|
const now = Date.now();
|
|
const oldSeconds = 24 * 60 * 60; // 1 day old
|
|
let bookmarks = [
|
|
{
|
|
dateAdded: new Date(now - oldSeconds * 1000),
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
title: "foo",
|
|
url: "https://mozilla1.com/dayOld",
|
|
},
|
|
{
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
title: "foo",
|
|
url: "https://mozilla1.com/nowNew",
|
|
},
|
|
];
|
|
for (let placeInfo of bookmarks) {
|
|
await PlacesUtils.bookmarks.insert(placeInfo);
|
|
}
|
|
|
|
links = await provider.getHighlights();
|
|
Assert.equal(
|
|
links.length,
|
|
0,
|
|
"adding bookmarks without visits doesn't yield more links"
|
|
);
|
|
|
|
// Add a history visit
|
|
let testURI = "http://mozilla.com/";
|
|
await PlacesTestUtils.addVisits(testURI);
|
|
|
|
links = await provider.getHighlights();
|
|
Assert.equal(
|
|
links.length,
|
|
0,
|
|
"adding visits without metadata doesn't yield more links"
|
|
);
|
|
|
|
// Add bookmark visits
|
|
for (let placeInfo of bookmarks) {
|
|
await PlacesTestUtils.addVisits(placeInfo.url);
|
|
}
|
|
|
|
links = await provider.getHighlights();
|
|
Assert.equal(links.length, 2, "adding visits to bookmarks yields more links");
|
|
Assert.equal(
|
|
links[0].url,
|
|
bookmarks[1].url,
|
|
"first bookmark is younger bookmark"
|
|
);
|
|
Assert.equal(links[0].type, "bookmark", "first bookmark is bookmark");
|
|
Assert.ok(links[0].date_added, "got a date_added for the bookmark");
|
|
Assert.equal(
|
|
links[1].url,
|
|
bookmarks[0].url,
|
|
"second bookmark is older bookmark"
|
|
);
|
|
Assert.equal(links[1].type, "bookmark", "second bookmark is bookmark");
|
|
Assert.ok(links[1].date_added, "got a date_added for the bookmark");
|
|
|
|
// Add metadata to history
|
|
await addMetadata(testURI);
|
|
|
|
links = await provider.getHighlights();
|
|
Assert.equal(links.length, 3, "adding metadata yield more links");
|
|
Assert.equal(links[0].url, bookmarks[1].url, "still have younger bookmark");
|
|
Assert.equal(links[1].url, bookmarks[0].url, "still have older bookmark");
|
|
Assert.equal(links[2].url, testURI, "added visit corresponds to added url");
|
|
Assert.equal(links[2].type, "history", "added visit is history");
|
|
|
|
links = await provider.getHighlights({ numItems: 2 });
|
|
Assert.equal(links.length, 2, "limited to 2 items");
|
|
Assert.equal(links[0].url, bookmarks[1].url, "still have younger bookmark");
|
|
Assert.equal(links[1].url, bookmarks[0].url, "still have older bookmark");
|
|
|
|
links = await provider.getHighlights({ excludeHistory: true });
|
|
Assert.equal(links.length, 2, "only have bookmarks");
|
|
Assert.equal(links[0].url, bookmarks[1].url, "still have younger bookmark");
|
|
Assert.equal(links[1].url, bookmarks[0].url, "still have older bookmark");
|
|
|
|
links = await provider.getHighlights({ excludeBookmarks: true });
|
|
Assert.equal(links.length, 1, "only have history");
|
|
Assert.equal(links[0].url, testURI, "only have the history now");
|
|
|
|
links = await provider.getHighlights({
|
|
excludeBookmarks: true,
|
|
excludeHistory: true,
|
|
});
|
|
Assert.equal(links.length, 0, "requested nothing, get nothing");
|
|
|
|
links = await provider.getHighlights({ bookmarkSecondsAgo: oldSeconds / 2 });
|
|
Assert.equal(links.length, 2, "old bookmark filtered out with");
|
|
Assert.equal(links[0].url, bookmarks[1].url, "still have newer bookmark");
|
|
Assert.equal(links[1].url, testURI, "still have the history");
|
|
|
|
// Add a visit and metadata to the older bookmark
|
|
await PlacesTestUtils.addVisits(bookmarks[0].url);
|
|
await addMetadata(bookmarks[0].url);
|
|
|
|
links = await provider.getHighlights({ bookmarkSecondsAgo: oldSeconds / 2 });
|
|
Assert.equal(links.length, 3, "old bookmark returns as history");
|
|
Assert.equal(links[0].url, bookmarks[1].url, "still have newer bookmark");
|
|
Assert.equal(
|
|
links[1].url,
|
|
bookmarks[0].url,
|
|
"old bookmark now is newer history"
|
|
);
|
|
Assert.equal(links[1].type, "history", "old bookmark now is history");
|
|
Assert.equal(links[2].url, testURI, "still have the history");
|
|
|
|
// Bookmark the history item
|
|
await PlacesUtils.bookmarks.insert({
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
title: "now a bookmark",
|
|
url: testURI,
|
|
});
|
|
|
|
links = await provider.getHighlights();
|
|
Assert.equal(
|
|
links.length,
|
|
3,
|
|
"a visited bookmark doesn't appear as bookmark and history"
|
|
);
|
|
Assert.equal(
|
|
links[0].url,
|
|
testURI,
|
|
"history is now the first, i.e., most recent, bookmark"
|
|
);
|
|
Assert.equal(links[0].type, "bookmark", "was history now bookmark");
|
|
Assert.ok(links[0].date_added, "got a date_added for the now bookmark");
|
|
Assert.equal(
|
|
links[1].url,
|
|
bookmarks[1].url,
|
|
"still have younger bookmark now second"
|
|
);
|
|
Assert.equal(
|
|
links[2].url,
|
|
bookmarks[0].url,
|
|
"still have older bookmark now third"
|
|
);
|
|
|
|
// Test the `withFavicons` option.
|
|
await PlacesTestUtils.addFavicons(new Map([[testURI, image1x1]]));
|
|
links = await provider.getHighlights({ withFavicons: true });
|
|
Assert.equal(links.length, 3, "We're not expecting a change in links");
|
|
Assert.equal(links[0].favicon, image1x1, "Link 1 should contain a favicon");
|
|
Assert.equal(links[1].favicon, null, "Link 2 has no favicon data");
|
|
Assert.equal(links[2].favicon, null, "Link 3 has no favicon data");
|
|
});
|
|
|
|
add_task(async function getHighlightsWithPocketSuccess() {
|
|
await setUpActivityStreamTest();
|
|
|
|
// Add a bookmark
|
|
let bookmark = {
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
title: "foo",
|
|
description: "desc",
|
|
preview_image_url: "foo.com/img.png",
|
|
url: "https://mozilla1.com/",
|
|
};
|
|
|
|
const fakeResponse = {
|
|
list: {
|
|
"123": {
|
|
time_added: "123",
|
|
image: { src: "foo.com/img.png" },
|
|
excerpt: "A description for foo",
|
|
resolved_title: "A title for foo",
|
|
resolved_url: "http://www.foo.com",
|
|
item_id: "123",
|
|
open_url: "http://www.getpocket.com/itemID",
|
|
status: "0",
|
|
},
|
|
"456": {
|
|
item_id: "456",
|
|
status: "2",
|
|
},
|
|
},
|
|
};
|
|
|
|
await PlacesUtils.bookmarks.insert(bookmark);
|
|
await PlacesTestUtils.addVisits(bookmark.url);
|
|
|
|
NewTabUtils.activityStreamProvider.fetchSavedPocketItems = () => fakeResponse;
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
|
|
// Force a cache invalidation
|
|
NewTabUtils.activityStreamLinks._pocketLastUpdated =
|
|
Date.now() - 70 * 60 * 1000;
|
|
NewTabUtils.activityStreamLinks._pocketLastLatest = -1;
|
|
let links = await provider.getHighlights();
|
|
|
|
// We should have 1 bookmark followed by 1 pocket story in highlights
|
|
// We should not have stored the second pocket item since it was deleted
|
|
Assert.equal(links.length, 2, "Should have 2 links in highlights");
|
|
|
|
// First highlight should be a bookmark
|
|
Assert.equal(links[0].url, bookmark.url, "The first link is the bookmark");
|
|
|
|
// Second highlight should be a Pocket item with the correct fields to display
|
|
let pocketItem = fakeResponse.list["123"];
|
|
let currentLink = links[1];
|
|
Assert.equal(currentLink.url, pocketItem.resolved_url, "Correct Pocket item");
|
|
Assert.equal(currentLink.type, "pocket", "Attached the correct type");
|
|
Assert.equal(
|
|
currentLink.preview_image_url,
|
|
pocketItem.image.src,
|
|
"Correct preview image was added"
|
|
);
|
|
Assert.equal(
|
|
currentLink.title,
|
|
pocketItem.resolved_title,
|
|
"Correct title was added"
|
|
);
|
|
Assert.equal(
|
|
currentLink.description,
|
|
pocketItem.excerpt,
|
|
"Correct description was added"
|
|
);
|
|
Assert.equal(
|
|
currentLink.pocket_id,
|
|
pocketItem.item_id,
|
|
"item_id was preserved"
|
|
);
|
|
Assert.equal(
|
|
currentLink.open_url,
|
|
`${pocketItem.open_url}?src=fx_new_tab`,
|
|
"open_url was preserved"
|
|
);
|
|
Assert.equal(
|
|
currentLink.date_added,
|
|
pocketItem.time_added * 1000,
|
|
"date_added was added to pocket item"
|
|
);
|
|
|
|
NewTabUtils.activityStreamLinks._savedPocketStories = null;
|
|
});
|
|
|
|
add_task(async function getHighlightsWithPocketCached() {
|
|
await setUpActivityStreamTest();
|
|
|
|
let fakeResponse = {
|
|
list: {
|
|
"123": {
|
|
time_added: "123",
|
|
image: { src: "foo.com/img.png" },
|
|
excerpt: "A description for foo",
|
|
resolved_title: "A title for foo",
|
|
resolved_url: "http://www.foo.com",
|
|
item_id: "123",
|
|
open_url: "http://www.getpocket.com/itemID",
|
|
status: "0",
|
|
},
|
|
"456": {
|
|
item_id: "456",
|
|
status: "2",
|
|
},
|
|
},
|
|
};
|
|
|
|
NewTabUtils.activityStreamProvider.fetchSavedPocketItems = () => fakeResponse;
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
|
|
let links = await provider.getHighlights();
|
|
Assert.equal(
|
|
links.length,
|
|
1,
|
|
"Sanity check that we got 1 link back for highlights"
|
|
);
|
|
Assert.equal(
|
|
links[0].url,
|
|
fakeResponse.list["123"].resolved_url,
|
|
"Sanity check that it was the pocket story"
|
|
);
|
|
|
|
// Update what the response would be
|
|
fakeResponse.list["789"] = {
|
|
time_added: "123",
|
|
image: { src: "bar.com/img.png" },
|
|
excerpt: "A description for bar",
|
|
resolved_title: "A title for bar",
|
|
resolved_url: "http://www.bar.com",
|
|
item_id: "789",
|
|
open_url: "http://www.getpocket.com/itemID",
|
|
status: "0",
|
|
};
|
|
|
|
// Call getHighlights again - this time we should get the cached links since we just updated
|
|
links = await provider.getHighlights();
|
|
Assert.equal(links.length, 1, "We still got 1 link back for highlights");
|
|
Assert.equal(
|
|
links[0].url,
|
|
fakeResponse.list["123"].resolved_url,
|
|
"It was still the same pocket story"
|
|
);
|
|
|
|
// Now force a cache invalidation and call getHighlights again
|
|
NewTabUtils.activityStreamLinks._pocketLastUpdated =
|
|
Date.now() - 70 * 60 * 1000;
|
|
NewTabUtils.activityStreamLinks._pocketLastLatest = -1;
|
|
links = await provider.getHighlights();
|
|
Assert.equal(
|
|
links.length,
|
|
2,
|
|
"This time we got fresh links with the new response"
|
|
);
|
|
Assert.equal(
|
|
links[0].url,
|
|
fakeResponse.list["123"].resolved_url,
|
|
"First link is unchanged"
|
|
);
|
|
Assert.equal(
|
|
links[1].url,
|
|
fakeResponse.list["789"].resolved_url,
|
|
"Second link is the new link"
|
|
);
|
|
|
|
NewTabUtils.activityStreamLinks._savedPocketStories = null;
|
|
});
|
|
|
|
add_task(async function getHighlightsWithPocketFailure() {
|
|
await setUpActivityStreamTest();
|
|
|
|
NewTabUtils.activityStreamProvider.fetchSavedPocketItems = function() {
|
|
throw new Error();
|
|
};
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
|
|
// Force a cache invalidation
|
|
NewTabUtils.activityStreamLinks._pocketLastUpdated =
|
|
Date.now() - 70 * 60 * 1000;
|
|
NewTabUtils.activityStreamLinks._pocketLastLatest = -1;
|
|
let links = await provider.getHighlights();
|
|
Assert.equal(links.length, 0, "Return empty links if we reject the promise");
|
|
});
|
|
|
|
add_task(async function getHighlightsWithPocketNoData() {
|
|
await setUpActivityStreamTest();
|
|
|
|
NewTabUtils.activityStreamProvider.fetchSavedPocketItems = () => {};
|
|
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
|
|
// Force a cache invalidation
|
|
NewTabUtils.activityStreamLinks._pocketLastUpdated =
|
|
Date.now() - 70 * 60 * 1000;
|
|
NewTabUtils.activityStreamLinks._pocketLastLatest = -1;
|
|
let links = await provider.getHighlights();
|
|
Assert.equal(
|
|
links.length,
|
|
0,
|
|
"Return empty links if we got no data back from the response"
|
|
);
|
|
});
|
|
|
|
add_task(async function getTopFrecentSites() {
|
|
await setUpActivityStreamTest();
|
|
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
let links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(links.length, 0, "empty history yields empty links");
|
|
|
|
// add a visit
|
|
let testURI = "http://mozilla.com/";
|
|
await PlacesTestUtils.addVisits(testURI);
|
|
|
|
links = await provider.getTopSites();
|
|
Assert.equal(
|
|
links.length,
|
|
0,
|
|
"adding a single visit doesn't exceed default threshold"
|
|
);
|
|
|
|
links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(links.length, 1, "adding a visit yields a link");
|
|
Assert.equal(links[0].url, testURI, "added visit corresponds to added url");
|
|
});
|
|
|
|
add_task(
|
|
{
|
|
skip_if: () =>
|
|
AppConstants.MOZ_APP_NAME == "thunderbird" ||
|
|
Services.prefs.getBoolPref(
|
|
"browser.topsites.useRemoteSetting"
|
|
) /* see bug 1664502 */,
|
|
},
|
|
async function getTopFrecentSites_improveSearch() {
|
|
await setUpActivityStreamTest();
|
|
const SEARCH_SHORTCUTS_EXPERIMENT_PREF =
|
|
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts";
|
|
Services.prefs.setBoolPref(SEARCH_SHORTCUTS_EXPERIMENT_PREF, true);
|
|
|
|
let testURI = "https://www.amazon.com?search=tv";
|
|
await PlacesTestUtils.addVisits(testURI);
|
|
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
let links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(
|
|
links.length,
|
|
1,
|
|
"sanity check that we got the link from top sites"
|
|
);
|
|
Assert.equal(
|
|
links[0].url,
|
|
"https://amazon.com",
|
|
"the amazon site was converted to generic search shortcut site"
|
|
);
|
|
|
|
Services.prefs.setBoolPref(SEARCH_SHORTCUTS_EXPERIMENT_PREF, false);
|
|
}
|
|
);
|
|
|
|
add_task(async function getTopFrecentSites_no_dedup() {
|
|
await setUpActivityStreamTest();
|
|
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
let links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(links.length, 0, "empty history yields empty links");
|
|
|
|
// Add a visits in reverse order they will be returned in when not deduped.
|
|
let testURIs = [
|
|
{ uri: "http://www.mozilla.com/" },
|
|
{ uri: "http://mozilla.com/" },
|
|
];
|
|
await PlacesTestUtils.addVisits(testURIs);
|
|
|
|
links = await provider.getTopSites();
|
|
Assert.equal(
|
|
links.length,
|
|
0,
|
|
"adding a single visit doesn't exceed default threshold"
|
|
);
|
|
|
|
links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(links.length, 1, "adding a visit yields a link");
|
|
// Plain domain is returned when deduped.
|
|
Assert.equal(
|
|
links[0].url,
|
|
testURIs[1].uri,
|
|
"added visit corresponds to added url"
|
|
);
|
|
|
|
links = await provider.getTopSites({
|
|
topsiteFrecency: 100,
|
|
onePerDomain: false,
|
|
});
|
|
Assert.equal(links.length, 2, "adding a visit yields a link");
|
|
Assert.equal(
|
|
links[0].url,
|
|
testURIs[1].uri,
|
|
"added visit corresponds to added url"
|
|
);
|
|
Assert.equal(
|
|
links[1].url,
|
|
testURIs[0].uri,
|
|
"added visit corresponds to added url"
|
|
);
|
|
});
|
|
|
|
add_task(async function getTopFrecentSites_dedupeWWW() {
|
|
await setUpActivityStreamTest();
|
|
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
|
|
let links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(links.length, 0, "empty history yields empty links");
|
|
|
|
// add a visit without www
|
|
let testURI = "http://mozilla.com";
|
|
await PlacesTestUtils.addVisits(testURI);
|
|
|
|
// add a visit with www
|
|
testURI = "http://www.mozilla.com";
|
|
await PlacesTestUtils.addVisits(testURI);
|
|
|
|
// Test combined frecency score
|
|
links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(links.length, 1, "adding both www. and no-www. yields one link");
|
|
Assert.equal(links[0].frecency, 200, "frecency scores are combined");
|
|
|
|
// add another page visit with www and without www
|
|
let noWWW = "http://mozilla.com/page";
|
|
await PlacesTestUtils.addVisits(noWWW);
|
|
let withWWW = "http://www.mozilla.com/page";
|
|
await PlacesTestUtils.addVisits(withWWW);
|
|
links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(links.length, 1, "adding both www. and no-www. yields one link");
|
|
Assert.equal(
|
|
links[0].frecency,
|
|
200,
|
|
"frecency scores are combined ignoring extra pages"
|
|
);
|
|
|
|
// add another visit with www
|
|
await PlacesTestUtils.addVisits(withWWW);
|
|
links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(links.length, 1, "still yields one link");
|
|
Assert.equal(links[0].url, withWWW, "more frecent www link is used");
|
|
Assert.equal(
|
|
links[0].frecency,
|
|
300,
|
|
"frecency scores are combined ignoring extra pages"
|
|
);
|
|
|
|
// add a couple more visits to the no-www page
|
|
await PlacesTestUtils.addVisits(noWWW);
|
|
await PlacesTestUtils.addVisits(noWWW);
|
|
links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(links.length, 1, "still yields one link");
|
|
Assert.equal(links[0].url, noWWW, "now more frecent no-www link is used");
|
|
Assert.equal(
|
|
links[0].frecency,
|
|
500,
|
|
"frecency scores are combined ignoring extra pages"
|
|
);
|
|
});
|
|
|
|
add_task(async function getTopFrencentSites_maxLimit() {
|
|
await setUpActivityStreamTest();
|
|
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
|
|
// add many visits
|
|
const MANY_LINKS = 20;
|
|
for (let i = 0; i < MANY_LINKS; i++) {
|
|
let testURI = `http://mozilla${i}.com`;
|
|
await PlacesTestUtils.addVisits(testURI);
|
|
}
|
|
|
|
let links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.ok(
|
|
links.length < MANY_LINKS,
|
|
"query default limited to less than many"
|
|
);
|
|
Assert.greater(links.length, 6, "query default to more than visible count");
|
|
});
|
|
|
|
add_task(async function getTopFrencentSites_allowedProtocols() {
|
|
await setUpActivityStreamTest();
|
|
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
|
|
// add a visit from a file:// site
|
|
let testURI = "file:///some/file/path.png";
|
|
await PlacesTestUtils.addVisits(testURI);
|
|
|
|
let links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(links.length, 0, "don't get sites with the file:// protocol");
|
|
|
|
// now add a site with an allowed protocol
|
|
testURI = "http://www.mozilla.com";
|
|
await PlacesTestUtils.addVisits(testURI);
|
|
|
|
links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(links.length, 1, "http:// is an allowed protocol");
|
|
|
|
// and just to be sure, add a visit to a site with ftp:// protocol
|
|
testURI = "ftp://bad/example";
|
|
await PlacesTestUtils.addVisits(testURI);
|
|
|
|
links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(
|
|
links.length,
|
|
1,
|
|
"we still only accept http:// and https:// for top sites"
|
|
);
|
|
|
|
// add a different allowed protocol
|
|
testURI = "https://https";
|
|
await PlacesTestUtils.addVisits(testURI);
|
|
|
|
links = await provider.getTopSites({ topsiteFrecency: 100 });
|
|
Assert.equal(
|
|
links.length,
|
|
2,
|
|
"we now accept both http:// and https:// for top sites"
|
|
);
|
|
});
|
|
|
|
add_task(async function getTopFrecentSites_order() {
|
|
await setUpActivityStreamTest();
|
|
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
let { TRANSITION_TYPED } = PlacesUtils.history;
|
|
|
|
let timeEarlier = timeDaysAgo(0);
|
|
let timeLater = timeDaysAgo(2);
|
|
|
|
let visits = [
|
|
// frecency 200
|
|
{
|
|
uri: "https://mozilla1.com/0",
|
|
visitDate: timeEarlier,
|
|
transition: TRANSITION_TYPED,
|
|
},
|
|
// sort by url, frecency 200
|
|
{
|
|
uri: "https://mozilla2.com/1",
|
|
visitDate: timeEarlier,
|
|
transition: TRANSITION_TYPED,
|
|
},
|
|
// sort by last visit date, frecency 200
|
|
{
|
|
uri: "https://mozilla3.com/2",
|
|
visitDate: timeLater,
|
|
transition: TRANSITION_TYPED,
|
|
},
|
|
// sort by frecency, frecency 10
|
|
{ uri: "https://mozilla0.com/", visitDate: timeLater },
|
|
];
|
|
|
|
let links = await provider.getTopSites({ topsiteFrecency: 0 });
|
|
Assert.equal(links.length, 0, "empty history yields empty links");
|
|
|
|
// map of page url to favicon url
|
|
let faviconData = new Map();
|
|
faviconData.set("https://mozilla3.com/2", image1x1);
|
|
|
|
await PlacesTestUtils.addVisits(visits);
|
|
await PlacesTestUtils.addFavicons(faviconData);
|
|
|
|
links = await provider.getTopSites({ topsiteFrecency: 0 });
|
|
Assert.equal(
|
|
links.length,
|
|
visits.length,
|
|
"number of links added is the same as obtain by getTopFrecentSites"
|
|
);
|
|
|
|
// first link doesn't have a favicon
|
|
Assert.equal(
|
|
links[0].url,
|
|
visits[0].uri,
|
|
"links are obtained in the expected order"
|
|
);
|
|
Assert.equal(null, links[0].favicon, "favicon data is stored as expected");
|
|
Assert.ok(
|
|
isVisitDateOK(links[0].lastVisitDate),
|
|
"visit date within expected range"
|
|
);
|
|
|
|
// second link doesn't have a favicon
|
|
Assert.equal(
|
|
links[1].url,
|
|
visits[1].uri,
|
|
"links are obtained in the expected order"
|
|
);
|
|
Assert.equal(null, links[1].favicon, "favicon data is stored as expected");
|
|
Assert.ok(
|
|
isVisitDateOK(links[1].lastVisitDate),
|
|
"visit date within expected range"
|
|
);
|
|
|
|
// third link should have the favicon data that we added
|
|
Assert.equal(
|
|
links[2].url,
|
|
visits[2].uri,
|
|
"links are obtained in the expected order"
|
|
);
|
|
Assert.equal(
|
|
faviconData.get(links[2].url),
|
|
links[2].favicon,
|
|
"favicon data is stored as expected"
|
|
);
|
|
Assert.ok(
|
|
isVisitDateOK(links[2].lastVisitDate),
|
|
"visit date within expected range"
|
|
);
|
|
|
|
// fourth link doesn't have a favicon
|
|
Assert.equal(
|
|
links[3].url,
|
|
visits[3].uri,
|
|
"links are obtained in the expected order"
|
|
);
|
|
Assert.equal(null, links[3].favicon, "favicon data is stored as expected");
|
|
Assert.ok(
|
|
isVisitDateOK(links[3].lastVisitDate),
|
|
"visit date within expected range"
|
|
);
|
|
});
|
|
|
|
add_task(async function getTopFrecentSites_hideWithSearchParam() {
|
|
await setUpActivityStreamTest();
|
|
|
|
let pref = "browser.newtabpage.activity-stream.hideTopSitesWithSearchParam";
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
|
|
// This maps URL search params to objects describing whether a URL with those
|
|
// params is expected to be included in the returned links. Each object maps
|
|
// from effective hide-with search params to whether the URL is expected to be
|
|
// included.
|
|
let tests = {
|
|
"": {
|
|
"": true,
|
|
test: true,
|
|
"test=": true,
|
|
"test=hide": true,
|
|
nomatch: true,
|
|
"nomatch=": true,
|
|
"nomatch=hide": true,
|
|
},
|
|
test: {
|
|
"": true,
|
|
test: false,
|
|
"test=": false,
|
|
"test=hide": true,
|
|
nomatch: true,
|
|
"nomatch=": true,
|
|
"nomatch=hide": true,
|
|
},
|
|
"test=hide": {
|
|
"": true,
|
|
test: false,
|
|
"test=": true,
|
|
"test=hide": false,
|
|
nomatch: true,
|
|
"nomatch=": true,
|
|
"nomatch=hide": true,
|
|
},
|
|
"test=foo&test=hide": {
|
|
"": true,
|
|
test: false,
|
|
"test=": true,
|
|
"test=hide": false,
|
|
nomatch: true,
|
|
"nomatch=": true,
|
|
"nomatch=hide": true,
|
|
},
|
|
};
|
|
|
|
for (let [urlParams, expected] of Object.entries(tests)) {
|
|
for (let prefValue of Object.keys(expected)) {
|
|
info(
|
|
"Running test: " + JSON.stringify({ urlParams, prefValue, expected })
|
|
);
|
|
|
|
// Add a visit to a URL with search params `urlParams`.
|
|
let url = new URL("http://example.com/");
|
|
url.search = urlParams;
|
|
await PlacesTestUtils.addVisits(url);
|
|
|
|
// Set the pref to `prefValue`.
|
|
Services.prefs.setCharPref(pref, prefValue);
|
|
|
|
// Call `getTopSites()` with all the test values for `hideWithSearchParam`
|
|
// plus undefined. When `hideWithSearchParam` is undefined, the pref value
|
|
// should be used. Otherwise it should override the pref.
|
|
for (let hideWithSearchParam of [undefined, ...Object.keys(expected)]) {
|
|
info(
|
|
"Calling getTopSites() with hideWithSearchParam: " +
|
|
JSON.stringify(hideWithSearchParam)
|
|
);
|
|
|
|
let options = { topsiteFrecency: 100 };
|
|
if (hideWithSearchParam !== undefined) {
|
|
options = { ...options, hideWithSearchParam };
|
|
}
|
|
let links = await provider.getTopSites(options);
|
|
|
|
let effectiveHideWithParam =
|
|
hideWithSearchParam === undefined ? prefValue : hideWithSearchParam;
|
|
if (expected[effectiveHideWithParam]) {
|
|
Assert.equal(links.length, 1, "One link returned");
|
|
Assert.equal(links[0].url, url.toString(), "Expected link returned");
|
|
} else {
|
|
Assert.equal(links.length, 0, "No links returned");
|
|
}
|
|
}
|
|
|
|
await PlacesUtils.history.clear();
|
|
}
|
|
}
|
|
|
|
Services.prefs.clearUserPref(pref);
|
|
});
|
|
|
|
add_task(async function activitySteamProvider_deleteHistoryLink() {
|
|
await setUpActivityStreamTest();
|
|
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
|
|
let { TRANSITION_TYPED } = PlacesUtils.history;
|
|
|
|
let visits = [
|
|
// frecency 200
|
|
{
|
|
uri: "https://mozilla1.com/0",
|
|
visitDate: timeDaysAgo(1),
|
|
transition: TRANSITION_TYPED,
|
|
},
|
|
// sort by url, frecency 200
|
|
{ uri: "https://mozilla2.com/1", visitDate: timeDaysAgo(0) },
|
|
];
|
|
|
|
let size = await getHistorySize();
|
|
Assert.equal(size, 0, "empty history has size 0");
|
|
|
|
await PlacesTestUtils.addVisits(visits);
|
|
|
|
size = await getHistorySize();
|
|
Assert.equal(size, 2, "expected history size");
|
|
|
|
// delete a link
|
|
let deleted = await provider.deleteHistoryEntry("https://mozilla2.com/1");
|
|
Assert.equal(deleted, true, "link is deleted");
|
|
|
|
// ensure that there's only one link left
|
|
size = await getHistorySize();
|
|
Assert.equal(size, 1, "expected history size");
|
|
|
|
// pin the link and delete it
|
|
const linkToPin = { url: "https://mozilla1.com/0" };
|
|
NewTabUtils.pinnedLinks.pin(linkToPin, 0);
|
|
|
|
// sanity check that the correct link was pinned
|
|
Assert.equal(
|
|
NewTabUtils.pinnedLinks.links.length,
|
|
1,
|
|
"added a link to pinned sites"
|
|
);
|
|
Assert.equal(
|
|
NewTabUtils.pinnedLinks.isPinned(linkToPin),
|
|
true,
|
|
"pinned the correct link"
|
|
);
|
|
|
|
// delete the pinned link and ensure it was both deleted from history and unpinned
|
|
deleted = await provider.deleteHistoryEntry("https://mozilla1.com/0");
|
|
size = await getHistorySize();
|
|
Assert.equal(deleted, true, "link is deleted");
|
|
Assert.equal(size, 0, "expected history size");
|
|
Assert.equal(
|
|
NewTabUtils.pinnedLinks.links.length,
|
|
0,
|
|
"unpinned the deleted link"
|
|
);
|
|
});
|
|
|
|
add_task(async function activityStream_deleteBookmark() {
|
|
await setUpActivityStreamTest();
|
|
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
let bookmarks = [
|
|
{
|
|
url: "https://mozilla1.com/0",
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
},
|
|
{
|
|
url: "https://mozilla1.com/1",
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
},
|
|
];
|
|
|
|
let bookmarksSize = await getBookmarksSize();
|
|
Assert.equal(bookmarksSize, 0, "empty bookmarks yields 0 size");
|
|
|
|
for (let placeInfo of bookmarks) {
|
|
await PlacesUtils.bookmarks.insert(placeInfo);
|
|
}
|
|
|
|
bookmarksSize = await getBookmarksSize();
|
|
Assert.equal(bookmarksSize, 2, "size 2 for 2 bookmarks added");
|
|
|
|
let bookmarkGuid = await new Promise(resolve =>
|
|
PlacesUtils.bookmarks.fetch({ url: bookmarks[0].url }, bookmark =>
|
|
resolve(bookmark.guid)
|
|
)
|
|
);
|
|
await provider.deleteBookmark(bookmarkGuid);
|
|
Assert.strictEqual(
|
|
await PlacesUtils.bookmarks.fetch(bookmarkGuid),
|
|
null,
|
|
"the bookmark should no longer be found"
|
|
);
|
|
bookmarksSize = await getBookmarksSize();
|
|
Assert.equal(bookmarksSize, 1, "size 1 after deleting");
|
|
});
|
|
|
|
add_task(async function activityStream_blockedURLs() {
|
|
await setUpActivityStreamTest();
|
|
|
|
let provider = NewTabUtils.activityStreamLinks;
|
|
NewTabUtils.blockedLinks.addObserver(provider);
|
|
|
|
let { TRANSITION_TYPED } = PlacesUtils.history;
|
|
|
|
let timeToday = timeDaysAgo(0);
|
|
let timeEarlier = timeDaysAgo(2);
|
|
|
|
let visits = [
|
|
{
|
|
uri: "https://example1.com/",
|
|
visitDate: timeToday,
|
|
transition: TRANSITION_TYPED,
|
|
},
|
|
{
|
|
uri: "https://example2.com/",
|
|
visitDate: timeToday,
|
|
transition: TRANSITION_TYPED,
|
|
},
|
|
{
|
|
uri: "https://example3.com/",
|
|
visitDate: timeEarlier,
|
|
transition: TRANSITION_TYPED,
|
|
},
|
|
{
|
|
uri: "https://example4.com/",
|
|
visitDate: timeEarlier,
|
|
transition: TRANSITION_TYPED,
|
|
},
|
|
];
|
|
await PlacesTestUtils.addVisits(visits);
|
|
await PlacesUtils.bookmarks.insert({
|
|
url: "https://example5.com/",
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
});
|
|
|
|
let sizeQueryResult;
|
|
|
|
// bookmarks
|
|
sizeQueryResult = await getBookmarksSize();
|
|
Assert.equal(sizeQueryResult, 1, "got the correct bookmark size");
|
|
});
|
|
|
|
add_task(async function activityStream_getTotalBookmarksCount() {
|
|
await setUpActivityStreamTest();
|
|
|
|
let provider = NewTabUtils.activityStreamProvider;
|
|
let bookmarks = [
|
|
{
|
|
url: "https://mozilla1.com/0",
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
},
|
|
{
|
|
url: "https://mozilla1.com/1",
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
},
|
|
];
|
|
|
|
let bookmarksSize = await provider.getTotalBookmarksCount();
|
|
Assert.equal(
|
|
bookmarksSize,
|
|
0,
|
|
".getTotalBookmarksCount() returns 0 for an empty bookmarks table"
|
|
);
|
|
|
|
for (const bookmark of bookmarks) {
|
|
await PlacesUtils.bookmarks.insert(bookmark);
|
|
}
|
|
|
|
bookmarksSize = await provider.getTotalBookmarksCount();
|
|
Assert.equal(
|
|
bookmarksSize,
|
|
2,
|
|
".getTotalBookmarksCount() returns 2 after 2 bookmarks are inserted"
|
|
);
|
|
});
|
|
|
|
function TestProvider(getLinksFn) {
|
|
this.getLinks = getLinksFn;
|
|
this._observers = new Set();
|
|
}
|
|
|
|
TestProvider.prototype = {
|
|
addObserver(observer) {
|
|
this._observers.add(observer);
|
|
},
|
|
notifyLinkChanged(link, index = -1, deleted = false) {
|
|
this._notifyObservers("onLinkChanged", link, index, deleted);
|
|
},
|
|
notifyManyLinksChanged() {
|
|
this._notifyObservers("onManyLinksChanged");
|
|
},
|
|
_notifyObservers() {
|
|
let observerMethodName = arguments[0];
|
|
let args = Array.prototype.slice.call(arguments, 1);
|
|
args.unshift(this);
|
|
for (let obs of this._observers) {
|
|
if (obs[observerMethodName]) {
|
|
obs[observerMethodName].apply(NewTabUtils.links, args);
|
|
}
|
|
}
|
|
},
|
|
};
|