diff options
Diffstat (limited to '')
-rw-r--r-- | browser/components/newtab/test/unit/lib/FaviconFeed.test.js | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/browser/components/newtab/test/unit/lib/FaviconFeed.test.js b/browser/components/newtab/test/unit/lib/FaviconFeed.test.js new file mode 100644 index 0000000000..e9be9b86ba --- /dev/null +++ b/browser/components/newtab/test/unit/lib/FaviconFeed.test.js @@ -0,0 +1,233 @@ +"use strict"; +import { FaviconFeed, fetchIconFromRedirects } from "lib/FaviconFeed.sys.mjs"; +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); + }); + }); +}); |