forked from mirrors/gecko-dev
822 lines
28 KiB
JavaScript
822 lines
28 KiB
JavaScript
"use strict";
|
|
|
|
import { actionTypes as at } from "common/Actions.sys.mjs";
|
|
import { Dedupe } from "common/Dedupe.sys.mjs";
|
|
import { GlobalOverrider } from "test/unit/utils";
|
|
import injector from "inject!lib/HighlightsFeed.jsm";
|
|
import { Screenshots } from "lib/Screenshots.jsm";
|
|
import { LinksCache } from "lib/LinksCache.sys.mjs";
|
|
|
|
const FAKE_LINKS = new Array(20)
|
|
.fill(null)
|
|
.map((v, i) => ({ url: `http://www.site${i}.com` }));
|
|
const FAKE_IMAGE = "data123";
|
|
|
|
describe("Highlights Feed", () => {
|
|
let HighlightsFeed;
|
|
let SECTION_ID;
|
|
let SYNC_BOOKMARKS_FINISHED_EVENT;
|
|
let BOOKMARKS_RESTORE_SUCCESS_EVENT;
|
|
let BOOKMARKS_RESTORE_FAILED_EVENT;
|
|
let feed;
|
|
let globals;
|
|
let sandbox;
|
|
let links;
|
|
let fakeScreenshot;
|
|
let fakeNewTabUtils;
|
|
let filterAdultStub;
|
|
let sectionsManagerStub;
|
|
let downloadsManagerStub;
|
|
let shortURLStub;
|
|
let fakePageThumbs;
|
|
|
|
beforeEach(() => {
|
|
globals = new GlobalOverrider();
|
|
sandbox = globals.sandbox;
|
|
fakeNewTabUtils = {
|
|
activityStreamLinks: {
|
|
getHighlights: sandbox.spy(() => Promise.resolve(links)),
|
|
deletePocketEntry: sandbox.spy(() => Promise.resolve({})),
|
|
archivePocketEntry: sandbox.spy(() => Promise.resolve({})),
|
|
},
|
|
activityStreamProvider: {
|
|
_processHighlights: sandbox.spy(l => l.slice(0, 1)),
|
|
},
|
|
};
|
|
sectionsManagerStub = {
|
|
onceInitialized: sinon.stub().callsFake(callback => callback()),
|
|
enableSection: sinon.spy(),
|
|
disableSection: sinon.spy(),
|
|
updateSection: sinon.spy(),
|
|
updateSectionCard: sinon.spy(),
|
|
sections: new Map([["highlights", { id: "highlights" }]]),
|
|
};
|
|
downloadsManagerStub = sinon.stub().returns({
|
|
getDownloads: () => [{ url: "https://site.com/download" }],
|
|
onAction: sinon.spy(),
|
|
init: sinon.spy(),
|
|
});
|
|
fakeScreenshot = {
|
|
getScreenshotForURL: sandbox.spy(() => Promise.resolve(FAKE_IMAGE)),
|
|
maybeCacheScreenshot: Screenshots.maybeCacheScreenshot,
|
|
_shouldGetScreenshots: sinon.stub().returns(true),
|
|
};
|
|
filterAdultStub = {
|
|
filter: sinon.stub().returnsArg(0),
|
|
};
|
|
shortURLStub = sinon
|
|
.stub()
|
|
.callsFake(site => site.url.match(/\/([^/]+)/)[1]);
|
|
fakePageThumbs = {
|
|
addExpirationFilter: sinon.stub(),
|
|
removeExpirationFilter: sinon.stub(),
|
|
};
|
|
|
|
globals.set({
|
|
NewTabUtils: fakeNewTabUtils,
|
|
PageThumbs: fakePageThumbs,
|
|
gFilterAdultEnabled: false,
|
|
LinksCache,
|
|
DownloadsManager: downloadsManagerStub,
|
|
FilterAdult: filterAdultStub,
|
|
Screenshots: fakeScreenshot,
|
|
});
|
|
({
|
|
HighlightsFeed,
|
|
SECTION_ID,
|
|
SYNC_BOOKMARKS_FINISHED_EVENT,
|
|
BOOKMARKS_RESTORE_SUCCESS_EVENT,
|
|
BOOKMARKS_RESTORE_FAILED_EVENT,
|
|
} = injector({
|
|
"lib/FilterAdult.jsm": { FilterAdult: filterAdultStub },
|
|
"lib/ShortURL.jsm": { shortURL: shortURLStub },
|
|
"lib/SectionsManager.jsm": { SectionsManager: sectionsManagerStub },
|
|
"lib/Screenshots.jsm": { Screenshots: fakeScreenshot },
|
|
"common/Dedupe.jsm": { Dedupe },
|
|
"lib/DownloadsManager.jsm": { DownloadsManager: downloadsManagerStub },
|
|
}));
|
|
sandbox.spy(global.Services.obs, "addObserver");
|
|
sandbox.spy(global.Services.obs, "removeObserver");
|
|
feed = new HighlightsFeed();
|
|
feed.store = {
|
|
dispatch: sinon.spy(),
|
|
getState() {
|
|
return this.state;
|
|
},
|
|
state: {
|
|
Prefs: {
|
|
values: {
|
|
"section.highlights.includePocket": false,
|
|
"section.highlights.includeDownloads": false,
|
|
},
|
|
},
|
|
TopSites: {
|
|
initialized: true,
|
|
rows: Array(12)
|
|
.fill(null)
|
|
.map((v, i) => ({ url: `http://www.topsite${i}.com` })),
|
|
},
|
|
Sections: [{ id: "highlights", initialized: false }],
|
|
},
|
|
subscribe: sinon.stub().callsFake(cb => {
|
|
cb();
|
|
return () => {};
|
|
}),
|
|
};
|
|
links = FAKE_LINKS;
|
|
});
|
|
afterEach(() => {
|
|
globals.restore();
|
|
});
|
|
|
|
describe("#init", () => {
|
|
it("should create a HighlightsFeed", () => {
|
|
assert.instanceOf(feed, HighlightsFeed);
|
|
});
|
|
it("should register a expiration filter", () => {
|
|
assert.calledOnce(fakePageThumbs.addExpirationFilter);
|
|
});
|
|
it("should add the sync observer", () => {
|
|
feed.onAction({ type: at.INIT });
|
|
assert.calledWith(
|
|
global.Services.obs.addObserver,
|
|
feed,
|
|
SYNC_BOOKMARKS_FINISHED_EVENT
|
|
);
|
|
assert.calledWith(
|
|
global.Services.obs.addObserver,
|
|
feed,
|
|
BOOKMARKS_RESTORE_SUCCESS_EVENT
|
|
);
|
|
assert.calledWith(
|
|
global.Services.obs.addObserver,
|
|
feed,
|
|
BOOKMARKS_RESTORE_FAILED_EVENT
|
|
);
|
|
});
|
|
it("should call SectionsManager.onceInitialized on INIT", () => {
|
|
feed.onAction({ type: at.INIT });
|
|
assert.calledOnce(sectionsManagerStub.onceInitialized);
|
|
});
|
|
it("should enable its section", () => {
|
|
feed.onAction({ type: at.INIT });
|
|
assert.calledOnce(sectionsManagerStub.enableSection);
|
|
assert.calledWith(sectionsManagerStub.enableSection, SECTION_ID);
|
|
});
|
|
it("should fetch highlights on postInit", () => {
|
|
feed.fetchHighlights = sinon.spy();
|
|
feed.postInit();
|
|
assert.calledOnce(feed.fetchHighlights);
|
|
});
|
|
it("should hook up the store for the DownloadsManager", () => {
|
|
feed.onAction({ type: at.INIT });
|
|
assert.calledOnce(feed.downloadsManager.init);
|
|
});
|
|
});
|
|
describe("#observe", () => {
|
|
beforeEach(() => {
|
|
feed.fetchHighlights = sinon.spy();
|
|
});
|
|
it("should fetch higlights when we are done a sync for bookmarks", () => {
|
|
feed.observe(null, SYNC_BOOKMARKS_FINISHED_EVENT, "bookmarks");
|
|
assert.calledWith(feed.fetchHighlights, { broadcast: true });
|
|
});
|
|
it("should fetch highlights after a successful import", () => {
|
|
feed.observe(null, BOOKMARKS_RESTORE_SUCCESS_EVENT, "html");
|
|
assert.calledWith(feed.fetchHighlights, { broadcast: true });
|
|
});
|
|
it("should fetch highlights after a failed import", () => {
|
|
feed.observe(null, BOOKMARKS_RESTORE_FAILED_EVENT, "json");
|
|
assert.calledWith(feed.fetchHighlights, { broadcast: true });
|
|
});
|
|
it("should not fetch higlights when we are doing a sync for something that is not bookmarks", () => {
|
|
feed.observe(null, SYNC_BOOKMARKS_FINISHED_EVENT, "tabs");
|
|
assert.notCalled(feed.fetchHighlights);
|
|
});
|
|
it("should not fetch higlights for other events", () => {
|
|
feed.observe(null, "someotherevent", "bookmarks");
|
|
assert.notCalled(feed.fetchHighlights);
|
|
});
|
|
});
|
|
describe("#filterForThumbnailExpiration", () => {
|
|
it("should pass rows.urls to the callback provided", () => {
|
|
const rows = [{ url: "foo.com" }, { url: "bar.com" }];
|
|
feed.store.state.Sections = [
|
|
{ id: "highlights", rows, initialized: true },
|
|
];
|
|
const stub = sinon.stub();
|
|
|
|
feed.filterForThumbnailExpiration(stub);
|
|
|
|
assert.calledOnce(stub);
|
|
assert.calledWithExactly(
|
|
stub,
|
|
rows.map(r => r.url)
|
|
);
|
|
});
|
|
it("should include preview_image_url (if present) in the callback results", () => {
|
|
const rows = [
|
|
{ url: "foo.com" },
|
|
{ url: "bar.com", preview_image_url: "bar.jpg" },
|
|
];
|
|
feed.store.state.Sections = [
|
|
{ id: "highlights", rows, initialized: true },
|
|
];
|
|
const stub = sinon.stub();
|
|
|
|
feed.filterForThumbnailExpiration(stub);
|
|
|
|
assert.calledOnce(stub);
|
|
assert.calledWithExactly(stub, ["foo.com", "bar.com", "bar.jpg"]);
|
|
});
|
|
it("should pass an empty array if not initialized", () => {
|
|
const rows = [{ url: "foo.com" }, { url: "bar.com" }];
|
|
feed.store.state.Sections = [{ rows, initialized: false }];
|
|
const stub = sinon.stub();
|
|
|
|
feed.filterForThumbnailExpiration(stub);
|
|
|
|
assert.calledOnce(stub);
|
|
assert.calledWithExactly(stub, []);
|
|
});
|
|
});
|
|
describe("#fetchHighlights", () => {
|
|
const fetchHighlights = async options => {
|
|
await feed.fetchHighlights(options);
|
|
return sectionsManagerStub.updateSection.firstCall.args[1].rows;
|
|
};
|
|
it("should return early if TopSites are not initialised", async () => {
|
|
sandbox.spy(feed.linksCache, "request");
|
|
feed.store.state.TopSites.initialized = false;
|
|
feed.store.state.Prefs.values["feeds.topsites"] = true;
|
|
feed.store.state.Prefs.values["feeds.system.topsites"] = true;
|
|
|
|
// Initially TopSites is uninitialised and fetchHighlights should return.
|
|
await feed.fetchHighlights();
|
|
|
|
assert.notCalled(fakeNewTabUtils.activityStreamLinks.getHighlights);
|
|
assert.notCalled(feed.linksCache.request);
|
|
});
|
|
it("should return early if Sections are not initialised", async () => {
|
|
sandbox.spy(feed.linksCache, "request");
|
|
feed.store.state.TopSites.initialized = true;
|
|
feed.store.state.Prefs.values["feeds.topsites"] = true;
|
|
feed.store.state.Prefs.values["feeds.system.topsites"] = true;
|
|
feed.store.state.Sections = [];
|
|
|
|
await feed.fetchHighlights();
|
|
|
|
assert.notCalled(fakeNewTabUtils.activityStreamLinks.getHighlights);
|
|
assert.notCalled(feed.linksCache.request);
|
|
});
|
|
it("should fetch Highlights if TopSites are initialised", async () => {
|
|
sandbox.spy(feed.linksCache, "request");
|
|
// fetchHighlights should continue
|
|
feed.store.state.TopSites.initialized = true;
|
|
|
|
await feed.fetchHighlights();
|
|
|
|
assert.calledOnce(feed.linksCache.request);
|
|
assert.calledOnce(fakeNewTabUtils.activityStreamLinks.getHighlights);
|
|
});
|
|
it("should chronologically order highlight data types", async () => {
|
|
links = [
|
|
{
|
|
url: "https://site0.com",
|
|
type: "bookmark",
|
|
bookmarkGuid: "1234",
|
|
date_added: Date.now() - 80,
|
|
}, // 3rd newest
|
|
{
|
|
url: "https://site1.com",
|
|
type: "history",
|
|
bookmarkGuid: "1234",
|
|
date_added: Date.now() - 60,
|
|
}, // append at the end
|
|
{
|
|
url: "https://site2.com",
|
|
type: "history",
|
|
date_added: Date.now() - 160,
|
|
}, // append at the end
|
|
{
|
|
url: "https://site3.com",
|
|
type: "history",
|
|
date_added: Date.now() - 60,
|
|
}, // append at the end
|
|
{ url: "https://site4.com", type: "pocket", date_added: Date.now() }, // newest highlight
|
|
{
|
|
url: "https://site5.com",
|
|
type: "pocket",
|
|
date_added: Date.now() - 100,
|
|
}, // 4th newest
|
|
{
|
|
url: "https://site6.com",
|
|
type: "bookmark",
|
|
bookmarkGuid: "1234",
|
|
date_added: Date.now() - 40,
|
|
}, // 2nd newest
|
|
];
|
|
const expectedChronological = [4, 6, 0, 5];
|
|
const expectedHistory = [1, 2, 3];
|
|
|
|
let highlights = await fetchHighlights();
|
|
|
|
[...expectedChronological, ...expectedHistory].forEach((link, index) => {
|
|
assert.propertyVal(
|
|
highlights[index],
|
|
"url",
|
|
links[link].url,
|
|
`highlight[${index}] should be link[${link}]`
|
|
);
|
|
});
|
|
});
|
|
it("should fetch Highlights if TopSites are not enabled", async () => {
|
|
sandbox.spy(feed.linksCache, "request");
|
|
feed.store.state.Prefs.values["feeds.system.topsites"] = false;
|
|
|
|
await feed.fetchHighlights();
|
|
|
|
assert.calledOnce(feed.linksCache.request);
|
|
assert.calledOnce(fakeNewTabUtils.activityStreamLinks.getHighlights);
|
|
});
|
|
it("should fetch Highlights if TopSites are not shown on NTP", async () => {
|
|
sandbox.spy(feed.linksCache, "request");
|
|
feed.store.state.Prefs.values["feeds.topsites"] = false;
|
|
|
|
await feed.fetchHighlights();
|
|
|
|
assert.calledOnce(feed.linksCache.request);
|
|
assert.calledOnce(fakeNewTabUtils.activityStreamLinks.getHighlights);
|
|
});
|
|
it("should add hostname and hasImage to each link", async () => {
|
|
links = [{ url: "https://mozilla.org" }];
|
|
|
|
const highlights = await fetchHighlights();
|
|
|
|
assert.equal(highlights[0].hostname, "mozilla.org");
|
|
assert.equal(highlights[0].hasImage, true);
|
|
});
|
|
it("should add an existing image if it exists to the link without calling fetchImage", async () => {
|
|
links = [{ url: "https://mozilla.org", image: FAKE_IMAGE }];
|
|
sinon.spy(feed, "fetchImage");
|
|
|
|
const highlights = await fetchHighlights();
|
|
|
|
assert.equal(highlights[0].image, FAKE_IMAGE);
|
|
assert.notCalled(feed.fetchImage);
|
|
});
|
|
it("should call fetchImage with the correct arguments for new links", async () => {
|
|
links = [
|
|
{
|
|
url: "https://mozilla.org",
|
|
preview_image_url: "https://mozilla.org/preview.jog",
|
|
},
|
|
];
|
|
sinon.spy(feed, "fetchImage");
|
|
|
|
await feed.fetchHighlights();
|
|
|
|
assert.calledOnce(feed.fetchImage);
|
|
const [arg] = feed.fetchImage.firstCall.args;
|
|
assert.propertyVal(arg, "url", links[0].url);
|
|
assert.propertyVal(arg, "preview_image_url", links[0].preview_image_url);
|
|
});
|
|
it("should not include any links already in Top Sites", async () => {
|
|
links = [
|
|
{ url: "https://mozilla.org" },
|
|
{ url: "http://www.topsite0.com" },
|
|
{ url: "http://www.topsite1.com" },
|
|
{ url: "http://www.topsite2.com" },
|
|
];
|
|
|
|
const highlights = await fetchHighlights();
|
|
|
|
assert.equal(highlights.length, 1);
|
|
assert.equal(highlights[0].url, links[0].url);
|
|
});
|
|
it("should include bookmark but not history already in Top Sites", async () => {
|
|
links = [
|
|
{ url: "http://www.topsite0.com", type: "bookmark" },
|
|
{ url: "http://www.topsite1.com", type: "history" },
|
|
];
|
|
|
|
const highlights = await fetchHighlights();
|
|
|
|
assert.equal(highlights.length, 1);
|
|
assert.equal(highlights[0].url, links[0].url);
|
|
});
|
|
it("should not include history of same hostname as a bookmark", async () => {
|
|
links = [
|
|
{ url: "https://site.com/bookmark", type: "bookmark" },
|
|
{ url: "https://site.com/history", type: "history" },
|
|
];
|
|
|
|
const highlights = await fetchHighlights();
|
|
|
|
assert.equal(highlights.length, 1);
|
|
assert.equal(highlights[0].url, links[0].url);
|
|
});
|
|
it("should take the first history of a hostname", async () => {
|
|
links = [
|
|
{ url: "https://site.com/first", type: "history" },
|
|
{ url: "https://site.com/second", type: "history" },
|
|
{ url: "https://other", type: "history" },
|
|
];
|
|
|
|
const highlights = await fetchHighlights();
|
|
|
|
assert.equal(highlights.length, 2);
|
|
assert.equal(highlights[0].url, links[0].url);
|
|
assert.equal(highlights[1].url, links[2].url);
|
|
});
|
|
it("should take a bookmark, a pocket, and downloaded item of the same hostname", async () => {
|
|
links = [
|
|
{ url: "https://site.com/bookmark", type: "bookmark" },
|
|
{ url: "https://site.com/pocket", type: "pocket" },
|
|
{ url: "https://site.com/download", type: "download" },
|
|
];
|
|
|
|
const highlights = await fetchHighlights();
|
|
|
|
assert.equal(highlights.length, 3);
|
|
assert.equal(highlights[0].url, links[0].url);
|
|
assert.equal(highlights[1].url, links[1].url);
|
|
assert.equal(highlights[2].url, links[2].url);
|
|
});
|
|
it("should includePocket pocket items when pref is true", async () => {
|
|
feed.store.state.Prefs.values["section.highlights.includePocket"] = true;
|
|
sandbox.spy(feed.linksCache, "request");
|
|
await feed.fetchHighlights();
|
|
|
|
assert.propertyVal(
|
|
feed.linksCache.request.firstCall.args[0],
|
|
"excludePocket",
|
|
false
|
|
);
|
|
});
|
|
it("should not includePocket pocket items when pref is false", async () => {
|
|
sandbox.spy(feed.linksCache, "request");
|
|
await feed.fetchHighlights();
|
|
|
|
assert.propertyVal(
|
|
feed.linksCache.request.firstCall.args[0],
|
|
"excludePocket",
|
|
true
|
|
);
|
|
});
|
|
it("should not include downloads when includeDownloads pref is false", async () => {
|
|
links = [
|
|
{ url: "https://site.com/bookmark", type: "bookmark" },
|
|
{ url: "https://site.com/pocket", type: "pocket" },
|
|
];
|
|
|
|
// Check that we don't have the downloaded item in highlights
|
|
const highlights = await fetchHighlights();
|
|
assert.equal(highlights.length, 2);
|
|
assert.equal(highlights[0].url, links[0].url);
|
|
assert.equal(highlights[1].url, links[1].url);
|
|
});
|
|
it("should include downloads when includeDownloads pref is true", async () => {
|
|
feed.store.state.Prefs.values[
|
|
"section.highlights.includeDownloads"
|
|
] = true;
|
|
links = [
|
|
{ url: "https://site.com/bookmark", type: "bookmark" },
|
|
{ url: "https://site.com/pocket", type: "pocket" },
|
|
];
|
|
|
|
// Check that we did get the downloaded item in highlights
|
|
const highlights = await fetchHighlights();
|
|
assert.equal(highlights.length, 3);
|
|
assert.equal(highlights[0].url, links[0].url);
|
|
assert.equal(highlights[1].url, links[1].url);
|
|
assert.equal(highlights[2].url, "https://site.com/download");
|
|
|
|
assert.propertyVal(highlights[2], "type", "download");
|
|
});
|
|
it("should only take 1 download", async () => {
|
|
feed.store.state.Prefs.values[
|
|
"section.highlights.includeDownloads"
|
|
] = true;
|
|
feed.downloadsManager.getDownloads = () => [
|
|
{ url: "https://site1.com/download" },
|
|
{ url: "https://site2.com/download" },
|
|
];
|
|
links = [{ url: "https://site.com/bookmark", type: "bookmark" }];
|
|
|
|
// Check that we did get the most single recent downloaded item in highlights
|
|
const highlights = await fetchHighlights();
|
|
assert.equal(highlights.length, 2);
|
|
assert.equal(highlights[0].url, links[0].url);
|
|
assert.equal(highlights[1].url, "https://site1.com/download");
|
|
});
|
|
it("should sort bookmarks, pocket, and downloads chronologically", async () => {
|
|
feed.store.state.Prefs.values[
|
|
"section.highlights.includeDownloads"
|
|
] = true;
|
|
feed.downloadsManager.getDownloads = () => [
|
|
{
|
|
url: "https://site1.com/download",
|
|
type: "download",
|
|
date_added: Date.now(),
|
|
},
|
|
];
|
|
links = [
|
|
{
|
|
url: "https://site.com/bookmark",
|
|
type: "bookmark",
|
|
date_added: Date.now() - 10000,
|
|
},
|
|
{
|
|
url: "https://site2.com/pocket",
|
|
type: "pocket",
|
|
date_added: Date.now() - 5000,
|
|
},
|
|
{
|
|
url: "https://site3.com/visited",
|
|
type: "history",
|
|
date_added: Date.now(),
|
|
},
|
|
];
|
|
|
|
// Check that the higlights are ordered chronologically by their 'date_added'
|
|
const highlights = await fetchHighlights();
|
|
assert.equal(highlights.length, 4);
|
|
assert.equal(highlights[0].url, "https://site1.com/download");
|
|
assert.equal(highlights[1].url, links[1].url);
|
|
assert.equal(highlights[2].url, links[0].url);
|
|
assert.equal(highlights[3].url, links[2].url); // history item goes last
|
|
});
|
|
it("should set type to bookmark if there is a bookmarkGuid", async () => {
|
|
feed.store.state.Prefs.values[
|
|
"section.highlights.includeBookmarks"
|
|
] = true;
|
|
links = [
|
|
{
|
|
url: "https://mozilla.org",
|
|
type: "history",
|
|
bookmarkGuid: "1234567890",
|
|
},
|
|
];
|
|
|
|
const highlights = await fetchHighlights();
|
|
|
|
assert.equal(highlights[0].type, "bookmark");
|
|
});
|
|
it("should keep history type if there is a bookmarkGuid but don't include bookmarks", async () => {
|
|
feed.store.state.Prefs.values[
|
|
"section.highlights.includeBookmarks"
|
|
] = false;
|
|
links = [
|
|
{
|
|
url: "https://mozilla.org",
|
|
type: "history",
|
|
bookmarkGuid: "1234567890",
|
|
},
|
|
];
|
|
|
|
const highlights = await fetchHighlights();
|
|
|
|
assert.propertyVal(highlights[0], "type", "history");
|
|
});
|
|
it("should filter out adult pages", async () => {
|
|
filterAdultStub.filter = sinon.stub().returns([]);
|
|
const highlights = await fetchHighlights();
|
|
|
|
// The stub filters out everything
|
|
assert.calledOnce(filterAdultStub.filter);
|
|
assert.equal(highlights.length, 0);
|
|
});
|
|
it("should not expose internal link properties", async () => {
|
|
const highlights = await fetchHighlights();
|
|
|
|
const internal = Object.keys(highlights[0]).filter(key =>
|
|
key.startsWith("__")
|
|
);
|
|
assert.equal(internal.join(""), "");
|
|
});
|
|
it("should broadcast if feed is not initialized", async () => {
|
|
links = [];
|
|
await fetchHighlights();
|
|
|
|
assert.calledOnce(sectionsManagerStub.updateSection);
|
|
assert.calledWithExactly(
|
|
sectionsManagerStub.updateSection,
|
|
SECTION_ID,
|
|
{ rows: [] },
|
|
true,
|
|
undefined
|
|
);
|
|
});
|
|
it("should broadcast if options.broadcast is true", async () => {
|
|
links = [];
|
|
feed.store.state.Sections[0].initialized = true;
|
|
await fetchHighlights({ broadcast: true });
|
|
|
|
assert.calledOnce(sectionsManagerStub.updateSection);
|
|
assert.calledWithExactly(
|
|
sectionsManagerStub.updateSection,
|
|
SECTION_ID,
|
|
{ rows: [] },
|
|
true,
|
|
undefined
|
|
);
|
|
});
|
|
it("should not broadcast if options.broadcast is false and initialized is true", async () => {
|
|
links = [];
|
|
feed.store.state.Sections[0].initialized = true;
|
|
await fetchHighlights({ broadcast: false });
|
|
|
|
assert.calledOnce(sectionsManagerStub.updateSection);
|
|
assert.calledWithExactly(
|
|
sectionsManagerStub.updateSection,
|
|
SECTION_ID,
|
|
{ rows: [] },
|
|
false,
|
|
undefined
|
|
);
|
|
});
|
|
});
|
|
describe("#fetchImage", () => {
|
|
const FAKE_URL = "https://mozilla.org";
|
|
const FAKE_IMAGE_URL = "https://mozilla.org/preview.jpg";
|
|
function fetchImage(page) {
|
|
return feed.fetchImage(
|
|
Object.assign({ __sharedCache: { updateLink() {} } }, page)
|
|
);
|
|
}
|
|
it("should capture the image, if available", async () => {
|
|
await fetchImage({
|
|
preview_image_url: FAKE_IMAGE_URL,
|
|
url: FAKE_URL,
|
|
});
|
|
|
|
assert.calledOnce(fakeScreenshot.getScreenshotForURL);
|
|
assert.calledWith(fakeScreenshot.getScreenshotForURL, FAKE_IMAGE_URL);
|
|
});
|
|
it("should fall back to capturing a screenshot", async () => {
|
|
await fetchImage({ url: FAKE_URL });
|
|
|
|
assert.calledOnce(fakeScreenshot.getScreenshotForURL);
|
|
assert.calledWith(fakeScreenshot.getScreenshotForURL, FAKE_URL);
|
|
});
|
|
it("should call SectionsManager.updateSectionCard with the right arguments", async () => {
|
|
await fetchImage({
|
|
preview_image_url: FAKE_IMAGE_URL,
|
|
url: FAKE_URL,
|
|
});
|
|
|
|
assert.calledOnce(sectionsManagerStub.updateSectionCard);
|
|
assert.calledWith(
|
|
sectionsManagerStub.updateSectionCard,
|
|
"highlights",
|
|
FAKE_URL,
|
|
{ image: FAKE_IMAGE },
|
|
true
|
|
);
|
|
});
|
|
it("should not update the card with the image", async () => {
|
|
const card = {
|
|
preview_image_url: FAKE_IMAGE_URL,
|
|
url: FAKE_URL,
|
|
};
|
|
|
|
await fetchImage(card);
|
|
|
|
assert.notProperty(card, "image");
|
|
});
|
|
});
|
|
describe("#uninit", () => {
|
|
it("should disable its section", () => {
|
|
feed.onAction({ type: at.UNINIT });
|
|
assert.calledOnce(sectionsManagerStub.disableSection);
|
|
assert.calledWith(sectionsManagerStub.disableSection, SECTION_ID);
|
|
});
|
|
it("should remove the expiration filter", () => {
|
|
feed.onAction({ type: at.UNINIT });
|
|
assert.calledOnce(fakePageThumbs.removeExpirationFilter);
|
|
});
|
|
it("should remove the sync and Places observers", () => {
|
|
feed.onAction({ type: at.UNINIT });
|
|
assert.calledWith(
|
|
global.Services.obs.removeObserver,
|
|
feed,
|
|
SYNC_BOOKMARKS_FINISHED_EVENT
|
|
);
|
|
assert.calledWith(
|
|
global.Services.obs.removeObserver,
|
|
feed,
|
|
BOOKMARKS_RESTORE_SUCCESS_EVENT
|
|
);
|
|
assert.calledWith(
|
|
global.Services.obs.removeObserver,
|
|
feed,
|
|
BOOKMARKS_RESTORE_FAILED_EVENT
|
|
);
|
|
});
|
|
});
|
|
describe("#onAction", () => {
|
|
it("should relay all actions to DownloadsManager.onAction", () => {
|
|
let action = {
|
|
type: at.COPY_DOWNLOAD_LINK,
|
|
data: { url: "foo.png" },
|
|
_target: {},
|
|
};
|
|
feed.onAction(action);
|
|
assert.calledWith(feed.downloadsManager.onAction, action);
|
|
});
|
|
it("should fetch highlights on SYSTEM_TICK", async () => {
|
|
await feed.fetchHighlights();
|
|
feed.fetchHighlights = sinon.spy();
|
|
feed.onAction({ type: at.SYSTEM_TICK });
|
|
|
|
assert.calledOnce(feed.fetchHighlights);
|
|
assert.calledWithExactly(feed.fetchHighlights, {
|
|
broadcast: false,
|
|
isStartup: false,
|
|
});
|
|
});
|
|
it("should fetch highlights on PREF_CHANGED for include prefs", async () => {
|
|
feed.fetchHighlights = sinon.spy();
|
|
|
|
feed.onAction({
|
|
type: at.PREF_CHANGED,
|
|
data: { name: "section.highlights.includeBookmarks" },
|
|
});
|
|
|
|
assert.calledOnce(feed.fetchHighlights);
|
|
assert.calledWith(feed.fetchHighlights, { broadcast: true });
|
|
});
|
|
it("should not fetch highlights on PREF_CHANGED for other prefs", async () => {
|
|
feed.fetchHighlights = sinon.spy();
|
|
|
|
feed.onAction({
|
|
type: at.PREF_CHANGED,
|
|
data: { name: "section.topstories.pocketCta" },
|
|
});
|
|
|
|
assert.notCalled(feed.fetchHighlights);
|
|
});
|
|
it("should fetch highlights on PLACES_HISTORY_CLEARED", async () => {
|
|
await feed.fetchHighlights();
|
|
feed.fetchHighlights = sinon.spy();
|
|
feed.onAction({ type: at.PLACES_HISTORY_CLEARED });
|
|
assert.calledOnce(feed.fetchHighlights);
|
|
assert.calledWith(feed.fetchHighlights, { broadcast: true });
|
|
});
|
|
it("should fetch highlights on DOWNLOAD_CHANGED", async () => {
|
|
await feed.fetchHighlights();
|
|
feed.fetchHighlights = sinon.spy();
|
|
feed.onAction({ type: at.DOWNLOAD_CHANGED });
|
|
assert.calledOnce(feed.fetchHighlights);
|
|
assert.calledWith(feed.fetchHighlights, { broadcast: true });
|
|
});
|
|
it("should fetch highlights on PLACES_LINKS_CHANGED", async () => {
|
|
await feed.fetchHighlights();
|
|
feed.fetchHighlights = sinon.spy();
|
|
sandbox.stub(feed.linksCache, "expire");
|
|
|
|
feed.onAction({ type: at.PLACES_LINKS_CHANGED });
|
|
assert.calledOnce(feed.fetchHighlights);
|
|
assert.calledWith(feed.fetchHighlights, { broadcast: false });
|
|
assert.calledOnce(feed.linksCache.expire);
|
|
});
|
|
it("should fetch highlights on PLACES_LINK_BLOCKED", async () => {
|
|
await feed.fetchHighlights();
|
|
feed.fetchHighlights = sinon.spy();
|
|
feed.onAction({ type: at.PLACES_LINK_BLOCKED });
|
|
assert.calledOnce(feed.fetchHighlights);
|
|
assert.calledWith(feed.fetchHighlights, { broadcast: true });
|
|
});
|
|
it("should fetch highlights and expire the cache on PLACES_SAVED_TO_POCKET", async () => {
|
|
await feed.fetchHighlights();
|
|
feed.fetchHighlights = sinon.spy();
|
|
sandbox.stub(feed.linksCache, "expire");
|
|
|
|
feed.onAction({ type: at.PLACES_SAVED_TO_POCKET });
|
|
assert.calledOnce(feed.fetchHighlights);
|
|
assert.calledWith(feed.fetchHighlights, { broadcast: false });
|
|
assert.calledOnce(feed.linksCache.expire);
|
|
});
|
|
it("should call fetchHighlights with broadcast false on TOP_SITES_UPDATED", () => {
|
|
sandbox.stub(feed, "fetchHighlights");
|
|
feed.onAction({ type: at.TOP_SITES_UPDATED });
|
|
|
|
assert.calledOnce(feed.fetchHighlights);
|
|
assert.calledWithExactly(feed.fetchHighlights, {
|
|
broadcast: false,
|
|
isStartup: false,
|
|
});
|
|
});
|
|
it("should call fetchHighlights when deleting or archiving from Pocket", async () => {
|
|
feed.fetchHighlights = sinon.spy();
|
|
feed.onAction({
|
|
type: at.POCKET_LINK_DELETED_OR_ARCHIVED,
|
|
data: { pocket_id: 12345 },
|
|
});
|
|
|
|
assert.calledOnce(feed.fetchHighlights);
|
|
assert.calledWithExactly(feed.fetchHighlights, { broadcast: true });
|
|
});
|
|
});
|
|
});
|