Testing the download functionality of a JavaScript unit

I need assistance in writing a unit test for the following function. Currently, I am only tracking how many times appendChild/removeChild is being called, but I believe there might be a better way to test this. Additionally, as a beginner in testing, I am unsure of what the unit test should entail. Any guidance on this matter would be greatly appreciated!

export default function download(blobUrl, fileName) {
  const link = document.createElement('a');
  link.setAttribute('href', blobUrl);
  link.setAttribute('download', `${fileName}.pdf`);
  link.style.display = 'none';

  document.body.appendChild(link);

  link.click();

  document.body.removeChild(link);
}

Answer №1

Here is the solution I came up with:

index.ts:

export default function saveFile(blobUrl, fileName) {
  const link = document.createElement('a');
  link.setAttribute('href', blobUrl);
  link.setAttribute('download', `${fileName}.pdf`);
  link.style.display = 'none';

  document.body.appendChild(link);

  link.click();

  document.body.removeChild(link);
}

index.spec.ts:

import saveFile from './';

describe('save File', () => {
  test('should save file correctly', () => {
    const mLink = { href: '', click: jest.fn(), download: '', style: { display: '' }, setAttribute: jest.fn() } as any;
    const createElementSpy = jest.spyOn(document, 'createElement').mockReturnValueOnce(mLink);
    document.body.appendChild = jest.fn();
    document.body.removeChild = jest.fn();
    saveFile('blobUrl', 'go');
    expect(createElementSpy).toBeCalledWith('a');
    expect(mLink.setAttribute.mock.calls.length).toBe(2);
    expect(mLink.setAttribute.mock.calls[0]).toEqual(['href', 'blobUrl']);
    expect(mLink.setAttribute.mock.calls[1]).toEqual(['download', 'go.pdf']);
    expect(mLink.style.display).toBe('none');
    expect(document.body.appendChild).toBeCalledWith(mLink);
    expect(mLink.click).toBeCalled();
    expect(document.body.removeChild).toBeCalledWith(mLink);
  });
});

Unit test results are in with full coverage achieved:

 PASS  src/stackoverflow/58445250/index.spec.ts
  save File
    ✓ should save file correctly (8ms)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 index.ts |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.571s, estimated 8s

Check out the source code here: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58445250

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Exploring the world of jQuery and client-side API design paradigms and

I have inherited a rather rough jQuery script for managing API requests and responses in JSON format. Each 'page' has its own set of ajax calls, resulting in a lot of repetition. Does anyone know of a helpful blog post or jQuery plugin that can ...

What methods can be used to identify if a browser is mobile and adjust the size of a video accordingly using JavaScript conditions?

My goal is to incorporate JavaScript and jQuery into my HTML page in order to detect if visitors are using mobile browsers, and display a video at different sizes based on this information. I have experimented with various methods, but none of them have p ...

Exploring an Array in Javascript derived from a PHP Array

I have a PHP variable named $TillArray that contains an array. I am trying to pass this array to a Javascript function in order to display an Alert message for each item within the array. Below is the code I have been using: <script type="text/javasc ...

Navigating through an array of objects in JavaScript

I've been struggling to extract data from an array of objects using pure javascript, but I'm just not seeing the results. Issue Resolved! A big shoutout for the invaluable personal assistance! Turns out, the array was being passed as a string a ...

Ways to extract subarray elements that meet a certain condition and break out of the loop

const winningTemplate = { firstRow: [0, 1, 2, 3, 4], secondRow: [5, 6, 7, 8, 9], thirdRow: [10, 11, 13, 14], fourthRow: [15, 16, 17, 18, 19], lastRow: [20, 21, 22, 23, 24], firstDiagonal: [0, 6, 18, 24], firstColumn: [0, 5, 10, ...

Disabling ngIf but still utilizing ngContent will render the template bindings

Creating a basic component in the following way: @Component({ selector: 'loader', template: `<div *ngIf='false'> <ng-content></ng-content> </div>`, }) export class Loader {} When it is imple ...

Working with AngularJS's $q promise and socket.io

I am interested in creating an angularJS promise that can work seamlessly with socket.io. Currently, I have a callback function set up to handle the response like this: function request(event, data, callback) { socket.emit(event, data); socket.on( ...

Issues with the functionality of the AngularJS button directive

Currently, I am working on developing a RESTful API utilizing Angular and NodeJS. However, I have encountered an issue where a button to navigate to the details page of my application is unresponsive. While I believe the button itself is correctly coded, I ...

`Inquiry into AJAX form submission problem`

Here is the HTML markup and JS code for my signup page. I encountered an issue where, if I leave all text inputs blank and click submit for the first time, it validates and shows an error message. However, when I click submit a second time, it directly sen ...

Encountering issues with compiling files in react app using webpack, failing to compile as anticipated

When it comes to compiling, I prefer using webpack with TypeScript files. In my webpack.config.js file: module.exports = async (env, options) => { const dev = options.mode === "development"; const config = { //Webpack configuration pr ...

Is it possible for a conditional type in TypeScript to be based on its own value?

Is it possible to use this type in TypeScript? type Person = { who: string; } type Person = Person.who === "me" ? Person & Me : Person; ...

Vue.js v-else-if directive not functioning properly: Unable to resolve directive: else-if

I am encountering a compilation error while using "if" and "else-if". [Vue warn]: Failed to resolve directive: else-if Here is the code I am working with: var app = new Vue({ el:"#app", data:{ lab_status : 2 } }); <script src="https: ...

Enhancing a validation form with the 'onblur' event handler

Exploring the realm of JavaScript, I find myself intrigued by the concept of creating a validation form that activates upon clicking out of the input field. Implementing various techniques to integrate this feature into an existing form has been both chall ...

Tips for examining a rate-limited HTTP request function

I am trying to test a naive rate limiter I implemented in Node.js for making HTTP requests to an external service. The service has a limit of 10 requests per second, and I am facing timing issues with my current implementation. Despite being aware of the i ...

Pending status persists for Axios post request

Here is a straightforward example of a POST request using Axios within Vue: import axios from 'axios' export default { name: 'HelloWorld', props: { msg: String }, mounted () { const code = 'test&apo ...

Reduce the length of JavaScript code

Several weeks back, I received assistance with some code for a drop-down menu. However, I am now looking to optimize the code as it appears quite lengthy in its current form. Any tips or guidance on shortening this code would be greatly appreciated. ...

"Implementing a dependent dropdown feature within a CodeIgniter application using data from

I am working with a table called "drivers" that has fields for "id", "name", and "mob". Currently, I am facing an issue with 2 dropdowns on my website: The first dropdown should display the names of drivers fetched from the database The second dropdown ...

Configure vue.config.js to generate distinct pages based on different environments

Currently, I am utilizing Vue with webpack to construct a Multi-Page Application and have the following setup: pages: { index: { entry: ... template: ... ... } page1: { entry: ... template: ... ... } } I am looking to add a deb ...

Steps for deactivating a button until the form has been submitted

Click here for the Fiddle and code sample: $(".addtowatchlistform").submit(function(e) { var data = $(this).serialize(); var url = $(this).attr("action"); var form = $(this); // Additional line $.post(url, data, function(data) { try { ...

Guide to leveraging clsx within nested components in React

I am currently using clsx within a React application and encountering an issue with how to utilize it when dealing with mappings and nested components. For instance: return ( <div> <button onClick={doSomething}>{isOpened ? <Component ...