forked from mirrors/gecko-dev
Depends on D165820 Differential Revision: https://phabricator.services.mozilla.com/D165821
233 lines
7.6 KiB
JavaScript
233 lines
7.6 KiB
JavaScript
"use strict";
|
|
import { FaviconFeed, fetchIconFromRedirects } from "lib/FaviconFeed.jsm";
|
|
import { actionTypes as at } from "common/Actions.sys.mjs";
|
|
import { GlobalOverrider } from "test/unit/utils";
|
|
|
|
const FAKE_ENDPOINT = "https://foo.com/";
|
|
|
|
describe("FaviconFeed", () => {
|
|
let feed;
|
|
let globals;
|
|
let sandbox;
|
|
let clock;
|
|
let siteIconsPref;
|
|
|
|
beforeEach(() => {
|
|
clock = sinon.useFakeTimers();
|
|
globals = new GlobalOverrider();
|
|
sandbox = globals.sandbox;
|
|
globals.set("PlacesUtils", {
|
|
favicons: {
|
|
setAndFetchFaviconForPage: sandbox.spy(),
|
|
getFaviconDataForPage: () => Promise.resolve(null),
|
|
FAVICON_LOAD_NON_PRIVATE: 1,
|
|
},
|
|
history: {
|
|
TRANSITIONS: {
|
|
REDIRECT_TEMPORARY: 1,
|
|
REDIRECT_PERMANENT: 2,
|
|
},
|
|
},
|
|
});
|
|
globals.set("NewTabUtils", {
|
|
activityStreamProvider: { executePlacesQuery: () => Promise.resolve([]) },
|
|
});
|
|
siteIconsPref = true;
|
|
sandbox
|
|
.stub(global.Services.prefs, "getBoolPref")
|
|
.withArgs("browser.chrome.site_icons")
|
|
.callsFake(() => siteIconsPref);
|
|
|
|
feed = new FaviconFeed();
|
|
feed.store = {
|
|
dispatch: sinon.spy(),
|
|
getState() {
|
|
return this.state;
|
|
},
|
|
state: {
|
|
Prefs: { values: { "tippyTop.service.endpoint": FAKE_ENDPOINT } },
|
|
},
|
|
};
|
|
});
|
|
afterEach(() => {
|
|
clock.restore();
|
|
globals.restore();
|
|
});
|
|
|
|
it("should create a FaviconFeed", () => {
|
|
assert.instanceOf(feed, FaviconFeed);
|
|
});
|
|
|
|
describe("#fetchIcon", () => {
|
|
let domain;
|
|
let url;
|
|
beforeEach(() => {
|
|
domain = "mozilla.org";
|
|
url = `https://${domain}/`;
|
|
feed.getSite = sandbox
|
|
.stub()
|
|
.returns(Promise.resolve({ domain, image_url: `${url}/icon.png` }));
|
|
feed._queryForRedirects.clear();
|
|
});
|
|
|
|
it("should setAndFetchFaviconForPage if the url is in the TippyTop data", async () => {
|
|
await feed.fetchIcon(url);
|
|
|
|
assert.calledOnce(global.PlacesUtils.favicons.setAndFetchFaviconForPage);
|
|
assert.calledWith(
|
|
global.PlacesUtils.favicons.setAndFetchFaviconForPage,
|
|
sinon.match({ spec: url }),
|
|
{ ref: "tippytop", spec: `${url}/icon.png` },
|
|
false,
|
|
global.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
|
null,
|
|
undefined
|
|
);
|
|
});
|
|
it("should NOT setAndFetchFaviconForPage if site_icons pref is false", async () => {
|
|
siteIconsPref = false;
|
|
|
|
await feed.fetchIcon(url);
|
|
|
|
assert.notCalled(global.PlacesUtils.favicons.setAndFetchFaviconForPage);
|
|
});
|
|
it("should NOT setAndFetchFaviconForPage if the url is NOT in the TippyTop data", async () => {
|
|
feed.getSite = sandbox.stub().returns(Promise.resolve(null));
|
|
await feed.fetchIcon("https://example.com");
|
|
|
|
assert.notCalled(global.PlacesUtils.favicons.setAndFetchFaviconForPage);
|
|
});
|
|
it("should issue a fetchIconFromRedirects if the url is NOT in the TippyTop data", async () => {
|
|
feed.getSite = sandbox.stub().returns(Promise.resolve(null));
|
|
sandbox.spy(global.Services.tm, "idleDispatchToMainThread");
|
|
|
|
await feed.fetchIcon("https://example.com");
|
|
|
|
assert.calledOnce(global.Services.tm.idleDispatchToMainThread);
|
|
});
|
|
it("should only issue fetchIconFromRedirects once on the same url", async () => {
|
|
feed.getSite = sandbox.stub().returns(Promise.resolve(null));
|
|
sandbox.spy(global.Services.tm, "idleDispatchToMainThread");
|
|
|
|
await feed.fetchIcon("https://example.com");
|
|
await feed.fetchIcon("https://example.com");
|
|
|
|
assert.calledOnce(global.Services.tm.idleDispatchToMainThread);
|
|
});
|
|
it("should issue fetchIconFromRedirects twice on two different urls", async () => {
|
|
feed.getSite = sandbox.stub().returns(Promise.resolve(null));
|
|
sandbox.spy(global.Services.tm, "idleDispatchToMainThread");
|
|
|
|
await feed.fetchIcon("https://example.com");
|
|
await feed.fetchIcon("https://another.example.com");
|
|
|
|
assert.calledTwice(global.Services.tm.idleDispatchToMainThread);
|
|
});
|
|
});
|
|
|
|
describe("#getSite", () => {
|
|
it("should return site data if RemoteSettings has an entry for the domain", async () => {
|
|
const get = () =>
|
|
Promise.resolve([{ domain: "example.com", image_url: "foo.img" }]);
|
|
feed._tippyTop = { get };
|
|
const site = await feed.getSite("example.com");
|
|
assert.equal(site.domain, "example.com");
|
|
});
|
|
it("should return null if RemoteSettings doesn't have an entry for the domain", async () => {
|
|
const get = () => Promise.resolve([]);
|
|
feed._tippyTop = { get };
|
|
const site = await feed.getSite("example.com");
|
|
assert.isNull(site);
|
|
});
|
|
it("should lazy init _tippyTop", async () => {
|
|
assert.isUndefined(feed._tippyTop);
|
|
await feed.getSite("example.com");
|
|
assert.ok(feed._tippyTop);
|
|
});
|
|
});
|
|
|
|
describe("#onAction", () => {
|
|
it("should fetchIcon on RICH_ICON_MISSING", async () => {
|
|
feed.fetchIcon = sinon.spy();
|
|
const url = "https://mozilla.org";
|
|
feed.onAction({ type: at.RICH_ICON_MISSING, data: { url } });
|
|
assert.calledOnce(feed.fetchIcon);
|
|
assert.calledWith(feed.fetchIcon, url);
|
|
});
|
|
});
|
|
|
|
describe("#fetchIconFromRedirects", () => {
|
|
let domain;
|
|
let url;
|
|
let iconUrl;
|
|
|
|
beforeEach(() => {
|
|
domain = "mozilla.org";
|
|
url = `https://${domain}/`;
|
|
iconUrl = `${url}/icon.png`;
|
|
});
|
|
it("should setAndFetchFaviconForPage if the url was redirected with a icon", async () => {
|
|
sandbox
|
|
.stub(global.NewTabUtils.activityStreamProvider, "executePlacesQuery")
|
|
.resolves([
|
|
{ visit_id: 1, url: domain },
|
|
{ visit_id: 2, url },
|
|
]);
|
|
sandbox
|
|
.stub(global.PlacesUtils.favicons, "getFaviconDataForPage")
|
|
.callsArgWith(1, { spec: iconUrl }, 0, null, null, 96);
|
|
|
|
await fetchIconFromRedirects(domain);
|
|
|
|
assert.calledOnce(global.PlacesUtils.favicons.setAndFetchFaviconForPage);
|
|
assert.calledWith(
|
|
global.PlacesUtils.favicons.setAndFetchFaviconForPage,
|
|
sinon.match({ spec: domain }),
|
|
{ spec: iconUrl },
|
|
false,
|
|
global.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
|
null,
|
|
undefined
|
|
);
|
|
});
|
|
it("should NOT setAndFetchFaviconForPage if the url doesn't have any redirect", async () => {
|
|
sandbox
|
|
.stub(global.NewTabUtils.activityStreamProvider, "executePlacesQuery")
|
|
.resolves([]);
|
|
|
|
await fetchIconFromRedirects(domain);
|
|
|
|
assert.notCalled(global.PlacesUtils.favicons.setAndFetchFaviconForPage);
|
|
});
|
|
it("should NOT setAndFetchFaviconForPage if the original url doesn't have a icon", async () => {
|
|
sandbox
|
|
.stub(global.NewTabUtils.activityStreamProvider, "executePlacesQuery")
|
|
.resolves([
|
|
{ visit_id: 1, url: domain },
|
|
{ visit_id: 2, url },
|
|
]);
|
|
sandbox
|
|
.stub(global.PlacesUtils.favicons, "getFaviconDataForPage")
|
|
.callsArgWith(1, null, null, null, null, null);
|
|
|
|
await fetchIconFromRedirects(domain);
|
|
|
|
assert.notCalled(global.PlacesUtils.favicons.setAndFetchFaviconForPage);
|
|
});
|
|
it("should NOT setAndFetchFaviconForPage if the original url doesn't have a rich icon", async () => {
|
|
sandbox
|
|
.stub(global.NewTabUtils.activityStreamProvider, "executePlacesQuery")
|
|
.resolves([
|
|
{ visit_id: 1, url: domain },
|
|
{ visit_id: 2, url },
|
|
]);
|
|
sandbox
|
|
.stub(global.PlacesUtils.favicons, "getFaviconDataForPage")
|
|
.callsArgWith(1, { spec: iconUrl }, 0, null, null, 16);
|
|
|
|
await fetchIconFromRedirects(domain);
|
|
|
|
assert.notCalled(global.PlacesUtils.favicons.setAndFetchFaviconForPage);
|
|
});
|
|
});
|
|
});
|