diff options
Diffstat (limited to '')
-rw-r--r-- | browser/components/newtab/test/unit/lib/DownloadsManager.test.js | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/browser/components/newtab/test/unit/lib/DownloadsManager.test.js b/browser/components/newtab/test/unit/lib/DownloadsManager.test.js new file mode 100644 index 0000000000..ac262baf90 --- /dev/null +++ b/browser/components/newtab/test/unit/lib/DownloadsManager.test.js @@ -0,0 +1,373 @@ +import { actionTypes as at } from "common/Actions.sys.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(), + }); + + 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); + }); + }); +}); |