2575 lines
73 KiB
JavaScript
2575 lines
73 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
const { TopSites, insertPinned, DEFAULT_TOP_SITES } =
|
|
ChromeUtils.importESModule("resource:///modules/topsites/TopSites.sys.mjs");
|
|
|
|
ChromeUtils.defineESModuleGetters(this, {
|
|
FilterAdult: "resource:///modules/FilterAdult.sys.mjs",
|
|
NewTabUtils: "resource://gre/modules/NewTabUtils.sys.mjs",
|
|
NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
|
|
sinon: "resource://testing-common/Sinon.sys.mjs",
|
|
PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs",
|
|
PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
|
|
SearchService: "resource://gre/modules/SearchService.sys.mjs",
|
|
TestUtils: "resource://testing-common/TestUtils.sys.mjs",
|
|
TOP_SITES_DEFAULT_ROWS: "resource:///modules/topsites/constants.mjs",
|
|
TOP_SITES_MAX_SITES_PER_ROW: "resource:///modules/topsites/constants.mjs",
|
|
});
|
|
|
|
const FAKE_FAVICON = "data987";
|
|
const FAKE_FAVICON_SIZE = 128;
|
|
const FAKE_FRECENCY = 200;
|
|
const FAKE_LINKS = new Array(2 * TOP_SITES_MAX_SITES_PER_ROW)
|
|
.fill(null)
|
|
.map((v, i) => ({
|
|
frecency: FAKE_FRECENCY,
|
|
url: `http://www.site${i}.com`,
|
|
}));
|
|
|
|
function FakeTippyTopProvider() {}
|
|
FakeTippyTopProvider.prototype = {
|
|
async init() {
|
|
this.initialized = true;
|
|
},
|
|
processSite(site) {
|
|
return site;
|
|
},
|
|
};
|
|
|
|
let gSearchServiceInitStub;
|
|
let gGetTopSitesStub;
|
|
|
|
function stubTopSites(sandbox) {
|
|
async function cleanup() {
|
|
if (TopSites._refreshing) {
|
|
info("Wait for refresh to finish.");
|
|
// Wait for refresh to finish or else removing the store while a process
|
|
// is running will result in errors.
|
|
await TestUtils.topicObserved("topsites-refreshed");
|
|
info("Top sites was refreshed.");
|
|
}
|
|
TopSites._tippyTopProvider.initialized = false;
|
|
TopSites.pinnedCache.clear();
|
|
TopSites.frecentCache.clear();
|
|
TopSites._reset();
|
|
stub.restore();
|
|
info("Finished cleaning up TopSites.");
|
|
}
|
|
|
|
// To avoid having to setup search for each test, we stub this method and
|
|
// unstub it when the unit test calls for the search shortcuts.
|
|
let stub = sandbox.stub(TopSites, "updateCustomSearchShortcuts");
|
|
|
|
TopSites._requestRichIcon = sandbox.stub();
|
|
// Set preferences to match the store state.
|
|
Services.prefs.setIntPref(
|
|
"browser.newtabpage.activity-stream.topSitesRows",
|
|
2
|
|
);
|
|
info("Created mock store for TopSites.");
|
|
return cleanup;
|
|
}
|
|
|
|
function createExpectedPinnedLink(link, index) {
|
|
link.isDefault = false;
|
|
link.isPinned = true;
|
|
link.searchTopSite = false;
|
|
link.favicon = FAKE_FAVICON;
|
|
link.faviconSize = FAKE_FAVICON_SIZE;
|
|
link.pinIndex = index;
|
|
return link;
|
|
}
|
|
|
|
function assertLinks(actualLinks, expectedLinks) {
|
|
Assert.equal(
|
|
actualLinks.length,
|
|
expectedLinks.length,
|
|
"Links have equal length."
|
|
);
|
|
for (let i = 0; i < actualLinks.length; ++i) {
|
|
Assert.deepEqual(actualLinks[i], expectedLinks[i], "Link entry matches");
|
|
}
|
|
}
|
|
|
|
add_setup(async () => {
|
|
// Places requires a profile.
|
|
do_get_profile();
|
|
|
|
let sandbox = sinon.createSandbox();
|
|
sandbox.stub(SearchService.prototype, "defaultEngine").get(() => {
|
|
return { identifier: "ddg", searchUrlDomain: "duckduckgo.com" };
|
|
});
|
|
|
|
gGetTopSitesStub = sandbox
|
|
.stub(NewTabUtils.activityStreamLinks, "getTopSites")
|
|
.resolves(FAKE_LINKS);
|
|
|
|
gSearchServiceInitStub = sandbox
|
|
.stub(SearchService.prototype, "init")
|
|
.resolves();
|
|
|
|
sandbox.stub(NewTabUtils.activityStreamProvider, "_faviconBytesToDataURI");
|
|
|
|
sandbox
|
|
.stub(NewTabUtils.activityStreamProvider, "_addFavicons")
|
|
.callsFake(l => {
|
|
return Promise.resolve(
|
|
l.map(link => {
|
|
link.favicon = FAKE_FAVICON;
|
|
link.faviconSize = FAKE_FAVICON_SIZE;
|
|
return link;
|
|
})
|
|
);
|
|
});
|
|
|
|
registerCleanupFunction(() => {
|
|
sandbox.restore();
|
|
});
|
|
});
|
|
|
|
add_task(async function test_construction() {
|
|
Assert.ok(TopSites._currentSearchHostname, "_currentSearchHostname defined");
|
|
});
|
|
|
|
add_task(async function test_refreshDefaults() {
|
|
let sandbox = sinon.createSandbox();
|
|
let cleanup = stubTopSites(sandbox);
|
|
Assert.ok(
|
|
!DEFAULT_TOP_SITES.length,
|
|
"Should have 0 DEFAULT_TOP_SITES initially."
|
|
);
|
|
|
|
// We have to init to subscribe to changes to the preferences.
|
|
await TopSites.init();
|
|
|
|
info(
|
|
"TopSites.refreshDefaults should add defaults on default.sites pref change."
|
|
);
|
|
Services.prefs.setStringPref(
|
|
"browser.newtabpage.activity-stream.default.sites",
|
|
"https://foo.com"
|
|
);
|
|
|
|
Assert.equal(
|
|
DEFAULT_TOP_SITES.length,
|
|
1,
|
|
"Should have 1 DEFAULT_TOP_SITES now."
|
|
);
|
|
|
|
// Reset the DEFAULT_TOP_SITES;
|
|
DEFAULT_TOP_SITES.length = 0;
|
|
|
|
info("refreshDefaults should refresh on topSiteRows PREF_CHANGED");
|
|
let refreshStub = sandbox.stub(TopSites, "refresh");
|
|
Services.prefs.setIntPref(
|
|
"browser.newtabpage.activity-stream.topSitesRows",
|
|
1
|
|
);
|
|
Assert.ok(TopSites.refresh.calledOnce, "refresh called");
|
|
refreshStub.restore();
|
|
|
|
// Reset the DEFAULT_TOP_SITES;
|
|
DEFAULT_TOP_SITES.length = 0;
|
|
|
|
info("refreshDefaults should have default sites with .isDefault = true");
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
Assert.equal(
|
|
DEFAULT_TOP_SITES.length,
|
|
1,
|
|
"Should have a DEFAULT_TOP_SITES now."
|
|
);
|
|
Assert.ok(
|
|
DEFAULT_TOP_SITES[0].isDefault,
|
|
"Lone top site should be the default."
|
|
);
|
|
|
|
// Reset the DEFAULT_TOP_SITES;
|
|
DEFAULT_TOP_SITES.length = 0;
|
|
|
|
info("refreshDefaults should have default sites with appropriate hostname");
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
Assert.equal(
|
|
DEFAULT_TOP_SITES.length,
|
|
1,
|
|
"Should have a DEFAULT_TOP_SITES now."
|
|
);
|
|
let [site] = DEFAULT_TOP_SITES;
|
|
Assert.equal(
|
|
site.hostname,
|
|
NewTabUtils.shortURL(site),
|
|
"Lone top site should have the right hostname."
|
|
);
|
|
|
|
// Reset the DEFAULT_TOP_SITES;
|
|
DEFAULT_TOP_SITES.length = 0;
|
|
|
|
info("refreshDefaults should add no defaults on empty pref");
|
|
TopSites.refreshDefaults("");
|
|
Assert.equal(
|
|
DEFAULT_TOP_SITES.length,
|
|
0,
|
|
"Should have 0 DEFAULT_TOP_SITES now."
|
|
);
|
|
|
|
info("refreshDefaults should be able to clear defaults");
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
TopSites.refreshDefaults("");
|
|
|
|
Assert.equal(
|
|
DEFAULT_TOP_SITES.length,
|
|
0,
|
|
"Should have 0 DEFAULT_TOP_SITES now."
|
|
);
|
|
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.default.sites"
|
|
);
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.topSitesRows"
|
|
);
|
|
TopSites.uninit();
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(
|
|
async function test_getLinksWithDefaults_on_SearchService_init_failure() {
|
|
let sandbox = sinon.createSandbox();
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
gSearchServiceInitStub.rejects(
|
|
new Error("Simulating search init failures")
|
|
);
|
|
|
|
const result = await TopSites.getLinksWithDefaults();
|
|
Assert.ok(result);
|
|
|
|
gSearchServiceInitStub.resolves();
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
}
|
|
);
|
|
|
|
add_task(async function test_getLinksWithDefaults() {
|
|
NewTabUtils.activityStreamLinks.getTopSites.resetHistory();
|
|
|
|
let sandbox = sinon.createSandbox();
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
info("getLinksWithDefaults should get the links from NewTabUtils");
|
|
let result = await TopSites.getLinksWithDefaults();
|
|
|
|
const reference = FAKE_LINKS.map(site =>
|
|
Object.assign({}, site, {
|
|
hostname: NewTabUtils.shortURL(site),
|
|
typedBonus: true,
|
|
})
|
|
);
|
|
|
|
Assert.deepEqual(result, reference);
|
|
Assert.ok(NewTabUtils.activityStreamLinks.getTopSites.calledOnce);
|
|
|
|
info("getLinksWithDefaults should indicate the links get typed bonus");
|
|
Assert.ok(result[0].typedBonus, "Expected typed bonus property to be true.");
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_filterAdult() {
|
|
let sandbox = sinon.createSandbox();
|
|
info("getLinksWithDefaults should filter out non-pinned adult sites");
|
|
|
|
sandbox.stub(FilterAdult, "filter").returns([]);
|
|
const TEST_URL = "https://foo.com/";
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "links").get(() => [{ url: TEST_URL }]);
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
const result = await TopSites.getLinksWithDefaults();
|
|
Assert.ok(FilterAdult.filter.calledOnce);
|
|
Assert.equal(result.length, 1);
|
|
Assert.equal(result[0].url, TEST_URL);
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_caching() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info(
|
|
"getLinksWithDefaults should filter out the defaults that have been blocked"
|
|
);
|
|
// make sure we only have one top site, and we block the only default site we have to show
|
|
const url = "www.myonlytopsite.com";
|
|
const topsite = {
|
|
frecency: FAKE_FRECENCY,
|
|
hostname: NewTabUtils.shortURL({ url }),
|
|
typedBonus: true,
|
|
url,
|
|
};
|
|
|
|
const blockedDefaultSite = { url: "https://foo.com" };
|
|
gGetTopSitesStub.resolves([topsite]);
|
|
sandbox.stub(NewTabUtils.blockedLinks, "isBlocked").callsFake(site => {
|
|
return site.url === blockedDefaultSite.url;
|
|
});
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
const result = await TopSites.getLinksWithDefaults();
|
|
|
|
// what we should be left with is just the top site we added, and not the default site we blocked
|
|
Assert.equal(result.length, 1);
|
|
Assert.deepEqual(result[0], topsite);
|
|
let foundBlocked = result.find(site => site.url === blockedDefaultSite.url);
|
|
Assert.ok(!foundBlocked, "Should not have found blocked site.");
|
|
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_dedupe() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info("getLinksWithDefaults should call dedupe.group on the links");
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
let stub = sandbox.stub(TopSites.dedupe, "group").callsFake((...id) => id);
|
|
await TopSites.getLinksWithDefaults();
|
|
|
|
Assert.ok(stub.calledOnce, "dedupe.group was called once");
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test__dedupe_key() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info("_dedupeKey should dedupe on hostname instead of url");
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
let site = { url: "foo", hostname: "bar" };
|
|
let result = TopSites._dedupeKey(site);
|
|
|
|
Assert.equal(result, site.hostname, "deduped on hostname");
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_adds_defaults() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info(
|
|
"getLinksWithDefaults should add defaults if there are are not enough links"
|
|
);
|
|
const TEST_LINKS = [{ frecency: FAKE_FRECENCY, url: "foo.com" }];
|
|
gGetTopSitesStub.resolves(TEST_LINKS);
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
let result = await TopSites.getLinksWithDefaults();
|
|
|
|
let reference = [...TEST_LINKS, ...DEFAULT_TOP_SITES].map(s =>
|
|
Object.assign({}, s, {
|
|
hostname: NewTabUtils.shortURL(s),
|
|
typedBonus: true,
|
|
})
|
|
);
|
|
|
|
Assert.deepEqual(result, reference);
|
|
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(
|
|
async function test_getLinksWithDefaults_adds_defaults_for_visible_slots() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info(
|
|
"getLinksWithDefaults should only add defaults up to the number of visible slots"
|
|
);
|
|
const numVisible = TOP_SITES_DEFAULT_ROWS * TOP_SITES_MAX_SITES_PER_ROW;
|
|
let testLinks = [];
|
|
for (let i = 0; i < numVisible - 1; i++) {
|
|
testLinks.push({ frecency: FAKE_FRECENCY, url: `foo${i}.com` });
|
|
}
|
|
gGetTopSitesStub.resolves(testLinks);
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
let result = await TopSites.getLinksWithDefaults();
|
|
|
|
let reference = [...testLinks, DEFAULT_TOP_SITES[0]].map(s =>
|
|
Object.assign({}, s, {
|
|
hostname: NewTabUtils.shortURL(s),
|
|
typedBonus: true,
|
|
})
|
|
);
|
|
|
|
Assert.equal(result.length, numVisible);
|
|
Assert.deepEqual(result, reference);
|
|
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
}
|
|
);
|
|
|
|
add_task(async function test_getLinksWithDefaults_no_throw_on_no_links() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info("getLinksWithDefaults should not throw if NewTabUtils returns null");
|
|
gGetTopSitesStub.resolves(null);
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
await TopSites.getLinksWithDefaults();
|
|
Assert.ok(true, "getLinksWithDefaults did not throw");
|
|
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_get_more_on_request() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info("getLinksWithDefaults should get more if the user has asked for more");
|
|
let testLinks = new Array(4 * TOP_SITES_MAX_SITES_PER_ROW)
|
|
.fill(null)
|
|
.map((v, i) => ({
|
|
frecency: FAKE_FRECENCY,
|
|
url: `http://www.site${i}.com`,
|
|
}));
|
|
gGetTopSitesStub.resolves(testLinks);
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
const TEST_ROWS = 3;
|
|
Services.prefs.setIntPref(
|
|
"browser.newtabpage.activity-stream.topSitesRows",
|
|
TEST_ROWS
|
|
);
|
|
|
|
let result = await TopSites.getLinksWithDefaults();
|
|
Assert.equal(result.length, TEST_ROWS * TOP_SITES_MAX_SITES_PER_ROW);
|
|
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.topSitesRows"
|
|
);
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_reuse_cache() {
|
|
let sandbox = sinon.createSandbox();
|
|
info("getLinksWithDefaults should reuse the cache on subsequent calls");
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
gGetTopSitesStub.resetHistory();
|
|
|
|
await TopSites.getLinksWithDefaults();
|
|
await TopSites.getLinksWithDefaults();
|
|
|
|
Assert.ok(
|
|
NewTabUtils.activityStreamLinks.getTopSites.calledOnce,
|
|
"getTopSites only called once"
|
|
);
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(
|
|
async function test_getLinksWithDefaults_ignore_cache_on_requesting_more() {
|
|
let sandbox = sinon.createSandbox();
|
|
info("getLinksWithDefaults should ignore the cache when requesting more");
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
gGetTopSitesStub.resetHistory();
|
|
|
|
await TopSites.getLinksWithDefaults();
|
|
Services.prefs.setIntPref(
|
|
"browser.newtabpage.activity-stream.topSitesRows",
|
|
3
|
|
);
|
|
await TopSites.getLinksWithDefaults();
|
|
|
|
Assert.ok(
|
|
NewTabUtils.activityStreamLinks.getTopSites.calledTwice,
|
|
"getTopSites called twice"
|
|
);
|
|
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.topSitesRows"
|
|
);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
}
|
|
);
|
|
|
|
add_task(
|
|
async function test_getLinksWithDefaults_migrate_pinned_favicon_data() {
|
|
let sandbox = sinon.createSandbox();
|
|
info(
|
|
"getLinksWithDefaults should migrate pinned favicon data without getting favicons again"
|
|
);
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
gGetTopSitesStub.resetHistory();
|
|
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [{ url: "https://foo.com/" }]);
|
|
|
|
await TopSites.getLinksWithDefaults();
|
|
|
|
let originalCallCount =
|
|
NewTabUtils.activityStreamProvider._addFavicons.callCount;
|
|
TopSites.pinnedCache.expire();
|
|
|
|
let result = await TopSites.getLinksWithDefaults();
|
|
|
|
Assert.equal(
|
|
NewTabUtils.activityStreamProvider._addFavicons.callCount,
|
|
originalCallCount,
|
|
"_addFavicons was not called again."
|
|
);
|
|
Assert.equal(result[0].favicon, FAKE_FAVICON);
|
|
Assert.equal(result[0].faviconSize, FAKE_FAVICON_SIZE);
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
}
|
|
);
|
|
|
|
add_task(async function test_getLinksWithDefaults_no_internal_properties() {
|
|
let sandbox = sinon.createSandbox();
|
|
info("getLinksWithDefaults should not expose internal link properties");
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
let result = await TopSites.getLinksWithDefaults();
|
|
|
|
let internal = Object.keys(result[0]).filter(key => key.startsWith("__"));
|
|
Assert.equal(internal.join(""), "");
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_copy_frecent_screenshot() {
|
|
// TopSites pulls data from NewTabUtils.activityStreamLinks.getTopSites()
|
|
// which can still pass screenshots to it if they are available.
|
|
let sandbox = sinon.createSandbox();
|
|
info(
|
|
"getLinksWithDefaults should copy the screenshot of the frecent site if it exists"
|
|
);
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
const TEST_SCREENSHOT = "screenshot";
|
|
|
|
gGetTopSitesStub.resolves([
|
|
{ url: "https://foo.com/", screenshot: TEST_SCREENSHOT },
|
|
]);
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [{ url: "https://foo.com/" }]);
|
|
|
|
let result = await TopSites.getLinksWithDefaults();
|
|
|
|
Assert.equal(result[0].screenshot, TEST_SCREENSHOT);
|
|
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_copies_both_screenshots() {
|
|
// TopSites pulls data from NewTabUtils.activityStreamLinks.getTopSites()
|
|
// and NewTabUtils.pinnedLinks which can pass screenshot data to it if they
|
|
// are available.
|
|
let sandbox = sinon.createSandbox();
|
|
info(
|
|
"getLinksWithDefaults should still copy the frecent screenshot if " +
|
|
"customScreenshotURL is set"
|
|
);
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
gGetTopSitesStub.resolves([
|
|
{ url: "https://foo.com/", screenshot: "screenshot" },
|
|
]);
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [{ url: "https://foo.com/", customScreenshotURL: "custom" }]);
|
|
|
|
let result = await TopSites.getLinksWithDefaults();
|
|
|
|
Assert.equal(result[0].screenshot, "screenshot");
|
|
Assert.equal(result[0].customScreenshotURL, "custom");
|
|
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_persist_screenshot() {
|
|
let sandbox = sinon.createSandbox();
|
|
info(
|
|
"getLinksWithDefaults should keep the same screenshot if no frecent site is found"
|
|
);
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
const CUSTOM_SCREENSHOT = "custom";
|
|
|
|
gGetTopSitesStub.resolves([]);
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [{ url: "https://foo.com/", screenshot: CUSTOM_SCREENSHOT }]);
|
|
|
|
let result = await TopSites.getLinksWithDefaults();
|
|
|
|
Assert.equal(result[0].screenshot, CUSTOM_SCREENSHOT);
|
|
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(
|
|
async function test_getLinksWithDefaults_no_overwrite_pinned_screenshot() {
|
|
let sandbox = sinon.createSandbox();
|
|
info("getLinksWithDefaults should not overwrite pinned site screenshot");
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
const EXISTING_SCREENSHOT = "some-screenshot";
|
|
|
|
gGetTopSitesStub.resolves([{ url: "https://foo.com/", screenshot: "foo" }]);
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [
|
|
{ url: "https://foo.com/", screenshot: EXISTING_SCREENSHOT },
|
|
]);
|
|
|
|
let result = await TopSites.getLinksWithDefaults();
|
|
|
|
Assert.equal(result[0].screenshot, EXISTING_SCREENSHOT);
|
|
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
}
|
|
);
|
|
|
|
add_task(
|
|
async function test_getLinksWithDefaults_no_searchTopSite_from_frecent() {
|
|
let sandbox = sinon.createSandbox();
|
|
info("getLinksWithDefaults should not set searchTopSite from frecent site");
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
const EXISTING_SCREENSHOT = "some-screenshot";
|
|
|
|
gGetTopSitesStub.resolves([
|
|
{
|
|
url: "https://foo.com/",
|
|
searchTopSite: true,
|
|
screenshot: EXISTING_SCREENSHOT,
|
|
},
|
|
]);
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [{ url: "https://foo.com/" }]);
|
|
|
|
let result = await TopSites.getLinksWithDefaults();
|
|
|
|
Assert.ok(!result[0].searchTopSite);
|
|
// But it should copy over other properties
|
|
Assert.equal(result[0].screenshot, EXISTING_SCREENSHOT);
|
|
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
}
|
|
);
|
|
|
|
add_task(async function test_getLinksWithDefaults_concurrency_getTopSites() {
|
|
let sandbox = sinon.createSandbox();
|
|
info(
|
|
"getLinksWithDefaults concurrent calls should call the backing data once"
|
|
);
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
NewTabUtils.activityStreamLinks.getTopSites.resetHistory();
|
|
|
|
await Promise.all([
|
|
TopSites.getLinksWithDefaults(),
|
|
TopSites.getLinksWithDefaults(),
|
|
]);
|
|
|
|
Assert.ok(
|
|
NewTabUtils.activityStreamLinks.getTopSites.calledOnce,
|
|
"getTopSites only called once"
|
|
);
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_deduping_no_dedupe_pinned() {
|
|
let sandbox = sinon.createSandbox();
|
|
info("getLinksWithDefaults should not dedupe pinned sites");
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults("https://foo.com");
|
|
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [
|
|
{ url: "https://developer.mozilla.org/en-US/docs/Web" },
|
|
{ url: "https://developer.mozilla.org/en-US/docs/Learn" },
|
|
]);
|
|
|
|
let sites = await TopSites.getLinksWithDefaults();
|
|
Assert.equal(sites.length, 2 * TOP_SITES_MAX_SITES_PER_ROW);
|
|
Assert.equal(sites[0].url, NewTabUtils.pinnedLinks.links[0].url);
|
|
Assert.equal(sites[1].url, NewTabUtils.pinnedLinks.links[1].url);
|
|
Assert.equal(sites[0].hostname, sites[1].hostname);
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_prefer_pinned_sites() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info("getLinksWithDefaults should prefer pinned sites over links");
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults();
|
|
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [
|
|
{ url: "https://developer.mozilla.org/en-US/docs/Web" },
|
|
{ url: "https://developer.mozilla.org/en-US/docs/Learn" },
|
|
]);
|
|
|
|
const SECOND_TOP_SITE_URL = "https://www.mozilla.org/";
|
|
|
|
gGetTopSitesStub.resolves([
|
|
{ frecency: FAKE_FRECENCY, url: "https://developer.mozilla.org/" },
|
|
{ frecency: FAKE_FRECENCY, url: SECOND_TOP_SITE_URL },
|
|
]);
|
|
|
|
let sites = await TopSites.getLinksWithDefaults();
|
|
|
|
// Expecting 3 links where there's 2 pinned and 1 www.mozilla.org, so
|
|
// the frecent with matching hostname as pinned is removed.
|
|
Assert.equal(sites.length, 3);
|
|
Assert.equal(sites[0].url, NewTabUtils.pinnedLinks.links[0].url);
|
|
Assert.equal(sites[1].url, NewTabUtils.pinnedLinks.links[1].url);
|
|
Assert.equal(sites[2].url, SECOND_TOP_SITE_URL);
|
|
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_title_and_null() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info("getLinksWithDefaults should return sites that have a title");
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults();
|
|
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [{ url: "https://github.com/mozilla/activity-stream" }]);
|
|
|
|
let sites = await TopSites.getLinksWithDefaults();
|
|
for (let site of sites) {
|
|
Assert.ok(site.hostname);
|
|
}
|
|
|
|
info("getLinksWithDefaults should not throw for null entries");
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "links").get(() => [null]);
|
|
await TopSites.getLinksWithDefaults();
|
|
Assert.ok(true, "getLinksWithDefaults didn't throw");
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_getLinksWithDefaults_calls__fetchIcon() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info("getLinksWithDefaults should return sites that have a title");
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
TopSites.refreshDefaults();
|
|
|
|
sandbox.spy(TopSites, "_fetchIcon");
|
|
let results = await TopSites.getLinksWithDefaults();
|
|
Assert.ok(results.length, "Got back some results");
|
|
Assert.equal(TopSites._fetchIcon.callCount, results.length);
|
|
for (let result of results) {
|
|
Assert.ok(TopSites._fetchIcon.calledWith(result));
|
|
}
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_init() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
sandbox.stub(NimbusFeatures.newtab, "onUpdate");
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
sandbox.stub(TopSites, "refresh");
|
|
await TopSites.init();
|
|
|
|
info("TopSites.init should call refresh");
|
|
Assert.ok(TopSites.refresh.calledOnce, "refresh called once");
|
|
Assert.ok(
|
|
TopSites.refresh.calledWithExactly({
|
|
isStartup: true,
|
|
})
|
|
);
|
|
|
|
TopSites.uninit();
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
/**
|
|
* If multiple callers are attempting to initializing TopSites, we should
|
|
* initialize only once and wait until its completed.
|
|
*/
|
|
add_task(async function test_multiple_init() {
|
|
info("Initing TopSites multiple times should call _readDefaults only once.");
|
|
let sandbox = sinon.createSandbox();
|
|
sandbox.stub(NimbusFeatures.newtab, "onUpdate");
|
|
sandbox.stub(TopSites, "_readDefaults");
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
Assert.ok(TopSites._readDefaults.notCalled, "Read defaults not called.");
|
|
for (let i = 0; i < 5; ++i) {
|
|
await TopSites.init();
|
|
}
|
|
Assert.ok(TopSites._readDefaults.calledOnce, "Read defaults called once.");
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_multiple_init_delay() {
|
|
TopSites.uninit();
|
|
|
|
info(
|
|
"Initing TopSites multiple times should allow callers " +
|
|
"only call readDefaults once and wait until its finished."
|
|
);
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
let resolvePromise;
|
|
let promise = new Promise(resolve => {
|
|
resolvePromise = resolve;
|
|
});
|
|
|
|
sandbox.stub(NimbusFeatures.newtab, "onUpdate");
|
|
sandbox.stub(TopSites, "_readDefaults").returns(promise);
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
Assert.ok(TopSites._readDefaults.notCalled, "Read defaults not called.");
|
|
let finishedPromiseCount = 0;
|
|
let promises = [];
|
|
let callInit = async () => {
|
|
await TopSites.init();
|
|
++finishedPromiseCount;
|
|
};
|
|
for (let i = 0; i < 5; ++i) {
|
|
promises.push(callInit());
|
|
}
|
|
Assert.equal(
|
|
finishedPromiseCount,
|
|
0,
|
|
"Finished promise count should be equal."
|
|
);
|
|
Assert.ok(TopSites._readDefaults.calledOnce, "Read defaults called once.");
|
|
|
|
info("Resolve the promises.");
|
|
resolvePromise();
|
|
await Promise.all(promises);
|
|
Assert.equal(
|
|
finishedPromiseCount,
|
|
5,
|
|
"Finished promise count should be equal."
|
|
);
|
|
Assert.ok(
|
|
TopSites._readDefaults.calledOnce,
|
|
"Read defaults was still only called once."
|
|
);
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_uninit() {
|
|
info("Un-initing TopSites should expire caches.");
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
sandbox.stub(TopSites, "refresh");
|
|
await TopSites.init();
|
|
|
|
sandbox.stub(TopSites.pinnedCache, "expire");
|
|
sandbox.stub(TopSites.frecentCache, "expire");
|
|
TopSites.uninit();
|
|
|
|
Assert.ok(
|
|
TopSites.pinnedCache.expire.calledOnce,
|
|
"pinnedCache.expire called once"
|
|
);
|
|
Assert.ok(
|
|
TopSites.frecentCache.expire.calledOnce,
|
|
"frecentCache.expire called once"
|
|
);
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_get_sites_init() {
|
|
info("TopSites.getSites should initialize TopSites if its not inited.");
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
sandbox.stub(TopSites, "init");
|
|
|
|
Assert.ok(TopSites.init.notCalled, "TopSites.init not called.");
|
|
await TopSites.getSites();
|
|
Assert.ok(TopSites.init.calledOnce, "TopSites.init called once.");
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_get_sites_already_inited() {
|
|
info(
|
|
"TopSites.getSites should not call related initialization methods " +
|
|
"more than once if TopSites is already inited."
|
|
);
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
sandbox.spy(TopSites, "_readDefaults");
|
|
await TopSites.init();
|
|
|
|
Assert.ok(
|
|
TopSites._readDefaults.calledOnce,
|
|
"TopSites._readDefaults called once."
|
|
);
|
|
Assert.ok(
|
|
TopSites.updateCustomSearchShortcuts.calledOnce,
|
|
"TopSites.updateCustomSearchShortcuts called once."
|
|
);
|
|
await TopSites.getSites();
|
|
Assert.ok(
|
|
TopSites._readDefaults.calledOnce,
|
|
"TopSites._readDefaults still only called once."
|
|
);
|
|
Assert.ok(
|
|
TopSites.updateCustomSearchShortcuts.calledOnce,
|
|
"TopSites.updateCustomSearchShortcuts still only called once."
|
|
);
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_get_sites_delayed_init() {
|
|
info("TopSites.getSites should wait until initialization is done.");
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
// Ensure it's not initialized.
|
|
TopSites.uninit();
|
|
|
|
let resolvePromise;
|
|
let promise = new Promise(resolve => {
|
|
resolvePromise = resolve;
|
|
});
|
|
sandbox.stub(TopSites, "init").returns(promise);
|
|
|
|
let promises = [];
|
|
let finishedPromiseCount = 0;
|
|
let callGetSites = async () => {
|
|
await TopSites.getSites();
|
|
finishedPromiseCount += 1;
|
|
};
|
|
for (let i = 0; i < 5; ++i) {
|
|
promises.push(callGetSites());
|
|
}
|
|
|
|
Assert.equal(
|
|
finishedPromiseCount,
|
|
0,
|
|
"All calls to TopSites.getSites() haven't finished."
|
|
);
|
|
resolvePromise();
|
|
await Promise.all(promises);
|
|
Assert.equal(
|
|
finishedPromiseCount,
|
|
5,
|
|
"All calls to TopSites.getSites() finished."
|
|
);
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_refresh() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
sandbox.stub(NimbusFeatures.newtab, "onUpdate");
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
sandbox.stub(TopSites, "_fetchIcon");
|
|
TopSites._startedUp = true;
|
|
|
|
info("TopSites.refresh should wait for tippytop to initialize");
|
|
TopSites._tippyTopProvider.initialized = false;
|
|
sandbox.stub(TopSites._tippyTopProvider, "init").resolves();
|
|
|
|
await TopSites.refresh();
|
|
|
|
Assert.ok(
|
|
TopSites._tippyTopProvider.init.calledOnce,
|
|
"TopSites._tippyTopProvider.init called once"
|
|
);
|
|
|
|
info(
|
|
"TopSites.refresh should not init the tippyTopProvider if already initialized"
|
|
);
|
|
TopSites._tippyTopProvider.initialized = true;
|
|
TopSites._tippyTopProvider.init.resetHistory();
|
|
|
|
await TopSites.refresh();
|
|
|
|
Assert.ok(
|
|
TopSites._tippyTopProvider.init.notCalled,
|
|
"tippyTopProvider not initted again"
|
|
);
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_refresh_updateTopSites() {
|
|
// Ensure that TopSites isn't already initialized.
|
|
TopSites.uninit();
|
|
|
|
let sandbox = sinon.createSandbox();
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
await TopSites.init();
|
|
TopSites._reset();
|
|
|
|
// Clear the internal store.
|
|
TopSites._reset();
|
|
|
|
let sites = await TopSites.getSites();
|
|
Assert.equal(sites.length, 0, "Sites is empty.");
|
|
|
|
info("TopSites.refresh should update TopSites.sites");
|
|
let promise = TestUtils.topicObserved("topsites-refreshed");
|
|
// TODO: On New Tab, subscribe to updates to Top Sites.
|
|
await TopSites.refresh({ isStartup: true });
|
|
await promise;
|
|
|
|
sites = await TopSites.getSites();
|
|
Assert.ok(sites.length, "Sites has values.");
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_refresh_dispatch() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info("TopSites.refresh should dispatch an action with the links returned");
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
sandbox.stub(TopSites, "_fetchIcon");
|
|
TopSites._startedUp = true;
|
|
|
|
await TopSites.refresh();
|
|
let reference = FAKE_LINKS.map(site =>
|
|
Object.assign({}, site, {
|
|
hostname: NewTabUtils.shortURL(site),
|
|
typedBonus: true,
|
|
})
|
|
);
|
|
|
|
// TODO: On New Tab, subscribe to updates to Top Sites.
|
|
let sites = await TopSites.getSites();
|
|
Assert.deepEqual(sites, reference, "Sites are updated.");
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_refresh_empty_slots() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info(
|
|
"TopSites.refresh should handle empty slots in the resulting top sites array"
|
|
);
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
sandbox.stub(TopSites, "_fetchIcon");
|
|
TopSites._startedUp = true;
|
|
|
|
gGetTopSitesStub.resolves([FAKE_LINKS[0]]);
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [
|
|
null,
|
|
null,
|
|
FAKE_LINKS[1],
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
FAKE_LINKS[2],
|
|
]);
|
|
await TopSites.refresh();
|
|
|
|
let reference = FAKE_LINKS.map(site =>
|
|
Object.assign({}, site, {
|
|
hostname: NewTabUtils.shortURL(site),
|
|
typedBonus: true,
|
|
})
|
|
);
|
|
const expected = [
|
|
reference[0],
|
|
null,
|
|
createExpectedPinnedLink(reference[1], 2),
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
createExpectedPinnedLink(reference[2], 8),
|
|
];
|
|
|
|
// TODO: On New Tab, subscribe to updates to Top Sites.
|
|
let sites = await TopSites.getSites();
|
|
assertLinks(sites, expected);
|
|
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_insert_part_2() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info(
|
|
"TopSites.handlePlacesEvents should call refresh without a target " +
|
|
"if we clear history."
|
|
);
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
sandbox.stub(TopSites, "refresh");
|
|
TopSites.refresh.resetHistory();
|
|
await PlacesUtils.history.clear();
|
|
Assert.ok(TopSites.refresh.calledOnce, "TopSites.refresh called once");
|
|
|
|
TopSites.refresh.resetHistory();
|
|
|
|
info(
|
|
"TopSites.handlePlacesEvents should call refresh without a target " +
|
|
"if we remove a Topsite from history"
|
|
);
|
|
let uri = Services.io.newURI("https://www.example.com/");
|
|
await PlacesTestUtils.addVisits({
|
|
uri,
|
|
transition: PlacesUtils.history.TRANSITION_TYPED,
|
|
visitDate: Date.now() * 1000,
|
|
});
|
|
Assert.ok(TopSites.refresh.notCalled, "TopSites.refresh not called");
|
|
await PlacesUtils.history.remove(uri);
|
|
|
|
Assert.ok(TopSites.refresh.calledOnce, "TopSites.refresh called once");
|
|
|
|
info("TopSites.handlePlacesEvents should call refresh on newtab-linkBlocked");
|
|
TopSites.refresh.resetHistory();
|
|
// The event dispatched in NewTabUtils when a link is blocked;
|
|
TopSites.observe(null, "newtab-linkBlocked", null);
|
|
Assert.ok(TopSites.refresh.calledOnce, "TopSites.refresh called once");
|
|
|
|
info("TopSites should call refresh on bookmark-added");
|
|
TopSites.refresh.resetHistory();
|
|
let bookmark = await PlacesUtils.bookmarks.insert({
|
|
url: "https://bookmark.example.com",
|
|
title: "Bookmark 1",
|
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
|
});
|
|
Assert.ok(TopSites.refresh.calledOnce, "TopSites.refresh called once");
|
|
|
|
info("TopSites should call refresh on bookmark-removed");
|
|
TopSites.refresh.resetHistory();
|
|
await PlacesUtils.bookmarks.remove(bookmark);
|
|
Assert.ok(TopSites.refresh.calledOnce, "TopSites.refresh called once");
|
|
|
|
info(
|
|
"TopSites.insert should call pin with correct args " +
|
|
"without an index specified"
|
|
);
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "pin");
|
|
|
|
let addAction = {
|
|
data: { site: { url: "foo.bar", label: "foo" } },
|
|
};
|
|
TopSites.insert(addAction);
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledOnce,
|
|
"NewTabUtils.pinnedLinks.pin called once"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(addAction.data.site, 0));
|
|
|
|
info("TopSites.insert should call pin with correct args");
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
let dropAction = {
|
|
data: { site: { url: "foo.bar", label: "foo" }, index: 3 },
|
|
};
|
|
TopSites.insert(dropAction);
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledOnce,
|
|
"NewTabUtils.pinnedLinks.pin called once"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(dropAction.data.site, 3));
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_insert_part_1() {
|
|
let sandbox = sinon.createSandbox();
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "pin");
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
{
|
|
info(
|
|
"TopSites.insert should pin site in first slot of pinned list with " +
|
|
"empty first slot"
|
|
);
|
|
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [null, { url: "example.com" }]);
|
|
let site = { url: "foo.bar", label: "foo" };
|
|
await TopSites.insert({ data: { site } });
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledOnce,
|
|
"NewTabUtils.pinnedLinks.pin called once"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site, 0));
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.insert should move a pinned site in first slot to the " +
|
|
"next slot: part 1"
|
|
);
|
|
let site1 = { url: "example.com" };
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "links").get(() => [site1]);
|
|
let site = { url: "foo.bar", label: "foo" };
|
|
|
|
await TopSites.insert({ data: { site } });
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledTwice,
|
|
"NewTabUtils.pinnedLinks.pin called twice"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site, 0));
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site1, 1));
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.insert should move a pinned site in first slot to the " +
|
|
"next slot: part 2"
|
|
);
|
|
let site1 = { url: "example.com" };
|
|
let site2 = { url: "example.org" };
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [site1, null, site2]);
|
|
let site = { url: "foo.bar", label: "foo" };
|
|
await TopSites.insert({ data: { site } });
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledTwice,
|
|
"NewTabUtils.pinnedLinks.pin called twice"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site, 0));
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site1, 1));
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
}
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_insert_part_2() {
|
|
let sandbox = sinon.createSandbox();
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "pin");
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
{
|
|
info(
|
|
"TopSites.insert should unpin the last site if all slots are " +
|
|
"already pinned"
|
|
);
|
|
let site1 = { url: "example.com" };
|
|
let site2 = { url: "example.org" };
|
|
let site3 = { url: "example.net" };
|
|
let site4 = { url: "example.biz" };
|
|
let site5 = { url: "example.info" };
|
|
let site6 = { url: "example.news" };
|
|
let site7 = { url: "example.lol" };
|
|
let site8 = { url: "example.golf" };
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [site1, site2, site3, site4, site5, site6, site7, site8]);
|
|
Services.prefs.setIntPref(
|
|
"browser.newtabpage.activity-stream.topSitesRows",
|
|
1
|
|
);
|
|
let site = { url: "foo.bar", label: "foo" };
|
|
await TopSites.insert({ data: { site } });
|
|
Assert.equal(
|
|
NewTabUtils.pinnedLinks.pin.callCount,
|
|
8,
|
|
"NewTabUtils.pinnedLinks.pin called 8 times"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site, 0));
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site1, 1));
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site2, 2));
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site3, 3));
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site4, 4));
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site5, 5));
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site6, 6));
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site7, 7));
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.topSitesRows"
|
|
);
|
|
}
|
|
|
|
{
|
|
info("TopSites.insert should trigger refresh");
|
|
sandbox.stub(TopSites, "refresh");
|
|
let addAction = {
|
|
data: { site: { url: "foo.com" } },
|
|
};
|
|
|
|
await TopSites.insert(addAction);
|
|
|
|
Assert.ok(TopSites.refresh.calledOnce, "TopSites.refresh called once");
|
|
}
|
|
|
|
{
|
|
info("TopSites.insert should correctly handle different index values");
|
|
let index = -1;
|
|
let site = { url: "foo.bar", label: "foo" };
|
|
let action = { data: { index, site } };
|
|
|
|
await TopSites.insert(action);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site, 0));
|
|
|
|
index = undefined;
|
|
await TopSites.insert(action);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site, 0));
|
|
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
}
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_insert_part_3() {
|
|
let sandbox = sinon.createSandbox();
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "pin");
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
{
|
|
info("TopSites.insert should pin site in specified slot that is free");
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [null, { url: "example.com" }]);
|
|
|
|
let site = { url: "foo.bar", label: "foo" };
|
|
|
|
await TopSites.insert({ data: { index: 2, site, draggedFromIndex: 0 } });
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledOnce,
|
|
"NewTabUtils.pinnedLinks.pin called once"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site, 2));
|
|
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.insert should move a pinned site in specified slot " +
|
|
"to the next slot"
|
|
);
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [null, null, { url: "example.com" }]);
|
|
|
|
let site = { url: "foo.bar", label: "foo" };
|
|
|
|
await TopSites.insert({ data: { index: 2, site, draggedFromIndex: 3 } });
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledTwice,
|
|
"NewTabUtils.pinnedLinks.pin called twice"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site, 2));
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledWith({ url: "example.com" }, 3)
|
|
);
|
|
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.insert should move pinned sites in the direction " +
|
|
"of the dragged site"
|
|
);
|
|
|
|
let site1 = { url: "foo.bar", label: "foo" };
|
|
let site2 = { url: "example.com", label: "example" };
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [null, null, site2]);
|
|
|
|
await TopSites.insert({
|
|
data: { index: 2, site: site1, draggedFromIndex: 0 },
|
|
});
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledTwice,
|
|
"NewTabUtils.pinnedLinks.pin called twice"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site1, 2));
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site2, 1));
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
|
|
await TopSites.insert({
|
|
data: { index: 2, site: site1, draggedFromIndex: 5 },
|
|
});
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledTwice,
|
|
"NewTabUtils.pinnedLinks.pin called twice"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site1, 2));
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site2, 3));
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
}
|
|
|
|
{
|
|
info("TopSites.insert should not insert past the visible top sites");
|
|
let site1 = { url: "foo.bar", label: "foo" };
|
|
await TopSites.insert({
|
|
data: { index: 42, site: site1, draggedFromIndex: 0 },
|
|
});
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.notCalled,
|
|
"NewTabUtils.pinnedLinks.pin wasn't called"
|
|
);
|
|
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
}
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_pin_part_1() {
|
|
let sandbox = sinon.createSandbox();
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "pin");
|
|
sandbox.spy(TopSites.pinnedCache, "request");
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
{
|
|
info("TopSites.pin should pin site in specified slot empty pinned list");
|
|
let site = {
|
|
url: "foo.bar",
|
|
label: "foo",
|
|
};
|
|
Assert.ok(
|
|
TopSites.pinnedCache.request.notCalled,
|
|
"TopSites.pinnedCache.request not called"
|
|
);
|
|
await TopSites.pin({ data: { index: 2, site } });
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.called,
|
|
"NewTabUtils.pinnedLinks.pin called"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site, 2));
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
TopSites.pinnedCache.request.resetHistory();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.pin should not do a link object lookup if custom " +
|
|
"screenshot field is not set"
|
|
);
|
|
let site = { url: "foo.bar", label: "foo" };
|
|
await TopSites.pin({ data: { index: 2, site } });
|
|
Assert.ok(
|
|
!TopSites.pinnedCache.request.called,
|
|
"TopSites.pinnedCache.request never called"
|
|
);
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
TopSites.pinnedCache.request.resetHistory();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.pin should pin site in specified slot of pinned " +
|
|
"list that is free"
|
|
);
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [null, { url: "example.com" }]);
|
|
|
|
let site = { url: "foo.bar", label: "foo" };
|
|
await TopSites.pin({ data: { index: 2, site } });
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledOnce,
|
|
"NewTabUtils.pinnedLinks.pin called once"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site, 2));
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
}
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_pin_part_2() {
|
|
let sandbox = sinon.createSandbox();
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "pin");
|
|
|
|
{
|
|
info("TopSites.pin should save the searchTopSite attribute if set");
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [null, { url: "example.com" }]);
|
|
|
|
let site = { url: "foo.bar", label: "foo", searchTopSite: true };
|
|
let cleanup = stubTopSites(sandbox);
|
|
await TopSites.pin({ data: { index: 2, site } });
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledOnce,
|
|
"NewTabUtils.pinnedLinks.pin called once"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.firstCall.args[0].searchTopSite);
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.pin should NOT move a pinned site in specified " +
|
|
"slot to the next slot"
|
|
);
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [null, null, { url: "example.com" }]);
|
|
|
|
let site = { url: "foo.bar", label: "foo" };
|
|
let cleanup = stubTopSites(sandbox);
|
|
await TopSites.pin({ data: { index: 2, site } });
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledOnce,
|
|
"NewTabUtils.pinnedLinks.pin called once"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.pin.calledWith(site, 2));
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.pin should not update LinksCache object with screenshot data" +
|
|
"properties between migrations"
|
|
);
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [{ url: "https://foo.com/" }]);
|
|
|
|
let cleanup = stubTopSites(sandbox);
|
|
let pinnedLinks = await TopSites.pinnedCache.request();
|
|
Assert.equal(pinnedLinks.length, 1);
|
|
TopSites.pinnedCache.expire();
|
|
|
|
pinnedLinks[0].__sharedCache.updateLink("screenshot", "foo");
|
|
|
|
pinnedLinks = await TopSites.pinnedCache.request();
|
|
Assert.equal(pinnedLinks[0].screenshot, undefined);
|
|
|
|
// Force cache expiration in order to trigger a migration of objects
|
|
TopSites.pinnedCache.expire();
|
|
pinnedLinks[0].__sharedCache.updateLink("screenshot", "bar");
|
|
|
|
pinnedLinks = await TopSites.pinnedCache.request();
|
|
Assert.equal(pinnedLinks[0].screenshot, undefined);
|
|
await cleanup();
|
|
}
|
|
|
|
sandbox.restore();
|
|
});
|
|
|
|
add_task(async function test_pin_part_3() {
|
|
let sandbox = sinon.createSandbox();
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "pin");
|
|
sandbox.spy(TopSites, "insert");
|
|
|
|
{
|
|
info("TopSites.pin should call insert if index < 0");
|
|
let site = { url: "foo.bar", label: "foo" };
|
|
let action = { data: { index: -1, site } };
|
|
let cleanup = stubTopSites(sandbox);
|
|
await TopSites.pin(action);
|
|
|
|
Assert.ok(TopSites.insert.calledOnce, "TopSites.insert called once");
|
|
Assert.ok(TopSites.insert.calledWithExactly(action));
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
TopSites.insert.resetHistory();
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info("TopSites.pin should not call insert if index == 0");
|
|
let site = { url: "foo.bar", label: "foo" };
|
|
let action = { data: { index: 0, site } };
|
|
let cleanup = stubTopSites(sandbox);
|
|
await TopSites.pin(action);
|
|
|
|
Assert.ok(!TopSites.insert.called, "TopSites.insert not called");
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info("TopSites.pin should trigger refresh");
|
|
let cleanup = stubTopSites(sandbox);
|
|
sandbox.stub(TopSites, "refresh");
|
|
let pinExistingAction = {
|
|
data: { site: FAKE_LINKS[4], index: 4 },
|
|
};
|
|
|
|
await TopSites.pin(pinExistingAction);
|
|
|
|
Assert.ok(TopSites.refresh.calledOnce, "TopSites.refresh called once");
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
await cleanup();
|
|
}
|
|
|
|
sandbox.restore();
|
|
});
|
|
|
|
add_task(async function test_pin_part_4() {
|
|
let sandbox = sinon.createSandbox();
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
info("TopSites.pin should call with correct parameters");
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "pin");
|
|
sandbox.spy(TopSites, "pin");
|
|
|
|
let pinAction = {
|
|
data: { site: { url: "foo.com" }, index: 7 },
|
|
};
|
|
await TopSites.pin(pinAction);
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledOnce,
|
|
"NewTabUtils.pinnedLinks.pin called once"
|
|
);
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledWithExactly(
|
|
pinAction.data.site,
|
|
pinAction.data.index
|
|
)
|
|
);
|
|
Assert.ok(
|
|
TopSites.pin.calledOnce,
|
|
"TopSites.pin should have been called once"
|
|
);
|
|
|
|
info(
|
|
"TopSites.pin should unblock a previously blocked top site if " +
|
|
"we are now adding it manually via 'Add a Top Site' option"
|
|
);
|
|
sandbox.stub(NewTabUtils.blockedLinks, "unblock");
|
|
pinAction = {
|
|
data: { site: { url: "foo.com" }, index: -1 },
|
|
};
|
|
await TopSites.pin(pinAction);
|
|
Assert.ok(
|
|
NewTabUtils.blockedLinks.unblock.calledWith({
|
|
url: pinAction.data.site.url,
|
|
})
|
|
);
|
|
|
|
info("TopSites.pin should call insert");
|
|
sandbox.stub(TopSites, "insert");
|
|
let addAction = {
|
|
data: { site: { url: "foo.com" } },
|
|
};
|
|
|
|
await TopSites.pin(addAction);
|
|
Assert.ok(TopSites.insert.calledOnce, "TopSites.insert called once");
|
|
|
|
info("TopSites.unpin should call unpin with correct parameters");
|
|
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [
|
|
null,
|
|
null,
|
|
{ url: "foo.com" },
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
FAKE_LINKS[0],
|
|
]);
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "unpin");
|
|
|
|
let unpinAction = {
|
|
data: { site: { url: "foo.com" } },
|
|
};
|
|
await TopSites.unpin(unpinAction);
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.unpin.calledOnce,
|
|
"NewTabUtils.pinnedLinks.unpin called once"
|
|
);
|
|
Assert.ok(NewTabUtils.pinnedLinks.unpin.calledWith(unpinAction.data.site));
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_integration() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
info("Test adding a pinned site and removing it with actions");
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
TopSites._startedUp = true;
|
|
|
|
TopSites._requestRichIcon = sandbox.stub();
|
|
let url = "https://pin.me";
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "pin").callsFake(link => {
|
|
NewTabUtils.pinnedLinks.links.push(link);
|
|
});
|
|
|
|
await TopSites.insert({ data: { site: { url } } });
|
|
await TestUtils.topicObserved("topsites-refreshed");
|
|
let oldSites = await TopSites.getSites();
|
|
NewTabUtils.pinnedLinks.links.pop();
|
|
// The event dispatched in NewTabUtils when a link is blocked;
|
|
TopSites.observe(null, "newtab-linkBlocked", null);
|
|
await TestUtils.topicObserved("topsites-refreshed");
|
|
let newSites = await TopSites.getSites();
|
|
|
|
Assert.equal(oldSites[0].url, url, "Url matches.");
|
|
Assert.equal(newSites[0].url, FAKE_LINKS[0].url, "Url matches.");
|
|
|
|
sandbox.restore();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_improvesearch_noDefaultSearchTile_experiment() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
sandbox.stub(SearchService.prototype, "getDefault").resolves({
|
|
identifier: "google",
|
|
});
|
|
|
|
{
|
|
info(
|
|
"TopSites.getLinksWithDefaults should filter out alexa top 5 " +
|
|
"search from the default sites"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile",
|
|
true
|
|
);
|
|
let top5Test = [
|
|
"https://google.com",
|
|
"https://search.yahoo.com",
|
|
"https://yahoo.com",
|
|
"https://bing.com",
|
|
"https://ask.com",
|
|
"https://duckduckgo.com",
|
|
];
|
|
|
|
gGetTopSitesStub.resolves([
|
|
{ url: "https://amazon.com" },
|
|
...top5Test.map(url => ({ url })),
|
|
]);
|
|
|
|
const urlsReturned = (await TopSites.getLinksWithDefaults()).map(
|
|
link => link.url
|
|
);
|
|
Assert.ok(
|
|
urlsReturned.includes("https://amazon.com"),
|
|
"amazon included in default links"
|
|
);
|
|
top5Test.forEach(url =>
|
|
Assert.ok(!urlsReturned.includes(url), `Should not include ${url}`)
|
|
);
|
|
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile"
|
|
);
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.getLinksWithDefaults should not filter out alexa, default " +
|
|
"search from the query results if the experiment pref is off"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile",
|
|
false
|
|
);
|
|
gGetTopSitesStub.resolves([
|
|
{ url: "https://google.com" },
|
|
{ url: "https://foo.com" },
|
|
{ url: "https://duckduckgo" },
|
|
]);
|
|
let urlsReturned = (await TopSites.getLinksWithDefaults()).map(
|
|
link => link.url
|
|
);
|
|
|
|
Assert.ok(urlsReturned.includes("https://google.com"));
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile"
|
|
);
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.getLinksWithDefaults should filter out the current " +
|
|
"default search from the default sites"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile",
|
|
true
|
|
);
|
|
|
|
sandbox.stub(TopSites, "_currentSearchHostname").get(() => "amazon");
|
|
Services.prefs.setStringPref(
|
|
"browser.newtabpage.activity-stream.default.sites",
|
|
"https://google.com,https://amazon.com"
|
|
);
|
|
gGetTopSitesStub.resolves([{ url: "https://foo.com" }]);
|
|
|
|
let urlsReturned = (await TopSites.getLinksWithDefaults()).map(
|
|
link => link.url
|
|
);
|
|
Assert.ok(!urlsReturned.includes("https://amazon.com"));
|
|
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile"
|
|
);
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.default.sites"
|
|
);
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.getLinksWithDefaults should not filter out current " +
|
|
"default search from pinned sites even if it matches the current " +
|
|
"default search"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile",
|
|
true
|
|
);
|
|
|
|
sandbox
|
|
.stub(NewTabUtils.pinnedLinks, "links")
|
|
.get(() => [{ url: "google.com" }]);
|
|
gGetTopSitesStub.resolves([{ url: "https://foo.com" }]);
|
|
|
|
let urlsReturned = (await TopSites.getLinksWithDefaults()).map(
|
|
link => link.url
|
|
);
|
|
Assert.ok(urlsReturned.includes("google.com"));
|
|
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile"
|
|
);
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
await cleanup();
|
|
}
|
|
|
|
sandbox.restore();
|
|
});
|
|
|
|
add_task(
|
|
async function test_improvesearch_noDefaultSearchTile_experiment_part_2() {
|
|
let sandbox = sinon.createSandbox();
|
|
|
|
sandbox.stub(SearchService.prototype, "getDefault").resolves({
|
|
identifier: "google",
|
|
});
|
|
|
|
sandbox.stub(TopSites, "refresh");
|
|
|
|
{
|
|
info(
|
|
"TopSites.getLinksWithDefaults should call refresh and set " +
|
|
"._currentSearchHostname to the new engine hostname when the " +
|
|
"default search engine has been set"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile",
|
|
true
|
|
);
|
|
|
|
TopSites.observe(
|
|
null,
|
|
"browser-search-engine-modified",
|
|
"engine-default"
|
|
);
|
|
Assert.equal(TopSites._currentSearchHostname, "duckduckgo");
|
|
// Refresh is called twice:
|
|
// 1) For the change of `noDefaultSearchTile`
|
|
// 2) Default search engine changed "browser-search-engine-modified"
|
|
Assert.ok(TopSites.refresh.calledTwice, "TopSites.refresh called twice");
|
|
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile"
|
|
);
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
TopSites.refresh.resetHistory();
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.getLinksWithDefaults should call refresh when the " +
|
|
"experiment pref has changed"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile",
|
|
true
|
|
);
|
|
Assert.ok(
|
|
TopSites.refresh.calledOnce,
|
|
"TopSites.refresh was called once"
|
|
);
|
|
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile",
|
|
false
|
|
);
|
|
Assert.ok(
|
|
TopSites.refresh.calledTwice,
|
|
"TopSites.refresh was called twice"
|
|
);
|
|
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile"
|
|
);
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
TopSites.refresh.resetHistory();
|
|
await cleanup();
|
|
}
|
|
|
|
sandbox.restore();
|
|
}
|
|
);
|
|
|
|
// eslint-disable-next-line max-statements
|
|
add_task(async function test_improvesearch_topSitesSearchShortcuts() {
|
|
let sandbox = sinon.createSandbox();
|
|
let searchEngines = [{ aliases: ["@google"] }, { aliases: ["@amazon"] }];
|
|
sandbox
|
|
.stub(SearchService.prototype, "getAppProvidedEngines")
|
|
.resolves(searchEngines);
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "pin").callsFake((site, index) => {
|
|
NewTabUtils.pinnedLinks.links[index] = site;
|
|
});
|
|
|
|
let prepTopSites = () => {
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts",
|
|
true
|
|
);
|
|
Services.prefs.setStringPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts.searchEngines",
|
|
"google,amazon"
|
|
);
|
|
Services.prefs.setStringPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts.havePinned",
|
|
""
|
|
);
|
|
};
|
|
|
|
{
|
|
info(
|
|
"TopSites should updateCustomSearchShortcuts when experiment " +
|
|
"pref is turned on"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
prepTopSites();
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts",
|
|
false
|
|
);
|
|
// stubTopSites stubs updateCustomSearchShortcuts, when we need to add
|
|
// a spy.
|
|
TopSites.updateCustomSearchShortcuts.restore();
|
|
sandbox.spy(TopSites, "updateCustomSearchShortcuts");
|
|
|
|
// turn the experiment on
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts",
|
|
true
|
|
);
|
|
|
|
Assert.ok(
|
|
TopSites.updateCustomSearchShortcuts.calledOnce,
|
|
"TopSites.updateCustomSearchShortcuts called once"
|
|
);
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts"
|
|
);
|
|
TopSites.updateCustomSearchShortcuts.restore();
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites should filter out default top sites that match a " +
|
|
"hostname of a search shortcut if previously blocked"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
prepTopSites();
|
|
TopSites.refreshDefaults("https://amazon.ca");
|
|
sandbox
|
|
.stub(NewTabUtils.blockedLinks, "links")
|
|
.value([{ url: "https://amazon.com" }]);
|
|
sandbox.stub(NewTabUtils.blockedLinks, "isBlocked").callsFake(site => {
|
|
return NewTabUtils.blockedLinks.links[0].url === site.url;
|
|
});
|
|
|
|
let urlsReturned = (await TopSites.getLinksWithDefaults()).map(
|
|
link => link.url
|
|
);
|
|
Assert.ok(!urlsReturned.includes("https://amazon.ca"));
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info("TopSites should update frecent search topsite icon");
|
|
let cleanup = stubTopSites(sandbox);
|
|
prepTopSites();
|
|
sandbox.stub(TopSites._tippyTopProvider, "processSite").callsFake(site => {
|
|
site.tippyTopIcon = "icon.png";
|
|
site.backgroundColor = "#fff";
|
|
return site;
|
|
});
|
|
gGetTopSitesStub.resolves([{ url: "https://google.com" }]);
|
|
|
|
let urlsReturned = await TopSites.getLinksWithDefaults();
|
|
|
|
let defaultSearchTopsite = urlsReturned.find(
|
|
s => s.url === "https://google.com"
|
|
);
|
|
Assert.ok(defaultSearchTopsite.searchTopSite);
|
|
Assert.equal(defaultSearchTopsite.tippyTopIcon, "icon.png");
|
|
Assert.equal(defaultSearchTopsite.backgroundColor, "#fff");
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
TopSites._tippyTopProvider.processSite.restore();
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info("TopSites should update default search topsite icon");
|
|
let cleanup = stubTopSites(sandbox);
|
|
prepTopSites();
|
|
sandbox.stub(TopSites._tippyTopProvider, "processSite").callsFake(site => {
|
|
site.tippyTopIcon = "icon.png";
|
|
site.backgroundColor = "#fff";
|
|
return site;
|
|
});
|
|
gGetTopSitesStub.resolves([{ url: "https://foo.com" }]);
|
|
|
|
let urlsReturned = await TopSites.getLinksWithDefaults();
|
|
|
|
let defaultSearchTopsite = urlsReturned.find(
|
|
s => s.url === "https://amazon.com"
|
|
);
|
|
Assert.ok(defaultSearchTopsite.searchTopSite);
|
|
Assert.equal(defaultSearchTopsite.tippyTopIcon, "icon.png");
|
|
Assert.equal(defaultSearchTopsite.backgroundColor, "#fff");
|
|
gGetTopSitesStub.resolves(FAKE_LINKS);
|
|
TopSites._tippyTopProvider.processSite.restore();
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites should dispatch UPDATE_SEARCH_SHORTCUTS on " +
|
|
"updateCustomSearchShortcuts"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
prepTopSites();
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.noDefaultSearchTile",
|
|
true
|
|
);
|
|
// stubTopSites stubs updateCustomSearchShortcuts, when in this case, we
|
|
// want to check the effect of the method.
|
|
TopSites.updateCustomSearchShortcuts.restore();
|
|
await TopSites.updateCustomSearchShortcuts();
|
|
let searchShortcuts = await TopSites.getSearchShortcuts();
|
|
Assert.deepEqual(searchShortcuts, [
|
|
{
|
|
keyword: "@google",
|
|
shortURL: "google",
|
|
url: "https://google.com",
|
|
backgroundColor: undefined,
|
|
smallFavicon:
|
|
"chrome://activity-stream/content/data/content/tippytop/favicons/google-com.ico",
|
|
tippyTopIcon:
|
|
"chrome://activity-stream/content/data/content/tippytop/images/google-com@2x.png",
|
|
},
|
|
{
|
|
keyword: "@amazon",
|
|
shortURL: "amazon",
|
|
url: "https://amazon.com",
|
|
backgroundColor: undefined,
|
|
smallFavicon:
|
|
"chrome://activity-stream/content/data/content/tippytop/favicons/amazon.ico",
|
|
tippyTopIcon:
|
|
"chrome://activity-stream/content/data/content/tippytop/images/amazon@2x.png",
|
|
},
|
|
]);
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites should refresh when top sites search shortcut feature gate pref changes."
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
prepTopSites();
|
|
|
|
let promise = TestUtils.topicObserved("topsites-refreshed");
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts",
|
|
false
|
|
);
|
|
await promise;
|
|
|
|
let sites = await TopSites.getSites();
|
|
let searchTopSiteCount = sites.reduce(
|
|
(acc, current) => (current.searchTopSite ? 1 : 0 + acc),
|
|
0
|
|
);
|
|
Assert.equal(searchTopSiteCount, 0, "Number of search top sites.");
|
|
|
|
promise = TestUtils.topicObserved("topsites-refreshed");
|
|
Services.prefs.setBoolPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts",
|
|
true
|
|
);
|
|
await promise;
|
|
sites = await TopSites.getSites();
|
|
searchTopSiteCount = sites.reduce(
|
|
(acc, current) => acc + (current.searchTopSite ? 1 : 0),
|
|
0
|
|
);
|
|
Assert.equal(searchTopSiteCount, 2, "Number of search top sites.");
|
|
await cleanup();
|
|
}
|
|
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts"
|
|
);
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts.searchEngines"
|
|
);
|
|
Services.prefs.clearUserPref(
|
|
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts.havePinned"
|
|
);
|
|
sandbox.restore();
|
|
});
|
|
|
|
add_task(async function test_updatePinnedSearchShortcuts() {
|
|
let sandbox = sinon.createSandbox();
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "pin");
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "unpin");
|
|
|
|
{
|
|
info(
|
|
"TopSites.updatePinnedSearchShortcuts should unpin a " +
|
|
"shortcut in deletedShortcuts"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
let deletedShortcuts = [
|
|
{
|
|
url: "https://google.com",
|
|
searchVendor: "google",
|
|
label: "google",
|
|
searchTopSite: true,
|
|
},
|
|
];
|
|
let addedShortcuts = [];
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "links").get(() => [
|
|
null,
|
|
null,
|
|
{
|
|
url: "https://amazon.com",
|
|
searchVendor: "amazon",
|
|
label: "amazon",
|
|
searchTopSite: true,
|
|
},
|
|
]);
|
|
TopSites.updatePinnedSearchShortcuts({ addedShortcuts, deletedShortcuts });
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.notCalled,
|
|
"NewTabUtils.pinnedLinks.pin not called"
|
|
);
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.unpin.calledOnce,
|
|
"NewTabUtils.pinnedLinks.unpin called once"
|
|
);
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.unpin.calledWith({
|
|
url: "https://google.com",
|
|
})
|
|
);
|
|
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
NewTabUtils.pinnedLinks.unpin.resetHistory();
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.updatePinnedSearchShortcuts should pin a shortcut " +
|
|
"in addedShortcuts"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
let addedShortcuts = [
|
|
{
|
|
url: "https://google.com",
|
|
searchVendor: "google",
|
|
label: "google",
|
|
searchTopSite: true,
|
|
},
|
|
];
|
|
let deletedShortcuts = [];
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "links").get(() => [
|
|
null,
|
|
null,
|
|
{
|
|
url: "https://amazon.com",
|
|
searchVendor: "amazon",
|
|
label: "amazon",
|
|
searchTopSite: true,
|
|
},
|
|
]);
|
|
TopSites.updatePinnedSearchShortcuts({ addedShortcuts, deletedShortcuts });
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.unpin.notCalled,
|
|
"NewTabUtils.pinnedLinks.unpin not called"
|
|
);
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledOnce,
|
|
"NewTabUtils.pinnedLinks.pin called once"
|
|
);
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledWith(
|
|
{
|
|
label: "google",
|
|
searchTopSite: true,
|
|
searchVendor: "google",
|
|
url: "https://google.com",
|
|
},
|
|
0
|
|
)
|
|
);
|
|
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
NewTabUtils.pinnedLinks.unpin.resetHistory();
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.updatePinnedSearchShortcuts should pin and unpin " +
|
|
"in the same action"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
let addedShortcuts = [
|
|
{
|
|
url: "https://google.com",
|
|
searchVendor: "google",
|
|
label: "google",
|
|
searchTopSite: true,
|
|
},
|
|
{
|
|
url: "https://ebay.com",
|
|
searchVendor: "ebay",
|
|
label: "ebay",
|
|
searchTopSite: true,
|
|
},
|
|
];
|
|
let deletedShortcuts = [
|
|
{
|
|
url: "https://amazon.com",
|
|
searchVendor: "amazon",
|
|
label: "amazon",
|
|
searchTopSite: true,
|
|
},
|
|
];
|
|
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "links").get(() => [
|
|
{ url: "https://foo.com" },
|
|
{
|
|
url: "https://amazon.com",
|
|
searchVendor: "amazon",
|
|
label: "amazon",
|
|
searchTopSite: true,
|
|
},
|
|
]);
|
|
TopSites.updatePinnedSearchShortcuts({ addedShortcuts, deletedShortcuts });
|
|
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.unpin.calledOnce,
|
|
"NewTabUtils.pinnedLinks.unpin called once"
|
|
);
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledTwice,
|
|
"NewTabUtils.pinnedLinks.pin called twice"
|
|
);
|
|
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
NewTabUtils.pinnedLinks.unpin.resetHistory();
|
|
await cleanup();
|
|
}
|
|
|
|
{
|
|
info(
|
|
"TopSites.updatePinnedSearchShortcuts should pin a shortcut in " +
|
|
"addedShortcuts even if pinnedLinks is full"
|
|
);
|
|
let cleanup = stubTopSites(sandbox);
|
|
|
|
let addedShortcuts = [
|
|
{
|
|
url: "https://google.com",
|
|
searchVendor: "google",
|
|
label: "google",
|
|
searchTopSite: true,
|
|
},
|
|
];
|
|
let deletedShortcuts = [];
|
|
sandbox.stub(NewTabUtils.pinnedLinks, "links").get(() => FAKE_LINKS);
|
|
TopSites.updatePinnedSearchShortcuts({ addedShortcuts, deletedShortcuts });
|
|
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.unpin.notCalled,
|
|
"NewTabUtils.pinnedLinks.unpin not called"
|
|
);
|
|
Assert.ok(
|
|
NewTabUtils.pinnedLinks.pin.calledWith(
|
|
{ label: "google", searchTopSite: true, url: "https://google.com" },
|
|
0
|
|
),
|
|
"NewTabUtils.pinnedLinks.unpin not called"
|
|
);
|
|
|
|
NewTabUtils.pinnedLinks.pin.resetHistory();
|
|
NewTabUtils.pinnedLinks.unpin.resetHistory();
|
|
await cleanup();
|
|
}
|
|
|
|
sandbox.restore();
|
|
});
|
|
|
|
add_task(async function test_insertPinned() {
|
|
info("#insertPinned");
|
|
|
|
function createLinks(count) {
|
|
return new Array(count).fill(null).map((v, i) => ({ url: `site${i}.com` }));
|
|
}
|
|
|
|
info("should place pinned links where they belong");
|
|
{
|
|
let links = createLinks(12);
|
|
const pinned = [
|
|
{ url: "http://github.com/mozilla/activity-stream", title: "moz/a-s" },
|
|
{ url: "http://example.com", title: "example" },
|
|
];
|
|
|
|
const result = insertPinned(links, pinned);
|
|
for (let index of [0, 1]) {
|
|
Assert.equal(result[index].url, pinned[index].url, "Pinned URL matches");
|
|
Assert.ok(result[index].isPinned, "Link is marked as pinned");
|
|
Assert.equal(result[index].pinIndex, index, "Pin index is correct");
|
|
}
|
|
Assert.deepEqual(result.slice(2), links, "Remaining links are unchanged");
|
|
}
|
|
|
|
info("should handle empty slots in the pinned list");
|
|
{
|
|
let links = createLinks(12);
|
|
const pinned = [
|
|
null,
|
|
{ url: "http://github.com/mozilla/activity-stream", title: "moz/a-s" },
|
|
null,
|
|
null,
|
|
{ url: "http://example.com", title: "example" },
|
|
];
|
|
|
|
const result = insertPinned(links, pinned);
|
|
for (let index of [1, 4]) {
|
|
Assert.equal(result[index].url, pinned[index].url, "Pinned URL matches");
|
|
Assert.ok(result[index].isPinned, "Link is marked as pinned");
|
|
Assert.equal(result[index].pinIndex, index, "Pin index is correct");
|
|
}
|
|
result.splice(4, 1);
|
|
result.splice(1, 1);
|
|
Assert.deepEqual(result, links, "Remaining links are unchanged");
|
|
}
|
|
|
|
info("should handle a pinned site past the end of the list of links");
|
|
{
|
|
const pinned = [];
|
|
pinned[11] = {
|
|
url: "http://github.com/mozilla/activity-stream",
|
|
title: "moz/a-s",
|
|
};
|
|
|
|
const result = insertPinned([], pinned);
|
|
Assert.equal(result[11].url, pinned[11].url, "Pinned URL matches");
|
|
Assert.ok(result[11].isPinned, "Link is marked as pinned");
|
|
Assert.equal(result[11].pinIndex, 11, "Pin index is correct");
|
|
}
|
|
|
|
info("should unpin previously pinned links no longer in the pinned list");
|
|
{
|
|
let links = createLinks(12);
|
|
const pinned = [];
|
|
links[2].isPinned = true;
|
|
links[2].pinIndex = 2;
|
|
|
|
const result = insertPinned(links, pinned);
|
|
Assert.ok(!result[2].isPinned, "isPinned property removed");
|
|
Assert.ok(!result[2].pinIndex, "pinIndex property removed");
|
|
}
|
|
|
|
info("should handle a link present in both the links and pinned list");
|
|
{
|
|
let links = createLinks(12);
|
|
const pinned = [links[7]];
|
|
|
|
const result = insertPinned(links, pinned);
|
|
Assert.equal(links.length, result.length, "Length of links is unchanged");
|
|
}
|
|
|
|
info("should not modify the original data");
|
|
{
|
|
let links = createLinks(12);
|
|
const pinned = [{ url: "http://example.com" }];
|
|
|
|
insertPinned(links, pinned);
|
|
|
|
Assert.equal(
|
|
typeof pinned[0].isPinned,
|
|
"undefined",
|
|
"Pinned data is not mutated"
|
|
);
|
|
}
|
|
});
|