Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
import { mockServices, stubGlobals } from "test/jest/test-utils";
const URL = "foo.com";
const FAKE_THUMBNAIL_PATH = "fake/path/thumb.jpg";
const FAKE_THUMBNAIL_THUMB =
describe("Screenshots", () => {
let Screenshots;
let restoreChromeUtils;
let restoreGlobals;
let consoleWarnStub;
let fakeServices;
let testFile;
let originalMethods;
// Screenshots.sys.mjs resolves XPCOMUtils and its lazy module getters at load
// time, so ChromeUtils has to exist before the module is evaluated. Pointing
// the lazy holder's prototype at globalThis is what lets the per-test stubs
// below (PageThumbs, gPrivilegedAboutProcessEnabled, ...) be seen.
beforeAll(async () => {
restoreChromeUtils = stubGlobals({
ChromeUtils: {
importESModule: () => ({
XPCOMUtils: { defineLazyPreferenceGetter: () => {} },
}),
defineESModuleGetters: object => {
Object.setPrototypeOf(object, globalThis);
return globalThis;
},
},
});
({ Screenshots } = await import("lib/Screenshots.sys.mjs"));
});
afterAll(() => {
restoreChromeUtils();
});
beforeEach(() => {
originalMethods = {
getScreenshotForURL: Screenshots.getScreenshotForURL,
_shouldGetScreenshots: Screenshots._shouldGetScreenshots,
};
consoleWarnStub = jest.spyOn(console, "warn").mockImplementation(() => {});
fakeServices = mockServices(["wm"]);
fakeServices.wm.getEnumerator.mockReturnValue(Array(10));
testFile = { size: 1 };
restoreGlobals = stubGlobals({
BackgroundPageThumbs: {
captureIfMissing: jest.fn(() => Promise.resolve()),
},
PageThumbs: {
_store: jest.fn(),
getThumbnailPath: jest.fn(() => FAKE_THUMBNAIL_PATH),
getThumbnailURL: jest.fn(() => FAKE_THUMBNAIL_THUMB),
},
PrivateBrowsingUtils: {
isWindowPrivate: jest.fn(() => false),
},
Services: fakeServices,
fetch: jest.fn(() =>
Promise.resolve({ blob: () => Promise.resolve(testFile) })
),
gPrivilegedAboutProcessEnabled: false,
});
});
afterEach(() => {
Object.assign(Screenshots, originalMethods);
restoreGlobals();
consoleWarnStub.mockRestore();
});
describe("#getScreenshotForURL", () => {
it("should call BackgroundPageThumbs.captureIfMissing with the correct url", async () => {
await Screenshots.getScreenshotForURL(URL);
expect(
globalThis.BackgroundPageThumbs.captureIfMissing
).toHaveBeenCalledWith(URL, expect.any(Object));
});
it("should call PageThumbs.getThumbnailPath with the correct url", async () => {
globalThis.gPrivilegedAboutProcessEnabled = false;
await Screenshots.getScreenshotForURL(URL);
expect(globalThis.PageThumbs.getThumbnailPath).toHaveBeenCalledWith(URL);
});
it("should call fetch", async () => {
await Screenshots.getScreenshotForURL(URL);
expect(globalThis.fetch).toHaveBeenCalledTimes(1);
});
it("should have the necessary keys in the response object", async () => {
const screenshot = await Screenshots.getScreenshotForURL(URL);
expect(screenshot.path).not.toBeUndefined();
expect(screenshot.data).not.toBeUndefined();
});
it("should get null if something goes wrong", async () => {
globalThis.BackgroundPageThumbs = {
captureIfMissing: () =>
Promise.reject(new Error("Cannot capture thumbnail")),
};
const screenshot = await Screenshots.getScreenshotForURL(URL);
expect(globalThis.PageThumbs._store).toHaveBeenCalledTimes(1);
expect(screenshot).toBeNull();
});
it("should get direct thumbnail url for privileged process", async () => {
globalThis.gPrivilegedAboutProcessEnabled = true;
await Screenshots.getScreenshotForURL(URL);
expect(globalThis.PageThumbs.getThumbnailURL).toHaveBeenCalledWith(URL);
});
it("should get null without storing if existing thumbnail is empty", async () => {
testFile.size = 0;
const screenshot = await Screenshots.getScreenshotForURL(URL);
expect(globalThis.PageThumbs._store).not.toHaveBeenCalled();
expect(screenshot).toBeNull();
});
});
describe("#maybeCacheScreenshot", () => {
let link;
beforeEach(() => {
link = {
__sharedCache: {
updateLink: (prop, val) => {
link[prop] = val;
},
},
};
});
it("should call getScreenshotForURL", () => {
Screenshots.getScreenshotForURL = jest.fn();
Screenshots._shouldGetScreenshots = jest.fn(() => true);
Screenshots.maybeCacheScreenshot(link, "mozilla.com", "image", jest.fn());
expect(Screenshots.getScreenshotForURL).toHaveBeenCalledTimes(1);
expect(Screenshots.getScreenshotForURL).toHaveBeenCalledWith(
"mozilla.com"
);
});
it("should not call getScreenshotForURL twice if a fetch is in progress", () => {
Screenshots.getScreenshotForURL = jest.fn(() => new Promise(() => {}));
Screenshots._shouldGetScreenshots = jest.fn(() => true);
Screenshots.maybeCacheScreenshot(link, "mozilla.com", "image", jest.fn());
Screenshots.maybeCacheScreenshot(link, "mozilla.org", "image", jest.fn());
expect(Screenshots.getScreenshotForURL).toHaveBeenCalledTimes(1);
expect(Screenshots.getScreenshotForURL).toHaveBeenCalledWith(
"mozilla.com"
);
});
it("should not call getScreenshotsForURL if property !== undefined", async () => {
Screenshots.getScreenshotForURL = jest.fn(() => Promise.resolve(null));
Screenshots._shouldGetScreenshots = jest.fn(() => true);
await Screenshots.maybeCacheScreenshot(
link,
"mozilla.com",
"image",
jest.fn()
);
await Screenshots.maybeCacheScreenshot(
link,
"mozilla.org",
"image",
jest.fn()
);
expect(Screenshots.getScreenshotForURL).toHaveBeenCalledTimes(1);
expect(Screenshots.getScreenshotForURL).toHaveBeenCalledWith(
"mozilla.com"
);
});
it("should check if we are in private browsing before getting screenshots", async () => {
Screenshots._shouldGetScreenshots = jest.fn(() => true);
await Screenshots.maybeCacheScreenshot(
link,
"mozilla.com",
"image",
jest.fn()
);
expect(Screenshots._shouldGetScreenshots).toHaveBeenCalledTimes(1);
});
it("should not get a screenshot if we are in private browsing", async () => {
Screenshots.getScreenshotForURL = jest.fn();
Screenshots._shouldGetScreenshots = jest.fn(() => false);
await Screenshots.maybeCacheScreenshot(
link,
"mozilla.com",
"image",
jest.fn()
);
expect(Screenshots.getScreenshotForURL).not.toHaveBeenCalled();
});
});
describe("#_shouldGetScreenshots", () => {
beforeEach(() => {
let more = 2;
fakeServices.wm.getEnumerator.mockImplementation(() =>
Array(Math.max(more--, 0))
);
});
it("should use private browsing utils to determine if a window is private", () => {
Screenshots._shouldGetScreenshots();
expect(
globalThis.PrivateBrowsingUtils.isWindowPrivate
).toHaveBeenCalledTimes(1);
});
it("should return true if there exists at least 1 non-private window", () => {
expect(Screenshots._shouldGetScreenshots()).toBe(true);
});
it("should return false if there exists private windows", () => {
globalThis.PrivateBrowsingUtils = {
isWindowPrivate: jest.fn(() => true),
};
expect(Screenshots._shouldGetScreenshots()).toBe(false);
expect(
globalThis.PrivateBrowsingUtils.isWindowPrivate
).toHaveBeenCalledTimes(2);
});
});
});