377 lines
14 KiB
JavaScript
377 lines
14 KiB
JavaScript
import { actionTypes as at } from "common/Actions.mjs";
|
|
import { DownloadsManager } from "lib/DownloadsManager.sys.mjs";
|
|
import { GlobalOverrider } from "test/unit/utils";
|
|
|
|
describe("Downloads Manager", () => {
|
|
let downloadsManager;
|
|
let globals;
|
|
const DOWNLOAD_URL = "https://site.com/download.mov";
|
|
|
|
beforeEach(() => {
|
|
globals = new GlobalOverrider();
|
|
global.Cc["@mozilla.org/timer;1"] = {
|
|
createInstance() {
|
|
return {
|
|
initWithCallback: sinon.stub().callsFake(callback => callback()),
|
|
cancel: sinon.spy(),
|
|
};
|
|
},
|
|
};
|
|
|
|
globals.set("DownloadsCommon", {
|
|
getData: sinon.stub().returns({
|
|
addView: sinon.stub(),
|
|
removeView: sinon.stub(),
|
|
}),
|
|
copyDownloadLink: sinon.stub(),
|
|
deleteDownload: sinon.stub().returns(Promise.resolve()),
|
|
openDownload: sinon.stub(),
|
|
showDownloadedFile: sinon.stub(),
|
|
});
|
|
|
|
globals.set("BrowserUtils", {
|
|
whereToOpenLink: sinon.stub().returns("current"),
|
|
});
|
|
|
|
downloadsManager = new DownloadsManager();
|
|
downloadsManager.init({ dispatch() {} });
|
|
downloadsManager.onDownloadAdded({
|
|
source: { url: DOWNLOAD_URL },
|
|
endTime: Date.now(),
|
|
target: { path: "/path/to/download.mov", exists: true },
|
|
succeeded: true,
|
|
refresh: async () => {},
|
|
});
|
|
assert.ok(downloadsManager._downloadItems.has(DOWNLOAD_URL));
|
|
|
|
globals.set("NewTabUtils", { blockedLinks: { isBlocked() {} } });
|
|
});
|
|
afterEach(() => {
|
|
downloadsManager._downloadItems.clear();
|
|
globals.restore();
|
|
});
|
|
describe("#init", () => {
|
|
it("should add a DownloadsCommon view on init", () => {
|
|
downloadsManager.init({ dispatch() {} });
|
|
assert.calledTwice(global.DownloadsCommon.getData().addView);
|
|
});
|
|
});
|
|
describe("#onAction", () => {
|
|
it("should copy the file on COPY_DOWNLOAD_LINK", () => {
|
|
downloadsManager.onAction({
|
|
type: at.COPY_DOWNLOAD_LINK,
|
|
data: { url: DOWNLOAD_URL },
|
|
});
|
|
assert.calledOnce(global.DownloadsCommon.copyDownloadLink);
|
|
});
|
|
it("should remove the file on REMOVE_DOWNLOAD_FILE", () => {
|
|
downloadsManager.onAction({
|
|
type: at.REMOVE_DOWNLOAD_FILE,
|
|
data: { url: DOWNLOAD_URL },
|
|
});
|
|
assert.calledOnce(global.DownloadsCommon.deleteDownload);
|
|
});
|
|
it("should show the file on SHOW_DOWNLOAD_FILE", () => {
|
|
downloadsManager.onAction({
|
|
type: at.SHOW_DOWNLOAD_FILE,
|
|
data: { url: DOWNLOAD_URL },
|
|
});
|
|
assert.calledOnce(global.DownloadsCommon.showDownloadedFile);
|
|
});
|
|
it("should open the file on OPEN_DOWNLOAD_FILE if the type is download", () => {
|
|
downloadsManager.onAction({
|
|
type: at.OPEN_DOWNLOAD_FILE,
|
|
data: { url: DOWNLOAD_URL, type: "download" },
|
|
_target: { browser: {} },
|
|
});
|
|
assert.calledOnce(global.DownloadsCommon.openDownload);
|
|
});
|
|
it("should copy the file on UNINIT", () => {
|
|
// DownloadsManager._downloadData needs to exist first
|
|
downloadsManager.onAction({ type: at.UNINIT });
|
|
assert.calledOnce(global.DownloadsCommon.getData().removeView);
|
|
});
|
|
it("should not execute a download command if we do not have the correct url", () => {
|
|
downloadsManager.onAction({
|
|
type: at.SHOW_DOWNLOAD_FILE,
|
|
data: { url: "unknown_url" },
|
|
});
|
|
assert.notCalled(global.DownloadsCommon.showDownloadedFile);
|
|
});
|
|
});
|
|
describe("#onDownloadAdded", () => {
|
|
let newDownload;
|
|
beforeEach(() => {
|
|
downloadsManager._downloadItems.clear();
|
|
newDownload = {
|
|
source: { url: "https://site.com/newDownload.mov" },
|
|
endTime: Date.now(),
|
|
target: { path: "/path/to/newDownload.mov", exists: true },
|
|
succeeded: true,
|
|
refresh: async () => {},
|
|
};
|
|
});
|
|
afterEach(() => {
|
|
downloadsManager._downloadItems.clear();
|
|
});
|
|
it("should add a download on onDownloadAdded", () => {
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
assert.ok(
|
|
downloadsManager._downloadItems.has("https://site.com/newDownload.mov")
|
|
);
|
|
});
|
|
it("should not add a download if it already exists", () => {
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
const results = downloadsManager._downloadItems;
|
|
assert.equal(results.size, 1);
|
|
});
|
|
it("should not return any downloads if no threshold is provided", async () => {
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
const results = await downloadsManager.getDownloads(null, {});
|
|
assert.equal(results.length, 0);
|
|
});
|
|
it("should stop at numItems when it found one it's looking for", async () => {
|
|
const aDownload = {
|
|
source: { url: "https://site.com/aDownload.pdf" },
|
|
endTime: Date.now(),
|
|
target: { path: "/path/to/aDownload.pdf", exists: true },
|
|
succeeded: true,
|
|
refresh: async () => {},
|
|
};
|
|
downloadsManager.onDownloadAdded(aDownload);
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
const results = await downloadsManager.getDownloads(Infinity, {
|
|
numItems: 1,
|
|
onlySucceeded: true,
|
|
onlyExists: true,
|
|
});
|
|
assert.equal(results.length, 1);
|
|
assert.equal(results[0].url, aDownload.source.url);
|
|
});
|
|
it("should get all the downloads younger than the threshold provided", async () => {
|
|
const oldDownload = {
|
|
source: { url: "https://site.com/oldDownload.pdf" },
|
|
endTime: Date.now() - 40 * 60 * 60 * 1000,
|
|
target: { path: "/path/to/oldDownload.pdf", exists: true },
|
|
succeeded: true,
|
|
refresh: async () => {},
|
|
};
|
|
// Add an old download (older than 36 hours in this case)
|
|
downloadsManager.onDownloadAdded(oldDownload);
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
const RECENT_DOWNLOAD_THRESHOLD = 36 * 60 * 60 * 1000;
|
|
const results = await downloadsManager.getDownloads(
|
|
RECENT_DOWNLOAD_THRESHOLD,
|
|
{ numItems: 5, onlySucceeded: true, onlyExists: true }
|
|
);
|
|
assert.equal(results.length, 1);
|
|
assert.equal(results[0].url, newDownload.source.url);
|
|
});
|
|
it("should dispatch DOWNLOAD_CHANGED when adding a download", () => {
|
|
downloadsManager._store.dispatch = sinon.spy();
|
|
downloadsManager._downloadTimer = null; // Nuke the timer
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
assert.calledOnce(downloadsManager._store.dispatch);
|
|
});
|
|
it("should refresh the downloads if onlyExists is true", async () => {
|
|
const aDownload = {
|
|
source: { url: "https://site.com/aDownload.pdf" },
|
|
endTime: Date.now() - 40 * 60 * 60 * 1000,
|
|
target: { path: "/path/to/aDownload.pdf", exists: true },
|
|
succeeded: true,
|
|
refresh: () => {},
|
|
};
|
|
sinon.stub(aDownload, "refresh").returns(Promise.resolve());
|
|
downloadsManager.onDownloadAdded(aDownload);
|
|
await downloadsManager.getDownloads(Infinity, {
|
|
numItems: 5,
|
|
onlySucceeded: true,
|
|
onlyExists: true,
|
|
});
|
|
assert.calledOnce(aDownload.refresh);
|
|
});
|
|
it("should not refresh the downloads if onlyExists is false (by default)", async () => {
|
|
const aDownload = {
|
|
source: { url: "https://site.com/aDownload.pdf" },
|
|
endTime: Date.now() - 40 * 60 * 60 * 1000,
|
|
target: { path: "/path/to/aDownload.pdf", exists: true },
|
|
succeeded: true,
|
|
refresh: () => {},
|
|
};
|
|
sinon.stub(aDownload, "refresh").returns(Promise.resolve());
|
|
downloadsManager.onDownloadAdded(aDownload);
|
|
await downloadsManager.getDownloads(Infinity, {
|
|
numItems: 5,
|
|
onlySucceeded: true,
|
|
});
|
|
assert.notCalled(aDownload.refresh);
|
|
});
|
|
it("should only return downloads that exist if specified", async () => {
|
|
const nonExistantDownload = {
|
|
source: { url: "https://site.com/nonExistantDownload.pdf" },
|
|
endTime: Date.now() - 40 * 60 * 60 * 1000,
|
|
target: { path: "/path/to/nonExistantDownload.pdf", exists: false },
|
|
succeeded: true,
|
|
refresh: async () => {},
|
|
};
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
downloadsManager.onDownloadAdded(nonExistantDownload);
|
|
const results = await downloadsManager.getDownloads(Infinity, {
|
|
numItems: 5,
|
|
onlySucceeded: true,
|
|
onlyExists: true,
|
|
});
|
|
assert.equal(results.length, 1);
|
|
assert.equal(results[0].url, newDownload.source.url);
|
|
});
|
|
it("should return all downloads that either exist or don't exist if not specified", async () => {
|
|
const nonExistantDownload = {
|
|
source: { url: "https://site.com/nonExistantDownload.pdf" },
|
|
endTime: Date.now() - 40 * 60 * 60 * 1000,
|
|
target: { path: "/path/to/nonExistantDownload.pdf", exists: false },
|
|
succeeded: true,
|
|
refresh: async () => {},
|
|
};
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
downloadsManager.onDownloadAdded(nonExistantDownload);
|
|
const results = await downloadsManager.getDownloads(Infinity, {
|
|
numItems: 5,
|
|
onlySucceeded: true,
|
|
});
|
|
assert.equal(results.length, 2);
|
|
assert.equal(results[0].url, newDownload.source.url);
|
|
assert.equal(results[1].url, nonExistantDownload.source.url);
|
|
});
|
|
it("should return only unblocked downloads", async () => {
|
|
const nonExistantDownload = {
|
|
source: { url: "https://site.com/nonExistantDownload.pdf" },
|
|
endTime: Date.now() - 40 * 60 * 60 * 1000,
|
|
target: { path: "/path/to/nonExistantDownload.pdf", exists: false },
|
|
succeeded: true,
|
|
refresh: async () => {},
|
|
};
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
downloadsManager.onDownloadAdded(nonExistantDownload);
|
|
globals.set("NewTabUtils", {
|
|
blockedLinks: {
|
|
isBlocked: item => item.url === nonExistantDownload.source.url,
|
|
},
|
|
});
|
|
|
|
const results = await downloadsManager.getDownloads(Infinity, {
|
|
numItems: 5,
|
|
onlySucceeded: true,
|
|
});
|
|
|
|
assert.equal(results.length, 1);
|
|
assert.propertyVal(results[0], "url", newDownload.source.url);
|
|
});
|
|
it("should only return downloads that were successful if specified", async () => {
|
|
const nonSuccessfulDownload = {
|
|
source: { url: "https://site.com/nonSuccessfulDownload.pdf" },
|
|
endTime: Date.now() - 40 * 60 * 60 * 1000,
|
|
target: { path: "/path/to/nonSuccessfulDownload.pdf", exists: false },
|
|
succeeded: false,
|
|
refresh: async () => {},
|
|
};
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
downloadsManager.onDownloadAdded(nonSuccessfulDownload);
|
|
const results = await downloadsManager.getDownloads(Infinity, {
|
|
numItems: 5,
|
|
onlySucceeded: true,
|
|
});
|
|
assert.equal(results.length, 1);
|
|
assert.equal(results[0].url, newDownload.source.url);
|
|
});
|
|
it("should return all downloads that were either successful or not if not specified", async () => {
|
|
const nonExistantDownload = {
|
|
source: { url: "https://site.com/nonExistantDownload.pdf" },
|
|
endTime: Date.now() - 40 * 60 * 60 * 1000,
|
|
target: { path: "/path/to/nonExistantDownload.pdf", exists: true },
|
|
succeeded: false,
|
|
refresh: async () => {},
|
|
};
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
downloadsManager.onDownloadAdded(nonExistantDownload);
|
|
const results = await downloadsManager.getDownloads(Infinity, {
|
|
numItems: 5,
|
|
});
|
|
assert.equal(results.length, 2);
|
|
assert.equal(results[0].url, newDownload.source.url);
|
|
assert.equal(results[1].url, nonExistantDownload.source.url);
|
|
});
|
|
it("should sort the downloads by recency", async () => {
|
|
const olderDownload1 = {
|
|
source: { url: "https://site.com/oldDownload1.pdf" },
|
|
endTime: Date.now() - 2 * 60 * 60 * 1000, // 2 hours ago
|
|
target: { path: "/path/to/oldDownload1.pdf", exists: true },
|
|
succeeded: true,
|
|
refresh: async () => {},
|
|
};
|
|
const olderDownload2 = {
|
|
source: { url: "https://site.com/oldDownload2.pdf" },
|
|
endTime: Date.now() - 60 * 60 * 1000, // 1 hour ago
|
|
target: { path: "/path/to/oldDownload2.pdf", exists: true },
|
|
succeeded: true,
|
|
refresh: async () => {},
|
|
};
|
|
// Add some older downloads and check that they are in order
|
|
downloadsManager.onDownloadAdded(olderDownload1);
|
|
downloadsManager.onDownloadAdded(olderDownload2);
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
const results = await downloadsManager.getDownloads(Infinity, {
|
|
numItems: 5,
|
|
onlySucceeded: true,
|
|
onlyExists: true,
|
|
});
|
|
assert.equal(results.length, 3);
|
|
assert.equal(results[0].url, newDownload.source.url);
|
|
assert.equal(results[1].url, olderDownload2.source.url);
|
|
assert.equal(results[2].url, olderDownload1.source.url);
|
|
});
|
|
it("should format the description properly if there is no file type", async () => {
|
|
newDownload.target.path = null;
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
const results = await downloadsManager.getDownloads(Infinity, {
|
|
numItems: 5,
|
|
onlySucceeded: true,
|
|
onlyExists: true,
|
|
});
|
|
assert.equal(results.length, 1);
|
|
assert.equal(results[0].description, "1.5 MB"); // see unit-entry.js to see where this comes from
|
|
});
|
|
});
|
|
describe("#onDownloadRemoved", () => {
|
|
let newDownload;
|
|
beforeEach(() => {
|
|
downloadsManager._downloadItems.clear();
|
|
newDownload = {
|
|
source: { url: "https://site.com/removeMe.mov" },
|
|
endTime: Date.now(),
|
|
target: { path: "/path/to/removeMe.mov", exists: true },
|
|
succeeded: true,
|
|
refresh: async () => {},
|
|
};
|
|
downloadsManager.onDownloadAdded(newDownload);
|
|
});
|
|
it("should remove a download if it exists on onDownloadRemoved", async () => {
|
|
downloadsManager.onDownloadRemoved({
|
|
source: { url: "https://site.com/removeMe.mov" },
|
|
});
|
|
const results = await downloadsManager.getDownloads(Infinity, {
|
|
numItems: 5,
|
|
});
|
|
assert.deepEqual(results, []);
|
|
});
|
|
it("should dispatch DOWNLOAD_CHANGED when removing a download", () => {
|
|
downloadsManager._store.dispatch = sinon.spy();
|
|
downloadsManager.onDownloadRemoved({
|
|
source: { url: "https://site.com/removeMe.mov" },
|
|
});
|
|
assert.calledOnce(downloadsManager._store.dispatch);
|
|
});
|
|
});
|
|
});
|