tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DownloadsManager.test.js (14771B)


      1 import { actionTypes as at } from "common/Actions.mjs";
      2 import { DownloadsManager } from "lib/DownloadsManager.sys.mjs";
      3 import { GlobalOverrider } from "test/unit/utils";
      4 
      5 describe("Downloads Manager", () => {
      6  let downloadsManager;
      7  let globals;
      8  const DOWNLOAD_URL = "https://site.com/download.mov";
      9 
     10  beforeEach(() => {
     11    globals = new GlobalOverrider();
     12    global.Cc["@mozilla.org/timer;1"] = {
     13      createInstance() {
     14        return {
     15          initWithCallback: sinon.stub().callsFake(callback => callback()),
     16          cancel: sinon.spy(),
     17        };
     18      },
     19    };
     20 
     21    globals.set("DownloadsCommon", {
     22      getData: sinon.stub().returns({
     23        addView: sinon.stub(),
     24        removeView: sinon.stub(),
     25      }),
     26      copyDownloadLink: sinon.stub(),
     27      deleteDownload: sinon.stub().returns(Promise.resolve()),
     28      openDownload: sinon.stub(),
     29      showDownloadedFile: sinon.stub(),
     30    });
     31 
     32    globals.set("BrowserUtils", {
     33      whereToOpenLink: sinon.stub().returns("current"),
     34    });
     35 
     36    downloadsManager = new DownloadsManager();
     37    downloadsManager.init({ dispatch() {} });
     38    downloadsManager.onDownloadAdded({
     39      source: { url: DOWNLOAD_URL },
     40      endTime: Date.now(),
     41      target: { path: "/path/to/download.mov", exists: true },
     42      succeeded: true,
     43      refresh: async () => {},
     44    });
     45    assert.ok(downloadsManager._downloadItems.has(DOWNLOAD_URL));
     46 
     47    globals.set("NewTabUtils", { blockedLinks: { isBlocked() {} } });
     48  });
     49  afterEach(() => {
     50    downloadsManager._downloadItems.clear();
     51    globals.restore();
     52  });
     53  describe("#init", () => {
     54    it("should add a DownloadsCommon view on init", () => {
     55      downloadsManager.init({ dispatch() {} });
     56      assert.calledTwice(global.DownloadsCommon.getData().addView);
     57    });
     58  });
     59  describe("#onAction", () => {
     60    it("should copy the file on COPY_DOWNLOAD_LINK", () => {
     61      downloadsManager.onAction({
     62        type: at.COPY_DOWNLOAD_LINK,
     63        data: { url: DOWNLOAD_URL },
     64      });
     65      assert.calledOnce(global.DownloadsCommon.copyDownloadLink);
     66    });
     67    it("should remove the file on REMOVE_DOWNLOAD_FILE", () => {
     68      downloadsManager.onAction({
     69        type: at.REMOVE_DOWNLOAD_FILE,
     70        data: { url: DOWNLOAD_URL },
     71      });
     72      assert.calledOnce(global.DownloadsCommon.deleteDownload);
     73    });
     74    it("should show the file on SHOW_DOWNLOAD_FILE", () => {
     75      downloadsManager.onAction({
     76        type: at.SHOW_DOWNLOAD_FILE,
     77        data: { url: DOWNLOAD_URL },
     78      });
     79      assert.calledOnce(global.DownloadsCommon.showDownloadedFile);
     80    });
     81    it("should open the file on OPEN_DOWNLOAD_FILE if the type is download", () => {
     82      downloadsManager.onAction({
     83        type: at.OPEN_DOWNLOAD_FILE,
     84        data: { url: DOWNLOAD_URL, type: "download" },
     85        _target: { browser: {} },
     86      });
     87      assert.calledOnce(global.DownloadsCommon.openDownload);
     88    });
     89    it("should copy the file on UNINIT", () => {
     90      // DownloadsManager._downloadData needs to exist first
     91      downloadsManager.onAction({ type: at.UNINIT });
     92      assert.calledOnce(global.DownloadsCommon.getData().removeView);
     93    });
     94    it("should not execute a download command if we do not have the correct url", () => {
     95      downloadsManager.onAction({
     96        type: at.SHOW_DOWNLOAD_FILE,
     97        data: { url: "unknown_url" },
     98      });
     99      assert.notCalled(global.DownloadsCommon.showDownloadedFile);
    100    });
    101  });
    102  describe("#onDownloadAdded", () => {
    103    let newDownload;
    104    beforeEach(() => {
    105      downloadsManager._downloadItems.clear();
    106      newDownload = {
    107        source: { url: "https://site.com/newDownload.mov" },
    108        endTime: Date.now(),
    109        target: { path: "/path/to/newDownload.mov", exists: true },
    110        succeeded: true,
    111        refresh: async () => {},
    112      };
    113    });
    114    afterEach(() => {
    115      downloadsManager._downloadItems.clear();
    116    });
    117    it("should add a download on onDownloadAdded", () => {
    118      downloadsManager.onDownloadAdded(newDownload);
    119      assert.ok(
    120        downloadsManager._downloadItems.has("https://site.com/newDownload.mov")
    121      );
    122    });
    123    it("should not add a download if it already exists", () => {
    124      downloadsManager.onDownloadAdded(newDownload);
    125      downloadsManager.onDownloadAdded(newDownload);
    126      downloadsManager.onDownloadAdded(newDownload);
    127      downloadsManager.onDownloadAdded(newDownload);
    128      const results = downloadsManager._downloadItems;
    129      assert.equal(results.size, 1);
    130    });
    131    it("should not return any downloads if no threshold is provided", async () => {
    132      downloadsManager.onDownloadAdded(newDownload);
    133      const results = await downloadsManager.getDownloads(null, {});
    134      assert.equal(results.length, 0);
    135    });
    136    it("should stop at numItems when it found one it's looking for", async () => {
    137      const aDownload = {
    138        source: { url: "https://site.com/aDownload.pdf" },
    139        endTime: Date.now(),
    140        target: { path: "/path/to/aDownload.pdf", exists: true },
    141        succeeded: true,
    142        refresh: async () => {},
    143      };
    144      downloadsManager.onDownloadAdded(aDownload);
    145      downloadsManager.onDownloadAdded(newDownload);
    146      const results = await downloadsManager.getDownloads(Infinity, {
    147        numItems: 1,
    148        onlySucceeded: true,
    149        onlyExists: true,
    150      });
    151      assert.equal(results.length, 1);
    152      assert.equal(results[0].url, aDownload.source.url);
    153    });
    154    it("should get all the downloads younger than the threshold provided", async () => {
    155      const oldDownload = {
    156        source: { url: "https://site.com/oldDownload.pdf" },
    157        endTime: Date.now() - 40 * 60 * 60 * 1000,
    158        target: { path: "/path/to/oldDownload.pdf", exists: true },
    159        succeeded: true,
    160        refresh: async () => {},
    161      };
    162      // Add an old download (older than 36 hours in this case)
    163      downloadsManager.onDownloadAdded(oldDownload);
    164      downloadsManager.onDownloadAdded(newDownload);
    165      const RECENT_DOWNLOAD_THRESHOLD = 36 * 60 * 60 * 1000;
    166      const results = await downloadsManager.getDownloads(
    167        RECENT_DOWNLOAD_THRESHOLD,
    168        { numItems: 5, onlySucceeded: true, onlyExists: true }
    169      );
    170      assert.equal(results.length, 1);
    171      assert.equal(results[0].url, newDownload.source.url);
    172    });
    173    it("should dispatch DOWNLOAD_CHANGED when adding a download", () => {
    174      downloadsManager._store.dispatch = sinon.spy();
    175      downloadsManager._downloadTimer = null; // Nuke the timer
    176      downloadsManager.onDownloadAdded(newDownload);
    177      assert.calledOnce(downloadsManager._store.dispatch);
    178    });
    179    it("should refresh the downloads if onlyExists is true", async () => {
    180      const aDownload = {
    181        source: { url: "https://site.com/aDownload.pdf" },
    182        endTime: Date.now() - 40 * 60 * 60 * 1000,
    183        target: { path: "/path/to/aDownload.pdf", exists: true },
    184        succeeded: true,
    185        refresh: () => {},
    186      };
    187      sinon.stub(aDownload, "refresh").returns(Promise.resolve());
    188      downloadsManager.onDownloadAdded(aDownload);
    189      await downloadsManager.getDownloads(Infinity, {
    190        numItems: 5,
    191        onlySucceeded: true,
    192        onlyExists: true,
    193      });
    194      assert.calledOnce(aDownload.refresh);
    195    });
    196    it("should not refresh the downloads if onlyExists is false (by default)", async () => {
    197      const aDownload = {
    198        source: { url: "https://site.com/aDownload.pdf" },
    199        endTime: Date.now() - 40 * 60 * 60 * 1000,
    200        target: { path: "/path/to/aDownload.pdf", exists: true },
    201        succeeded: true,
    202        refresh: () => {},
    203      };
    204      sinon.stub(aDownload, "refresh").returns(Promise.resolve());
    205      downloadsManager.onDownloadAdded(aDownload);
    206      await downloadsManager.getDownloads(Infinity, {
    207        numItems: 5,
    208        onlySucceeded: true,
    209      });
    210      assert.notCalled(aDownload.refresh);
    211    });
    212    it("should only return downloads that exist if specified", async () => {
    213      const nonExistantDownload = {
    214        source: { url: "https://site.com/nonExistantDownload.pdf" },
    215        endTime: Date.now() - 40 * 60 * 60 * 1000,
    216        target: { path: "/path/to/nonExistantDownload.pdf", exists: false },
    217        succeeded: true,
    218        refresh: async () => {},
    219      };
    220      downloadsManager.onDownloadAdded(newDownload);
    221      downloadsManager.onDownloadAdded(nonExistantDownload);
    222      const results = await downloadsManager.getDownloads(Infinity, {
    223        numItems: 5,
    224        onlySucceeded: true,
    225        onlyExists: true,
    226      });
    227      assert.equal(results.length, 1);
    228      assert.equal(results[0].url, newDownload.source.url);
    229    });
    230    it("should return all downloads that either exist or don't exist if not specified", async () => {
    231      const nonExistantDownload = {
    232        source: { url: "https://site.com/nonExistantDownload.pdf" },
    233        endTime: Date.now() - 40 * 60 * 60 * 1000,
    234        target: { path: "/path/to/nonExistantDownload.pdf", exists: false },
    235        succeeded: true,
    236        refresh: async () => {},
    237      };
    238      downloadsManager.onDownloadAdded(newDownload);
    239      downloadsManager.onDownloadAdded(nonExistantDownload);
    240      const results = await downloadsManager.getDownloads(Infinity, {
    241        numItems: 5,
    242        onlySucceeded: true,
    243      });
    244      assert.equal(results.length, 2);
    245      assert.equal(results[0].url, newDownload.source.url);
    246      assert.equal(results[1].url, nonExistantDownload.source.url);
    247    });
    248    it("should return only unblocked downloads", async () => {
    249      const nonExistantDownload = {
    250        source: { url: "https://site.com/nonExistantDownload.pdf" },
    251        endTime: Date.now() - 40 * 60 * 60 * 1000,
    252        target: { path: "/path/to/nonExistantDownload.pdf", exists: false },
    253        succeeded: true,
    254        refresh: async () => {},
    255      };
    256      downloadsManager.onDownloadAdded(newDownload);
    257      downloadsManager.onDownloadAdded(nonExistantDownload);
    258      globals.set("NewTabUtils", {
    259        blockedLinks: {
    260          isBlocked: item => item.url === nonExistantDownload.source.url,
    261        },
    262      });
    263 
    264      const results = await downloadsManager.getDownloads(Infinity, {
    265        numItems: 5,
    266        onlySucceeded: true,
    267      });
    268 
    269      assert.equal(results.length, 1);
    270      assert.propertyVal(results[0], "url", newDownload.source.url);
    271    });
    272    it("should only return downloads that were successful if specified", async () => {
    273      const nonSuccessfulDownload = {
    274        source: { url: "https://site.com/nonSuccessfulDownload.pdf" },
    275        endTime: Date.now() - 40 * 60 * 60 * 1000,
    276        target: { path: "/path/to/nonSuccessfulDownload.pdf", exists: false },
    277        succeeded: false,
    278        refresh: async () => {},
    279      };
    280      downloadsManager.onDownloadAdded(newDownload);
    281      downloadsManager.onDownloadAdded(nonSuccessfulDownload);
    282      const results = await downloadsManager.getDownloads(Infinity, {
    283        numItems: 5,
    284        onlySucceeded: true,
    285      });
    286      assert.equal(results.length, 1);
    287      assert.equal(results[0].url, newDownload.source.url);
    288    });
    289    it("should return all downloads that were either successful or not if not specified", async () => {
    290      const nonExistantDownload = {
    291        source: { url: "https://site.com/nonExistantDownload.pdf" },
    292        endTime: Date.now() - 40 * 60 * 60 * 1000,
    293        target: { path: "/path/to/nonExistantDownload.pdf", exists: true },
    294        succeeded: false,
    295        refresh: async () => {},
    296      };
    297      downloadsManager.onDownloadAdded(newDownload);
    298      downloadsManager.onDownloadAdded(nonExistantDownload);
    299      const results = await downloadsManager.getDownloads(Infinity, {
    300        numItems: 5,
    301      });
    302      assert.equal(results.length, 2);
    303      assert.equal(results[0].url, newDownload.source.url);
    304      assert.equal(results[1].url, nonExistantDownload.source.url);
    305    });
    306    it("should sort the downloads by recency", async () => {
    307      const olderDownload1 = {
    308        source: { url: "https://site.com/oldDownload1.pdf" },
    309        endTime: Date.now() - 2 * 60 * 60 * 1000, // 2 hours ago
    310        target: { path: "/path/to/oldDownload1.pdf", exists: true },
    311        succeeded: true,
    312        refresh: async () => {},
    313      };
    314      const olderDownload2 = {
    315        source: { url: "https://site.com/oldDownload2.pdf" },
    316        endTime: Date.now() - 60 * 60 * 1000, // 1 hour ago
    317        target: { path: "/path/to/oldDownload2.pdf", exists: true },
    318        succeeded: true,
    319        refresh: async () => {},
    320      };
    321      // Add some older downloads and check that they are in order
    322      downloadsManager.onDownloadAdded(olderDownload1);
    323      downloadsManager.onDownloadAdded(olderDownload2);
    324      downloadsManager.onDownloadAdded(newDownload);
    325      const results = await downloadsManager.getDownloads(Infinity, {
    326        numItems: 5,
    327        onlySucceeded: true,
    328        onlyExists: true,
    329      });
    330      assert.equal(results.length, 3);
    331      assert.equal(results[0].url, newDownload.source.url);
    332      assert.equal(results[1].url, olderDownload2.source.url);
    333      assert.equal(results[2].url, olderDownload1.source.url);
    334    });
    335    it("should format the description properly if there is no file type", async () => {
    336      newDownload.target.path = null;
    337      downloadsManager.onDownloadAdded(newDownload);
    338      const results = await downloadsManager.getDownloads(Infinity, {
    339        numItems: 5,
    340        onlySucceeded: true,
    341        onlyExists: true,
    342      });
    343      assert.equal(results.length, 1);
    344      assert.equal(results[0].description, "1.5 MB"); // see unit-entry.js to see where this comes from
    345    });
    346  });
    347  describe("#onDownloadRemoved", () => {
    348    let newDownload;
    349    beforeEach(() => {
    350      downloadsManager._downloadItems.clear();
    351      newDownload = {
    352        source: { url: "https://site.com/removeMe.mov" },
    353        endTime: Date.now(),
    354        target: { path: "/path/to/removeMe.mov", exists: true },
    355        succeeded: true,
    356        refresh: async () => {},
    357      };
    358      downloadsManager.onDownloadAdded(newDownload);
    359    });
    360    it("should remove a download if it exists on onDownloadRemoved", async () => {
    361      downloadsManager.onDownloadRemoved({
    362        source: { url: "https://site.com/removeMe.mov" },
    363      });
    364      const results = await downloadsManager.getDownloads(Infinity, {
    365        numItems: 5,
    366      });
    367      assert.deepEqual(results, []);
    368    });
    369    it("should dispatch DOWNLOAD_CHANGED when removing a download", () => {
    370      downloadsManager._store.dispatch = sinon.spy();
    371      downloadsManager.onDownloadRemoved({
    372        source: { url: "https://site.com/removeMe.mov" },
    373      });
    374      assert.calledOnce(downloadsManager._store.dispatch);
    375    });
    376  });
    377 });