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));
},
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>
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();
});
});
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' })),
}));
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)