Unit test downloading a file
Tags: javascript, testing, vue
Published: 2021-05-03 16:45:51

## 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.

```js
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));
    },
```

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.

```html
<a :href="pdfUrl" :download="label">download</a>
```
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.

```js
  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();
    });
  });
```
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

```js
// needs to be outside of describe block!
jest.mock('axios', () => ({
  get: jest.fn(() => Promise.resolve({ data: 'content' })),
}));
```
## 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](https://twitter.com/ah_yagoub)