DEV Community

Cover image for Unit test downloading a file
Ahmed Yagoub
Ahmed Yagoub

Posted on

Unit test downloading a file

Overview

In this article, I am going to show you how to add the functionality of downloading a pdf to an application using Javascript. As well, I am going to show you how to test it in Jest and vue-test-utils.

The function

We can use this Javascript function to download the pdf file.
pdfUrl and label are the url of the file you need to download and the label you want the downloaded file to have.

The pdfUrl and label are being passed in as props to the component.

downloadFile() {
        axios
          .get(this.pdfUrl, { responseType: 'blob' })
          .then((response) => {
            const blob = new Blob([response.data], { type: 'application/pdf' });
            const link = document.createElement('a');
            link.href = URL.createObjectURL(blob);
            link.download = this.label;
            link.click();
            URL.revokeObjectURL(link.href);
          })
          .catch((error) => console.error(error));
    },
Enter fullscreen mode Exit fullscreen mode

After I wrote this function (which is a Vue component method) on my project , I realized that downloading a file can easily be done with HTML via adding a download attribute.

<a :href="pdfUrl" :download="label">download</a>
Enter fullscreen mode Exit fullscreen mode

The gotcha with this technique is that it only works for same-origin-urls. i.e the website is https://mywebsite.com and the pdfUrl is https://mywebsite.com/mypdf.pdf

However, in my case, the pdfUrl is of a different origin as the pdf is stored in Amazon S3.

Testing

Let's now write a unit test for the function, to have confidence that it works correctly.

  it('should download a file', (done) => {
    const wrapper = mount(component, {    propsData: {
        label: 'label',
        pdfUrl: 'https://pdf.com',
      },});
    const link = {
      click: jest.fn(),
    };

    global.URL.createObjectURL = jest.fn(() => 'https://pdf.com');
    global.URL.revokeObjectURL = jest.fn();
    global.Blob = function(content, options) {
      return { content, options };
    };

    jest.spyOn(document, 'createElement').mockImplementation(() => link);
    wrapper.find(*class-selector*).trigger('click');

    wrapper.vm.$nextTick(() => {
      expect(link.download).toBe('label');
      expect(link.href).toBe('https://pdf.com');
      expect(link.click).toHaveBeenCalledTimes(1);
      done();
    });
  });
Enter fullscreen mode Exit fullscreen mode

The first line in the test is for mounting the component in Vue. We pass mount the component name and an option object.

Then, declare a link variable (object) and add a click method to it.

The test also involves a lot of mocking as we don't need to test Blob and URL which are available on the window (global) object.

We spy on the document.createElement function and mock its implementation

Now, we just need to find the element and click it to invoke the function.

As the function is Async, I used the $nextTick with the done() function as we need to wait for vue to update. Otherwise, we are making the assertions before the function completes and the test would fail.

Finally, we assert that the link we created has the correct download and href attributes as well as asserting it is clicked.

side Note

I should also point out that we need to mock axios at the top of the test file

// needs to be outside of describe block!
jest.mock('axios', () => ({
  get: jest.fn(() => Promise.resolve({ data: 'content' })),
}));
Enter fullscreen mode Exit fullscreen mode

Conclusion

We have seen how to download a file in Javascript as well as unit testing it in Jest and Vue-test-utils.

I hope it is helpful, If you have questions or feedback, drop a comment or reach out to me on Twitter

Top comments (0)