Testing a Jest unit on a function that invokes another function which in turn returns a Promise

I have a function that triggers another function which returns a Promise. Below is the code snippet for reference:

export const func1 = ({
  contentRef,
  onShareFile,
  t,
  trackOnShareFile,
}) => e => {
  trackOnShareFile()
  try {
    func2(contentRef).then(url => {
      onShareFile({
        title: t('shareFileTitle'),
        type: 'application/pdf',
        url,
      })
    }).catch(e => {
      if (process.env.NODE_ENV === 'development') {
        console.error(e)
      }
    })
    e.preventDefault()
  } catch (e) {
    if (process.env.NODE_ENV === 'development') {
      console.error(e)
    }
  }
}

The function func2, called within func1, looks something like this:

const func2 = element => {
  return import('html2pdf.js').then(html2pdf => {
    return html2pdf.default().set({ margin: 12 }).from(element).toPdf().output('datauristring').then(pdfAsString => {
      return pdfAsString.split(',')[1]
    }).then(base64String => {
      return `data:application/pdf;base64,${base64String}`
    })
  })
}

I am currently working on writing unit tests for func1 but facing some challenges. So far, I've tried the following:

describe('#func1', () => {
  it('calls `trackOnShareFile`', () => {
      // given
      const props = {
        trackOnShareFile: jest.fn(),
        onShareFile: jest.fn(),
        shareFileTitle: 'foo',
        contentRef: { innerHTML: '<div>hello world</div>' },
      }
      const eventMock = {
        preventDefault: () => {},
      }
      // when
      func1(props)(eventMock)
      // then
      expect(props.trackOnShareFile).toBeCalledTimes(1)
    })
    it('calls `onShareFile` prop', () => {
      // given
      const props = {
        trackOnShareFile: jest.fn(),
        onShareFile: jest.fn(),
        shareFileTitle: 'foo',
        contentRef: { innerHTML: '<div>hello world</div>' },
      }
      const eventMock = {
        preventDefault: () => {},
      }
      // when
      func1(props)(eventMock)
      // then
      expect(props.onShareFile).toBeCalledTimes(1)
    })
  })

While the first test passes successfully, the second one throws an error stating

Expected mock function to have been called one time, but it was called zero times.
. I'm seeking guidance on how to correctly write this test. Any assistance would be greatly appreciated.

Answer №1

Sweet, I finally got it to work!

To kick things off, we need to simulate the data-url-generator (which is where we bring in func2). The html2pdf library won't function properly in the testing environment due to its use of a fake DOM that lacks complete canvas graphics support.

jest.mock('./data-url-generator', () => jest.fn())

Next, the test can be written as follows:

it('triggers the `onShareFile` prop', done => {
    // given
    const t = key => `[${key}]`
    const urlMock = 'data:application/pdf;base64,PGh0bWw+PGJvZHk+PGRpdj5oZWxsbyB3b3JsZDwvZGl2PjwvYm9keT48L2h0bWw+'
    const shareFileTitle = 'bar'
    const contentRef = document.createElement('div')
    contentRef.textContent = 'hello world'
    const trackOnShareFile = () => { }
    const eventMock = {
      preventDefault: () => { },
    }
    func2.mockResolvedValue(urlMock)
    const onShareFileMock = ({ title, type, url }) => {
      // then
      expect(func2).toHaveBeenCalledTimes(1)
      expect(func2).toHaveBeenCalledWith(contentRef)
      expect(title).toBe('[shareFileTitle]')
      expect(type).toBe('application/pdf')
      expect(url).toBe(urlMock)
      done()
    }
    // when
    func1({
      contentRef,
      onShareFile: onShareFileMock,
      shareFileTitle,
      t,
      trackOnShareFile,
    })(eventMock)
  })

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

Is there a way to nest arrays within arrays in JavaScript?

Array ( [0] => Array ( [contactId] => 5 [companyId] => 54 [personName] => Awais [contactNo] => 0321-1111111 [contactType] => Partner ) ) data[0].personName I ...

Exploring multiple global styles within a component in Next.js

I have encountered a challenge in my Next.js project. Currently, I am using a component that imports only one CSS file like this: import stylesheet from '../src/styles/first.scss'; This CSS file is then utilized in the following manner: return ( ...

Is it possible to perform direct URL searches using react-router-dom?

Encountering an issue when attempting to directly copy a route, resulting in the following error: Error: Cannot Access / home Despite utilizing various methods such as browserHistory, I am unable to successfully render views when navigating with menu i ...

React Router imports and renders multiple components

I'm currently working on developing a basic Login System. When I try to register, both components are loaded into the App Component. Here is my code: class App extends React.Component { render() { return ( <div className="row"> ...

The sorting function is failing to produce the expected order of values

Currently, I am working on a feature to sort an array of objects based on user-selected values. Strangely, the function returns the same result no matter which case is executed. I have thoroughly checked each case and they are functioning correctly; howeve ...

Navigate to the location using AngularJS elements in the JavaScript iframe1

Dealing with an issue while working on AngularJS. I am facing a frustrating problem where I am attempting to use one link to open links in two separate iframes. All aspects of this function correctly, except for the actual links. The issue arises when usin ...

Click-triggered CSS animations

Trying to achieve an effect with regular JS (not jQuery) by making images shake after they are clicked, but running into issues. HTML: <img id='s1_imgB' class="fragment"... onClick="wrongAnswer()"... JS: function wrongAnswer(){ docume ...

Locating the JSON path within an object

Need help with checking if a specific path is present in a JSON object? var data = { "schemaOne": { "name": "abc", "Path": "i.abc", "count": 5347, "subFolders": [ ] }, "schemaTwo": { "name": "cde", "Path": "i.cde", " ...

Remove any words that are not included in the specified list

Here is the code snippet to achieve the desired functionality: const { words } = require("../../json/words.json") const args = message.content.split(' ') const wordss = words.filter(m=> m.includes(args)) if(args > 1 || !wordss) { ...

Trouble encountered with images failing to load after deployment on Vercel platform

I am in the process of creating a portfolio website and need to showcase multiple images and videos for each project. Here is the folder structure I have set up: Currently, I am using a map function to fetch and display all the images: { project.Images. ...

Utilizing the Global Module in NestJs: A Step-by-Step Guide

My current project is built using NestJS for the back-end. I recently discovered that in NestJS, we have the ability to create Global Modules. Here is an example of how my global module is structured: //Module import {Global, Module} from "@nestjs/commo ...

Replace the function if it is specified in the object, otherwise use the default functionality

Having a calendar widget written in TypeScript, I am able to bind a listener to a separate function. However, I desire this separate function to have default functionality until someone overrides it in the config object passed to the constructor. Within th ...

What is the best way to store data from multiple selected rows in different datagrids into a single state?

Programming Languages : JavaScript with React, Redux Toolkit, and Material-UI Issue : My goal is to synchronize the selection of checkboxes across multiple datagrids into one central state Attempts Made : I first attempted to manage checkbox selection fo ...

The JavaScript function modifies the value stored in the local storage

I'm in the process of developing a website that requires updating the value of my local storage when certain JavaScript functions are executed. Currently, I have this code snippet: localStorage.setItem('colorvar', '#EBDBC2'); I&ap ...

What is the process for adding a dot to the package.json file using the npm-pkg command?

I need help using the npm pkg set command to create a package.json file with the following structure: { ... "exports": { ".": { "import": "./dist/my-lib.js", "require": "./dist/my-l ...

What is the best way to showcase a table below a form containing multiple inputs using JavaScript?

Context: The form I have contains various input fields. Upon pressing the [verify] button, only the "first name" is displayed. My goal is to display all input fields, whether empty or filled, in a table format similar to that of the form. Exploration: ...

Push the accordion tab upwards towards the top of the browser

I am working on an accordion menu that contains lengthy content. To improve user experience, I want to implement a slide effect when the accordion content is opened. Currently, when the first two menu items are opened, the content of the last item is disp ...

Font size determined by both the width and height of the viewport

I'll be brief and direct, so hear me out: When using VW, the font-size changes based on the viewport width. With VH, the font-size adjusts according to the viewport height. Now, I have a question: Is there a way to scale my font-size based on ...

How can I create a custom AppBar transition using Material-UI?

Is there a way to incorporate transitions into the AppBar element within Material-UI? I have tried adjusting the class properties, but unfortunately, I'm not seeing any animation. Can anyone pinpoint what the issue might be? To see the code in action ...

What is the best way to iterate through an ID using jQuery?

After pulling the list of doctors in my area from the database and displaying it on my webpage, I now want to load each doctor's "About" content inside a Bootstrap modal. I added an "about" column within the same database table where the doctors' ...